Merge branch 'backport-3.16-link-libs-config-case'
diff --git a/.clang-format b/.clang-format
index 0c7d6b0..4bfce44 100644
--- a/.clang-format
+++ b/.clang-format
@@ -22,7 +22,9 @@
 IncludeCategories:
   - Regex:           '^[<"]cmConfigure\.h'
     Priority:        -1
-  - Regex:           '^(<|")cm/'
+  - Regex:           '^<queue>'
+    Priority:        1
+  - Regex:           '^(<|")cm(ext)?/'
     Priority:        2
   - Regex:           '^(<|")windows\.h'
     Priority:        3
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim
index 5de117b..0676f7e 100644
--- a/Auxiliary/vim/syntax/cmake.vim
+++ b/Auxiliary/vim/syntax/cmake.vim
@@ -101,6 +101,7 @@
             \ CLEAN_NO_CUSTOM
             \ CMAKE_CONFIGURE_DEPENDS
             \ CMAKE_CXX_KNOWN_FEATURES
+            \ CMAKE_CUDA_KNOWN_FEATURES
             \ CMAKE_C_KNOWN_FEATURES
             \ CMAKE_ROLE
             \ COMMON_LANGUAGE_RUNTIME
@@ -220,6 +221,7 @@
             \ JOB_POOLS
             \ JOB_POOL_COMPILE
             \ JOB_POOL_LINK
+            \ JOB_POOL_PRECOMPILE_HEADER
             \ KEEP_EXTENSION
             \ LABELS
             \ LANGUAGE
@@ -725,6 +727,7 @@
             \ CMAKE_CUDA_COMPILER_AR
             \ CMAKE_CUDA_COMPILER_ARCHITECTURE_ID
             \ CMAKE_CUDA_COMPILER_EXTERNAL_TOOLCHAIN
+            \ CMAKE_CUDA_COMPILE_FEATURES
             \ CMAKE_CUDA_COMPILER_ID
             \ CMAKE_CUDA_COMPILER_LAUNCHER
             \ CMAKE_CUDA_COMPILER_LOADED
@@ -1064,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
@@ -2862,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
@@ -3166,6 +3175,7 @@
             \ target_link_directories
             \ target_link_libraries
             \ target_link_options
+            \ target_precompile_headers
             \ target_sources
             \ try_compile
             \ try_run
@@ -3322,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..18b8d7d 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()
 
 
@@ -368,7 +367,7 @@
   # Setup third-party libraries.
   # Everything in the tree should be able to include files from the
   # Utilities directory.
-  if (CMAKE_SYSTEM_NAME STREQUAL "AIX" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+  if ((CMAKE_SYSTEM_NAME STREQUAL "AIX" OR CMAKE_SYSTEM_NAME STREQUAL "OS400") AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
     # using -isystem option generate error "template with C linkage"
     include_directories("${CMake_SOURCE_DIR}/Utilities/std")
   else()
@@ -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/CTestCustom.cmake.in b/CTestCustom.cmake.in
index d3ab9d3..fb8e099 100644
--- a/CTestCustom.cmake.in
+++ b/CTestCustom.cmake.in
@@ -72,6 +72,7 @@
   "cm(StringCommand|CTestTestHandler)\\.cxx.*warning.*rand.*isn.*t random" # we do not do crypto
   "cm(StringCommand|CTestTestHandler)\\.cxx.*warning.*srand.*seed choices are.*poor" # we do not do crypto
   "IPA warning: function.*multiply defined in"
+  "LICENSE WARNING" # PGI license expiry.  Not useful in nightly testing.
 
   # Ignore compiler summary warning, assuming prior text has matched some
   # other warning expression:
diff --git a/Copyright.txt b/Copyright.txt
index f236214..b867d01 100644
--- a/Copyright.txt
+++ b/Copyright.txt
@@ -1,5 +1,5 @@
 CMake - Cross Platform Makefile Generator
-Copyright 2000-2019 Kitware, Inc. and Contributors
+Copyright 2000-2020 Kitware, Inc. and Contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -99,6 +99,7 @@
 * Sebastian Holtermann <sebholt@xwmw.org>
 * Stephen Kelly <steveire@gmail.com>
 * Sylvain Joubert <joubert.sy@gmail.com>
+* The Qt Company Ltd.
 * Thomas Sondergaard <ts@medical-insight.com>
 * Tobias Hunger <tobias.hunger@qt.io>
 * Todd Gamblin <tgamblin@llnl.gov>
diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst
index aba3742..9279748 100644
--- a/Help/command/add_custom_command.rst
+++ b/Help/command/add_custom_command.rst
@@ -68,6 +68,9 @@
   order-only dependencies to ensure the byproducts will be
   available before their dependents build.
 
+  The :ref:`Makefile Generators` will remove ``BYPRODUCTS`` and other
+  :prop_sf:`GENERATED` files during ``make clean``.
+
 ``COMMAND``
   Specify the command-line(s) to execute at build time.
   If more than one ``COMMAND`` is specified they will be executed in order,
@@ -112,24 +115,42 @@
   build time.
 
 ``DEPENDS``
-  Specify files on which the command depends.  If any dependency is
-  an ``OUTPUT`` of another custom command in the same directory
-  (``CMakeLists.txt`` file) CMake automatically brings the other
+  Specify files on which the command depends.  Each argument is converted
+  to a dependency as follows:
+
+  1. If the argument is the name of a target (created by the
+     :command:`add_custom_target`, :command:`add_executable`, or
+     :command:`add_library` command) a target-level dependency is
+     created to make sure the target is built before any target
+     using this custom command.  Additionally, if the target is an
+     executable or library, a file-level dependency is created to
+     cause the custom command to re-run whenever the target is
+     recompiled.
+
+  2. If the argument is an absolute path, a file-level dependency
+     is created on that path.
+
+  3. If the argument is the name of a source file that has been
+     added to a target or on which a source file property has been set,
+     a file-level dependency is created on that source file.
+
+  4. If the argument is a relative path and it exists in the current
+     source directory, a file-level dependency is created on that
+     file in the current source directory.
+
+  5. Otherwise, a file-level dependency is created on that path relative
+     to the current binary directory.
+
+  If any dependency is an ``OUTPUT`` of another custom command in the same
+  directory (``CMakeLists.txt`` file), CMake automatically brings the other
   custom command into the target in which this command is built.
   A target-level dependency is added if any dependency is listed as
   ``BYPRODUCTS`` of a target or any of its build events in the same
   directory to ensure the byproducts will be available.
-  If ``DEPENDS`` is not specified the command will run whenever
+
+  If ``DEPENDS`` is not specified, the command will run whenever
   the ``OUTPUT`` is missing; if the command does not actually
-  create the ``OUTPUT`` then the rule will always run.
-  If ``DEPENDS`` specifies any target (created by the
-  :command:`add_custom_target`, :command:`add_executable`, or
-  :command:`add_library` command) a target-level dependency is
-  created to make sure the target is built before any target
-  using this custom command.  Additionally, if the target is an
-  executable or library a file-level dependency is created to
-  cause the custom command to re-run whenever the target is
-  recompiled.
+  create the ``OUTPUT``, the rule will always run.
 
   Arguments to ``DEPENDS`` may use
   :manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/command/add_custom_target.rst b/Help/command/add_custom_target.rst
index 2d5f5f0..56ab414 100644
--- a/Help/command/add_custom_target.rst
+++ b/Help/command/add_custom_target.rst
@@ -49,6 +49,9 @@
   order-only dependencies to ensure the byproducts will be
   available before their dependents build.
 
+  The :ref:`Makefile Generators` will remove ``BYPRODUCTS`` and other
+  :prop_sf:`GENERATED` files during ``make clean``.
+
 ``COMMAND``
   Specify the command-line(s) to execute at build time.
   If more than one ``COMMAND`` is specified they will be executed in order,
diff --git a/Help/command/ctest_test.rst b/Help/command/ctest_test.rst
index 7a3393b..5c67b2c 100644
--- a/Help/command/ctest_test.rst
+++ b/Help/command/ctest_test.rst
@@ -23,6 +23,7 @@
              [STOP_TIME <time-of-day>]
              [RETURN_VALUE <result-var>]
              [CAPTURE_CMAKE_ERROR <result-var>]
+             [REPEAT <mode>:<n>]
              [QUIET]
              )
 
@@ -95,6 +96,25 @@
   and then the ``--test-load`` command-line argument to :manual:`ctest(1)`.
   See also the ``TestLoad`` setting in the :ref:`CTest Test Step`.
 
+``REPEAT <mode>:<n>``
+  Run tests repeatedly based on the given ``<mode>`` up to ``<n>`` times.
+  The modes are:
+
+  ``UNTIL_FAIL``
+    Require each test to run ``<n>`` times without failing in order to pass.
+    This is useful in finding sporadic failures in test cases.
+
+  ``UNTIL_PASS``
+    Allow each test to run up to ``<n>`` times in order to pass.
+    Repeats tests if they fail for any reason.
+    This is useful in tolerating sporadic failures in test cases.
+
+  ``AFTER_TIMEOUT``
+    Allow each test to run up to ``<n>`` times in order to pass.
+    Repeats tests only if they timeout.
+    This is useful in tolerating sporadic timeouts in test cases
+    on busy machines.
+
 ``SCHEDULE_RANDOM <ON|OFF>``
   Launch tests in a random order.  This may be useful for detecting
   implicit test dependencies.
diff --git a/Help/command/file.rst b/Help/command/file.rst
index b186177..df7d8ba 100644
--- a/Help/command/file.rst
+++ b/Help/command/file.rst
@@ -540,7 +540,7 @@
 By default ``GLOB_RECURSE`` omits directories from result list - setting
 ``LIST_DIRECTORIES`` to true adds directories to result list.
 If ``FOLLOW_SYMLINKS`` is given or policy :policy:`CMP0009` is not set to
-``OLD`` then ``LIST_DIRECTORIES`` treats symlinks as directories.
+``NEW`` then ``LIST_DIRECTORIES`` treats symlinks as directories.
 
 Examples of recursive globbing include::
 
diff --git a/Help/command/foreach.rst b/Help/command/foreach.rst
index ae2afb2..a01a104 100644
--- a/Help/command/foreach.rst
+++ b/Help/command/foreach.rst
@@ -47,7 +47,7 @@
 
 .. code-block:: cmake
 
-  foreach(loop_var IN [LISTS [<lists>]] [ITEMS [<items>]])
+  foreach(<loop_var> IN [LISTS [<lists>]] [ITEMS [<items>]])
 
 In this variant, ``<lists>`` is a whitespace or semicolon
 separated list of list-valued variables. The ``foreach``
@@ -82,3 +82,46 @@
   -- X=6
   -- X=7
   -- X=8
+
+
+.. code-block:: cmake
+
+  foreach(<loop_var>... IN ZIP_LISTS <lists>)
+
+In this variant, ``<lists>`` is a whitespace or semicolon
+separated list of list-valued variables. The ``foreach``
+command iterates over each list simultaneously setting the
+iteration variables as follows:
+
+- if the only ``loop_var`` given, then it sets a series of
+  ``loop_var_N`` variables to the current item from the
+  corresponding list;
+- if multiple variable names passed, their count should match
+  the lists variables count;
+- if any of the lists are shorter, the corresponding iteration
+  variable is not defined for the current iteration.
+
+.. code-block:: cmake
+
+  list(APPEND English one two three four)
+  list(APPEND Bahasa satu dua tiga)
+
+  foreach(num IN ZIP_LISTS English Bahasa)
+      message(STATUS "num_0=${num_0}, num_1=${num_1}")
+  endforeach()
+
+  foreach(en ba IN ZIP_LISTS English Bahasa)
+      message(STATUS "en=${en}, ba=${ba}")
+  endforeach()
+
+yields
+::
+
+  -- num_0=one, num_1=satu
+  -- num_0=two, num_1=dua
+  -- num_0=three, num_1=tiga
+  -- num_0=four, num_1=
+  -- en=one, ba=satu
+  -- en=two, ba=dua
+  -- en=three, ba=tiga
+  -- en=four, ba=
diff --git a/Help/command/macro.rst b/Help/command/macro.rst
index 05e5d79..3f6f2f9 100644
--- a/Help/command/macro.rst
+++ b/Help/command/macro.rst
@@ -91,6 +91,12 @@
 from the scope of the macro call.  To avoid confusion, it is recommended
 to avoid :command:`return()` in macros altogether.
 
+Unlike a function, the :variable:`CMAKE_CURRENT_FUNCTION`,
+:variable:`CMAKE_CURRENT_FUNCTION_LIST_DIR`,
+:variable:`CMAKE_CURRENT_FUNCTION_LIST_FILE`,
+:variable:`CMAKE_CURRENT_FUNCTION_LIST_LINE` variables are not
+set for macro.
+
 .. _`Argument Caveats`:
 
 Argument Caveats
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/command/message.rst b/Help/command/message.rst
index c614286..6bc0e4c 100644
--- a/Help/command/message.rst
+++ b/Help/command/message.rst
@@ -1,13 +1,33 @@
 message
 -------
 
-Display a message to the user.
+Log a message.
+
+Synopsis
+^^^^^^^^
+
+.. parsed-literal::
+
+  `General messages`_
+    message([<mode>] "message text" ...)
+
+  `Reporting checks`_
+    message(<checkState> "message text" ...)
+
+
+General messages
+^^^^^^^^^^^^^^^^
 
 .. code-block:: cmake
 
-  message([<mode>] "message to display" ...)
+  message([<mode>] "message text" ...)
 
-The optional ``<mode>`` keyword determines the type of message:
+Record the specified message text in the log.  If more than one message
+string is given, they are concatenated into a single message with no
+separator between the strings.
+
+The optional ``<mode>`` keyword determines the type of message, which
+influences the way the message is handled:
 
 ``FATAL_ERROR``
   CMake Error, stop processing and generation.
@@ -59,12 +79,104 @@
 messages one at a time on a status line and other messages in an
 interactive pop-up box.  The ``--log-level`` command-line option to each of
 these tools can be used to control which messages will be shown.
+To make a log level persist between CMake runs, the
+:variable:`CMAKE_MESSAGE_LOG_LEVEL` variable can be set instead.
+Note that the command line option takes precedence over the cache variable.
 
-Messages of log levels ``NOTICE`` and below will also have each line preceded
+Messages of log levels ``NOTICE`` and below will have each line preceded
 by the content of the :variable:`CMAKE_MESSAGE_INDENT` variable (converted to
 a single string by concatenating its list items).  For ``STATUS`` to ``TRACE``
 messages, this indenting content will be inserted after the hyphens.
 
+Messages of log levels ``NOTICE`` and below can also have each line preceded
+with context of the form ``[some.context.example]``.  The content between the
+square brackets is obtained by converting the :variable:`CMAKE_MESSAGE_CONTEXT`
+list variable to a dot-separated string.  The message context will always
+appear before any indenting content but after any automatically added leading
+hyphens. By default, message context is not shown, it has to be explicitly
+enabled by giving the :manual:`cmake <cmake(1)>` ``--log-context``
+command-line option or by setting the :variable:`CMAKE_MESSAGE_CONTEXT_SHOW`
+variable to true.  See the :variable:`CMAKE_MESSAGE_CONTEXT` documentation for
+usage examples.
+
 CMake Warning and Error message text displays using a simple markup
 language.  Non-indented text is formatted in line-wrapped paragraphs
 delimited by newlines.  Indented text is considered pre-formatted.
+
+
+Reporting checks
+^^^^^^^^^^^^^^^^
+
+A common pattern in CMake output is a message indicating the start of some
+sort of check, followed by another message reporting the result of that check.
+For example:
+
+.. code-block:: cmake
+
+  message(STATUS "Looking for someheader.h")
+  #... do the checks, set checkSuccess with the result
+  if(checkSuccess)
+    message(STATUS "Looking for someheader.h - found")
+  else()
+    message(STATUS "Looking for someheader.h - not found")
+  endif()
+
+This can be more robustly and conveniently expressed using the ``CHECK_...``
+keyword form of the ``message()`` command:
+
+.. code-block:: cmake
+
+  message(<checkState> "message" ...)
+
+where ``<checkState>`` must be one of the following:
+
+  ``CHECK_START``
+    Record a concise message about the check about to be performed.
+
+  ``CHECK_PASS``
+    Record a successful result for a check.
+
+  ``CHECK_FAIL``
+    Record an unsuccessful result for a check.
+
+When recording a check result, the command repeats the message from the most
+recently started check for which no result has yet been reported, then some
+separator characters and then the message text provided after the
+``CHECK_PASS`` or ``CHECK_FAIL`` keyword.  Check messages are always reported
+at ``STATUS`` log level.
+
+Checks may be nested and every ``CHECK_START`` should have exactly one
+matching ``CHECK_PASS`` or ``CHECK_FAIL``.
+The :variable:`CMAKE_MESSAGE_INDENT` variable can also be used to add
+indenting to nested checks if desired.  For example:
+
+.. code-block:: cmake
+
+  message(CHECK_START "Finding my things")
+  list(APPEND CMAKE_MESSAGE_INDENT "  ")
+  unset(missingComponents)
+
+  message(CHECK_START "Finding partA")
+  # ... do check, assume we find A
+  message(CHECK_PASS "found")
+
+  message(CHECK_START "Finding partB")
+  # ... do check, assume we don't find B
+  list(APPEND missingComponents B)
+  message(CHECK_FAIL "not found")
+
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+  if(missingComponents)
+    message(CHECK_FAIL "missing components: ${missingComponents}")
+  else()
+    message(CHECK_PASS "all components found")
+  endif()
+
+Output from the above would appear something like the following::
+
+  -- Finding my things
+  --   Finding partA
+  --   Finding partA - found
+  --   Finding partB
+  --   Finding partB - not found
+  -- Finding my things - missing components: B
diff --git a/Help/command/project.rst b/Help/command/project.rst
index 3951456..b6093d3 100644
--- a/Help/command/project.rst
+++ b/Help/command/project.rst
@@ -102,9 +102,12 @@
 Code Injection
 ^^^^^^^^^^^^^^
 
-If the :variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variable is set, the file
-pointed to by that variable will be included as the first step of the
+If the :variable:`CMAKE_PROJECT_INCLUDE_BEFORE` or
+:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE` variables are set,
+the files they point to will be included as the first step of the
 ``project()`` command.
+If both are set, then :variable:`CMAKE_PROJECT_INCLUDE_BEFORE` will be
+included before :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`.
 
 If the :variable:`CMAKE_PROJECT_INCLUDE` or
 :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE` variables are set, the files
diff --git a/Help/command/target_compile_features.rst b/Help/command/target_compile_features.rst
index 9271cd5..c5401e6 100644
--- a/Help/command/target_compile_features.rst
+++ b/Help/command/target_compile_features.rst
@@ -8,9 +8,9 @@
   target_compile_features(<target> <PRIVATE|PUBLIC|INTERFACE> <feature> [...])
 
 Specifies compiler features required when compiling a given target.  If the
-feature is not listed in the :variable:`CMAKE_C_COMPILE_FEATURES` variable
-or :variable:`CMAKE_CXX_COMPILE_FEATURES` variable,
-then an error will be reported by CMake.  If the use of the feature requires
+feature is not listed in the :variable:`CMAKE_C_COMPILE_FEATURES`,
+:variable:`CMAKE_CUDA_COMPILE_FEATURES`, or :variable:`CMAKE_CXX_COMPILE_FEATURES`
+variables, then an error will be reported by CMake.  If the use of the feature requires
 an additional compiler flag, such as ``-std=gnu++11``, the flag will be added
 automatically.
 
diff --git a/Help/cpack_gen/dmg.rst b/Help/cpack_gen/dmg.rst
index 1e37889..cede0f2 100644
--- a/Help/cpack_gen/dmg.rst
+++ b/Help/cpack_gen/dmg.rst
@@ -54,10 +54,12 @@
 
   Directory where license and menu files for different languages are stored.
   Setting this causes CPack to look for a ``<language>.menu.txt`` and
-  ``<language>.license.txt`` file for every language defined in
-  ``CPACK_DMG_SLA_LANGUAGES``. If both this variable and
+  ``<language>.license.txt`` or ``<language>.license.rtf`` file for every
+  language defined in ``CPACK_DMG_SLA_LANGUAGES``.  If both this variable and
   ``CPACK_RESOURCE_FILE_LICENSE`` are set, CPack will only look for the menu
-  files and use the same license file for all languages.
+  files and use the same license file for all languages.  If both
+  ``<language>.license.txt`` and ``<language>.license.rtf`` exist, the ``.txt``
+  file will be used.
 
 .. variable:: CPACK_DMG_SLA_LANGUAGES
 
@@ -81,6 +83,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/cpack_gen/ifw.rst b/Help/cpack_gen/ifw.rst
index feccd3d..4a9ab99 100644
--- a/Help/cpack_gen/ifw.rst
+++ b/Help/cpack_gen/ifw.rst
@@ -1,43 +1,38 @@
 CPack IFW Generator
 -------------------
 
-See :module:`CPackIFW` for details on the CPackIFW module.
-
-.. _QtIFW: http://doc.qt.io/qtinstallerframework/index.html
-
-
 Overview
 ^^^^^^^^
 
-CPack ``IFW`` generator helps you to create online and offline
-binary cross-platform installers with a graphical user interface.
+This :manual:`cpack generator <cpack-generators(7)>` generates
+configuration and meta information for the `Qt Installer Framework
+<http://doc.qt.io/qtinstallerframework/index.html>`_ (QtIFW).
 
-CPack IFW generator prepares project installation and generates configuration
-and meta information for QtIFW_ tools.
+QtIFW provides tools and utilities to create installers for
+the platforms supported by `Qt <https://www.qt.io>`_: Linux,
+Microsoft Windows, and macOS.
 
-The QtIFW_ provides a set of tools and utilities to create
-installers for the supported desktop Qt platforms: Linux, Microsoft Windows,
-and macOS.
-
-You should also install QtIFW_ to use CPack ``IFW`` generator.
+To make use of this generator, QtIFW should also be installed.
+The module :module:`CPackIFW` looks for the location of the
+QtIFW command-line utilities.
 
 Hints
 ^^^^^
 
-Generally, the CPack ``IFW`` generator automatically finds QtIFW_ tools,
-but if you don't use a default path for installation of the QtIFW_ tools,
+Generally, the CPack ``IFW`` generator automatically finds QtIFW tools,
+but if you don't use a default path for installation of the QtIFW tools,
 the path may be specified in either a CMake or an environment variable:
 
 .. variable:: CPACK_IFW_ROOT
 
- An CMake variable which specifies the location of the QtIFW_ tool suite.
+ An CMake variable which specifies the location of the QtIFW tool suite.
 
  The variable will be cached in the ``CPackConfig.cmake`` file and used at
  CPack runtime.
 
 .. variable:: QTIFWDIR
 
- An environment variable which specifies the location of the QtIFW_ tool
+ An environment variable which specifies the location of the QtIFW tool
  suite.
 
 .. note::
@@ -53,7 +48,7 @@
 Some variables and command arguments support internationalization via
 CMake script. This is an optional feature.
 
-Installers created by QtIFW_ tools have built-in support for
+Installers created by QtIFW tools have built-in support for
 internationalization and many phrases are localized to many languages,
 but this does not apply to the description of the your components and groups
 that will be distributed.
@@ -185,7 +180,7 @@
  Filename of the generated maintenance tool.
  The platform-specific executable file extension is appended.
 
- By default used QtIFW_ defaults (``maintenancetool``).
+ By default used QtIFW defaults (``maintenancetool``).
 
 .. variable:: CPACK_IFW_PACKAGE_REMOVE_TARGET_DIR
 
@@ -197,19 +192,19 @@
 
  Filename for the configuration of the generated maintenance tool.
 
- By default used QtIFW_ defaults (``maintenancetool.ini``).
+ By default used QtIFW defaults (``maintenancetool.ini``).
 
 .. variable:: CPACK_IFW_PACKAGE_ALLOW_NON_ASCII_CHARACTERS
 
  Set to ``ON`` if the installation path can contain non-ASCII characters.
 
- Is ``ON`` for QtIFW_ less 2.0 tools.
+ Is ``ON`` for QtIFW less 2.0 tools.
 
 .. variable:: CPACK_IFW_PACKAGE_ALLOW_SPACE_IN_PATH
 
  Set to ``OFF`` if the installation path cannot contain space characters.
 
- Is ``ON`` for QtIFW_ less 2.0 tools.
+ Is ``ON`` for QtIFW less 2.0 tools.
 
 .. variable:: CPACK_IFW_PACKAGE_CONTROL_SCRIPT
 
@@ -266,14 +261,14 @@
 
  Additional prepared repository dirs that will be used to resolve and
  repack dependent components. This feature available only
- since QtIFW_ 3.1.
+ since QtIFW 3.1.
 
 Tools
 """""
 
 .. variable:: CPACK_IFW_FRAMEWORK_VERSION
 
- The version of used QtIFW_ tools.
+ The version of used QtIFW tools.
 
 .. variable:: CPACK_IFW_BINARYCREATOR_EXECUTABLE
 
diff --git a/Help/cpack_gen/nsis.rst b/Help/cpack_gen/nsis.rst
index cd2aea6..a310e9f 100644
--- a/Help/cpack_gen/nsis.rst
+++ b/Help/cpack_gen/nsis.rst
@@ -128,3 +128,28 @@
   set(CPACK_NSIS_MENU_LINKS
       "doc/cmake-@CMake_VERSION_MAJOR@.@CMake_VERSION_MINOR@/cmake.html"
       "CMake Help" "https://cmake.org" "CMake Web Site")
+
+.. variable:: CPACK_NSIS_UNINSTALL_NAME
+
+ Specify the name of the program to uninstall the version.
+ Default is ``Uninstall``.
+
+.. variable:: CPACK_NSIS_WELCOME_TITLE
+
+  The title to display on the top of the page for the welcome page.
+
+.. variable:: CPACK_NSIS_WELCOME_TITLE_3LINES
+
+ Display the title in the welcome page on 3 lines instead of 2.
+
+.. variable:: CPACK_NSIS_FINISH_TITLE
+
+ The title to display on the top of the page for the finish page.
+
+.. variable:: CPACK_NSIS_FINISH_TITLE_3LINES
+
+ Display the title in the finish page on 3 lines instead of 2.
+
+.. variable:: CPACK_NSIS_MUI_HEADERIMAGE
+
+ The image to display on the header of installers pages.
diff --git a/Help/cpack_gen/packagemaker.rst b/Help/cpack_gen/packagemaker.rst
index e9464b7..c2a450e 100644
--- a/Help/cpack_gen/packagemaker.rst
+++ b/Help/cpack_gen/packagemaker.rst
@@ -3,6 +3,11 @@
 
 PackageMaker CPack generator (macOS).
 
+.. deprecated:: 3.17
+
+  Xcode no longer distributes the PackageMaker tools.
+  This CPack generator will be removed in a future version of CPack.
+
 Variables specific to CPack PackageMaker generator
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -15,9 +20,60 @@
  compatible with. Different versions of macOS support different
  features. For example, CPack can only build component-based installers for
  macOS 10.4 or newer, and can only build installers that download
- component son-the-fly for macOS 10.5 or newer. If left blank, this value
+ components on-the-fly for macOS 10.5 or newer. If left blank, this value
  will be set to the minimum version of macOS that supports the requested
  features. Set this variable to some value (e.g., 10.4) only if you want to
  guarantee that your installer will work on that version of macOS, and
  don't mind missing extra features available in the installer shipping with
  later versions of macOS.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND
+
+ Adds a background to Distribtion XML if specified. The value contains the
+ path to image in ``Resources`` directory.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_ALIGNMENT
+
+ Adds an ``alignment`` attribute to the background in Distribution XML.
+ Refer to Apple documentation for valid values.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_SCALING
+
+ Adds a ``scaling`` attribute to the background in Distribution XML.
+ Refer to Apple documentation for valid values.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_MIME_TYPE
+
+ Adds a ``mime-type`` attribute to the background in Distribution XML.
+ The option contains MIME type of an image.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_UTI
+
+ Adds an ``uti`` attribute to the background in Distribution XML.
+ The option contains UTI type of an image.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_DARKAQUA
+
+ Adds a background for the Dark Aqua theme to Distribution XML if
+ specified. The value contains the path to image in ``Resources``
+ directory.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_DARKAQUA_ALIGNMENT
+
+ Does the same as :variable:`CPACK_PACKAGEMAKER_BACKGROUND_ALIGNMENT` option,
+ but for the dark theme.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_DARKAQUA_SCALING
+
+ Does the same as :variable:`CPACK_PACKAGEMAKER_BACKGROUND_SCALING` option,
+ but for the dark theme.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_DARKAQUA_MIME_TYPE
+
+ Does the same as :variable:`CPACK_PACKAGEMAKER_BACKGROUND_MIME_TYPE` option,
+ but for the dark theme.
+
+.. variable:: CPACK_PACKAGEMAKER_BACKGROUND_DARKAQUA_UTI
+
+ Does the same as :variable:`CPACK_PACKAGEMAKER_BACKGROUND_UTI` option,
+ but for the dark theme.
diff --git a/Help/cpack_gen/productbuild.rst b/Help/cpack_gen/productbuild.rst
index d22fcd4..82b79ae 100644
--- a/Help/cpack_gen/productbuild.rst
+++ b/Help/cpack_gen/productbuild.rst
@@ -58,7 +58,6 @@
  component name.  No ``postinstall`` script is added if this variable is not
  defined for a given component.
 
-
 .. variable:: CPACK_PRODUCTBUILD_RESOURCES_DIR
 
  If specified the productbuild generator copies files from this directory
@@ -66,3 +65,54 @@
  before the :variable:`CPACK_RESOURCE_FILE_WELCOME`,
  :variable:`CPACK_RESOURCE_FILE_README`, and
  :variable:`CPACK_RESOURCE_FILE_LICENSE` files are copied.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND
+
+ Adds a background to Distribtion XML if specified. The value contains the
+ path to image in ``Resources`` directory.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_ALIGNMENT
+
+ Adds an ``alignment`` attribute to the background in Distribution XML.
+ Refer to Apple documentation for valid values.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_SCALING
+
+ Adds a ``scaling`` attribute to the background in Distribution XML.
+ Refer to Apple documentation for valid values.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_MIME_TYPE
+
+ Adds a ``mime-type`` attribute to the background in Distribution XML.
+ The option contains MIME type of an image.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_UTI
+
+ Adds an ``uti`` attribute to the background in Distribution XML.
+ The option contains UTI type of an image.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA
+
+ Adds a background for the Dark Aqua theme to Distribution XML if
+ specified. The value contains the path to image in ``Resources``
+ directory.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA_ALIGNMENT
+
+ Does the same as :variable:`CPACK_PRODUCTBUILD_BACKGROUND_ALIGNMENT` option,
+ but for the dark theme.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA_SCALING
+
+ Does the same as :variable:`CPACK_PRODUCTBUILD_BACKGROUND_SCALING` option,
+ but for the dark theme.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA_MIME_TYPE
+
+ Does the same as :variable:`CPACK_PRODUCTBUILD_BACKGROUND_MIME_TYPE` option,
+ but for the dark theme.
+
+.. variable:: CPACK_PRODUCTBUILD_BACKGROUND_DARKAQUA_UTI
+
+ Does the same as :variable:`CPACK_PRODUCTBUILD_BACKGROUND_UTI` option,
+ but for the dark theme.
diff --git a/Help/dev/maint.rst b/Help/dev/maint.rst
index 44e2273..a1c1a6f 100644
--- a/Help/dev/maint.rst
+++ b/Help/dev/maint.rst
@@ -14,6 +14,11 @@
 The `CMake Review Process`_ requires a maintainer to issue the ``Do: merge``
 command to integrate a merge request.  Please check at least the following:
 
+* If the MR source branch (or part of it) should be backported
+  to the ``release`` branch (and is already based on a commit
+  contained in the ``release`` branch), add a ``Backport: release`` or
+  ``Backport: release:<commit-ish>`` trailing line to the MR description.
+
 * If the MR source branch is not named well for the change it makes
   (e.g. it is just ``master`` or the patch changed during review),
   add a ``Topic-rename: <topic>`` trailing line to the MR description
@@ -38,9 +43,10 @@
   of various nightly builders.)
 
 * Ensure that the MR targets the ``master`` branch.  A MR intended for
-  the ``release`` branch should be based on ``release`` but still merged
-  to ``master`` first (via ``Do: merge``).  A maintainer may then merge
-  the MR topic to ``release`` manually.
+  the ``release`` branch should be based on ``release`` but still target
+  ``master``.  Use the above-mentioned ``Backport: release`` line to tell
+  ``Do: merge`` to merge to both.  If a MR is merged without the backport
+  line, a maintainer may still merge the MR topic to ``release`` manually.
 
 Maintain Current Release
 ========================
@@ -51,6 +57,12 @@
 number of the current release in the form ``$major.$minor``.  It is always
 merged into ``master`` before publishing.
 
+To merge an open MR to the ``release`` branch, edit its description to
+use the ``Backport: release`` line mentioned above and then ``Do: merge``
+normally.  To update the ``release`` branch manually (e.g. to merge a
+``$topic`` branch that was merged without the backport line), use the
+following procedure.
+
 Before merging a ``$topic`` branch into ``release``, verify that the
 ``$topic`` branch has already been merged to ``master`` via the usual
 ``Do: merge`` process.  Then, to merge the ``$topic`` branch into
diff --git a/Help/dev/review.rst b/Help/dev/review.rst
index cbde6fe..8ec41d2 100644
--- a/Help/dev/review.rst
+++ b/Help/dev/review.rst
@@ -53,6 +53,10 @@
   to a period of inactivity.  See the `Expire`_ step.  Use this label
   after closing a MR for this reason.
 
+* ``workflow:external-discussion`` indicates that the MR has been closed
+  pending discussion elsewhere.  See the `External Discussion`_ step.
+  Use this label after closing a MR for this reason.
+
 The workflow status labels are intended to be mutually exclusive,
 so please remove any existing workflow label when adding one.
 
@@ -429,6 +433,21 @@
 in the MR description (the following have no effect if used in a MR
 comment instead):
 
+* ``Backport: release[:<commit-ish>]``: merge the topic branch into
+  the ``release`` branch to backport the change.  This is allowed
+  only if the topic branch is based on a commit in ``release`` already.
+  If only part of the topic branch should be backported, specify it as
+  ``:<commit-ish>``.  The ``<commit-ish>`` may use `git rev-parse`_
+  syntax to reference commits relative to the topic ``HEAD``.
+  See additional `backport instructions`_ for details.
+  For example:
+
+  ``Backport: release``
+    Merge the topic branch head into both ``release`` and ``master``.
+  ``Backport: release:HEAD~1^2``
+    Merge the topic branch head's parent's second parent commit into
+    the ``release`` branch.  Merge the topic branch head to ``master``.
+
 * ``Topic-rename: <topic>``: substitute ``<topic>`` for the name of
   the MR topic branch in the constructed merge commit message.
   It is also used in merge commits constructed by ``Do: stage``.
@@ -436,6 +455,8 @@
   rename set in the MR description.
 
 .. _`CMake GitLab Project Masters`: https://gitlab.kitware.com/cmake/cmake/settings/members
+.. _`backport instructions`: https://gitlab.kitware.com/utils/git-workflow/wikis/Backport-topics
+.. _`git rev-parse`: https://git-scm.com/docs/git-rev-parse
 
 Close
 -----
diff --git a/Help/envvar/CMAKE_EXPORT_COMPILE_COMMANDS.rst b/Help/envvar/CMAKE_EXPORT_COMPILE_COMMANDS.rst
new file mode 100644
index 0000000..e9e0810
--- /dev/null
+++ b/Help/envvar/CMAKE_EXPORT_COMPILE_COMMANDS.rst
@@ -0,0 +1,9 @@
+CMAKE_EXPORT_COMPILE_COMMANDS
+-----------------------------
+
+.. include:: ENV_VAR.txt
+
+The default value for :variable:`CMAKE_EXPORT_COMPILE_COMMANDS` when there
+is no explicit configuration given on the first run while creating a new
+build tree.  On later runs in an existing build tree the value persists in
+the cache as :variable:`CMAKE_EXPORT_COMPILE_COMMANDS`.
diff --git a/Help/envvar/CMAKE_LANG_COMPILER_LAUNCHER.rst b/Help/envvar/CMAKE_LANG_COMPILER_LAUNCHER.rst
new file mode 100644
index 0000000..4f91e9a
--- /dev/null
+++ b/Help/envvar/CMAKE_LANG_COMPILER_LAUNCHER.rst
@@ -0,0 +1,10 @@
+CMAKE_<LANG>_COMPILER_LAUNCHER
+------------------------------
+
+.. include:: ENV_VAR.txt
+
+Default compiler launcher to use for the specified language. Will only be used
+by CMake to initialize the variable on the first configuration. Afterwards, it
+is available through the cache setting of the variable of the same name. For
+any configuration run (including the first), the environment variable will be
+ignored if the :variable:`CMAKE_<LANG>_COMPILER_LAUNCHER` variable is defined.
diff --git a/Help/generator/Ninja Multi-Config.rst b/Help/generator/Ninja Multi-Config.rst
new file mode 100644
index 0000000..1f68535
--- /dev/null
+++ b/Help/generator/Ninja Multi-Config.rst
@@ -0,0 +1,121 @@
+Ninja Multi-Config
+------------------
+
+Generates multiple ``build-<Config>.ninja`` files.
+
+This generator is very much like the :generator:`Ninja` generator, but with
+some key differences. Only these differences will be discussed in this
+document.
+
+Unlike the :generator:`Ninja` generator, ``Ninja Multi-Config`` generates
+multiple configurations at once with :variable:`CMAKE_CONFIGURATION_TYPES`
+instead of only one configuration with :variable:`CMAKE_BUILD_TYPE`. One
+``build-<Config>.ninja`` file will be generated for each of these
+configurations (with ``<Config>`` being the configuration name.) These files
+are intended to be run with ``ninja -f build-<Config>.ninja``. A
+``build.ninja`` file is also generated, using the configuration from either
+:variable:`CMAKE_DEFAULT_BUILD_TYPE` or the first item from
+:variable:`CMAKE_CONFIGURATION_TYPES`.
+
+``cmake --build . --config <Config>`` will always use ``build-<Config>.ninja``
+to build. If no ``--config`` argument is specified, ``cmake --build .`` will
+default to ``build-Debug.ninja``, unless a ``build.ninja`` is generated (see
+below), in which case that will be used instead.
+
+Each ``build-<Config>.ninja`` file contains ``<target>`` targets as well as
+``<target>:<Config>`` targets, where ``<Config>`` is the same as the
+configuration specified in ``build-<Config>.ninja`` Additionally, if
+cross-config mode is enabled, ``build-<Config>.ninja`` may contain
+``<target>:<OtherConfig>`` targets, where ``<OtherConfig>`` is a cross-config,
+as well as ``<target>:all``, which builds the target in all cross-configs. See
+below for how to enable cross-config mode.
+
+The ``Ninja Multi-Config`` generator recognizes the following variables:
+
+:variable:`CMAKE_CONFIGURATION_TYPES`
+  Specifies the total set of configurations to build. See the variable's
+  documentation for more information.
+
+:variable:`CMAKE_CROSS_CONFIGS`
+  Specifies a :ref:`semicolon-separated list <CMake Language Lists>` of
+  configurations available from all ``build-<Config>.ninja`` files.
+  This variable activates cross-config mode.
+  Targets from each config specified in this variable can be built from any
+  ``build-<Config>.ninja`` file. Custom commands will use the configuration
+  native to ``build-<Config>.ninja``. If it is set to ``all``, all
+  configurations from :variable:`CMAKE_CONFIGURATION_TYPES` are cross-configs.
+  If it is not specified, or empty, each ``build-<Config>.ninja`` file will
+  only contain build rules for its own configuration.
+
+  The value of this variable must be a subset of
+  :variable:`CMAKE_CONFIGURATION_TYPES`.
+
+:variable:`CMAKE_DEFAULT_BUILD_TYPE`
+  Specifies the configuration to use by default in a ``build.ninja`` file. If
+  this variable is specified, ``build.ninja`` uses build rules from
+  ``build-<Config>.ninja`` by default. All custom commands are executed with
+  this configuration. If the variable is not specified, the first item from
+  :variable:`CMAKE_CONFIGURATION_TYPES` is used instead.
+
+  The value of this variable must be one of the items from
+  :variable:`CMAKE_CONFIGURATION_TYPES`.
+
+:variable:`CMAKE_DEFAULT_CONFIGS`
+  Specifies a :ref:`semicolon-separated list <CMake Language Lists>` of
+  configurations to build for a target in ``build.ninja``
+  if no ``:<Config>`` suffix is specified. If it is set to ``all``, all
+  configurations from :variable:`CMAKE_CROSS_CONFIGS` are used. If
+  it is not specified, it defaults to
+  :variable:`CMAKE_DEFAULT_BUILD_TYPE`.
+
+  For example, if you set
+  :variable:`CMAKE_DEFAULT_BUILD_TYPE` to ``Release``, but
+  set :variable:`CMAKE_DEFAULT_CONFIGS` 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.
+
+  The value of this variable must be a subset of
+  :variable:`CMAKE_CROSS_CONFIGS` or be the same as
+  :variable:`CMAKE_DEFAULT_BUILD_TYPE`. It must not be
+  specified if :variable:`CMAKE_DEFAULT_BUILD_TYPE` or
+  :variable:`CMAKE_CROSS_CONFIGS` is not used.
+
+Consider the following example:
+
+.. code-block:: cmake
+
+  cmake_minimum_required(VERSION 3.16)
+  project(MultiConfigNinja C)
+
+  add_executable(generator generator.c)
+  add_custom_command(OUTPUT generated.c COMMAND generator generated.c)
+  add_library(generated ${CMAKE_BINARY_DIR}/generated.c)
+
+Now assume you configure the project with ``Ninja Multi-Config`` and run one of
+the following commands:
+
+.. code-block:: shell
+
+  ninja -f build-Debug.ninja generated
+  # OR
+  cmake --build . --config Debug --target generated
+
+This would build the ``Debug`` configuration of ``generator``, which would be
+used to generate ``generated.c``, which would be used to build the ``Debug``
+configuration of ``generated``.
+
+But if :variable:`CMAKE_CROSS_CONFIGS` is set to ``all``, and you run the
+following instead:
+
+.. code-block:: shell
+
+  ninja -f build-Release.ninja generated:Debug
+  # OR
+  cmake --build . --config Release --target generated:Debug
+
+This would build the ``Release`` configuration of ``generator``, which would be
+used to generate ``generated.c``, which would be used to build the ``Debug``
+configuration of ``generated``. This is useful for running a release-optimized
+version of a generator utility while still building the debug version of the
+targets built with the generated code.
diff --git a/Help/generator/Ninja.rst b/Help/generator/Ninja.rst
index c75d2c4..275055d 100644
--- a/Help/generator/Ninja.rst
+++ b/Help/generator/Ninja.rst
@@ -1,7 +1,7 @@
 Ninja
 -----
 
-Generates build.ninja files.
+Generates ``build.ninja`` files.
 
 A ``build.ninja`` file is generated into the build tree.  Use the ninja
 program to build the project through the ``all`` target and install the
@@ -38,3 +38,9 @@
 a branch of Ninja with the required features on `github.com/Kitware/ninja`_.
 
 .. _`github.com/Kitware/ninja`: https://github.com/Kitware/ninja/tree/features-for-fortran#readme
+
+See Also
+^^^^^^^^
+
+The :generator:`Ninja Multi-Config` generator is similar to the ``Ninja``
+generator, but generates multiple configurations at once.
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/Complete/MultiCPackConfig.cmake b/Help/guide/tutorial/Complete/MultiCPackConfig.cmake
new file mode 100644
index 0000000..c2583df
--- /dev/null
+++ b/Help/guide/tutorial/Complete/MultiCPackConfig.cmake
@@ -0,0 +1,6 @@
+include("release/CPackConfig.cmake")
+
+set(CPACK_INSTALL_CMAKE_PROJECTS
+    "debug;Tutorial;ALL;/"
+    "release;Tutorial;ALL;/"
+    )
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/MultiPackage/CMakeLists.txt b/Help/guide/tutorial/MultiPackage/CMakeLists.txt
deleted file mode 100644
index 01d417a..0000000
--- a/Help/guide/tutorial/MultiPackage/CMakeLists.txt
+++ /dev/null
@@ -1,112 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-
-# set the project name and version
-project(Tutorial VERSION 1.0)
-
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED True)
-
-
-# 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
-set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
-set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
-set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
-
-option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
-
-if(APPLE)
-  set(CMAKE_INSTALL_RPATH "@executable_path/../lib")
-elseif(UNIX)
-  set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
-endif()
-
-# configure a header file to pass the version number only
-configure_file(TutorialConfig.h.in TutorialConfig.h)
-
-# add the MathFunctions library
-add_subdirectory(MathFunctions)
-
-# add the executable
-add_executable(Tutorial tutorial.cxx)
-target_link_libraries(Tutorial PUBLIC MathFunctions)
-
-# add the binary tree to the search path for include files
-# so that we will find TutorialConfig.h
-target_include_directories(Tutorial PUBLIC
-                           "${PROJECT_BINARY_DIR}"
-                           )
-
-# add the install targets
-install(TARGETS Tutorial DESTINATION bin)
-install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
-  DESTINATION include
-  )
-
-# enable testing
-enable_testing()
-
-# does the application run
-add_test(NAME Runs COMMAND Tutorial 25)
-
-# does the usage message work?
-add_test(NAME Usage COMMAND Tutorial)
-set_tests_properties(Usage
-  PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
-  )
-
-# define a function to simplify adding tests
-function(do_test target arg result)
-  add_test(NAME Comp${arg} COMMAND ${target} ${arg})
-  set_tests_properties(Comp${arg}
-    PROPERTIES PASS_REGULAR_EXPRESSION ${result}
-    )
-endfunction(do_test)
-
-# do a bunch of result based tests
-do_test(Tutorial 4 "4 is 2")
-do_test(Tutorial 9 "9 is 3")
-do_test(Tutorial 5 "5 is 2.236")
-do_test(Tutorial 7 "7 is 2.645")
-do_test(Tutorial 25 "25 is 5")
-do_test(Tutorial -25 "-25 is [-nan|nan|0]")
-do_test(Tutorial 0.0001 "0.0001 is 0.01")
-
-include(InstallRequiredSystemLibraries)
-set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
-set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
-set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
-include(CPack)
-
-# install the configuration targets
-install(EXPORT MathFunctionsTargets
-  FILE MathFunctionsTargets.cmake
-  DESTINATION lib/cmake/MathFunctions
-)
-
-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}/MathFunctionsConfig.cmake"
-  INSTALL_DESTINATION "lib/cmake/example"
-  NO_SET_AND_CHECK_MACRO
-  NO_CHECK_REQUIRED_COMPONENTS_MACRO
-  )
-# generate the version file for the config file
-write_basic_package_version_file(
-  "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
-  VERSION "${Tutorial_VERSION_MAJOR}.${Tutorial_VERSION_MINOR}"
-  COMPATIBILITY AnyNewerVersion
-)
-
-# install the configuration file
-install(FILES
-  ${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake
-  DESTINATION lib/cmake/MathFunctions
-  )
-
-# generate the export targets for the build tree
-# needs to be after the install(TARGETS ) command
-export(EXPORT MathFunctionsTargets
-  FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake"
-)
diff --git a/Help/guide/tutorial/MultiPackage/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/MultiPackage/MathFunctions/CMakeLists.txt
deleted file mode 100644
index a2df2a7..0000000
--- a/Help/guide/tutorial/MultiPackage/MathFunctions/CMakeLists.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-# add the library that runs
-add_library(MathFunctions MathFunctions.cxx)
-
-# state that anybody linking to us needs to include the current source dir
-# to find MathFunctions.h, while we don't.
-target_include_directories(MathFunctions
-                           INTERFACE
-                            $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
-                            $<INSTALL_INTERFACE:include>
-                           )
-
-# should we use our own math functions
-option(USE_MYMATH "Use tutorial provided math implementation" ON)
-if(USE_MYMATH)
-
-  target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
-
-  # first we add the executable that generates the table
-  add_executable(MakeTable MakeTable.cxx)
-
-  # add the command to generate the source code
-  add_custom_command(
-    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
-    COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
-    DEPENDS MakeTable
-    )
-
-  # library that just does sqrt
-  add_library(SqrtLibrary STATIC
-              mysqrt.cxx
-              ${CMAKE_CURRENT_BINARY_DIR}/Table.h
-              )
-
-  # state that we depend on our binary dir to find Table.h
-  target_include_directories(SqrtLibrary PRIVATE
-                             ${CMAKE_CURRENT_BINARY_DIR}
-                             )
-
-  # state that SqrtLibrary need PIC when the default is shared libraries
-  set_target_properties(SqrtLibrary PROPERTIES
-                        POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
-                        )
-
-  target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
-endif()
-
-# 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
-        DESTINATION lib
-        EXPORT MathFunctionsTargets)
-install(FILES MathFunctions.h DESTINATION include)
diff --git a/Help/guide/tutorial/MultiPackage/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/MultiPackage/MathFunctions/mysqrt.cxx
deleted file mode 100644
index 5e622be..0000000
--- a/Help/guide/tutorial/MultiPackage/MathFunctions/mysqrt.cxx
+++ /dev/null
@@ -1,38 +0,0 @@
-#include <iostream>
-
-#include "MathFunctions.h"
-
-// include the generated table
-#include "Table.h"
-
-namespace mathfunctions {
-namespace detail {
-// a hack square root calculation using simple operations
-double mysqrt(double x)
-{
-  if (x <= 0) {
-    return 0;
-  }
-
-  // use the table to help find an initial value
-  double result = x;
-  if (x >= 1 && x < 10) {
-    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) {
-      result = 0.1;
-    }
-    double delta = x - (result * result);
-    result = result + 0.5 * delta / result;
-    std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
-  }
-
-  return result;
-}
-}
-}
diff --git a/Help/guide/tutorial/MultiPackage/MultiCPackConfig.cmake b/Help/guide/tutorial/MultiPackage/MultiCPackConfig.cmake
deleted file mode 100644
index 403b633..0000000
--- a/Help/guide/tutorial/MultiPackage/MultiCPackConfig.cmake
+++ /dev/null
@@ -1,7 +0,0 @@
-
-include("release/CPackConfig.cmake")
-
-set(CPACK_INSTALL_CMAKE_PROJECTS
-    "debug;Tutorial;ALL;/"
-    "release;Tutorial;ALL;/"
-    )
diff --git a/Help/guide/tutorial/MultiPackage/TutorialConfig.h.in b/Help/guide/tutorial/MultiPackage/TutorialConfig.h.in
deleted file mode 100644
index 8cd2fc9..0000000
--- a/Help/guide/tutorial/MultiPackage/TutorialConfig.h.in
+++ /dev/null
@@ -1,3 +0,0 @@
-// the configured version number
-#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/MultiPackage/tutorial.cxx
deleted file mode 100644
index f97805b..0000000
--- a/Help/guide/tutorial/MultiPackage/tutorial.cxx
+++ /dev/null
@@ -1,25 +0,0 @@
-// A simple program that computes the square root of a number
-#include <iostream>
-#include <string>
-
-#include "MathFunctions.h"
-#include "TutorialConfig.h"
-
-int main(int argc, char* argv[])
-{
-  if (argc < 2) {
-    std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
-              << Tutorial_VERSION_MINOR << std::endl;
-    std::cout << "Usage: " << argv[0] << " number" << std::endl;
-    return 1;
-  }
-
-  // convert input to double
-  double inputValue = std::stod(argv[1]);
-
-  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/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/Step12/CMakeLists.txt b/Help/guide/tutorial/Step12/CMakeLists.txt
new file mode 100644
index 0000000..eca79d9
--- /dev/null
+++ b/Help/guide/tutorial/Step12/CMakeLists.txt
@@ -0,0 +1,120 @@
+cmake_minimum_required(VERSION 3.15)
+
+# set the project name and version
+project(Tutorial VERSION 1.0)
+
+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
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
+
+option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
+
+if(APPLE)
+  set(CMAKE_INSTALL_RPATH "@executable_path/../lib")
+elseif(UNIX)
+  set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
+endif()
+
+# configure a header file to pass the version number only
+configure_file(TutorialConfig.h.in TutorialConfig.h)
+
+# add the MathFunctions library
+add_subdirectory(MathFunctions)
+
+# add the executable
+add_executable(Tutorial tutorial.cxx)
+target_link_libraries(Tutorial PUBLIC MathFunctions)
+
+# add the binary tree to the search path for include files
+# so that we will find TutorialConfig.h
+target_include_directories(Tutorial PUBLIC
+                           "${PROJECT_BINARY_DIR}"
+                           )
+
+# add the install targets
+install(TARGETS Tutorial DESTINATION bin)
+install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
+  DESTINATION include
+  )
+
+# enable testing
+enable_testing()
+
+# does the application run
+add_test(NAME Runs COMMAND Tutorial 25)
+
+# does the usage message work?
+add_test(NAME Usage COMMAND Tutorial)
+set_tests_properties(Usage
+  PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
+  )
+
+# define a function to simplify adding tests
+function(do_test target arg result)
+  add_test(NAME Comp${arg} COMMAND ${target} ${arg})
+  set_tests_properties(Comp${arg}
+    PROPERTIES PASS_REGULAR_EXPRESSION ${result}
+    )
+endfunction(do_test)
+
+# do a bunch of result based tests
+do_test(Tutorial 4 "4 is 2")
+do_test(Tutorial 9 "9 is 3")
+do_test(Tutorial 5 "5 is 2.236")
+do_test(Tutorial 7 "7 is 2.645")
+do_test(Tutorial 25 "25 is 5")
+do_test(Tutorial -25 "-25 is [-nan|nan|0]")
+do_test(Tutorial 0.0001 "0.0001 is 0.01")
+
+include(InstallRequiredSystemLibraries)
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
+set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
+set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
+include(CPack)
+
+# install the configuration targets
+install(EXPORT MathFunctionsTargets
+  FILE MathFunctionsTargets.cmake
+  DESTINATION lib/cmake/MathFunctions
+)
+
+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}/MathFunctionsConfig.cmake"
+  INSTALL_DESTINATION "lib/cmake/example"
+  NO_SET_AND_CHECK_MACRO
+  NO_CHECK_REQUIRED_COMPONENTS_MACRO
+  )
+# generate the version file for the config file
+write_basic_package_version_file(
+  "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
+  VERSION "${Tutorial_VERSION_MAJOR}.${Tutorial_VERSION_MINOR}"
+  COMPATIBILITY AnyNewerVersion
+)
+
+# install the configuration file
+install(FILES
+  ${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake
+  DESTINATION lib/cmake/MathFunctions
+  )
+
+# generate the export targets for the build tree
+# needs to be after the install(TARGETS ) command
+export(EXPORT MathFunctionsTargets
+  FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake"
+)
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/Step12/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt
new file mode 100644
index 0000000..720ee64
--- /dev/null
+++ b/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt
@@ -0,0 +1,59 @@
+# add the library that runs
+add_library(MathFunctions MathFunctions.cxx)
+
+# state that anybody linking to us needs to include the current source dir
+# to find MathFunctions.h, while we don't.
+target_include_directories(MathFunctions
+                           INTERFACE
+                            $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+                            $<INSTALL_INTERFACE:include>
+                           )
+
+# should we use our own math functions
+option(USE_MYMATH "Use tutorial provided math implementation" ON)
+if(USE_MYMATH)
+
+  target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
+
+  # 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(
+    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+    COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+    DEPENDS MakeTable
+    )
+
+  # library that just does sqrt
+  add_library(SqrtLibrary STATIC
+              mysqrt.cxx
+              ${CMAKE_CURRENT_BINARY_DIR}/Table.h
+              )
+
+  # state that we depend on our binary dir to find Table.h
+  target_include_directories(SqrtLibrary PRIVATE
+                             ${CMAKE_CURRENT_BINARY_DIR}
+                             )
+
+  # state that SqrtLibrary need PIC when the default is shared libraries
+  set_target_properties(SqrtLibrary PROPERTIES
+                        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")
+
+# install rules
+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/Step12/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step12/MathFunctions/mysqrt.cxx
new file mode 100644
index 0000000..8153f18
--- /dev/null
+++ b/Help/guide/tutorial/Step12/MathFunctions/mysqrt.cxx
@@ -0,0 +1,37 @@
+#include <iostream>
+
+#include "MathFunctions.h"
+
+// include the generated table
+#include "Table.h"
+
+namespace mathfunctions {
+namespace detail {
+// a hack square root calculation using simple operations
+double mysqrt(double x)
+{
+  if (x <= 0) {
+    return 0;
+  }
+
+  // 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)];
+  }
+
+  // do ten iterations
+  for (int i = 0; i < 10; ++i) {
+    if (result <= 0) {
+      result = 0.1;
+    }
+    double delta = x - (result * result);
+    result = result + 0.5 * delta / result;
+    std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
+  }
+
+  return result;
+}
+}
+}
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/Step12/TutorialConfig.h.in b/Help/guide/tutorial/Step12/TutorialConfig.h.in
new file mode 100644
index 0000000..7e4d7fa
--- /dev/null
+++ b/Help/guide/tutorial/Step12/TutorialConfig.h.in
@@ -0,0 +1,3 @@
+// 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/Step12/tutorial.cxx b/Help/guide/tutorial/Step12/tutorial.cxx
new file mode 100644
index 0000000..a4f44d5
--- /dev/null
+++ b/Help/guide/tutorial/Step12/tutorial.cxx
@@ -0,0 +1,26 @@
+// A simple program that computes the square root of a number
+#include <iostream>
+#include <string>
+
+#include "MathFunctions.h"
+#include "TutorialConfig.h"
+
+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;
+    return 1;
+  }
+
+  // convert input to double
+  const double inputValue = std::stod(argv[1]);
+
+  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/index.rst b/Help/guide/tutorial/index.rst
index d74d160..a844cbf 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
 
@@ -180,7 +183,7 @@
                                   )
 
 Now let us make the MathFunctions library optional. While for the tutorial
-there really isn’t any need to do so, for larger projects this is a common
+there really isn't any need to do so, for larger projects this is a common
 occurrence. The first step is to add an option to the top-level
 ``CMakeLists.txt`` file.
 
@@ -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/ID_RESERVE.txt b/Help/manual/ID_RESERVE.txt
new file mode 100644
index 0000000..be2b163
--- /dev/null
+++ b/Help/manual/ID_RESERVE.txt
@@ -0,0 +1,7 @@
+.. note::
+
+  CMake reserves identifiers that:
+
+  * begin with ``CMAKE_`` (upper-, lower-, or mixed-case), or
+  * begin with ``_CMAKE_`` (upper-, lower-, or mixed-case), or
+  * begin with ``_`` followed by the name of any :manual:`CMake Command <cmake-commands(7)>`.
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-compile-features.7.rst b/Help/manual/cmake-compile-features.7.rst
index a14e322..05dc038 100644
--- a/Help/manual/cmake-compile-features.7.rst
+++ b/Help/manual/cmake-compile-features.7.rst
@@ -19,11 +19,11 @@
 CMake provides a primary user interface based on granular handling of
 the features, not the language standard that introduced the feature.
 
-The :prop_gbl:`CMAKE_C_KNOWN_FEATURES` and
-:prop_gbl:`CMAKE_CXX_KNOWN_FEATURES` global properties contain all the
+The :prop_gbl:`CMAKE_C_KNOWN_FEATURES`, :prop_gbl:`CMAKE_CUDA_KNOWN_FEATURES`,
+and :prop_gbl:`CMAKE_CXX_KNOWN_FEATURES` global properties contain all the
 features known to CMake, regardless of compiler support for the feature.
-The :variable:`CMAKE_C_COMPILE_FEATURES` and
-:variable:`CMAKE_CXX_COMPILE_FEATURES` variables contain all features
+The :variable:`CMAKE_C_COMPILE_FEATURES`, :variable:`CMAKE_CUDA_COMPILE_FEATURES`
+, and :variable:`CMAKE_CXX_COMPILE_FEATURES` variables contain all features
 CMake knows are known to the compiler, regardless of language standard
 or compile flags needed to use them.
 
@@ -368,8 +368,9 @@
 * all compilers and versions listed above with only meta-features for C++.
 * ``TI``: Texas Instruments compiler.
 
-CMake is currently aware of the :prop_tgt:`CUDA standards <CUDA_STANDARD>`
-from the following :variable:`compiler ids <CMAKE_<LANG>_COMPILER_ID>` as of the
+CMake is currently aware of the :prop_tgt:`CUDA standards <CUDA_STANDARD>` and
+their associated meta-features (e.g. ``cuda_std_11``) available from the
+following :variable:`compiler ids <CMAKE_<LANG>_COMPILER_ID>` as of the
 versions specified for each:
 
 * ``NVIDIA``: NVIDIA nvcc compiler 7.5+.
diff --git a/Help/manual/cmake-env-variables.7.rst b/Help/manual/cmake-env-variables.7.rst
index 96ceb94..adfc39e 100644
--- a/Help/manual/cmake-env-variables.7.rst
+++ b/Help/manual/cmake-env-variables.7.rst
@@ -23,10 +23,12 @@
 
    /envvar/CMAKE_BUILD_PARALLEL_LEVEL
    /envvar/CMAKE_CONFIG_TYPE
+   /envvar/CMAKE_EXPORT_COMPILE_COMMANDS
    /envvar/CMAKE_GENERATOR
    /envvar/CMAKE_GENERATOR_INSTANCE
    /envvar/CMAKE_GENERATOR_PLATFORM
    /envvar/CMAKE_GENERATOR_TOOLSET
+   /envvar/CMAKE_LANG_COMPILER_LAUNCHER
    /envvar/CMAKE_MSVCIDE_RUN_PATH
    /envvar/CMAKE_NO_VERBOSE
    /envvar/CMAKE_OSX_ARCHITECTURES
diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
index 04b6ed2..12eecd9 100644
--- a/Help/manual/cmake-file-api.7.rst
+++ b/Help/manual/cmake-file-api.7.rst
@@ -199,6 +199,7 @@
         "root": "/prefix/share/cmake-3.14"
       },
       "generator": {
+        "multiConfig": false,
         "name": "Unix Makefiles"
       }
     },
@@ -267,6 +268,9 @@
     A JSON object describing the CMake generator used for the build.
     It has members:
 
+    ``multiConfig``
+      A boolean specifying whether the generator supports multiple output
+      configurations.
     ``name``
       A string specifying the name of the generator.
     ``platform``
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index 75f4bd4..691481b 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -596,7 +596,8 @@
   requirement.
 ``$<INSTALL_PREFIX>``
   Content of the install prefix when the target is exported via
-  :command:`install(EXPORT)` and empty otherwise.
+  :command:`install(EXPORT)`, or when evaluated in
+  :prop_tgt:`INSTALL_NAME_DIR`, and empty otherwise.
 
 Output-Related Expressions
 --------------------------
diff --git a/Help/manual/cmake-generators.7.rst b/Help/manual/cmake-generators.7.rst
index 41f7652..6f88c0a 100644
--- a/Help/manual/cmake-generators.7.rst
+++ b/Help/manual/cmake-generators.7.rst
@@ -52,13 +52,14 @@
    /generator/Unix Makefiles
    /generator/Watcom WMake
 
-Ninja Generator
-^^^^^^^^^^^^^^^
+Ninja Generators
+^^^^^^^^^^^^^^^^
 
 .. toctree::
    :maxdepth: 1
 
    /generator/Ninja
+   /generator/Ninja Multi-Config
 
 .. _`IDE Build Tool Generators`:
 
diff --git a/Help/manual/cmake-language.7.rst b/Help/manual/cmake-language.7.rst
index 4ca8e3a..b7f0861 100644
--- a/Help/manual/cmake-language.7.rst
+++ b/Help/manual/cmake-language.7.rst
@@ -567,6 +567,8 @@
 that are provided by CMake or have meaning to CMake when set
 by project code.
 
+.. include:: ID_RESERVE.txt
+
 .. _`CMake Language Environment Variables`:
 
 Environment Variables
diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst
index c60dc40..be64112 100644
--- a/Help/manual/cmake-modules.7.rst
+++ b/Help/manual/cmake-modules.7.rst
@@ -122,6 +122,7 @@
    /module/FindCABLE
    /module/FindCoin3D
    /module/FindCups
+   /module/FindCUDAToolkit
    /module/FindCURL
    /module/FindCurses
    /module/FindCVS
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 44ea1a8..c256250 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -51,6 +51,18 @@
 to determine whether to report an error on use of deprecated macros or
 functions.
 
+Policies Introduced by CMake 3.17
+=================================
+
+.. 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>
+
 Policies Introduced by CMake 3.16
 =================================
 
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index e704371..060a072 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -22,10 +22,13 @@
    /prop_gbl/AUTOMOC_TARGETS_FOLDER
    /prop_gbl/AUTORCC_SOURCE_GROUP
    /prop_gbl/CMAKE_C_KNOWN_FEATURES
+   /prop_gbl/CMAKE_CUDA_KNOWN_FEATURES
    /prop_gbl/CMAKE_CXX_KNOWN_FEATURES
    /prop_gbl/CMAKE_ROLE
    /prop_gbl/DEBUG_CONFIGURATIONS
    /prop_gbl/DISABLED_FEATURES
+   /prop_gbl/ECLIPSE_EXTRA_CPROJECT_CONTENTS
+   /prop_gbl/ECLIPSE_EXTRA_NATURES
    /prop_gbl/ENABLED_FEATURES
    /prop_gbl/ENABLED_LANGUAGES
    /prop_gbl/FIND_LIBRARY_USE_LIB32_PATHS
@@ -36,12 +39,10 @@
    /prop_gbl/GLOBAL_DEPENDS_DEBUG_MODE
    /prop_gbl/GLOBAL_DEPENDS_NO_CYCLES
    /prop_gbl/IN_TRY_COMPILE
+   /prop_gbl/JOB_POOLS
    /prop_gbl/PACKAGES_FOUND
    /prop_gbl/PACKAGES_NOT_FOUND
-   /prop_gbl/JOB_POOLS
    /prop_gbl/PREDEFINED_TARGETS_FOLDER
-   /prop_gbl/ECLIPSE_EXTRA_NATURES
-   /prop_gbl/ECLIPSE_EXTRA_CPROJECT_CONTENTS
    /prop_gbl/REPORT_UNDEFINED_PROPERTIES
    /prop_gbl/RULE_LAUNCH_COMPILE
    /prop_gbl/RULE_LAUNCH_CUSTOM
@@ -103,6 +104,7 @@
    :maxdepth: 1
 
    /prop_tgt/ADDITIONAL_CLEAN_FILES
+   /prop_tgt/AIX_EXPORT_ALL_SYMBOLS
    /prop_tgt/ALIASED_TARGET
    /prop_tgt/ANDROID_ANT_ADDITIONAL_OPTIONS
    /prop_tgt/ANDROID_API
@@ -129,20 +131,20 @@
    /prop_tgt/AUTOGEN_ORIGIN_DEPENDS
    /prop_tgt/AUTOGEN_PARALLEL
    /prop_tgt/AUTOGEN_TARGET_DEPENDS
+   /prop_tgt/AUTOMOC
    /prop_tgt/AUTOMOC_COMPILER_PREDEFINES
    /prop_tgt/AUTOMOC_DEPEND_FILTERS
    /prop_tgt/AUTOMOC_EXECUTABLE
    /prop_tgt/AUTOMOC_MACRO_NAMES
    /prop_tgt/AUTOMOC_MOC_OPTIONS
    /prop_tgt/AUTOMOC_PATH_PREFIX
-   /prop_tgt/AUTOMOC
+   /prop_tgt/AUTORCC
+   /prop_tgt/AUTORCC_EXECUTABLE
+   /prop_tgt/AUTORCC_OPTIONS
    /prop_tgt/AUTOUIC
    /prop_tgt/AUTOUIC_EXECUTABLE
    /prop_tgt/AUTOUIC_OPTIONS
    /prop_tgt/AUTOUIC_SEARCH_PATHS
-   /prop_tgt/AUTORCC
-   /prop_tgt/AUTORCC_EXECUTABLE
-   /prop_tgt/AUTORCC_OPTIONS
    /prop_tgt/BINARY_DIR
    /prop_tgt/BUILD_RPATH
    /prop_tgt/BUILD_RPATH_USE_ORIGIN
@@ -172,6 +174,7 @@
    /prop_tgt/CUDA_PTX_COMPILATION
    /prop_tgt/CUDA_SEPARABLE_COMPILATION
    /prop_tgt/CUDA_RESOLVE_DEVICE_SYMBOLS
+   /prop_tgt/CUDA_RUNTIME_LIBRARY
    /prop_tgt/CUDA_EXTENSIONS
    /prop_tgt/CUDA_STANDARD
    /prop_tgt/CUDA_STANDARD_REQUIRED
@@ -182,7 +185,9 @@
    /prop_tgt/DEFINE_SYMBOL
    /prop_tgt/DEPLOYMENT_REMOTE_DIRECTORY
    /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
@@ -251,6 +256,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
@@ -279,6 +285,8 @@
    /prop_tgt/LINK_WHAT_YOU_USE
    /prop_tgt/LOCATION_CONFIG
    /prop_tgt/LOCATION
+   /prop_tgt/MACHO_COMPATIBILITY_VERSION
+   /prop_tgt/MACHO_CURRENT_VERSION
    /prop_tgt/MACOSX_BUNDLE_INFO_PLIST
    /prop_tgt/MACOSX_BUNDLE
    /prop_tgt/MACOSX_FRAMEWORK_INFO_PLIST
@@ -348,6 +356,7 @@
    /prop_tgt/VS_DOTNET_REFERENCES
    /prop_tgt/VS_DOTNET_REFERENCES_COPY_LOCAL
    /prop_tgt/VS_DOTNET_TARGET_FRAMEWORK_VERSION
+   /prop_tgt/VS_DOTNET_DOCUMENTATION_FILE
    /prop_tgt/VS_DPI_AWARE
    /prop_tgt/VS_GLOBAL_KEYWORD
    /prop_tgt/VS_GLOBAL_PROJECT_TYPES
@@ -396,6 +405,7 @@
    /prop_tgt/XCODE_SCHEME_THREAD_SANITIZER_STOP
    /prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER
    /prop_tgt/XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP
+   /prop_tgt/XCODE_SCHEME_WORKING_DIRECTORY
    /prop_tgt/XCODE_SCHEME_ZOMBIE_OBJECTS
    /prop_tgt/XCTEST
 
@@ -442,8 +452,8 @@
    :maxdepth: 1
 
    /prop_sf/ABSTRACT
-   /prop_sf/AUTOUIC_OPTIONS
    /prop_sf/AUTORCC_OPTIONS
+   /prop_sf/AUTOUIC_OPTIONS
    /prop_sf/COMPILE_DEFINITIONS
    /prop_sf/COMPILE_FLAGS
    /prop_sf/COMPILE_OPTIONS
diff --git a/Help/manual/cmake-toolchains.7.rst b/Help/manual/cmake-toolchains.7.rst
index f233d08..e8badd4 100644
--- a/Help/manual/cmake-toolchains.7.rst
+++ b/Help/manual/cmake-toolchains.7.rst
@@ -233,6 +233,9 @@
   set(CMAKE_CXX_COMPILER QCC)
   set(CMAKE_CXX_COMPILER_TARGET ${arch})
 
+  set(CMAKE_SYSROOT $ENV{QNX_TARGET})
+
+
 Cross Compiling for Windows CE
 ------------------------------
 
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 53b7f8d..fc27739 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -14,6 +14,7 @@
 :ref:`Variables <CMake Language Variables>`
 section in the cmake-language manual.
 
+.. include:: ID_RESERVE.txt
 
 Variables that Provide Information
 ==================================
@@ -37,17 +38,24 @@
    /variable/CMAKE_CROSSCOMPILING_EMULATOR
    /variable/CMAKE_CTEST_COMMAND
    /variable/CMAKE_CURRENT_BINARY_DIR
+   /variable/CMAKE_CURRENT_FUNCTION
+   /variable/CMAKE_CURRENT_FUNCTION_LIST_DIR
+   /variable/CMAKE_CURRENT_FUNCTION_LIST_FILE
+   /variable/CMAKE_CURRENT_FUNCTION_LIST_LINE
    /variable/CMAKE_CURRENT_LIST_DIR
    /variable/CMAKE_CURRENT_LIST_FILE
    /variable/CMAKE_CURRENT_LIST_LINE
    /variable/CMAKE_CURRENT_SOURCE_DIR
+   /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
    /variable/CMAKE_EXTRA_GENERATOR
    /variable/CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES
+   /variable/CMAKE_FIND_DEBUG_MODE
    /variable/CMAKE_FIND_PACKAGE_NAME
    /variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION
    /variable/CMAKE_FIND_PACKAGE_SORT_ORDER
@@ -59,6 +67,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
@@ -70,7 +79,6 @@
    /variable/CMAKE_MAKE_PROGRAM
    /variable/CMAKE_MATCH_COUNT
    /variable/CMAKE_MATCH_n
-   /variable/CMAKE_MESSAGE_INDENT
    /variable/CMAKE_MINIMUM_REQUIRED_VERSION
    /variable/CMAKE_MINOR_VERSION
    /variable/CMAKE_NETRC
@@ -155,7 +163,6 @@
    /variable/CMAKE_CODELITE_USE_TARGETS
    /variable/CMAKE_COLOR_MAKEFILE
    /variable/CMAKE_CONFIGURATION_TYPES
-   /variable/CMAKE_DEBUG_TARGET_PROPERTIES
    /variable/CMAKE_DEPENDS_IN_PROJECT_ONLY
    /variable/CMAKE_DISABLE_FIND_PACKAGE_PackageName
    /variable/CMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES
@@ -206,6 +213,10 @@
    /variable/CMAKE_LINK_DIRECTORIES_BEFORE
    /variable/CMAKE_MFC_FLAG
    /variable/CMAKE_MAXIMUM_RECURSION_DEPTH
+   /variable/CMAKE_MESSAGE_CONTEXT
+   /variable/CMAKE_MESSAGE_CONTEXT_SHOW
+   /variable/CMAKE_MESSAGE_INDENT
+   /variable/CMAKE_MESSAGE_LOG_LEVEL
    /variable/CMAKE_MODULE_PATH
    /variable/CMAKE_POLICY_DEFAULT_CMPNNNN
    /variable/CMAKE_POLICY_WARNING_CMPNNNN
@@ -214,6 +225,7 @@
    /variable/CMAKE_PROJECT_INCLUDE
    /variable/CMAKE_PROJECT_INCLUDE_BEFORE
    /variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE
+   /variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE
    /variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY
    /variable/CMAKE_STAGING_PREFIX
    /variable/CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS
@@ -239,6 +251,7 @@
    /variable/CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER
    /variable/CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS
    /variable/CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
+   /variable/CMAKE_XCODE_SCHEME_ENVIRONMENT
    /variable/CMAKE_XCODE_SCHEME_GUARD_MALLOC
    /variable/CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP
    /variable/CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES
@@ -248,6 +261,7 @@
    /variable/CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP
    /variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER
    /variable/CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP
+   /variable/CMAKE_XCODE_SCHEME_WORKING_DIRECTORY
    /variable/CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS
    /variable/PackageName_ROOT
 
@@ -309,6 +323,7 @@
 .. toctree::
    :maxdepth: 1
 
+   /variable/CMAKE_AIX_EXPORT_ALL_SYMBOLS
    /variable/CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS
    /variable/CMAKE_ANDROID_API
    /variable/CMAKE_ANDROID_API_MIN
@@ -357,9 +372,14 @@
    /variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY
    /variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG
    /variable/CMAKE_CONFIG_POSTFIX
+   /variable/CMAKE_CROSS_CONFIGS
+   /variable/CMAKE_CTEST_ARGUMENTS
    /variable/CMAKE_CUDA_SEPARABLE_COMPILATION
    /variable/CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS
+   /variable/CMAKE_CUDA_RUNTIME_LIBRARY
    /variable/CMAKE_DEBUG_POSTFIX
+   /variable/CMAKE_DEFAULT_BUILD_TYPE
+   /variable/CMAKE_DEFAULT_CONFIGS
    /variable/CMAKE_DISABLE_PRECOMPILE_HEADERS
    /variable/CMAKE_ENABLE_EXPORTS
    /variable/CMAKE_EXE_LINKER_FLAGS
@@ -466,6 +486,7 @@
    /variable/CMAKE_COMPILER_IS_GNUCC
    /variable/CMAKE_COMPILER_IS_GNUCXX
    /variable/CMAKE_COMPILER_IS_GNUG77
+   /variable/CMAKE_CUDA_COMPILE_FEATURES
    /variable/CMAKE_CUDA_HOST_COMPILER
    /variable/CMAKE_CUDA_EXTENSIONS
    /variable/CMAKE_CUDA_STANDARD
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index 4ab55a0..28a081f 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -206,9 +206,24 @@
  The :command:`message` command will only output messages of the specified
  log level or higher.  The default log level is ``STATUS``.
 
+ To make a log level persist between CMake runs, set
+ :variable:`CMAKE_MESSAGE_LOG_LEVEL` as a cache variable instead.
+ If both the command line option and the variable are given, the command line
+ option takes precedence.
+
  For backward compatibility reasons, ``--loglevel`` is also accepted as a
  synonym for this option.
 
+``--log-context``
+ Enable the :command:`message` command outputting context attached to each
+ message.
+
+ This option turns on showing context for the current CMake run only.
+ To make showing the context persistent for all subsequent CMake runs, set
+ :variable:`CMAKE_MESSAGE_CONTEXT_SHOW` as a cache variable instead.
+ When this command line option is given, :variable:`CMAKE_MESSAGE_CONTEXT_SHOW`
+ is ignored.
+
 ``--debug-trycompile``
  Do not delete the :command:`try_compile` build tree.
  Only useful on one :command:`try_compile` at a time.
@@ -226,6 +241,12 @@
  Print extra information during the cmake run like stack traces with
  :command:`message(SEND_ERROR)` calls.
 
+``--debug-find``
+ Put cmake find in a debug mode.
+
+ Print extra find call information during the cmake run to standard
+ error. Output is designed for human consumption and not for parsing.
+
 ``--trace``
  Put cmake in trace mode.
 
@@ -236,6 +257,74 @@
 
  Like ``--trace``, but with variables expanded.
 
+``--trace-format=<format>``
+ Put cmake in trace mode and sets the trace output format.
+
+ ``<format>`` can be one of the following values.
+
+   ``human``
+     Prints each trace line in a human-readable format. This is the
+     default format.
+
+   ``json-v1``
+     Prints each line as a separate JSON document. Each document is
+     separated by a newline ( ``\n`` ). It is guaranteed that no
+     newline characters will be present inside a JSON document.
+
+     JSON trace format:
+
+     .. code-block:: json
+
+       {
+         "file": "/full/path/to/the/CMake/file.txt",
+         "line": 0,
+         "cmd": "add_executable",
+         "args": ["foo", "bar"],
+         "time": 1579512535.9687231,
+         "frame": 2
+       }
+
+     The members are:
+
+     ``file``
+       The full path to the CMake source file where the function
+       was called.
+
+     ``line``
+       The line in ``file`` of the function call.
+
+     ``cmd``
+       The name of the function that was called.
+
+     ``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
+
+     JSON trace format:
+
+     .. code-block:: json
+
+       {
+         "version": {
+           "major": 1,
+           "minor": 0
+         }
+       }
+
+     The members are:
+
+     ``version``
+       Indicates the version of the JSON format. The version has a
+       major and minor components following semantic version conventions.
+
 ``--trace-source=<file>``
  Put cmake in trace mode, but output only lines of a specified file.
 
@@ -539,22 +628,38 @@
      7a0b54896fe5e70cca6dd643ad6f672614b189bf26f8153061c4d219474b05dad08c4e729af9f4b009f1a1a280cb625454bf587c690f4617c27e3aebdf3b7a2d  file2.txt
 
 ``remove [-f] <file>...``
-  Remove the file(s). If any of the listed files already do not
-  exist, the command returns a non-zero exit code, but no message
-  is logged. The ``-f`` option changes the behavior to return a
+  .. deprecated:: 3.17
+
+  Remove the file(s). The planned behaviour was that if any of the
+  listed files already do not exist, the command returns a non-zero exit code,
+  but no message is logged. The ``-f`` option changes the behavior to return a
   zero exit code (i.e. success) in such situations instead.
   ``remove`` does not follow symlinks. That means it remove only symlinks
   and not files it point to.
 
+  The implementation was buggy and always returned 0. It cannot be fixed without
+  breaking backwards compatibility. Use ``rm`` instead.
+
 ``remove_directory <dir>...``
-  Remove ``<dir>`` directories and their contents.  If a directory does
+  .. deprecated:: 3.17
+
+  Remove ``<dir>`` directories and their contents. If a directory does
   not exist it will be silently ignored.  If ``<dir>`` is a symlink to
   a directory, just the symlink will be removed.
+  Use ``rm`` instead.
 
 ``rename <oldname> <newname>``
   Rename a file or directory (on one volume). If file with the ``<newname>`` name
   already exists, then it will be silently replaced.
 
+``rm [-rRf] <file> <dir>...``
+  Remove the files ``<file>`` or directories ``dir``.
+  Use ``-r`` or ``-R`` to remove directories and their contents recursively.
+  If any of the listed files/directories do not exist, the command returns a
+  non-zero exit code, but no message is logged. The ``-f`` option changes
+  the behavior to return a zero exit code (i.e. success) in such
+  situations instead.
+
 ``server``
   Launch :manual:`cmake-server(7)` mode.
 
diff --git a/Help/manual/ctest.1.rst b/Help/manual/ctest.1.rst
index e29ebca..6503f0e 100644
--- a/Help/manual/ctest.1.rst
+++ b/Help/manual/ctest.1.rst
@@ -261,10 +261,27 @@
  fail, subsequent calls to CTest with the ``--rerun-failed`` option will run
  the set of tests that most recently failed (if any).
 
-``--repeat-until-fail <n>``
- Require each test to run ``<n>`` times without failing in order to pass.
+``--repeat <mode>:<n>``
+  Run tests repeatedly based on the given ``<mode>`` up to ``<n>`` times.
+  The modes are:
 
- This is useful in finding sporadic failures in test cases.
+  ``until-fail``
+    Require each test to run ``<n>`` times without failing in order to pass.
+    This is useful in finding sporadic failures in test cases.
+
+  ``until-pass``
+    Allow each test to run up to ``<n>`` times in order to pass.
+    Repeats tests if they fail for any reason.
+    This is useful in tolerating sporadic failures in test cases.
+
+  ``after-timeout``
+    Allow each test to run up to ``<n>`` times in order to pass.
+    Repeats tests only if they timeout.
+    This is useful in tolerating sporadic timeouts in test cases
+    on busy machines.
+
+``--repeat-until-fail <n>``
+ Equivalent to ``--repeat until-fail:<n>``.
 
 ``--max-width <width>``
  Set the max width for a test name to output.
@@ -353,6 +370,14 @@
  This option will not run any tests, it will simply print the list of
  all labels associated with the test set.
 
+``--no-tests=<[error|ignore]>``
+ Regard no tests found either as error or ignore it.
+
+ If no tests were found, the default behavior of CTest is to always log an
+ error message but to return an error code in script mode only.  This option
+ unifies the behavior of CTest by either returning an error code if no tests
+ were found or by ignoring it.
+
 .. include:: OPTIONS_HELP.txt
 
 .. _`Label and Subproject Summary`:
@@ -1096,6 +1121,20 @@
   * `CTest Script`_ variable: none
   * :module:`CTest` module variable: ``VALGRIND_COMMAND_OPTIONS``
 
+``DrMemoryCommand``
+  Specify a ``MemoryCheckCommand`` that is known to be a command-line
+  compatible with DrMemory.
+
+  * `CTest Script`_ variable: none
+  * :module:`CTest` module variable: ``DRMEMORY_COMMAND``
+
+``DrMemoryCommandOptions``
+  Specify command-line options to the ``DrMemoryCommand`` tool.
+  They will be placed prior to the test command line.
+
+  * `CTest Script`_ variable: none
+  * :module:`CTest` module variable: ``DRMEMORY_COMMAND_OPTIONS``
+
 .. _`CTest Submit Step`:
 
 CTest Submit Step
@@ -1292,6 +1331,15 @@
 resources are in use and which are free, scheduling tests in a way that
 prevents them from trying to claim resources that are not available.
 
+When the resource allocation feature is used, CTest will not oversubscribe
+resources. For example, if a resource has 8 slots, CTest will not run tests
+that collectively use more than 8 slots at a time. This has the effect of
+limiting how many tests can run at any given time, even if a high ``-j``
+argument is used, if those tests all use some slots from the same resource.
+In addition, it means that a single test that uses more of a resource than is
+available on a machine will not run at all (and will be reported as
+``Not Run``).
+
 A common use case for this feature is for tests that require the use of a GPU.
 Multiple tests can simultaneously allocate memory from a GPU, but if too many
 tests try to do this at once, some of them will fail to allocate, resulting in
diff --git a/Help/module/FindCUDAToolkit.rst b/Help/module/FindCUDAToolkit.rst
new file mode 100644
index 0000000..5f01d68
--- /dev/null
+++ b/Help/module/FindCUDAToolkit.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/FindCUDAToolkit.cmake
diff --git a/Help/policy/CMP0098.rst b/Help/policy/CMP0098.rst
new file mode 100644
index 0000000..6d1443b
--- /dev/null
+++ b/Help/policy/CMP0098.rst
@@ -0,0 +1,30 @@
+CMP0098
+-------
+
+:module:`FindFLEX` runs ``flex`` in directory
+:variable:`CMAKE_CURRENT_BINARY_DIR` when executing.
+
+The module provides a ``FLEX_TARGET`` macro which generates FLEX output.
+In CMake 3.16 and below the macro would generate a custom command that runs
+``flex`` in the current source directory.  CMake 3.17 and later prefer to
+run it in the build directory and use :variable:`CMAKE_CURRENT_BINARY_DIR`
+as the ``WORKING_DIRECTORY`` of its :command:`add_custom_command` invocation.
+This ensures that any implicitly generated file is written relative to the
+build tree rather than the source tree, unless the generated file is
+provided as absolute path.
+
+This policy provides compatibility for projects that have not been updated
+to expect the new behavior.
+
+The ``OLD`` behavior for this policy is for ``FLEX_TARGET`` to use
+the current source directory for the ``WORKING_DIRECTORY`` and where
+to generate implicit files. The ``NEW`` behavior of this policy is to
+use the current binary directory for the ``WORKING_DIRECTORY`` relative to
+which implicit files are generated unless provided as absolute path.
+
+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/CMP0099.rst b/Help/policy/CMP0099.rst
new file mode 100644
index 0000000..c897e7b
--- /dev/null
+++ b/Help/policy/CMP0099.rst
@@ -0,0 +1,24 @@
+CMP0099
+-------
+
+Target link properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
+:prop_tgt:`INTERFACE_LINK_DIRECTORIES` and :prop_tgt:`INTERFACE_LINK_DEPENDS`
+are now transitive over private dependencies of static libraries.
+
+In CMake 3.16 and below the interface link properties attached to libraries
+are not propagated for private dependencies of static libraries.
+Only the libraries themselves are propagated to link the dependent binary.
+CMake 3.17 and later prefer to propagate all interface link properties.
+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 propagate interface link
+properties. The ``NEW`` behavior of this policy is to propagate interface link
+properties.
+
+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/CMP0100.rst b/Help/policy/CMP0100.rst
new file mode 100644
index 0000000..b24d013
--- /dev/null
+++ b/Help/policy/CMP0100.rst
@@ -0,0 +1,40 @@
+CMP0100
+-------
+
+Let :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC` process
+header files that end with a ``.hh`` extension.
+
+Since version 3.17, CMake processes header files that end with a
+``.hh`` extension in :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`.
+In earlier CMake versions, these header files were ignored by
+:prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`.
+
+This policy affects how header files that end with a ``.hh`` extension
+get treated in :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`.
+
+The ``OLD`` behavior for this policy is to ignore ``.hh`` header files
+in :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`.
+
+The ``NEW`` behavior for this policy is to process ``.hh`` header files
+in :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC` just like other header files.
+
+.. note::
+
+  To silence the ``CMP0100`` warning source files can be excluded from
+  :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC` processing by setting the
+  source file properties :prop_sf:`SKIP_AUTOMOC`, :prop_sf:`SKIP_AUTOUIC` or
+  :prop_sf:`SKIP_AUTOGEN`.
+
+  .. code-block:: cmake
+
+    # Source skip example:
+    set_property(SOURCE /path/to/file1.hh PROPERTY SKIP_AUTOMOC ON)
+    set_property(SOURCE /path/to/file2.hh PROPERTY SKIP_AUTOUIC ON)
+    set_property(SOURCE /path/to/file3.hh PROPERTY SKIP_AUTOGEN ON)
+
+This policy was introduced in CMake version 3.17.0.  CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/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_gbl/CMAKE_CUDA_KNOWN_FEATURES.rst b/Help/prop_gbl/CMAKE_CUDA_KNOWN_FEATURES.rst
new file mode 100644
index 0000000..44e37fe
--- /dev/null
+++ b/Help/prop_gbl/CMAKE_CUDA_KNOWN_FEATURES.rst
@@ -0,0 +1,30 @@
+CMAKE_CUDA_KNOWN_FEATURES
+-------------------------
+
+List of CUDA features known to this version of CMake.
+
+The features listed in this global property may be known to be available to the
+CUDA compiler.  If the feature is available with the C++ compiler, it will
+be listed in the :variable:`CMAKE_CUDA_COMPILE_FEATURES` variable.
+
+The features listed here may be used with the :command:`target_compile_features`
+command.  See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
+
+
+The features known to this version of CMake are:
+
+``cuda_std_03``
+  Compiler mode is at least CUDA/C++ 03.
+
+``cuda_std_11``
+  Compiler mode is at least CUDA/C++ 11.
+
+``cuda_std_14``
+  Compiler mode is at least CUDA/C++ 14.
+
+``cuda_std_17``
+  Compiler mode is at least CUDA/C++ 17.
+
+``cuda_std_20``
+  Compiler mode is at least CUDA/C++ 20.
diff --git a/Help/prop_sf/GENERATED.rst b/Help/prop_sf/GENERATED.rst
index d430ee2..48ff70c 100644
--- a/Help/prop_sf/GENERATED.rst
+++ b/Help/prop_sf/GENERATED.rst
@@ -4,16 +4,29 @@
 Is this source file generated as part of the build or CMake process.
 
 Tells the internal CMake engine that a source file is generated by an outside
-process such as another build step, or the execution of CMake itself. This
-information is then used to exempt the file from any existence or validity
-checks. Generated files are created by the execution of commands such as
-:command:`add_custom_command` and :command:`file(GENERATE)`.
+process such as another build step, or the execution of CMake itself.
+This information is then used to exempt the file from any existence or
+validity checks.
 
-When a generated file created by an :command:`add_custom_command` command
-is explicitly listed as a source file for any target in the same
-directory scope (which usually means the same ``CMakeLists.txt`` file),
-CMake will automatically create a dependency to make sure the file is
-generated before building that target.
+Any file that is
+
+- created by the execution of commands such as
+  :command:`add_custom_command` and :command:`file(GENERATE)`
+- listed as one of the ``BYPRODUCTS`` of an :command:`add_custom_command`
+  or :command:`add_custom_target` command, or
+- created by a CMake ``AUTOGEN`` operation such as :prop_tgt:`AUTOMOC`,
+  :prop_tgt:`AUTORCC`, or :prop_tgt:`AUTOUIC`
+
+will be marked with the ``GENERATED`` property.
+
+When a generated file created as the ``OUTPUT`` of an
+:command:`add_custom_command` command is explicitly listed as a source file
+for any target in the same directory scope (which usually means the same
+``CMakeLists.txt`` file), CMake will automatically create a dependency to
+make sure the file is generated before building that target.
+
+The :ref:`Makefile Generators` will remove ``GENERATED`` files during
+``make clean``.
 
 Generated sources may be hidden in some IDE tools, while in others they might
 be shown. For the special case of sources generated by CMake's :prop_tgt:`AUTOMOC`
diff --git a/Help/prop_tgt/AIX_EXPORT_ALL_SYMBOLS.rst b/Help/prop_tgt/AIX_EXPORT_ALL_SYMBOLS.rst
new file mode 100644
index 0000000..15ddc0b
--- /dev/null
+++ b/Help/prop_tgt/AIX_EXPORT_ALL_SYMBOLS.rst
@@ -0,0 +1,12 @@
+AIX_EXPORT_ALL_SYMBOLS
+----------------------
+
+On AIX, CMake automatically exports all symbols from shared libraries, and
+from executables with the :prop_tgt:`ENABLE_EXPORTS` target property set.
+Explicitly disable this boolean property to suppress the behavior and
+export no symbols by default.  In this case it is expected that the project
+will use other means to export some symbols.
+
+This property is initialized by the value of
+the :variable:`CMAKE_AIX_EXPORT_ALL_SYMBOLS` variable if it is set
+when a target is created.
diff --git a/Help/prop_tgt/AUTOGEN_PARALLEL.rst b/Help/prop_tgt/AUTOGEN_PARALLEL.rst
index 07fbc5a..968b619 100644
--- a/Help/prop_tgt/AUTOGEN_PARALLEL.rst
+++ b/Help/prop_tgt/AUTOGEN_PARALLEL.rst
@@ -4,9 +4,9 @@
 Number of parallel ``moc`` or ``uic`` processes to start when using
 :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC`.
 
-The custom `<origin>_autogen` target starts a number of threads of which
+The custom ``<origin>_autogen`` target starts a number of threads of which
 each one parses a source file and on demand starts a ``moc`` or ``uic``
-process.  :prop_tgt:`AUTOGEN_PARALLEL` controls how many parallel threads
+process.  ``AUTOGEN_PARALLEL`` controls how many parallel threads
 (and therefore ``moc`` or ``uic`` processes) are started.
 
 - An empty (or unset) value or the string ``AUTO`` sets the number of
@@ -14,7 +14,7 @@
 - A positive non zero integer value sets the exact thread/process count.
 - Otherwise a single thread/process is started.
 
-By default :prop_tgt:`AUTOGEN_PARALLEL` is initialized from
+By default ``AUTOGEN_PARALLEL`` is initialized from
 :variable:`CMAKE_AUTOGEN_PARALLEL`.
 
 See the :manual:`cmake-qt(7)` manual for more information on using CMake
diff --git a/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst b/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst
index d5c5e14..92b52a3 100644
--- a/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst
+++ b/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst
@@ -33,4 +33,4 @@
   :prop_sf:`SKIP_AUTOUIC`, :prop_sf:`SKIP_AUTOGEN` or :policy:`CMP0071` or
 - a file that isn't in the origin target's sources
 
-it must added to :prop_tgt:`AUTOGEN_TARGET_DEPENDS`.
+it must be added to :prop_tgt:`AUTOGEN_TARGET_DEPENDS`.
diff --git a/Help/prop_tgt/AUTOMOC.rst b/Help/prop_tgt/AUTOMOC.rst
index f6dfabd..c18859b 100644
--- a/Help/prop_tgt/AUTOMOC.rst
+++ b/Help/prop_tgt/AUTOMOC.rst
@@ -172,7 +172,7 @@
 then the version variables might not be available to the :prop_tgt:`AUTOMOC`
 enabled target.
 In that case the version variables can be forwarded from the
-`find_package(Qt[45]...)` calling context to the :command:`add_executable`
+``find_package(Qt[45]...)`` calling context to the :command:`add_executable`
 or :command:`add_library` calling context as directory properties.
 The following Qt5 example demonstrates the procedure.
 
diff --git a/Help/prop_tgt/AUTOMOC_DEPEND_FILTERS.rst b/Help/prop_tgt/AUTOMOC_DEPEND_FILTERS.rst
index 69957bf..6eda26c 100644
--- a/Help/prop_tgt/AUTOMOC_DEPEND_FILTERS.rst
+++ b/Help/prop_tgt/AUTOMOC_DEPEND_FILTERS.rst
@@ -26,6 +26,9 @@
 By default :prop_tgt:`AUTOMOC_DEPEND_FILTERS` is initialized from
 :variable:`CMAKE_AUTOMOC_DEPEND_FILTERS`, which is empty by default.
 
+From Qt 5.15.0 on this variable is ignored as moc is able to output the correct
+dependencies.
+
 See the :manual:`cmake-qt(7)` manual for more information on using CMake
 with Qt.
 
diff --git a/Help/prop_tgt/AUTOMOC_MOC_OPTIONS.rst b/Help/prop_tgt/AUTOMOC_MOC_OPTIONS.rst
index ebd5c49..330849b 100644
--- a/Help/prop_tgt/AUTOMOC_MOC_OPTIONS.rst
+++ b/Help/prop_tgt/AUTOMOC_MOC_OPTIONS.rst
@@ -1,7 +1,7 @@
 AUTOMOC_MOC_OPTIONS
 -------------------
 
-Additional options for moc when using :prop_tgt:`AUTOMOC`
+Additional options for ``moc`` when using :prop_tgt:`AUTOMOC`
 
 This property is only used if the :prop_tgt:`AUTOMOC` property is ``ON``
 for this target.  In this case, it holds additional command line
@@ -9,7 +9,9 @@
 it is equivalent to the optional ``OPTIONS`` argument of the
 :module:`qt4_wrap_cpp() <FindQt4>` macro.
 
-By default it is empty.
+This property is initialized by the value of the
+:variable:`CMAKE_AUTOMOC_MOC_OPTIONS` variable if it is set when a target
+is created, or an empty string otherwise.
 
 See the :manual:`cmake-qt(7)` manual for more information on using CMake
 with Qt.
diff --git a/Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst b/Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst
index e2ebb3f..3e3059d 100644
--- a/Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst
+++ b/Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst
@@ -21,11 +21,11 @@
 Reproducible builds
 ^^^^^^^^^^^^^^^^^^^
 
-For reproducible builds is is recommended to keep headers that are ``moc``
+For reproducible builds it is recommended to keep headers that are ``moc``
 compiled in one of the target
 :command:`include directories <target_include_directories>` and set
 :prop_tgt:`AUTOMOC_PATH_PREFIX` to ``ON`` (which is the default).  This ensures
-that
+that:
 
 - ``moc`` output files are identical on different build setups,
 - ``moc`` output files will compile correctly when the source and/or
diff --git a/Help/prop_tgt/AUTORCC.rst b/Help/prop_tgt/AUTORCC.rst
index cca3e58..9a98f44 100644
--- a/Help/prop_tgt/AUTORCC.rst
+++ b/Help/prop_tgt/AUTORCC.rst
@@ -31,9 +31,10 @@
 The ``rcc`` executable will be detected automatically, but can be forced to
 a certain binary by setting this target property.
 
-:prop_sf:`AUTORCC_OPTIONS`:
-Additional command line options for ``rcc`` can be set via this ``.qrc``
-source file property.
+:prop_tgt:`AUTORCC_OPTIONS`:
+Additional command line options for ``rcc`` can be set via this target
+property.  The corresponding :prop_sf:`AUTORCC_OPTIONS` source file property
+can be used to specify options to be applied only to a specific ``.qrc`` file.
 
 :prop_sf:`SKIP_AUTORCC`:
 ``.qrc`` files can be excluded from :prop_tgt:`AUTORCC` processing by
diff --git a/Help/prop_tgt/AUTORCC_OPTIONS.rst b/Help/prop_tgt/AUTORCC_OPTIONS.rst
index d6ade5a..5261aff 100644
--- a/Help/prop_tgt/AUTORCC_OPTIONS.rst
+++ b/Help/prop_tgt/AUTORCC_OPTIONS.rst
@@ -8,11 +8,9 @@
 i.e. it is equivalent to the optional ``OPTIONS`` argument of the
 :module:`qt4_add_resources() <FindQt4>` macro.
 
-By default it is empty.
-
 This property is initialized by the value of the
 :variable:`CMAKE_AUTORCC_OPTIONS` variable if it is set when a target is
-created.
+created, or an empty string otherwise.
 
 The options set on the target may be overridden by :prop_sf:`AUTORCC_OPTIONS`
 set on the ``.qrc`` source file.
diff --git a/Help/prop_tgt/AUTOUIC.rst b/Help/prop_tgt/AUTOUIC.rst
index 5cf8755..cd24f5e 100644
--- a/Help/prop_tgt/AUTOUIC.rst
+++ b/Help/prop_tgt/AUTOUIC.rst
@@ -52,8 +52,11 @@
 The ``uic`` executable will be detected automatically, but can be forced to
 a certain binary using this target property.
 
-:prop_sf:`AUTOUIC_OPTIONS`: Additional command line options for ``uic`` can
-be set via this source file property on a ``<base_name>.ui`` file.
+:prop_tgt:`AUTOUIC_OPTIONS`:
+Additional command line options for ``uic`` can be set via this target
+property.  The corresponding :prop_sf:`AUTOUIC_OPTIONS` source file property
+can be used to specify options to be applied only to a specific
+``<base_name>.ui`` file.
 
 :prop_sf:`SKIP_AUTOUIC`:
 Source files can be excluded from :prop_tgt:`AUTOUIC` processing by setting
diff --git a/Help/prop_tgt/AUTOUIC_OPTIONS.rst b/Help/prop_tgt/AUTOUIC_OPTIONS.rst
index 3f613b9..425ea1c 100644
--- a/Help/prop_tgt/AUTOUIC_OPTIONS.rst
+++ b/Help/prop_tgt/AUTOUIC_OPTIONS.rst
@@ -8,11 +8,9 @@
 equivalent to the optional ``OPTIONS`` argument of the
 :module:`qt4_wrap_ui() <FindQt4>` macro.
 
-By default it is empty.
-
 This property is initialized by the value of the
 :variable:`CMAKE_AUTOUIC_OPTIONS` variable if it is set when a target is
-created.
+created, or an empty string otherwise.
 
 The options set on the target may be overridden by :prop_sf:`AUTOUIC_OPTIONS`
 set on the ``.ui`` source file.
diff --git a/Help/prop_tgt/COMPILE_FEATURES.rst b/Help/prop_tgt/COMPILE_FEATURES.rst
index 195215e..46aec4f 100644
--- a/Help/prop_tgt/COMPILE_FEATURES.rst
+++ b/Help/prop_tgt/COMPILE_FEATURES.rst
@@ -4,7 +4,8 @@
 Compiler features enabled for this target.
 
 The list of features in this property are a subset of the features listed
-in the :variable:`CMAKE_CXX_COMPILE_FEATURES` variable.
+in the :variable:`CMAKE_C_COMPILE_FEATURES`, :variable:`CMAKE_CUDA_COMPILE_FEATURES`, and
+:variable:`CMAKE_CXX_COMPILE_FEATURES` variables.
 
 Contents of ``COMPILE_FEATURES`` may use "generator expressions" with the
 syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)` manual for
diff --git a/Help/prop_tgt/CUDA_RUNTIME_LIBRARY-VALUES.txt b/Help/prop_tgt/CUDA_RUNTIME_LIBRARY-VALUES.txt
new file mode 100644
index 0000000..a6d7050
--- /dev/null
+++ b/Help/prop_tgt/CUDA_RUNTIME_LIBRARY-VALUES.txt
@@ -0,0 +1,9 @@
+``None``
+  Link with ``-cudart=none`` or equivalent flag(s) to use no CUDA
+  runtime library.
+``Shared``
+  Link with ``-cudart=shared`` or equivalent flag(s) to use a
+  dynamically-linked CUDA runtime library.
+``Static``
+  Link with ``-cudart=static`` or equivalent flag(s) to use a
+  statically-linked CUDA runtime library.
diff --git a/Help/prop_tgt/CUDA_RUNTIME_LIBRARY.rst b/Help/prop_tgt/CUDA_RUNTIME_LIBRARY.rst
new file mode 100644
index 0000000..0782765
--- /dev/null
+++ b/Help/prop_tgt/CUDA_RUNTIME_LIBRARY.rst
@@ -0,0 +1,21 @@
+CUDA_RUNTIME_LIBRARY
+--------------------
+
+Select the CUDA runtime library for use by compilers targeting the CUDA language.
+
+The allowed case insensitive values are:
+
+.. include:: CUDA_RUNTIME_LIBRARY-VALUES.txt
+
+Contents of ``CUDA_RUNTIME_LIBRARY`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+If this property is not set then CMake uses the default value
+``Static`` to select the CUDA runtime library.
+
+.. note::
+
+  This property has effect only when the ``CUDA`` language is enabled. To
+  control the CUDA runtime linking when only using the CUDA SDK with the
+  ``C`` or ``C++`` language we recommend using the :module:`FindCUDAToolkit`
+  module.
diff --git a/Help/prop_tgt/DEPRECATION.rst b/Help/prop_tgt/DEPRECATION.rst
new file mode 100644
index 0000000..fef2e2e
--- /dev/null
+++ b/Help/prop_tgt/DEPRECATION.rst
@@ -0,0 +1,7 @@
+DEPRECATION
+-----------
+
+Deprecation message from imported target's developer.
+
+``DEPRECATION`` is the message regarding a deprecation status to be displayed
+to downstream users of a target.
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/INSTALL_NAME_DIR.rst b/Help/prop_tgt/INSTALL_NAME_DIR.rst
index 2216072..747615a 100644
--- a/Help/prop_tgt/INSTALL_NAME_DIR.rst
+++ b/Help/prop_tgt/INSTALL_NAME_DIR.rst
@@ -10,3 +10,7 @@
 This property is initialized by the value of the variable
 :variable:`CMAKE_INSTALL_NAME_DIR` if it is set when a target is
 created.
+
+This property supports :manual:`generator expressions <cmake-generator-expressions(7)>`.
+In particular, the ``$<INSTALL_PREFIX>`` generator expression can be used to set the
+directory relative to the install-time prefix.
diff --git a/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst b/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst
index d8be954..d16a7a1 100644
--- a/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst
+++ b/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst
@@ -3,8 +3,12 @@
 
 Add paths to linker search and installed rpath.
 
-``INSTALL_RPATH_USE_LINK_PATH`` is a boolean that if set to ``True`` will
-append directories in the linker search path and outside the project
-to the :prop_tgt:`INSTALL_RPATH`.  This property is initialized by the value of
-the variable ``CMAKE_INSTALL_RPATH_USE_LINK_PATH`` if it is set when a
-target is created.
+``INSTALL_RPATH_USE_LINK_PATH`` is a boolean that if set to ``True``
+will append to the runtime search path (rpath) of installed binaries
+any directories outside the project that are in the linker search path or
+contain linked library files.  The directories are appended after the
+value of the :prop_tgt:`INSTALL_RPATH` target property.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_INSTALL_RPATH_USE_LINK_PATH` if it is set when a target is
+created.
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/MACHO_COMPATIBILITY_VERSION.rst b/Help/prop_tgt/MACHO_COMPATIBILITY_VERSION.rst
new file mode 100644
index 0000000..f3fedba
--- /dev/null
+++ b/Help/prop_tgt/MACHO_COMPATIBILITY_VERSION.rst
@@ -0,0 +1,14 @@
+MACHO_COMPATIBILITY_VERSION
+---------------------------
+
+What compatibility version number is this target for Mach-O binaries.
+
+For shared libraries on Mach-O systems (e.g. macOS, iOS)
+the ``MACHO_COMPATIBILITY_VERSION`` property correspond to
+``compatibility version`` and :prop_tgt:`MACHO_CURRENT_VERSION` to
+``current version``.
+See the :prop_tgt:`FRAMEWORK` target property for an example.
+
+Versions of Mach-O binaries may be checked with the ``otool -L <binary>``
+command.  If ``MACHO_COMPATIBILITY_VERSION`` is not set, the value of
+the :prop_tgt:`SOVERSION` property will be used.
diff --git a/Help/prop_tgt/MACHO_CURRENT_VERSION.rst b/Help/prop_tgt/MACHO_CURRENT_VERSION.rst
new file mode 100644
index 0000000..4a1d3f0
--- /dev/null
+++ b/Help/prop_tgt/MACHO_CURRENT_VERSION.rst
@@ -0,0 +1,13 @@
+MACHO_CURRENT_VERSION
+---------------------
+
+What current version number is this target for Mach-O binaries.
+
+For shared libraries on Mach-O systems (e.g. macOS, iOS)
+the :prop_tgt:`MACHO_COMPATIBILITY_VERSION` property correspond to
+``compatibility version`` and ``MACHO_CURRENT_VERSION`` to ``current version``.
+See the :prop_tgt:`FRAMEWORK` target property for an example.
+
+Versions of Mach-O binaries may be checked with the ``otool -L <binary>``
+command.  If ``MACHO_CURRENT_VERSION`` is not set, the value of
+the :prop_tgt:`VERSION` property will be used.
diff --git a/Help/prop_tgt/SOVERSION.rst b/Help/prop_tgt/SOVERSION.rst
index b07c17c..d6f8a94 100644
--- a/Help/prop_tgt/SOVERSION.rst
+++ b/Help/prop_tgt/SOVERSION.rst
@@ -21,7 +21,9 @@
 ^^^^^^^^^^^^^^^
 
 For shared libraries and executables on Mach-O systems (e.g. macOS, iOS),
-the ``SOVERSION`` property corresponds to *compatibility version* and
-:prop_tgt:`VERSION` to *current version*.  See the :prop_tgt:`FRAMEWORK` target
-property for an example.  Versions of Mach-O binaries may be checked with the
-``otool -L <binary>`` command.
+the ``SOVERSION`` property is a fallback to
+:prop_tgt:`MACHO_COMPATIBILITY_VERSION` property which corresponds to
+*compatiblity version* and :prop_tgt:`VERSION` is a fallback to
+:prop_tgt:`MACHO_CURRENT_VERSION` which corresponds to *current version*.
+See the :prop_tgt:`FRAMEWORK` target property for an example.  Versions
+of Mach-O binaries may be checked with the ``otool -L <binary>`` command.
diff --git a/Help/prop_tgt/VERSION.rst b/Help/prop_tgt/VERSION.rst
index ff3b303..f592f4a 100644
--- a/Help/prop_tgt/VERSION.rst
+++ b/Help/prop_tgt/VERSION.rst
@@ -23,7 +23,9 @@
 ^^^^^^^^^^^^^^^
 
 For shared libraries and executables on Mach-O systems (e.g. macOS, iOS),
-the :prop_tgt:`SOVERSION` property correspond to *compatibility version* and
-``VERSION`` to *current version*.  See the :prop_tgt:`FRAMEWORK` target
+the ``VERSION`` property is a fallback to :prop_tgt:`MACHO_CURRENT_VERSION`
+property which corresponds to *current version* and :prop_tgt:`SOVERSION`
+is a fallback to :prop_tgt:`MACHO_COMPATIBILITY_VERSION` which corresponds
+to *compatiblity version*.  See the :prop_tgt:`FRAMEWORK` target
 property for an example.  Versions of Mach-O binaries may be checked with the
 ``otool -L <binary>`` command.
diff --git a/Help/prop_tgt/VS_DOTNET_DOCUMENTATION_FILE.rst b/Help/prop_tgt/VS_DOTNET_DOCUMENTATION_FILE.rst
new file mode 100644
index 0000000..1bc361c
--- /dev/null
+++ b/Help/prop_tgt/VS_DOTNET_DOCUMENTATION_FILE.rst
@@ -0,0 +1,6 @@
+VS_DOTNET_DOCUMENTATION_FILE
+----------------------------
+
+Visual Studio managed project .NET documentation output
+
+Sets the target XML documentation file output.
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/prop_tgt/XCODE_SCHEME_WORKING_DIRECTORY.rst b/Help/prop_tgt/XCODE_SCHEME_WORKING_DIRECTORY.rst
new file mode 100644
index 0000000..7ffa74b
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_WORKING_DIRECTORY.rst
@@ -0,0 +1,13 @@
+XCODE_SCHEME_WORKING_DIRECTORY
+------------------------------
+
+Specify the ``Working Directory`` a of the `Run` and `Profile`
+action in the generated Xcode scheme. In case the value contains
+generator expressions those are evaluated.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_WORKING_DIRECTORY` if it is set
+when a target is created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/release/3.17.rst b/Help/release/3.17.rst
new file mode 100644
index 0000000..c2cfdf0
--- /dev/null
+++ b/Help/release/3.17.rst
@@ -0,0 +1,321 @@
+CMake 3.17 Release Notes
+************************
+
+.. only:: html
+
+  .. contents::
+
+Changes made since CMake 3.16 include the following.
+
+New Features
+============
+
+Generators
+----------
+
+* :manual:`cmake(1)` gained a :generator:`Ninja Multi-Config` generator,
+  which is similar to the :generator:`Ninja` generator but can be used to build
+  multiple configurations at once.
+
+* :ref:`Visual Studio Generators` learned to support per-config sources.
+  Previously only :ref:`Command-Line Build Tool Generators` supported them.
+
+* :ref:`Visual Studio Generators` for VS 2010 and above now support
+  specifying the ``VCTargetsPath`` value for project files in
+  :variable:`CMAKE_GENERATOR_TOOLSET` setting.
+
+* :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.
+
+Languages
+---------
+
+* The :manual:`Compile Features <cmake-compile-features(7)>` functionality
+  now offers meta-features for the CUDA language standard levels
+  (e.g. ``cuda_std_03``, ``cuda_std_14``).  See
+  :prop_gbl:`CMAKE_CUDA_KNOWN_FEATURES`.
+
+Compilers
+---------
+
+* The IBM XL Fortran compiler is now supported by the :generator:`Ninja`
+  generator.
+
+Command-Line
+------------
+
+* :manual:`cmake(1)` gained a ``--debug-find`` command-line option to
+  enable additional human-readable output on where ``find_*`` commands search.
+
+* :manual:`cmake(1)` gained a ``--trace-format`` command-line option that
+  can be used to set the ``--trace`` output format. Currently, the old
+  human readable and the new JSON format are supported. The new JSON format
+  is easier to parse automatically than the existing format.
+
+* :manual:`cmake(1)` gained a ``-E rm`` command-line tool that can be
+  used to remove directories and files.  This supersedes the existing
+  ``-E remove`` and ``-E remove_directory`` tools and has better semantics.
+
+Commands
+--------
+
+* The :command:`add_custom_command` command learned to interpret paths in
+  ``DEPENDS`` arguments that are specified relative to the current
+  binary directory.
+
+* The :command:`foreach` command learned a new ``ZIP_LISTS`` option to iterate
+  over multiple lists simultaneously.
+
+* The :command:`load_cache(READ_WITH_PREFIX)` command mode is now allowed
+  when using ``cmake -P`` to :ref:`Run a Script <Script Processing Mode>`.
+
+* The :command:`message` command learned to output context provided in
+  the :variable:`CMAKE_MESSAGE_CONTEXT` variable for log levels
+  ``NOTICE`` and below.  Enable this output with the new ``--log-context``
+  command-line option or :variable:`CMAKE_MESSAGE_CONTEXT_SHOW` variable.
+
+* The :command:`message` command gained new keywords ``CHECK_START``,
+  ``CHECK_PASS`` and ``CHECK_FAIL``.
+
+* The :command:`target_compile_options` command now honors the ``BEFORE``
+  keyword more consistently.  See policy :policy:`CMP0101`.
+
+Variables
+---------
+
+* 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.
+
+* The following variables are now defined inside a :command:`function`:
+
+  - :variable:`CMAKE_CURRENT_FUNCTION`
+  - :variable:`CMAKE_CURRENT_FUNCTION_LIST_DIR`
+  - :variable:`CMAKE_CURRENT_FUNCTION_LIST_FILE`
+  - :variable:`CMAKE_CURRENT_FUNCTION_LIST_LINE`
+
+* The :variable:`CMAKE_CUDA_RUNTIME_LIBRARY` variable and
+  :prop_tgt:`CUDA_RUNTIME_LIBRARY` target property were introduced to
+  select the CUDA runtime library used when linking targets that
+  use CUDA.
+
+* The :variable:`CMAKE_FIND_DEBUG_MODE` variable was introduced to
+  print extra ``find_*`` call information during the cmake run to standard
+  error. Output is designed for human consumption and not for parsing.
+
+* The :variable:`CMAKE_EXPORT_COMPILE_COMMANDS` variable now takes its
+  initial value from the :envvar:`CMAKE_EXPORT_COMPILE_COMMANDS` environment
+  variable if no explicit configuration is given.
+
+* The :variable:`CMAKE_<LANG>_COMPILER_LAUNCHER` variable, if not set
+  explicitly, now takes its initial value from the
+  :envvar:`CMAKE_<LANG>_COMPILER_LAUNCHER` environment variable.
+
+* The :variable:`CMAKE_MESSAGE_LOG_LEVEL` variable can now be used
+  to persist a log level between CMake runs, unlike the ``--log-level``
+  command line option which only applies to that particular run.
+
+* The :variable:`CMAKE_XCODE_SCHEME_ENVIRONMENT` variable was added
+  to initialize the :prop_tgt:`XCODE_SCHEME_ENVIRONMENT` target property.
+
+* The :variable:`CMAKE_XCODE_SCHEME_WORKING_DIRECTORY` variable and
+  associated :prop_tgt:`XCODE_SCHEME_WORKING_DIRECTORY` target property
+  were added to tell the :generator:`Xcode` generator to set the value of
+  the ``Custom Working Directory`` schema option.
+
+Properties
+----------
+
+* The :prop_tgt:`AIX_EXPORT_ALL_SYMBOLS` target property and associated
+  :variable:`CMAKE_AIX_EXPORT_ALL_SYMBOLS` variable were created to
+  optionally explicitly disable automatic export of symbols from shared
+  libraries on AIX.
+
+* The :prop_tgt:`DEPRECATION` target property was added to mark
+  a target as deprecated.  If a linked target is marked as
+  deprecated, a warning with the deprecation message is issued
+  at generate time.
+
+* The :prop_tgt:`INSTALL_NAME_DIR` target property now supports
+  :manual:`generator expressions <cmake-generator-expressions(7)>`.
+  In particular, the ``$<INSTALL_PREFIX>`` generator expression can
+  be used to set the directory relative to the install-time prefix.
+
+* Target properties :prop_tgt:`MACHO_COMPATIBILITY_VERSION` and
+  :prop_tgt:`MACHO_CURRENT_VERSION` were added to set the
+  ``compatibility_version`` and ``curent_version``, respectively,
+  for Mach-O binaries.  For backwards compatibility, if these properties
+  are not set, :prop_tgt:`SOVERSION` and :prop_tgt:`VERSION`
+  are used respectively as fallbacks.
+
+* The :prop_tgt:`VS_DOTNET_DOCUMENTATION_FILE` target property was added
+  to tell :ref:`Visual Studio Generators` to generate a ``DocumentationFile``
+  reference in ``.csproj`` files.
+
+Modules
+-------
+
+* The :module:`ExternalProject` module :command:`ExternalProject_Add`
+  command gained a ``GIT_SUBMODULES_RECURSE`` option to specify whether
+  Git submodules should be updated recursively.  The default is on to
+  preserve existing behavior.
+
+* The :module:`FindCUDAToolkit` module was added to find the
+  CUDA Toolkit without enabling CUDA as a language.
+
+* The :module:`FindCURL` module learned to find CURL using
+  the ``CURLConfig.cmake`` package configuration file generated by
+  CURL's cmake buildsystem.  It also gained a new ``CURL_NO_CURL_CMAKE``
+  option to disable this behavior.
+
+* The :module:`FindFLEX` module's ``FLEX_TARGET`` command now runs ``flex``
+  with :variable:`CMAKE_CURRENT_BINARY_DIR` as the working directory.
+  See policy :policy:`CMP0098`.
+
+* The :module:`FindLibArchive` module now provides an imported target
+  for libarchive.
+
+* The :module:`FindPython` module has learned to find Python components
+  in active virtual environments managed by ``conda``.
+
+* The :module:`FindPython3` and :module:`FindPython` modules gained,
+  respectively, variable ``Python3_SOABI`` and ``Python_SOABI`` giving
+  the standard extension suffix for modules. Moreover, commands
+  ``Python3_add_library()`` and ``Python_add_library()`` gained the option
+  ``WITH_SOABI`` to prefix the library suffix with the value of ``SOABI``.
+
+* The :module:`FindLibXml2` module now provides an imported target for the
+  ``xmllint`` executable.
+
+Autogen
+-------
+
+* :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTOUIC` learned to process headers
+  with a ``.hh`` extension.  See policy :policy:`CMP0100`.
+
+CTest
+-----
+
+* The :variable:`CTEST_CONFIGURATION_TYPE` variable is now set from the
+  command line when :manual:`ctest(1)` is invoked with ``-C <cfg>``.
+
+* The :manual:`ctest(1)` tool gained support for Dr. Memory to run
+  memcheck runs.
+
+* The :manual:`ctest(1)` tool gained a ``--no-tests=<[error|ignore]>`` option
+  to explicitly set and unify the behavior between direct invocation and
+  script mode if no tests were found.
+
+* The :manual:`ctest(1)` tool gained a ``--repeat <mode>:<n>`` option
+  to specify conditions in which to repeat tests.  This generalizes
+  the existing ``--repeat-until-fail <n>`` option to add modes for
+  ``until-pass`` and ``after-timeout``.
+
+* The :command:`ctest_test` command gained a ``REPEAT <mode>:<n>`` option
+  to specify conditions in which to repeat tests.
+
+CPack
+-----
+
+* 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.
+
+* The :cpack_gen:`CPack DragNDrop Generator` learned to handle
+  RTF formatted license files.  When :variable:`CPACK_DMG_SLA_DIR`
+  variable is set, ``<language>.license.rtf`` is considered, but
+  only as a fallback when the plaintext (``.txt``) file is not found
+  in order to maintain backwards compatibility.
+
+* The :cpack_gen:`CPack NSIS Generator` gained a new variable
+  :variable:`CPACK_NSIS_MUI_HEADERIMAGE` to set the header image.
+  To not break existing setups, it still defaults to
+  :variable:`CPACK_PACKAGE_ICON` if the new variable is not set.
+
+* The :cpack_gen:`CPack NSIS Generator` now supports
+  :variable:`CPACK_NSIS_UNINSTALL_NAME`.
+  This can be used to specify the name of the Uninstall program.
+
+* The :cpack_gen:`CPack NSIS Generator` now supports
+  :variable:`CPACK_NSIS_WELCOME_TITLE` and
+  :variable:`CPACK_NSIS_WELCOME_TITLE_3LINES`.
+  These can be used to specify the welcome page title and display it in 3 lines.
+
+* The :cpack_gen:`CPack NSIS Generator` now supports
+  :variable:`CPACK_NSIS_FINISH_TITLE` and
+  :variable:`CPACK_NSIS_FINISH_TITLE_3LINES`.
+  These can be used to specify the finish page title and display it in 3 lines.
+
+* The :cpack_gen:`CPack productbuild Generator` gained support for a
+  :variable:`CPACK_PRODUCTBUILD_BACKGROUND` variable to specify a background
+  image for the macOS installer.
+
+Other
+-----
+
+* :manual:`ccmake(1)` now displays cache values using colors
+  based on the entry type if the terminal supports color.
+
+* :manual:`ccmake(1)` now displays messages and a progress bar during
+  configure and generate.  It will keep the output displayed if any
+  errors or warnings occurred.
+
+Deprecated and Removed Features
+===============================
+
+* An explicit deprecation diagnostic was added for policy ``CMP0068``
+  and policy ``CMP0069`` (``CMP0067`` and below were already deprecated).
+  The :manual:`cmake-policies(7)` manual explains that the OLD behaviors
+  of all policies are deprecated and that projects should port to the
+  NEW behaviors.
+
+* The :cpack_gen:`CPack PackageMaker Generator` generator has been
+  deprecated because Xcode no longer distributes the PackageMaker tools.
+  The undocumented ``OSXX11`` generator has also been deprecated.
+
+* The :manual:`cmake(1)` command-line ``-E remove`` and ``-E remove_directory``
+  tools are deprecated in favor of the new ``-E rm`` tool.  The older tools
+  always returned 0 if a named path did not exist even without the force
+  option and cannot be fixed without breaking compatibility, and so have
+  been superseded.
+
+Other Changes
+=============
+
+* The :manual:`file API <cmake-file-api(7)>` index file now emits a
+  ``multiConfig`` flag specifying whether or not the generator supports
+  multiple output configurations.
+
+* Target link properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
+  :prop_tgt:`INTERFACE_LINK_DIRECTORIES` and
+  :prop_tgt:`INTERFACE_LINK_DEPENDS` are now transitive over private
+  dependencies on static libraries.
+  See policy :policy:`CMP0099`.
+
+* 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.
+
+* The :generator:`MinGW Makefiles` generator no longer issues an error if
+  ``sh.exe`` is present in the environment's ``PATH``.
+
+* The :generator:`Ninja` generator now prefers the first ninja build
+  tool to appear in the ``PATH`` no matter whether it is called
+  ``ninja-build``, ``ninja``, or ``samu``.  Previously the first
+  of those names to appear anywhere in the ``PATH`` would be preferred.
+
+* With SDCC the ``sdar`` tool is now preferred over ``sdcclib`` as librarian.
+  The latter was deprecated by SDCC 3.2.0 and removed in SDCC 3.8.6.
+
+* With SDCC the default flags no longer include any target-specific flags.
+  Previously the default flags were hard-coded for 8051.
+
+* The :variable:`CMAKE_VS_GLOBALS` variable value now applies during
+  compiler identification and in targets created by the
+  :command:`add_custom_target` command.
+
+* The :generator:`Xcode` generator no longer hard-codes ``-Wmost``,
+  ``-Wno-four-char-constants``, and ``-Wno-unknown-pragmas`` warning flags.
diff --git a/Help/release/index.rst b/Help/release/index.rst
index 0cc3f97..5d1f8a2 100644
--- a/Help/release/index.rst
+++ b/Help/release/index.rst
@@ -13,6 +13,7 @@
 .. toctree::
    :maxdepth: 1
 
+   3.17 <3.17>
    3.16 <3.16>
    3.15 <3.15>
    3.14 <3.14>
diff --git a/Help/variable/CMAKE_AIX_EXPORT_ALL_SYMBOLS.rst b/Help/variable/CMAKE_AIX_EXPORT_ALL_SYMBOLS.rst
new file mode 100644
index 0000000..c64dd48
--- /dev/null
+++ b/Help/variable/CMAKE_AIX_EXPORT_ALL_SYMBOLS.rst
@@ -0,0 +1,6 @@
+CMAKE_AIX_EXPORT_ALL_SYMBOLS
+----------------------------
+
+Default value for :prop_tgt:`AIX_EXPORT_ALL_SYMBOLS` target property.
+This variable is used to initialize the property on each target as it is
+created.
diff --git a/Help/variable/CMAKE_CFG_INTDIR.rst b/Help/variable/CMAKE_CFG_INTDIR.rst
index af82f75..842654e 100644
--- a/Help/variable/CMAKE_CFG_INTDIR.rst
+++ b/Help/variable/CMAKE_CFG_INTDIR.rst
@@ -16,6 +16,13 @@
   $(Configuration)     = Visual Studio 10
   $(CONFIGURATION)     = Xcode
   .                    = Make-based tools
+  .                    = Ninja
+  ${CONFIGURATION}     = Ninja Multi-Config
+
+Note that this variable only has limited support on
+:generator:`Ninja Multi-Config`. It is recommended that you use the
+``$<CONFIG>`` :manual:`generator expression <cmake-generator-expressions(7)>`
+instead.
 
 Since these values are evaluated by the native build system, this
 variable is suitable only for use in command lines that will be
diff --git a/Help/variable/CMAKE_CROSS_CONFIGS.rst b/Help/variable/CMAKE_CROSS_CONFIGS.rst
new file mode 100644
index 0000000..c850af2
--- /dev/null
+++ b/Help/variable/CMAKE_CROSS_CONFIGS.rst
@@ -0,0 +1,7 @@
+CMAKE_CROSS_CONFIGS
+-------------------
+
+Specifies a :ref:`semicolon-separated list <CMake Language Lists>` of
+configurations available from all ``build-<Config>.ninja`` files in the
+:generator:`Ninja Multi-Config` generator. See the generator's
+documentation for more details.
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_CUDA_COMPILE_FEATURES.rst b/Help/variable/CMAKE_CUDA_COMPILE_FEATURES.rst
new file mode 100644
index 0000000..2cd2650
--- /dev/null
+++ b/Help/variable/CMAKE_CUDA_COMPILE_FEATURES.rst
@@ -0,0 +1,11 @@
+CMAKE_CUDA_COMPILE_FEATURES
+---------------------------
+
+List of features known to the CUDA compiler
+
+These features are known to be available for use with the CUDA compiler. This
+list is a subset of the features listed in the
+:prop_gbl:`CMAKE_CUDA_KNOWN_FEATURES` global property.
+
+See the :manual:`cmake-compile-features(7)` manual for information on
+compile features and a list of supported compilers.
diff --git a/Help/variable/CMAKE_CUDA_RUNTIME_LIBRARY.rst b/Help/variable/CMAKE_CUDA_RUNTIME_LIBRARY.rst
new file mode 100644
index 0000000..ea1c1b8
--- /dev/null
+++ b/Help/variable/CMAKE_CUDA_RUNTIME_LIBRARY.rst
@@ -0,0 +1,24 @@
+CMAKE_CUDA_RUNTIME_LIBRARY
+--------------------------
+
+Select the CUDA runtime library for use by compilers targeting the MSVC ABI.
+This variable is used to initialize the :prop_tgt:`CUDA_RUNTIME_LIBRARY`
+property on all targets as they are created.
+
+The allowed case insensitive values are:
+
+.. include:: ../prop_tgt/CUDA_RUNTIME_LIBRARY-VALUES.txt
+
+Contents of ``CMAKE_CUDA_RUNTIME_LIBRARY`` may use
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+If this variable is not set then the :prop_tgt:`CUDA_RUNTIME_LIBRARY` target
+property will not be set automatically.  If that property is not set then
+CMake uses the default value ``Static`` to select the CUDA runtime library.
+
+.. note::
+
+  This property has effect only when the ``CUDA`` language is enabled. To
+  control the CUDA runtime linking when only using the CUDA SDK with the
+  ``C`` or ``C++`` language we recommend using the :module:`FindCUDAToolkit`
+  module.
diff --git a/Help/variable/CMAKE_CURRENT_FUNCTION.rst b/Help/variable/CMAKE_CURRENT_FUNCTION.rst
new file mode 100644
index 0000000..aa2936c
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_FUNCTION.rst
@@ -0,0 +1,6 @@
+CMAKE_CURRENT_FUNCTION
+----------------------
+
+When executing code inside a :command:`function`, this variable
+contains the name of the current function.  It can be used for
+diagnostic or debug messages.
diff --git a/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_DIR.rst b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_DIR.rst
new file mode 100644
index 0000000..0119381
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_DIR.rst
@@ -0,0 +1,33 @@
+CMAKE_CURRENT_FUNCTION_LIST_DIR
+-------------------------------
+
+When executing code inside a :command:`function`, this variable
+contains the full directory of the listfile defining the current function.
+
+It is quite common practice in CMake that modules use some additional files
+(e.g., templates to render).  And the code typically did the following:
+
+.. code-block:: cmake
+    :caption: Bad
+
+    set(_THIS_MODULE_BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
+
+    function(foo)
+      configure_file(
+        "${_THIS_MODULE_BASE_DIR}/some.template.in"
+        some.output
+      )
+    endfunction()
+
+Using this variable inside a function eliminates the neccessity of the
+additional one with "global" scope:
+
+.. code-block:: cmake
+    :caption: Good
+
+    function(foo)
+      configure_file(
+        "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/some.template.in"
+        some.output
+      )
+    endfunction()
diff --git a/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_FILE.rst b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_FILE.rst
new file mode 100644
index 0000000..d2c846a
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_FILE.rst
@@ -0,0 +1,5 @@
+CMAKE_CURRENT_FUNCTION_LIST_FILE
+--------------------------------
+
+When executing code inside a :command:`function`, this variable
+contains the full path to the listfile declaring a current function.
diff --git a/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_LINE.rst b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_LINE.rst
new file mode 100644
index 0000000..5a7cd13
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_LINE.rst
@@ -0,0 +1,5 @@
+CMAKE_CURRENT_FUNCTION_LIST_LINE
+--------------------------------
+
+When executing code inside a :command:`function`, this variable
+contains the line number in the listfile where a current function has defined.
diff --git a/Help/variable/CMAKE_DEFAULT_BUILD_TYPE.rst b/Help/variable/CMAKE_DEFAULT_BUILD_TYPE.rst
new file mode 100644
index 0000000..62ee0d2
--- /dev/null
+++ b/Help/variable/CMAKE_DEFAULT_BUILD_TYPE.rst
@@ -0,0 +1,6 @@
+CMAKE_DEFAULT_BUILD_TYPE
+------------------------
+
+Specifies the configuration to use by default in a ``build.ninja`` file in the
+:generator:`Ninja Multi-Config` generator. See the generator's documentation
+for more details.
diff --git a/Help/variable/CMAKE_DEFAULT_CONFIGS.rst b/Help/variable/CMAKE_DEFAULT_CONFIGS.rst
new file mode 100644
index 0000000..86d8a5a
--- /dev/null
+++ b/Help/variable/CMAKE_DEFAULT_CONFIGS.rst
@@ -0,0 +1,7 @@
+CMAKE_DEFAULT_CONFIGS
+---------------------
+
+Specifies a :ref:`semicolon-separated list <CMake Language Lists>` of configurations
+to build for a target in ``build.ninja`` if no ``:<Config>`` suffix is specified in
+the :generator:`Ninja Multi-Config` generator.
+See the generator's documentation for more details.
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_EXPORT_COMPILE_COMMANDS.rst b/Help/variable/CMAKE_EXPORT_COMPILE_COMMANDS.rst
index 4548abc..6d2450b 100644
--- a/Help/variable/CMAKE_EXPORT_COMPILE_COMMANDS.rst
+++ b/Help/variable/CMAKE_EXPORT_COMPILE_COMMANDS.rst
@@ -25,6 +25,9 @@
     }
   ]
 
+This is initialized by the :envvar:`CMAKE_EXPORT_COMPILE_COMMANDS` environment
+variable.
+
 .. note::
   This option is implemented only by :ref:`Makefile Generators`
   and the :generator:`Ninja`.  It is ignored on other generators.
diff --git a/Help/variable/CMAKE_FIND_DEBUG_MODE.rst b/Help/variable/CMAKE_FIND_DEBUG_MODE.rst
new file mode 100644
index 0000000..33ffdd6
--- /dev/null
+++ b/Help/variable/CMAKE_FIND_DEBUG_MODE.rst
@@ -0,0 +1,22 @@
+CMAKE_FIND_DEBUG_MODE
+---------------------
+
+Print extra find call information for the following commands to standard
+error:
+* :command:`find_program`
+* :command:`find_library`
+* :command:`find_file`
+* :command:`find_path`
+* :command:`find_package`
+
+Output is designed for human consumption and not for parsing.
+Enabling this variable is equivalent to using :manual:`cmake <cmake(1)>` ``--debug-find``
+with the added ability to enable debugging for a subset of find calls.
+
+.. code-block:: cmake
+
+  set(CMAKE_FIND_DEBUG_MODE TRUE)
+  find_program(...)
+  set(CMAKE_FIND_DEBUG_MODE FALSE)
+
+Default is unset.
diff --git a/Help/variable/CMAKE_GENERATOR_TOOLSET.rst b/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
index 222824f..53ad2f3 100644
--- a/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
+++ b/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
@@ -58,3 +58,8 @@
   Specify the toolset version to use.  Supported by VS 2017
   and above with the specified toolset installed.
   See the :variable:`CMAKE_VS_PLATFORM_TOOLSET_VERSION` variable.
+
+``VCTargetsPath=<path>``
+  Specify an alternative ``VCTargetsPath`` value for Visual Studio
+  project files.  This allows use of VS platform extension configuration
+  files (``.props`` and ``.targets``) that are not installed with VS.
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_HOST_SYSTEM_PROCESSOR.rst b/Help/variable/CMAKE_HOST_SYSTEM_PROCESSOR.rst
index ba8a850..5f08728 100644
--- a/Help/variable/CMAKE_HOST_SYSTEM_PROCESSOR.rst
+++ b/Help/variable/CMAKE_HOST_SYSTEM_PROCESSOR.rst
@@ -3,6 +3,13 @@
 
 The name of the CPU CMake is running on.
 
-On systems that support ``uname``, this variable is set to the output of
-``uname -p``.  On Windows it is set to the value of the environment variable
-``PROCESSOR_ARCHITECTURE``.
+On Windows, this variable is set to the value of the environment variable
+``PROCESSOR_ARCHITECTURE``. On systems that support ``uname``, this variable is
+set to the output of:
+
+- ``uname -m`` on GNU, Linux, Cygwin, Darwin, Android, or
+- ``arch`` on OpenBSD, or
+- on other systems,
+
+  * ``uname -p`` if its exit code is nonzero, or
+  * ``uname -m`` otherwise.
diff --git a/Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst b/Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst
index 78148d5..a99c108 100644
--- a/Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst
+++ b/Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst
@@ -3,7 +3,11 @@
 
 Add paths to linker search and installed rpath.
 
-``CMAKE_INSTALL_RPATH_USE_LINK_PATH`` is a boolean that if set to ``true``
-will append directories in the linker search path and outside the
-project to the :prop_tgt:`INSTALL_RPATH`.  This is used to initialize the
-target property :prop_tgt:`INSTALL_RPATH_USE_LINK_PATH` for all targets.
+``CMAKE_INSTALL_RPATH_USE_LINK_PATH`` is a boolean that if set to ``True``
+will append to the runtime search path (rpath) of installed binaries
+any directories outside the project that are in the linker search path or
+contain linked library files.  The directories are appended after the
+value of the :prop_tgt:`INSTALL_RPATH` target property.
+
+This varibale is used to initialize the target property
+:prop_tgt:`INSTALL_RPATH_USE_LINK_PATH` for all targets.
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_LANG_COMPILER_LAUNCHER.rst b/Help/variable/CMAKE_LANG_COMPILER_LAUNCHER.rst
index 6b7e35a..c76e2d0 100644
--- a/Help/variable/CMAKE_LANG_COMPILER_LAUNCHER.rst
+++ b/Help/variable/CMAKE_LANG_COMPILER_LAUNCHER.rst
@@ -5,3 +5,6 @@
 This variable is used to initialize the property on each target as it is
 created.  This is done only when ``<LANG>`` is ``C``, ``CXX``, ``Fortran``,
 ``OBJC``, ``OBJCXX``, or ``CUDA``.
+
+This variable is initialized to the :envvar:`CMAKE_<LANG>_COMPILER_LAUNCHER`
+environment variable if it is set.
diff --git a/Help/variable/CMAKE_MESSAGE_CONTEXT.rst b/Help/variable/CMAKE_MESSAGE_CONTEXT.rst
new file mode 100644
index 0000000..6b4ca40
--- /dev/null
+++ b/Help/variable/CMAKE_MESSAGE_CONTEXT.rst
@@ -0,0 +1,62 @@
+CMAKE_MESSAGE_CONTEXT
+---------------------
+
+When enabled by the :manual:`cmake <cmake(1)>` ``--log-context`` command line
+option or the :variable:`CMAKE_MESSAGE_CONTEXT_SHOW` variable, the
+:command:`message` command converts the ``CMAKE_MESSAGE_CONTEXT`` list into a
+dot-separated string surrounded by square brackets and prepends it to each line
+for messages of log levels ``NOTICE`` and below.
+
+For logging contexts to work effectively, projects should generally
+``APPEND`` and ``POP_BACK`` an item to the current value of
+``CMAKE_MESSAGE_CONTEXT`` rather than replace it.
+Projects should not assume the message context at the top of the source tree
+is empty, as there are scenarios where the context might have already been set
+(e.g. hierarchical projects).
+
+.. warning::
+
+  Valid context names are restricted to anything that could be used
+  as a CMake variable name.  All names that begin with an underscore
+  or the string ``cmake_`` are also reserved for use by CMake and
+  should not be used by projects.
+
+Example:
+
+.. code-block:: cmake
+
+  function(bar)
+    list(APPEND CMAKE_MESSAGE_CONTEXT "bar")
+    message(VERBOSE "bar VERBOSE message")
+  endfunction()
+
+  function(baz)
+    list(APPEND CMAKE_MESSAGE_CONTEXT "baz")
+    message(DEBUG "baz DEBUG message")
+  endfunction()
+
+  function(foo)
+    list(APPEND CMAKE_MESSAGE_CONTEXT "foo")
+    bar()
+    message(TRACE "foo TRACE message")
+    baz()
+  endfunction()
+
+  list(APPEND CMAKE_MESSAGE_CONTEXT "top")
+
+  message(VERBOSE "Before `foo`")
+  foo()
+  message(VERBOSE "After `foo`")
+
+  list(POP_BACK CMAKE_MESSAGE_CONTEXT)
+
+
+Which results in the following output:
+
+.. code-block:: none
+
+  -- [top] Before `foo`
+  -- [top.foo.bar] bar VERBOSE message
+  -- [top.foo] foo TRACE message
+  -- [top.foo.baz] baz DEBUG message
+  -- [top] After `foo`
diff --git a/Help/variable/CMAKE_MESSAGE_CONTEXT_SHOW.rst b/Help/variable/CMAKE_MESSAGE_CONTEXT_SHOW.rst
new file mode 100644
index 0000000..7ec218e
--- /dev/null
+++ b/Help/variable/CMAKE_MESSAGE_CONTEXT_SHOW.rst
@@ -0,0 +1,15 @@
+CMAKE_MESSAGE_CONTEXT_SHOW
+--------------------------
+
+Setting this variable to true enables showing a context with each line
+logged by the :command:`message` command (see :variable:`CMAKE_MESSAGE_CONTEXT`
+for how the context itself is specified).
+
+This variable is an alternative to providing the ``--log-context`` option
+on the :manual:`cmake <cmake(1)>` command line.  Whereas the command line
+option will apply only to that one CMake run, setting
+``CMAKE_MESSAGE_CONTEXT_SHOW`` to true as a cache variable will ensure that
+subsequent CMake runs will continue to show the message context.
+
+Projects should not set ``CMAKE_MESSAGE_CONTEXT_SHOW``.  It is intended for
+users so that they may control whether or not to include context with messages.
diff --git a/Help/variable/CMAKE_MESSAGE_LOG_LEVEL.rst b/Help/variable/CMAKE_MESSAGE_LOG_LEVEL.rst
new file mode 100644
index 0000000..1d4cfe6
--- /dev/null
+++ b/Help/variable/CMAKE_MESSAGE_LOG_LEVEL.rst
@@ -0,0 +1,15 @@
+CMAKE_MESSAGE_LOG_LEVEL
+-----------------------
+
+When set, this variable specifies the logging level used by the
+:command:`message` command.  Valid values are the same as those for the
+``--log-level`` command line option of the :manual:`cmake(1)` program.
+If this variable is set and the ``--log-level`` command line option is
+given, the command line option takes precedence.
+
+The main advantage to using this variable is to make a log level persist
+between CMake runs.  Setting it as a cache variable will ensure that
+subsequent CMake runs will continue to use the chosen log level.
+
+Projects should not set this variable, it is intended for users so that
+they may control the log level according to their own needs.
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/Help/variable/CMAKE_PROJECT_INCLUDE.rst b/Help/variable/CMAKE_PROJECT_INCLUDE.rst
index 965c94e..5835264 100644
--- a/Help/variable/CMAKE_PROJECT_INCLUDE.rst
+++ b/Help/variable/CMAKE_PROJECT_INCLUDE.rst
@@ -5,5 +5,6 @@
 :command:`project` command calls.  This is intended for injecting custom code
 into project builds without modifying their source.
 
-See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE` and
+See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`,
+:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE` and
 :variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variables.
diff --git a/Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst b/Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst
index 70b15e6..280c14a 100644
--- a/Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst
+++ b/Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst
@@ -5,5 +5,6 @@
 :command:`project` command calls.  This is intended for injecting custom code
 into project builds without modifying their source.
 
-See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE` and
+See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`,
+:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE` and
 :variable:`CMAKE_PROJECT_INCLUDE` variables.
diff --git a/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE.rst b/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE.rst
index 3485c38..74247f1 100644
--- a/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE.rst
+++ b/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE.rst
@@ -6,5 +6,6 @@
 name.  This is intended for injecting custom code into project builds without
 modifying their source.
 
-See also the :variable:`CMAKE_PROJECT_INCLUDE` and
+See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`,
+:variable:`CMAKE_PROJECT_INCLUDE` and
 :variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variables.
diff --git a/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE.rst b/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE.rst
new file mode 100644
index 0000000..db1432d
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE.rst
@@ -0,0 +1,11 @@
+CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE
+-------------------------------------------
+
+A CMake language file or module to be included as the first step of any
+:command:`project` command calls that specify ``<PROJECT-NAME>`` as the project
+name.  This is intended for injecting custom code into project builds without
+modifying their source.
+
+See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`,
+:variable:`CMAKE_PROJECT_INCLUDE` and
+:variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variables.
diff --git a/Help/variable/CMAKE_VS_WINRT_BY_DEFAULT.rst b/Help/variable/CMAKE_VS_WINRT_BY_DEFAULT.rst
index 2ba8fe2..2eea424 100644
--- a/Help/variable/CMAKE_VS_WINRT_BY_DEFAULT.rst
+++ b/Help/variable/CMAKE_VS_WINRT_BY_DEFAULT.rst
@@ -1,8 +1,18 @@
 CMAKE_VS_WINRT_BY_DEFAULT
 -------------------------
 
-Tell :ref:`Visual Studio Generators` for VS 2010 and above that the
-target platform compiles as WinRT by default (compiles with ``/ZW``).
+Inform :ref:`Visual Studio Generators` for VS 2010 and above that the
+target platform enables WinRT compilation by default and it needs to
+be explicitly disabled if ``/ZW`` or :prop_tgt:`VS_WINRT_COMPONENT` is
+omitted (as opposed to enabling it when either of those options is
+present)
+
+This makes cmake configuration consistent in terms of WinRT among
+platforms - if you did not enable the WinRT compilation explicitly, it
+will be disabled (by either not enabling it or explicitly disabling it)
+
+Note: WinRT compilation is always explicitly disabled for C language
+source files, even if it is expliclty enabled for a project
 
 This variable is meant to be set by a
 :variable:`toolchain file <CMAKE_TOOLCHAIN_FILE>` for such platforms.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_ENVIRONMENT.rst b/Help/variable/CMAKE_XCODE_SCHEME_ENVIRONMENT.rst
new file mode 100644
index 0000000..4832659
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_ENVIRONMENT.rst
@@ -0,0 +1,15 @@
+CMAKE_XCODE_SCHEME_ENVIRONMENT
+------------------------------
+
+Specify environment variables that should be added to the Arguments
+section of the generated Xcode scheme.
+
+If set to a list of environment variables and values of the form
+``MYVAR=value`` those environment variables will be added to the
+scheme.
+
+This variable initializes the :prop_tgt:`XCODE_SCHEME_ENVIRONMENT`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_WORKING_DIRECTORY.rst b/Help/variable/CMAKE_XCODE_SCHEME_WORKING_DIRECTORY.rst
new file mode 100644
index 0000000..cc690f7
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_WORKING_DIRECTORY.rst
@@ -0,0 +1,12 @@
+CMAKE_XCODE_SCHEME_WORKING_DIRECTORY
+------------------------------------
+
+Specify the ``Working Directory`` a of the `Run` and `Profile`
+action in the generated Xcode scheme.
+
+This variable initializes the
+:prop_tgt:`XCODE_SCHEME_WORKING_DIRECTORY`
+property on all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/variable/CTEST_CONFIGURATION_TYPE.rst b/Help/variable/CTEST_CONFIGURATION_TYPE.rst
index c905480..9e277fa 100644
--- a/Help/variable/CTEST_CONFIGURATION_TYPE.rst
+++ b/Help/variable/CTEST_CONFIGURATION_TYPE.rst
@@ -3,3 +3,6 @@
 
 Specify the CTest ``DefaultCTestConfigurationType`` setting
 in a :manual:`ctest(1)` dashboard client script.
+
+If the configuration type is set via ``-C <cfg>`` from the command line
+then this variable is populated accordingly.
diff --git a/Help/variable/CTEST_MEMORYCHECK_TYPE.rst b/Help/variable/CTEST_MEMORYCHECK_TYPE.rst
index b8b4c30..4e7d5c0 100644
--- a/Help/variable/CTEST_MEMORYCHECK_TYPE.rst
+++ b/Help/variable/CTEST_MEMORYCHECK_TYPE.rst
@@ -3,6 +3,6 @@
 
 Specify the CTest ``MemoryCheckType`` setting
 in a :manual:`ctest(1)` dashboard client script.
-Valid values are ``Valgrind``, ``Purify``, ``BoundsChecker``, and
+Valid values are ``Valgrind``, ``Purify``, ``BoundsChecker``, ``DrMemory`` and
 ``ThreadSanitizer``, ``AddressSanitizer``, ``LeakSanitizer``, ``MemorySanitizer``, and
 ``UndefinedBehaviorSanitizer``.
diff --git a/Modules/AndroidTestUtilities.cmake b/Modules/AndroidTestUtilities.cmake
index e333cdb..95e2ef7 100644
--- a/Modules/AndroidTestUtilities.cmake
+++ b/Modules/AndroidTestUtilities.cmake
@@ -76,8 +76,6 @@
 
 include(${CMAKE_CURRENT_LIST_DIR}/ExternalData.cmake)
 
-set(_AndroidTestUtilities_SELF_DIR "${CMAKE_CURRENT_LIST_DIR}")
-
 # The parameters to this function should be set to the list of directories,
 # files, and libraries that need to be installed prior to testing.
 function(android_add_test_data test_name)
@@ -159,6 +157,6 @@
       "-Darg_files=${processed_FILES}"
       "-Darg_libs=${AST_LIBS}"
       "-Darg_src_dir=${CMAKE_CURRENT_SOURCE_DIR}"
-      -P ${_AndroidTestUtilities_SELF_DIR}/AndroidTestUtilities/PushToAndroidDevice.cmake)
+      -P ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/AndroidTestUtilities/PushToAndroidDevice.cmake)
   endif()
 endfunction()
diff --git a/Modules/CMakeAddFortranSubdirectory.cmake b/Modules/CMakeAddFortranSubdirectory.cmake
index 2613569..69a8417 100644
--- a/Modules/CMakeAddFortranSubdirectory.cmake
+++ b/Modules/CMakeAddFortranSubdirectory.cmake
@@ -43,7 +43,6 @@
 binaries during ``make install``.
 #]=======================================================================]
 
-set(_MS_MINGW_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR})
 include(CheckLanguage)
 include(ExternalProject)
 
@@ -87,11 +86,11 @@
   file(TO_NATIVE_PATH "${MINGW_PATH}" MINGW_PATH)
   string(REPLACE "\\" "\\\\" MINGW_PATH "${MINGW_PATH}")
   configure_file(
-    ${_MS_MINGW_SOURCE_DIR}/CMakeAddFortranSubdirectory/config_mingw.cmake.in
+    ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/CMakeAddFortranSubdirectory/config_mingw.cmake.in
     ${build_dir}/config_mingw.cmake
     @ONLY)
   configure_file(
-    ${_MS_MINGW_SOURCE_DIR}/CMakeAddFortranSubdirectory/build_mingw.cmake.in
+    ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/CMakeAddFortranSubdirectory/build_mingw.cmake.in
     ${build_dir}/build_mingw.cmake
     @ONLY)
 endfunction()
@@ -150,17 +149,9 @@
     -P ${build_dir}/config_mingw.cmake
     BUILD_COMMAND ${CMAKE_COMMAND}
     -P ${build_dir}/build_mingw.cmake
+    BUILD_ALWAYS 1
     INSTALL_COMMAND ""
     )
-  # make the external project always run make with each build
-  externalproject_add_step(${project_name}_build forcebuild
-    COMMAND ${CMAKE_COMMAND}
-    -E remove
-    ${CMAKE_CURRENT_BUILD_DIR}/${project_name}-prefix/src/${project_name}-stamp/${project_name}-build
-    DEPENDEES configure
-    DEPENDERS build
-    ALWAYS 1
-    )
   # create imported targets for all libraries
   foreach(lib ${libraries})
     add_library(${lib} SHARED IMPORTED GLOBAL)
diff --git a/Modules/CMakeCInformation.cmake b/Modules/CMakeCInformation.cmake
index df43559..1e08bb7 100644
--- a/Modules/CMakeCInformation.cmake
+++ b/Modules/CMakeCInformation.cmake
@@ -110,6 +110,11 @@
   mark_as_advanced(CMAKE_C_STANDARD_LIBRARIES)
 endif()
 
+if(NOT CMAKE_C_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_C_COMPILER_LAUNCHER})
+  set(CMAKE_C_COMPILER_LAUNCHER "$ENV{CMAKE_C_COMPILER_LAUNCHER}"
+    CACHE STRING "Compiler launcher for C.")
+endif()
+
 include(CMakeCommonLanguageInclude)
 
 # now define the following rule variables
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/CMakeCUDACompiler.cmake.in b/Modules/CMakeCUDACompiler.cmake.in
index 711129a..4a615a3 100644
--- a/Modules/CMakeCUDACompiler.cmake.in
+++ b/Modules/CMakeCUDACompiler.cmake.in
@@ -4,7 +4,16 @@
 set(CMAKE_CUDA_COMPILER_ID "@CMAKE_CUDA_COMPILER_ID@")
 set(CMAKE_CUDA_COMPILER_VERSION "@CMAKE_CUDA_COMPILER_VERSION@")
 set(CMAKE_CUDA_STANDARD_COMPUTED_DEFAULT "@CMAKE_CUDA_STANDARD_COMPUTED_DEFAULT@")
+set(CMAKE_CUDA_COMPILE_FEATURES "@CMAKE_CUDA_COMPILE_FEATURES@")
+set(CMAKE_CUDA03_COMPILE_FEATURES "@CMAKE_CUDA03_COMPILE_FEATURES@")
+set(CMAKE_CUDA11_COMPILE_FEATURES "@CMAKE_CUDA11_COMPILE_FEATURES@")
+set(CMAKE_CUDA14_COMPILE_FEATURES "@CMAKE_CUDA14_COMPILE_FEATURES@")
+set(CMAKE_CUDA17_COMPILE_FEATURES "@CMAKE_CUDA17_COMPILE_FEATURES@")
+set(CMAKE_CUDA20_COMPILE_FEATURES "@CMAKE_CUDA20_COMPILE_FEATURES@")
+
+set(CMAKE_CUDA_PLATFORM_ID "@CMAKE_CUDA_PLATFORM_ID@")
 set(CMAKE_CUDA_SIMULATE_ID "@CMAKE_CUDA_SIMULATE_ID@")
+set(CMAKE_CUDA_COMPILER_FRONTEND_VARIANT "@CMAKE_CUDA_COMPILER_FRONTEND_VARIANT@")
 set(CMAKE_CUDA_SIMULATE_VERSION "@CMAKE_CUDA_SIMULATE_VERSION@")
 @SET_MSVC_CUDA_ARCHITECTURE_ID@
 
@@ -17,6 +26,22 @@
 set(CMAKE_CUDA_LINKER_PREFERENCE 15)
 set(CMAKE_CUDA_LINKER_PREFERENCE_PROPAGATES 1)
 
+set(CMAKE_CUDA_SIZEOF_DATA_PTR "@CMAKE_CUDA_SIZEOF_DATA_PTR@")
+set(CMAKE_CUDA_COMPILER_ABI "@CMAKE_CUDA_COMPILER_ABI@")
+set(CMAKE_CUDA_LIBRARY_ARCHITECTURE "@CMAKE_CUDA_LIBRARY_ARCHITECTURE@")
+
+if(CMAKE_CUDA_SIZEOF_DATA_PTR)
+  set(CMAKE_SIZEOF_VOID_P "${CMAKE_CUDA_SIZEOF_DATA_PTR}")
+endif()
+
+if(CMAKE_CUDA_COMPILER_ABI)
+  set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_CUDA_COMPILER_ABI}")
+endif()
+
+if(CMAKE_CUDA_LIBRARY_ARCHITECTURE)
+  set(CMAKE_LIBRARY_ARCHITECTURE "@CMAKE_CUDA_LIBRARY_ARCHITECTURE@")
+endif()
+
 set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "@CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES@")
 
 set(CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES "@CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES@")
diff --git a/Modules/CMakeCUDACompilerId.cu.in b/Modules/CMakeCUDACompilerId.cu.in
index 6eda924..2055de2 100644
--- a/Modules/CMakeCUDACompilerId.cu.in
+++ b/Modules/CMakeCUDACompilerId.cu.in
@@ -26,7 +26,7 @@
 #elif __cplusplus >= 201103L
   "11"
 #else
-  "98"
+  "03"
 #endif
 "]";
 
diff --git a/Modules/CMakeCUDAInformation.cmake b/Modules/CMakeCUDAInformation.cmake
index b0d80d1..974f5fa 100644
--- a/Modules/CMakeCUDAInformation.cmake
+++ b/Modules/CMakeCUDAInformation.cmake
@@ -82,6 +82,11 @@
   mark_as_advanced(CMAKE_CUDA_STANDARD_LIBRARIES)
 endif()
 
+if(NOT CMAKE_CUDA_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_CUDA_COMPILER_LAUNCHER})
+  set(CMAKE_CUDA_COMPILER_LAUNCHER "$ENV{CMAKE_CUDA_COMPILER_LAUNCHER}"
+    CACHE STRING "Compiler launcher for CUDA.")
+endif()
+
 include(CMakeCommonLanguageInclude)
 
 # now define the following rules:
@@ -93,9 +98,7 @@
 # CMAKE_CUDA_LINK_EXECUTABLE
 
 if(CMAKE_CUDA_HOST_COMPILER)
-  set(CMAKE_CUDA_HOST_FLAGS "-ccbin=<CMAKE_CUDA_HOST_COMPILER>")
-else()
-  set(CMAKE_CUDA_HOST_FLAGS "")
+  string(APPEND _CMAKE_CUDA_EXTRA_FLAGS " -ccbin=<CMAKE_CUDA_HOST_COMPILER>")
 endif()
 
 set(__IMPLICT_LINKS )
@@ -135,26 +138,26 @@
 #Specify how to compile when ptx has been requested
 if(NOT CMAKE_CUDA_COMPILE_PTX_COMPILATION)
   set(CMAKE_CUDA_COMPILE_PTX_COMPILATION
-    "<CMAKE_CUDA_COMPILER> ${CMAKE_CUDA_HOST_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -x cu -ptx <SOURCE> -o <OBJECT>")
+    "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -x cu -ptx <SOURCE> -o <OBJECT>")
 endif()
 
 #Specify how to compile when separable compilation has been requested
 if(NOT CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION)
   set(CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION
-    "<CMAKE_CUDA_COMPILER> ${CMAKE_CUDA_HOST_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -x cu -dc <SOURCE> -o <OBJECT>")
+    "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -x cu -dc <SOURCE> -o <OBJECT>")
 endif()
 
 #Specify how to compile when whole compilation has been requested
 if(NOT CMAKE_CUDA_COMPILE_WHOLE_COMPILATION)
   set(CMAKE_CUDA_COMPILE_WHOLE_COMPILATION
-    "<CMAKE_CUDA_COMPILER> ${CMAKE_CUDA_HOST_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -x cu -c <SOURCE> -o <OBJECT>")
+    "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -x cu -c <SOURCE> -o <OBJECT>")
 endif()
 
-if(CMAKE_GENERATOR STREQUAL "Ninja")
+if(CMAKE_GENERATOR STREQUAL "Ninja" AND NOT CMAKE_DEPFILE_FLAGS_CUDA )
   set(CMAKE_CUDA_COMPILE_DEPENDENCY_DETECTION
-    "<CMAKE_CUDA_COMPILER> ${CMAKE_CUDA_HOST_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -x cu -M <SOURCE> -MT <OBJECT> -o $DEP_FILE")
+    "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -x cu -M <SOURCE> -MT <OBJECT> -o $DEP_FILE")
   #The Ninja generator uses the make file dependency files to determine what
-  #files need to be recompiled. Unfortunately, nvcc doesn't support building
+  #files need to be recompiled. Unfortunately, nvcc < 10.2 doesn't support building
   #a source file and generating the dependencies of said file in a single
   #invocation. Instead we have to state that you need to chain two commands.
   #
@@ -171,13 +174,6 @@
     "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_LINKS}")
 endif()
 
-if( CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA" AND
-    CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "8.0.0")
-  set(_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS "-Wno-deprecated-gpu-targets")
-else()
-  set(_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS "")
-endif()
-
 # Add implicit host link directories that contain device libraries
 # to the device link line.
 set(__IMPLICT_DLINK_DIRS ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
@@ -192,14 +188,15 @@
 endforeach()
 unset(__IMPLICT_DLINK_DIRS)
 
+
 #These are used when linking relocatable (dc) cuda code
 if(NOT CMAKE_CUDA_DEVICE_LINK_LIBRARY)
   set(CMAKE_CUDA_DEVICE_LINK_LIBRARY
-    "<CMAKE_CUDA_COMPILER> ${CMAKE_CUDA_HOST_FLAGS} <LANGUAGE_COMPILE_FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_DLINK_FLAGS}")
+    "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_DLINK_FLAGS}")
 endif()
 if(NOT CMAKE_CUDA_DEVICE_LINK_EXECUTABLE)
   set(CMAKE_CUDA_DEVICE_LINK_EXECUTABLE
-    "<CMAKE_CUDA_COMPILER> ${CMAKE_CUDA_HOST_FLAGS} <FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_DLINK_FLAGS}")
+    "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_DLINK_FLAGS}")
 endif()
 
 unset(_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS)
diff --git a/Modules/CMakeCXXInformation.cmake b/Modules/CMakeCXXInformation.cmake
index a896b99..da7440a 100644
--- a/Modules/CMakeCXXInformation.cmake
+++ b/Modules/CMakeCXXInformation.cmake
@@ -207,6 +207,11 @@
   mark_as_advanced(CMAKE_CXX_STANDARD_LIBRARIES)
 endif()
 
+if(NOT CMAKE_CXX_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_CXX_COMPILER_LAUNCHER})
+  set(CMAKE_CXX_COMPILER_LAUNCHER "$ENV{CMAKE_CXX_COMPILER_LAUNCHER}"
+    CACHE STRING "Compiler launcher for CXX.")
+endif()
+
 include(CMakeCommonLanguageInclude)
 
 # now define the following rules:
diff --git a/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake b/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
index e1ce617..2dc75d6 100644
--- a/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
+++ b/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
@@ -9,6 +9,7 @@
 macro (CHECK_COMPILER_FLAG_COMMON_PATTERNS _VAR)
   set(${_VAR}
     FAIL_REGEX "[Uu]nrecogni[sz]ed .*option"               # GNU, NAG
+    FAIL_REGEX "switch .* is no longer supported"          # GNU
     FAIL_REGEX "unknown .*option"                          # Clang
     FAIL_REGEX "optimization flag .* not supported"        # Clang
     FAIL_REGEX "unknown argument ignored"                  # Clang (cl)
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/CMakeDetermineCompileFeatures.cmake b/Modules/CMakeDetermineCompileFeatures.cmake
index 01a81a1..b50e5f1 100644
--- a/Modules/CMakeDetermineCompileFeatures.cmake
+++ b/Modules/CMakeDetermineCompileFeatures.cmake
@@ -5,7 +5,7 @@
 function(cmake_determine_compile_features lang)
 
   if(lang STREQUAL C AND COMMAND cmake_record_c_compile_features)
-    message(STATUS "Detecting ${lang} compile features")
+    message(CHECK_START "Detecting ${lang} compile features")
 
     set(CMAKE_C90_COMPILE_FEATURES)
     set(CMAKE_C99_COMPILE_FEATURES)
@@ -16,7 +16,7 @@
     cmake_record_c_compile_features()
 
     if(NOT _result EQUAL 0)
-      message(STATUS "Detecting ${lang} compile features - failed")
+      message(CHECK_FAIL "failed")
       return()
     endif()
 
@@ -40,10 +40,10 @@
     set(CMAKE_C99_COMPILE_FEATURES ${CMAKE_C99_COMPILE_FEATURES} PARENT_SCOPE)
     set(CMAKE_C11_COMPILE_FEATURES ${CMAKE_C11_COMPILE_FEATURES} PARENT_SCOPE)
 
-    message(STATUS "Detecting ${lang} compile features - done")
+    message(CHECK_PASS "done")
 
   elseif(lang STREQUAL CXX AND COMMAND cmake_record_cxx_compile_features)
-    message(STATUS "Detecting ${lang} compile features")
+    message(CHECK_START "Detecting ${lang} compile features")
 
     set(CMAKE_CXX98_COMPILE_FEATURES)
     set(CMAKE_CXX11_COMPILE_FEATURES)
@@ -56,7 +56,7 @@
     cmake_record_cxx_compile_features()
 
     if(NOT _result EQUAL 0)
-      message(STATUS "Detecting ${lang} compile features - failed")
+      message(CHECK_FAIL "failed")
       return()
     endif()
 
@@ -90,7 +90,58 @@
     set(CMAKE_CXX17_COMPILE_FEATURES ${CMAKE_CXX17_COMPILE_FEATURES} PARENT_SCOPE)
     set(CMAKE_CXX20_COMPILE_FEATURES ${CMAKE_CXX20_COMPILE_FEATURES} PARENT_SCOPE)
 
-    message(STATUS "Detecting ${lang} compile features - done")
+    message(CHECK_PASS "done")
+
+  elseif(lang STREQUAL CUDA AND COMMAND cmake_record_cuda_compile_features)
+    message(CHECK_START "Detecting ${lang} compile features")
+
+    set(CMAKE_CUDA03_COMPILE_FEATURES)
+    set(CMAKE_CUDA11_COMPILE_FEATURES)
+    set(CMAKE_CUDA14_COMPILE_FEATURES)
+    set(CMAKE_CUDA17_COMPILE_FEATURES)
+    set(CMAKE_CUDA20_COMPILE_FEATURES)
+
+    include("${CMAKE_ROOT}/Modules/Internal/FeatureTesting.cmake")
+
+    cmake_record_cuda_compile_features()
+
+    if(NOT _result EQUAL 0)
+      message(CHECK_FAIL "failed")
+      return()
+    endif()
+
+  if (CMAKE_CUDA17_COMPILE_FEATURES AND CMAKE_CUDA20_COMPILE_FEATURES)
+      list(REMOVE_ITEM CMAKE_CUDA20_COMPILE_FEATURES ${CMAKE_CUDA17_COMPILE_FEATURES})
+    endif()
+    if (CMAKE_CUDA14_COMPILE_FEATURES AND CMAKE_CUDA17_COMPILE_FEATURES)
+      list(REMOVE_ITEM CMAKE_CUDA17_COMPILE_FEATURES ${CMAKE_CUDA14_COMPILE_FEATURES})
+    endif()
+    if (CMAKE_CUDA11_COMPILE_FEATURES AND CMAKE_CUDA14_COMPILE_FEATURES)
+      list(REMOVE_ITEM CMAKE_CUDA14_COMPILE_FEATURES ${CMAKE_CUDA11_COMPILE_FEATURES})
+    endif()
+    if (CMAKE_CUDA03_COMPILE_FEATURES AND CMAKE_CUDA11_COMPILE_FEATURES)
+      list(REMOVE_ITEM CMAKE_CUDA11_COMPILE_FEATURES ${CMAKE_CUDA03_COMPILE_FEATURES})
+    endif()
+
+    if(NOT CMAKE_CUDA_COMPILE_FEATURES)
+      set(CMAKE_CUDA_COMPILE_FEATURES
+        ${CMAKE_CUDA03_COMPILE_FEATURES}
+        ${CMAKE_CUDA11_COMPILE_FEATURES}
+        ${CMAKE_CUDA14_COMPILE_FEATURES}
+        ${CMAKE_CUDA17_COMPILE_FEATURES}
+        ${CMAKE_CUDA20_COMPILE_FEATURES}
+      )
+    endif()
+
+    set(CMAKE_CUDA_COMPILE_FEATURES ${CMAKE_CUDA_COMPILE_FEATURES} PARENT_SCOPE)
+    set(CMAKE_CUDA03_COMPILE_FEATURES ${CMAKE_CUDA03_COMPILE_FEATURES} PARENT_SCOPE)
+    set(CMAKE_CUDA11_COMPILE_FEATURES ${CMAKE_CUDA11_COMPILE_FEATURES} PARENT_SCOPE)
+    set(CMAKE_CUDA14_COMPILE_FEATURES ${CMAKE_CUDA14_COMPILE_FEATURES} PARENT_SCOPE)
+    set(CMAKE_CUDA17_COMPILE_FEATURES ${CMAKE_CUDA17_COMPILE_FEATURES} PARENT_SCOPE)
+    set(CMAKE_CUDA20_COMPILE_FEATURES ${CMAKE_CUDA20_COMPILE_FEATURES} PARENT_SCOPE)
+
+    message(CHECK_PASS "done")
+
   endif()
 
 endfunction()
diff --git a/Modules/CMakeDetermineCompilerABI.cmake b/Modules/CMakeDetermineCompilerABI.cmake
index 06f3ba2..e1b3c52 100644
--- a/Modules/CMakeDetermineCompilerABI.cmake
+++ b/Modules/CMakeDetermineCompilerABI.cmake
@@ -12,7 +12,7 @@
 
 function(CMAKE_DETERMINE_COMPILER_ABI lang src)
   if(NOT DEFINED CMAKE_${lang}_ABI_COMPILED)
-    message(STATUS "Detecting ${lang} compiler ABI info")
+    message(CHECK_START "Detecting ${lang} compiler ABI info")
 
     # Compile the ABI identification source.
     set(BIN "${CMAKE_PLATFORM_INFO_DIR}/CMakeDetermineCompilerABI_${lang}.bin")
@@ -32,6 +32,9 @@
     endif()
     __TestCompiler_setTryCompileTargetType()
 
+    # Avoid failing ABI detection on warnings.
+    string(REGEX REPLACE "(^| )-Werror(=[^ ]*)?( |$)" " " CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS}")
+
     # Save the current LC_ALL, LC_MESSAGES, and LANG environment variables
     # and set them to "C" that way GCC's "search starts here" text is in
     # English and we can grok it.
@@ -66,7 +69,7 @@
 
     # Load the resulting information strings.
     if(CMAKE_${lang}_ABI_COMPILED AND NOT _copy_error)
-      message(STATUS "Detecting ${lang} compiler ABI info - done")
+      message(CHECK_PASS "done")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Detecting ${lang} compiler ABI info compiled with the following output:\n${OUTPUT}\n\n")
       file(STRINGS "${BIN}" ABI_STRINGS LIMIT_COUNT 2 REGEX "INFO:[A-Za-z0-9_]+\\[[^]]*\\]")
@@ -124,8 +127,7 @@
       # a try-compile
       if("${lang}" MATCHES "Fortran"
           AND "${CMAKE_GENERATOR}" MATCHES "Visual Studio")
-        set(_desc "Determine Intel Fortran Compiler Implicit Link Path")
-        message(STATUS "${_desc}")
+        message(CHECK_START "Determine Intel Fortran Compiler Implicit Link Path")
         # Build a sample project which reports symbols.
         try_compile(IFORT_LIB_PATH_COMPILED
           ${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath
@@ -138,8 +140,7 @@
           "${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath/output.txt"
           "${_output}")
         include(${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath/output.cmake OPTIONAL)
-        set(_desc "Determine Intel Fortran Compiler Implicit Link Path -- done")
-        message(STATUS "${_desc}")
+        message(CHECK_PASS "done")
       endif()
 
       # Implicit link libraries cannot be used explicitly for multiple
@@ -163,10 +164,22 @@
             break()
           endif()
         endforeach()
+      elseif(CMAKE_CXX_COMPILER_ID STREQUAL QCC)
+        foreach(dir ${implicit_dirs})
+          if (dir MATCHES "/lib$")
+            get_filename_component(assumedArchDir "${dir}" DIRECTORY)
+            get_filename_component(archParentDir "${assumedArchDir}" DIRECTORY)
+            if (archParentDir STREQUAL CMAKE_SYSROOT)
+              get_filename_component(archDirName "${assumedArchDir}" NAME)
+              set(CMAKE_${lang}_LIBRARY_ARCHITECTURE "${archDirName}" PARENT_SCOPE)
+              break()
+            endif()
+          endif()
+        endforeach()
       endif()
 
     else()
-      message(STATUS "Detecting ${lang} compiler ABI info - failed")
+      message(CHECK_FAIL "failed")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Detecting ${lang} compiler ABI info failed to compile with the following output:\n${OUTPUT}\n${_copy_error}\n\n")
     endif()
diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake
index 7b571c3..d125791 100644
--- a/Modules/CMakeDetermineCompilerId.cmake
+++ b/Modules/CMakeDetermineCompilerId.cmake
@@ -182,6 +182,10 @@
     message(STATUS "The ${lang} compiler identification is unknown")
   endif()
 
+  if(lang STREQUAL "Fortran" AND CMAKE_${lang}_COMPILER_ID STREQUAL "XL")
+    set(CMAKE_${lang}_XL_CPP "${CMAKE_${lang}_COMPILER_ID_CPP}" PARENT_SCOPE)
+  endif()
+
   set(CMAKE_${lang}_COMPILER_ID "${CMAKE_${lang}_COMPILER_ID}" PARENT_SCOPE)
   set(CMAKE_${lang}_PLATFORM_ID "${CMAKE_${lang}_PLATFORM_ID}" PARENT_SCOPE)
   set(CMAKE_${lang}_COMPILER_ARCHITECTURE_ID "${CMAKE_${lang}_COMPILER_ARCHITECTURE_ID}" PARENT_SCOPE)
@@ -242,7 +246,7 @@
     set(id_platform ${CMAKE_VS_PLATFORM_NAME})
     set(id_lang "${lang}")
     set(id_PostBuildEvent_Command "")
-    if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "^[Ll][Ll][Vv][Mm](_v[0-9]+(_xp)?)?$")
+    if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "^([Ll][Ll][Vv][Mm](_v[0-9]+(_xp)?)?|[Cc][Ll][Aa][Nn][Gg][Cc][Ll])$")
       set(id_cl_var "ClangClExecutable")
     elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*")
       set(id_cl clang.exe)
@@ -318,6 +322,15 @@
     if(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION)
       set(id_WindowsTargetPlatformVersion "<WindowsTargetPlatformVersion>${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}</WindowsTargetPlatformVersion>")
     endif()
+    if(CMAKE_VS_PLATFORM_TOOLSET_VCTARGETS_CUSTOM_DIR)
+      set(id_ToolsetVCTargetsDir "<VCTargetsPath>${CMAKE_VS_PLATFORM_TOOLSET_VCTARGETS_CUSTOM_DIR}</VCTargetsPath>")
+    endif()
+    set(id_CustomGlobals "")
+    foreach(pair IN LISTS CMAKE_VS_GLOBALS)
+      if("${pair}" MATCHES "([^=]+)=(.*)$")
+        string(APPEND id_CustomGlobals "<${CMAKE_MATCH_1}>${CMAKE_MATCH_2}</${CMAKE_MATCH_1}>\n    ")
+      endif()
+    endforeach()
     if(id_platform STREQUAL ARM64)
       set(id_WindowsSDKDesktopARMSupport "<WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support>")
     elseif(id_platform STREQUAL ARM)
@@ -353,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>")
@@ -363,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()
@@ -534,6 +548,12 @@
       ERROR_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
       RESULT_VARIABLE CMAKE_${lang}_COMPILER_ID_RESULT
       )
+    if("${CMAKE_${lang}_COMPILER_ID_OUTPUT}" MATCHES "exec: [^\n]*\\((/[^,\n]*/cpp),CMakeFortranCompilerId.F")
+      set(_cpp "${CMAKE_MATCH_1}")
+      if(EXISTS "${_cpp}")
+        set(CMAKE_${lang}_COMPILER_ID_CPP "${_cpp}" PARENT_SCOPE)
+      endif()
+    endif()
   endif()
 
   # Check the result of compilation.
diff --git a/Modules/CMakeDetermineFortranCompiler.cmake b/Modules/CMakeDetermineFortranCompiler.cmake
index 5ddd64f..e850541 100644
--- a/Modules/CMakeDetermineFortranCompiler.cmake
+++ b/Modules/CMakeDetermineFortranCompiler.cmake
@@ -271,6 +271,11 @@
 include(Compiler/${CMAKE_Fortran_COMPILER_ID}-FindBinUtils OPTIONAL)
 unset(_CMAKE_PROCESSING_LANGUAGE)
 
+if(CMAKE_Fortran_XL_CPP)
+  set(_SET_CMAKE_Fortran_XL_CPP
+    "set(CMAKE_Fortran_XL_CPP \"${CMAKE_Fortran_XL_CPP}\")")
+endif()
+
 if(CMAKE_Fortran_COMPILER_ARCHITECTURE_ID)
   set(_SET_CMAKE_Fortran_COMPILER_ARCHITECTURE_ID
     "set(CMAKE_Fortran_COMPILER_ARCHITECTURE_ID ${CMAKE_Fortran_COMPILER_ARCHITECTURE_ID})")
diff --git a/Modules/CMakeDetermineSwiftCompiler.cmake b/Modules/CMakeDetermineSwiftCompiler.cmake
index 9aafe48..688133f 100644
--- a/Modules/CMakeDetermineSwiftCompiler.cmake
+++ b/Modules/CMakeDetermineSwiftCompiler.cmake
@@ -16,7 +16,7 @@
   endif()
   set(CMAKE_Swift_COMPILER_XCODE_TYPE sourcecode.swift)
   _cmake_find_compiler_path(Swift)
-elseif("${CMAKE_GENERATOR}" STREQUAL "Ninja")
+elseif("${CMAKE_GENERATOR}" MATCHES "^Ninja")
   if(CMAKE_Swift_COMPILER)
     _cmake_find_compiler_path(Swift)
   else()
diff --git a/Modules/CMakeDetermineSystem.cmake b/Modules/CMakeDetermineSystem.cmake
index dc208c6..f3ec4da 100644
--- a/Modules/CMakeDetermineSystem.cmake
+++ b/Modules/CMakeDetermineSystem.cmake
@@ -43,7 +43,7 @@
     else()
       exec_program(${CMAKE_UNAME} ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION)
     endif()
-    if(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux|CYGWIN.*|Darwin|^GNU$")
+    if(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux|CYGWIN.*|Darwin|^GNU$|Android")
       exec_program(${CMAKE_UNAME} ARGS -m OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
         RETURN_VALUE val)
       if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin" AND
diff --git a/Modules/CMakeFortranCompiler.cmake.in b/Modules/CMakeFortranCompiler.cmake.in
index ae7b73a..34f44aa 100644
--- a/Modules/CMakeFortranCompiler.cmake.in
+++ b/Modules/CMakeFortranCompiler.cmake.in
@@ -6,6 +6,7 @@
 set(CMAKE_Fortran_PLATFORM_ID "@CMAKE_Fortran_PLATFORM_ID@")
 set(CMAKE_Fortran_SIMULATE_ID "@CMAKE_Fortran_SIMULATE_ID@")
 set(CMAKE_Fortran_SIMULATE_VERSION "@CMAKE_Fortran_SIMULATE_VERSION@")
+@_SET_CMAKE_Fortran_XL_CPP@
 @_SET_CMAKE_Fortran_COMPILER_ARCHITECTURE_ID@
 @SET_MSVC_Fortran_ARCHITECTURE_ID@
 set(CMAKE_AR "@CMAKE_AR@")
diff --git a/Modules/CMakeFortranInformation.cmake b/Modules/CMakeFortranInformation.cmake
index ffa6a24..e80716b 100644
--- a/Modules/CMakeFortranInformation.cmake
+++ b/Modules/CMakeFortranInformation.cmake
@@ -163,6 +163,11 @@
 
 cmake_initialize_per_config_variable(CMAKE_Fortran_FLAGS "Flags used by the Fortran compiler")
 
+if(NOT CMAKE_Fortran_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_Fortran_COMPILER_LAUNCHER})
+  set(CMAKE_Fortran_COMPILER_LAUNCHER "$ENV{CMAKE_Fortran_COMPILER_LAUNCHER}"
+    CACHE STRING "Compiler launcher for Fortran.")
+endif()
+
 include(CMakeCommonLanguageInclude)
 
 # now define the following rule variables
diff --git a/Modules/CMakeGenericSystem.cmake b/Modules/CMakeGenericSystem.cmake
index 77d8cfd..f539b46 100644
--- a/Modules/CMakeGenericSystem.cmake
+++ b/Modules/CMakeGenericSystem.cmake
@@ -27,7 +27,7 @@
 set(CMAKE_AUTOGEN_ORIGIN_DEPENDS ON)
 set(CMAKE_AUTOMOC_COMPILER_PREDEFINES ON)
 set(CMAKE_AUTOMOC_PATH_PREFIX ON)
-set(CMAKE_AUTOMOC_MACRO_NAMES "Q_OBJECT" "Q_GADGET" "Q_NAMESPACE")
+set(CMAKE_AUTOMOC_MACRO_NAMES "Q_OBJECT" "Q_GADGET" "Q_NAMESPACE" "Q_NAMESPACE_EXPORT")
 
 # basically all general purpose OSs support shared libs
 set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
@@ -51,16 +51,16 @@
     set_property(GLOBAL PROPERTY TARGET_MESSAGES ${CMAKE_TARGET_MESSAGES})
   endif()
   if(CMAKE_GENERATOR MATCHES "Unix Makefiles")
-    set(CMAKE_EXPORT_COMPILE_COMMANDS OFF CACHE BOOL
-      "Enable/Disable output of compile commands during generation."
+    set(CMAKE_EXPORT_COMPILE_COMMANDS "$ENV{CMAKE_EXPORT_COMPILE_COMMANDS}"
+      CACHE BOOL "Enable/Disable output of compile commands during generation."
       )
     mark_as_advanced(CMAKE_EXPORT_COMPILE_COMMANDS)
   endif()
 endif()
 
 if(CMAKE_GENERATOR MATCHES "Ninja")
-  set(CMAKE_EXPORT_COMPILE_COMMANDS OFF CACHE BOOL
-    "Enable/Disable output of compile commands during generation."
+  set(CMAKE_EXPORT_COMPILE_COMMANDS "$ENV{CMAKE_EXPORT_COMPILE_COMMANDS}"
+    CACHE BOOL "Enable/Disable output of compile commands during generation."
     )
   mark_as_advanced(CMAKE_EXPORT_COMPILE_COMMANDS)
 endif()
diff --git a/Modules/CMakeGraphVizOptions.cmake b/Modules/CMakeGraphVizOptions.cmake
index 1911e73..be4a3be 100644
--- a/Modules/CMakeGraphVizOptions.cmake
+++ b/Modules/CMakeGraphVizOptions.cmake
@@ -5,119 +5,145 @@
 CMakeGraphVizOptions
 --------------------
 
-The builtin graphviz support of CMake.
+The builtin Graphviz support of CMake.
 
-Variables specific to the graphviz support
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Generating Graphviz files
+^^^^^^^^^^^^^^^^^^^^^^^^^
 
-CMake
-can generate `graphviz <http://www.graphviz.org/>`_ files, showing the dependencies between the
-targets in a project and also external libraries which are linked
-against.  When CMake is run with the ``--graphviz=foo.dot`` option, it will
-produce:
+CMake can generate `Graphviz <https://www.graphviz.org/>`_ files showing the
+dependencies between the targets in a project, as well as external libraries
+which are linked against.
 
-* a ``foo.dot`` file showing all dependencies in the project
-* a ``foo.dot.<target>`` file for each target, file showing on which other targets the respective target depends
-* a ``foo.dot.<target>.dependers`` file, showing which other targets depend on the respective target
+When running CMake with the ``--graphviz=foo.dot`` option, it produces:
 
-The different dependency types ``PUBLIC``, ``PRIVATE`` and ``INTERFACE``
+* a ``foo.dot`` file, showing all dependencies in the project
+* a ``foo.dot.<target>`` file for each target, showing on which other targets
+  it depends
+* a ``foo.dot.<target>.dependers`` file for each target, showing which other
+  targets depend on it
+
+Those .dot files can be converted to images using the *dot* command from the
+Graphviz package:
+
+.. code-block:: shell
+
+  dot -Tpng -o foo.png foo.dot
+
+The different dependency types ``PUBLIC``, ``INTERFACE`` and ``PRIVATE``
 are represented as solid, dashed and dotted edges.
 
-This can result in huge graphs.  Using the file
-``CMakeGraphVizOptions.cmake`` the look and content of the generated
-graphs can be influenced.  This file is searched first in
-:variable:`CMAKE_BINARY_DIR` and then in :variable:`CMAKE_SOURCE_DIR`.  If found, it is
-read and the variables set in it are used to adjust options for the
-generated graphviz files.
+Variables specific to the Graphviz support
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-.. variable:: GRAPHVIZ_GRAPH_TYPE
-
- The graph type.
-
- * Mandatory : NO
- * Default   : "digraph"
-
- Valid graph types are:
-
- * "graph" : Nodes are joined with lines
- * "digraph" : Nodes are joined with arrows showing direction
- * "strict graph" : Like "graph" but max one line between each node
- * "strict digraph" : Like "graph" but max one line between each node in each direction
+The resulting graphs can be huge.  The look and content of the generated graphs
+can be controlled using the file ``CMakeGraphVizOptions.cmake``.  This file is
+first searched in :variable:`CMAKE_BINARY_DIR`, and then in
+:variable:`CMAKE_SOURCE_DIR`.  If found, the variables set in it are used to
+adjust options for the generated Graphviz files.
 
 .. variable:: GRAPHVIZ_GRAPH_NAME
 
  The graph name.
 
- * Mandatory : NO
- * Default   : "GG"
+ * Mandatory: NO
+ * Default: value of :variable:`CMAKE_PROJECT_NAME`
 
 .. variable:: GRAPHVIZ_GRAPH_HEADER
 
- The header written at the top of the graphviz file.
+ The header written at the top of the Graphviz files.
 
- * Mandatory : NO
- * Default   : "node [n  fontsize = "12"];"
+ * Mandatory: NO
+ * Default: "node [ fontsize = "12" ];"
 
 .. variable:: GRAPHVIZ_NODE_PREFIX
 
- The prefix for each node in the graphviz file.
+ The prefix for each node in the Graphviz files.
 
- * Mandatory : NO
- * Default   : "node"
+ * Mandatory: NO
+ * Default: "node"
 
 .. variable:: GRAPHVIZ_EXECUTABLES
 
- Set this to FALSE to exclude executables from the generated graphs.
+ Set to FALSE to exclude executables from the generated graphs.
 
- * Mandatory : NO
- * Default   : TRUE
+ * Mandatory: NO
+ * Default: TRUE
 
 .. variable:: GRAPHVIZ_STATIC_LIBS
 
- Set this to FALSE to exclude static libraries from the generated graphs.
+ Set to FALSE to exclude static libraries from the generated graphs.
 
- * Mandatory : NO
- * Default   : TRUE
+ * Mandatory: NO
+ * Default: TRUE
 
 .. variable:: GRAPHVIZ_SHARED_LIBS
 
- Set this to FALSE to exclude shared libraries from the generated graphs.
+ Set to FALSE to exclude shared libraries from the generated graphs.
 
- * Mandatory : NO
- * Default   : TRUE
+ * Mandatory: NO
+ * Default: TRUE
 
 .. variable:: GRAPHVIZ_MODULE_LIBS
 
- Set this to FALSE to exclude module libraries from the generated graphs.
+ Set to FALSE to exclude module libraries from the generated graphs.
 
- * Mandatory : NO
- * Default   : TRUE
+ * Mandatory: NO
+ * Default: TRUE
+
+.. variable:: GRAPHVIZ_INTERFACE_LIBS
+
+ Set to FALSE to exclude interface libraries from the generated graphs.
+
+ * Mandatory: NO
+ * Default: TRUE
+
+.. variable:: GRAPHVIZ_OBJECT_LIBS
+
+ Set to FALSE to exclude object libraries from the generated graphs.
+
+ * Mandatory: NO
+ * Default: TRUE
+
+.. variable:: GRAPHVIZ_UNKNOWN_LIBS
+
+ Set to FALSE to exclude unknown libraries from the generated graphs.
+
+ * Mandatory: NO
+ * Default: TRUE
 
 .. variable:: GRAPHVIZ_EXTERNAL_LIBS
 
- Set this to FALSE to exclude external libraries from the generated graphs.
+ Set to FALSE to exclude external libraries from the generated graphs.
 
- * Mandatory : NO
- * Default   : TRUE
+ * Mandatory: NO
+ * Default: TRUE
+
+.. variable:: GRAPHVIZ_CUSTOM_TARGETS
+
+ Set to TRUE to include custom targets in the generated graphs.
+
+ * Mandatory: NO
+ * Default: FALSE
 
 .. variable:: GRAPHVIZ_IGNORE_TARGETS
 
- A list of regular expressions for ignoring targets.
+ A list of regular expressions for names of targets to exclude from the
+ generated graphs.
 
- * Mandatory : NO
- * Default   : empty
+ * Mandatory: NO
+ * Default: empty
 
 .. variable:: GRAPHVIZ_GENERATE_PER_TARGET
 
- Set this to FALSE to exclude per target graphs ``foo.dot.<target>``.
+ Set to FALSE to not generate per-target graphs ``foo.dot.<target>``.
 
- * Mandatory : NO
- * Default   : TRUE
+ * Mandatory: NO
+ * Default: TRUE
 
 .. variable:: GRAPHVIZ_GENERATE_DEPENDERS
 
- Set this to FALSE to exclude depender graphs ``foo.dot.<target>.dependers``.
+ Set to FALSE to not generate depender graphs ``foo.dot.<target>.dependers``.
 
- * Mandatory : NO
- * Default   : TRUE
+ * Mandatory: NO
+ * Default: TRUE
 #]=======================================================================]
diff --git a/Modules/CMakeMinGWFindMake.cmake b/Modules/CMakeMinGWFindMake.cmake
index 523f00c..f026e9a 100644
--- a/Modules/CMakeMinGWFindMake.cmake
+++ b/Modules/CMakeMinGWFindMake.cmake
@@ -7,10 +7,5 @@
   c:/MinGW/bin /MinGW/bin
   "[HKEY_CURRENT_USER\\Software\\CodeBlocks;Path]/MinGW/bin"
   )
-find_program(CMAKE_SH sh.exe )
-if(CMAKE_SH)
-  message(FATAL_ERROR "sh.exe was found in your PATH, here:\n${CMAKE_SH}\nFor MinGW make to work correctly sh.exe must NOT be in your path.\nRun cmake from a shell that does not have sh.exe in your PATH.\nIf you want to use a UNIX shell, then use MSYS Makefiles.\n")
-  set(CMAKE_MAKE_PROGRAM NOTFOUND)
-endif()
 
-mark_as_advanced(CMAKE_MAKE_PROGRAM CMAKE_SH)
+mark_as_advanced(CMAKE_MAKE_PROGRAM)
diff --git a/Modules/CMakeNinjaFindMake.cmake b/Modules/CMakeNinjaFindMake.cmake
index 702af13..32f78da 100644
--- a/Modules/CMakeNinjaFindMake.cmake
+++ b/Modules/CMakeNinjaFindMake.cmake
@@ -4,5 +4,6 @@
 
 find_program(CMAKE_MAKE_PROGRAM
   NAMES ninja-build ninja samu
+  NAMES_PER_DIR
   DOC "Program used to build from build.ninja files.")
 mark_as_advanced(CMAKE_MAKE_PROGRAM)
diff --git a/Modules/CMakeOBJCInformation.cmake b/Modules/CMakeOBJCInformation.cmake
index cb61cb8..15a3311 100644
--- a/Modules/CMakeOBJCInformation.cmake
+++ b/Modules/CMakeOBJCInformation.cmake
@@ -110,6 +110,11 @@
   mark_as_advanced(CMAKE_OBJC_STANDARD_LIBRARIES)
 endif()
 
+if(NOT CMAKE_OBJC_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_OBJC_COMPILER_LAUNCHER})
+  set(CMAKE_OBJC_COMPILER_LAUNCHER "$ENV{CMAKE_OBJC_COMPILER_LAUNCHER}"
+    CACHE STRING "Compiler launcher for OBJC.")
+endif()
+
 include(CMakeCommonLanguageInclude)
 
 # now define the following rule variables
diff --git a/Modules/CMakeOBJCXXInformation.cmake b/Modules/CMakeOBJCXXInformation.cmake
index 71ac26a..cb349d7 100644
--- a/Modules/CMakeOBJCXXInformation.cmake
+++ b/Modules/CMakeOBJCXXInformation.cmake
@@ -203,6 +203,11 @@
   mark_as_advanced(CMAKE_OBJCXX_STANDARD_LIBRARIES)
 endif()
 
+if(NOT CMAKE_OBJCXX_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_OBJCXX_COMPILER_LAUNCHER})
+  set(CMAKE_OBJCXX_COMPILER_LAUNCHER "$ENV{CMAKE_OBJCXX_COMPILER_LAUNCHER}"
+    CACHE STRING "Compiler launcher for OBJCXX.")
+endif()
+
 include(CMakeCommonLanguageInclude)
 
 # now define the following rules:
diff --git a/Modules/CMakePrintSystemInformation.cmake b/Modules/CMakePrintSystemInformation.cmake
index f873a4d..8d5cf5c 100644
--- a/Modules/CMakePrintSystemInformation.cmake
+++ b/Modules/CMakePrintSystemInformation.cmake
@@ -5,9 +5,9 @@
 CMakePrintSystemInformation
 ---------------------------
 
-print system information
+Print system information.
 
-This file can be used for diagnostic purposes just include it in a
+This module serves diagnostic purposes. Just include it in a
 project to see various internal CMake variables.
 #]=======================================================================]
 
diff --git a/Modules/CMakeSwiftCompiler.cmake.in b/Modules/CMakeSwiftCompiler.cmake.in
index 7c8d1c1..47ada38 100644
--- a/Modules/CMakeSwiftCompiler.cmake.in
+++ b/Modules/CMakeSwiftCompiler.cmake.in
@@ -12,3 +12,5 @@
 
 set(CMAKE_Swift_COMPILER_ID_RUN 1)
 set(CMAKE_Swift_SOURCE_FILE_EXTENSIONS swift)
+
+set(CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES "@CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES@")
diff --git a/Modules/CMakeSwiftInformation.cmake b/Modules/CMakeSwiftInformation.cmake
index 2c54da0..8f0909c 100644
--- a/Modules/CMakeSwiftInformation.cmake
+++ b/Modules/CMakeSwiftInformation.cmake
@@ -17,6 +17,8 @@
   include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_Swift_COMPILER_ID}-Swift OPTIONAL)
 endif()
 
+set(CMAKE_EXE_EXPORTS_Swift_FLAG "-emit-module -emit-module-path <SWIFT_MODULE> ${CMAKE_Swift_IMPLIB_LINKER_FLAGS}")
+
 set(CMAKE_INCLUDE_FLAG_Swift "-I ")
 if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
   set(CMAKE_SHARED_LIBRARY_SONAME_Swift_FLAG "-Xlinker -install_name -Xlinker ")
@@ -25,8 +27,15 @@
 endif()
 
 if(NOT CMAKE_SYSTEM_NAME STREQUAL Windows)
+  set(CMAKE_EXECUTABLE_RUNTIME_Swift_FLAG "-Xlinker -rpath -Xlinker ")
   set(CMAKE_SHARED_LIBRARY_RUNTIME_Swift_FLAG "-Xlinker -rpath -Xlinker ")
-  set(CMAKE_SHARED_LIBRARY_RUNTIME_Swift_FLAG_SEP ":")
+  if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+    set(CMAKE_EXECUTABLE_RUNTIME_Swift_FLAG_SEP "")
+    set(CMAKE_SHARED_LIBRARY_RUNTIME_Swift_FLAG_SEP "")
+  else()
+    set(CMAKE_EXECUTABLE_RUNTIME_Swift_FLAG_SEP ":")
+    set(CMAKE_SHARED_LIBRARY_RUNTIME_Swift_FLAG_SEP ":")
+  endif()
 endif()
 
 set(CMAKE_Swift_COMPILE_OPTIONS_TARGET "-target ")
@@ -72,10 +81,6 @@
   cmake_host_system_information(RESULT CMAKE_Swift_NUM_THREADS QUERY NUMBER_OF_LOGICAL_CORES)
 endif()
 
-if(CMAKE_SYSTEM_NAME STREQUAL Windows)
-  set(CMAKE_Swift_IMPLIB_LINKER_FLAGS "-Xlinker -implib:<TARGET_IMPLIB>")
-endif()
-
 if(NOT CMAKE_Swift_CREATE_SHARED_LIBRARY)
   set(CMAKE_Swift_CREATE_SHARED_LIBRARY "<CMAKE_Swift_COMPILER> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -j ${CMAKE_Swift_NUM_THREADS} -emit-library -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> ${CMAKE_Swift_IMPLIB_LINKER_FLAGS} <LINK_LIBRARIES>")
 endif()
@@ -85,7 +90,7 @@
 endif()
 
 if(NOT CMAKE_Swift_LINK_EXECUTABLE)
-  set(CMAKE_Swift_LINK_EXECUTABLE "<CMAKE_Swift_COMPILER> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -j ${CMAKE_Swift_NUM_THREADS} -emit-executable -o <TARGET> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> ${CMAKE_Swift_IMPLIB_LINKER_FLAGS} <LINK_LIBRARIES>")
+  set(CMAKE_Swift_LINK_EXECUTABLE "<CMAKE_Swift_COMPILER> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -j ${CMAKE_Swift_NUM_THREADS} -emit-executable -o <TARGET> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>")
 endif()
 
 if(NOT CMAKE_Swift_CREATE_STATIC_LIBRARY)
diff --git a/Modules/CMakeTestCCompiler.cmake b/Modules/CMakeTestCCompiler.cmake
index 7bf6fde..eadea89 100644
--- a/Modules/CMakeTestCCompiler.cmake
+++ b/Modules/CMakeTestCCompiler.cmake
@@ -27,7 +27,7 @@
 # is set and cmake stops processing commands and will not generate
 # any makefiles or projects.
 if(NOT CMAKE_C_COMPILER_WORKS)
-  PrintTestCompilerStatus("C" "")
+  PrintTestCompilerStatus("C")
   __TestCompiler_setTryCompileTargetType()
   file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testCCompiler.c
     "#ifdef __cplusplus\n"
@@ -52,7 +52,7 @@
 endif()
 
 if(NOT CMAKE_C_COMPILER_WORKS)
-  PrintTestCompilerStatus("C" " -- broken")
+  PrintTestCompilerResult(CHECK_FAIL "broken")
   file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
     "Determining if the C compiler works failed with "
     "the following output:\n${__CMAKE_C_COMPILER_OUTPUT}\n\n")
@@ -63,7 +63,7 @@
     "CMake will not be able to correctly generate this project.")
 else()
   if(C_TEST_WAS_RUN)
-    PrintTestCompilerStatus("C" " -- works")
+    PrintTestCompilerResult(CHECK_PASS "works")
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
       "Determining if the C compiler works passed with "
       "the following output:\n${__CMAKE_C_COMPILER_OUTPUT}\n\n")
diff --git a/Modules/CMakeTestCSharpCompiler.cmake b/Modules/CMakeTestCSharpCompiler.cmake
index 6715c30..1119a45 100644
--- a/Modules/CMakeTestCSharpCompiler.cmake
+++ b/Modules/CMakeTestCSharpCompiler.cmake
@@ -20,7 +20,9 @@
 # is set and cmake stops processing commands and will not generate
 # any makefiles or projects.
 if(NOT CMAKE_CSharp_COMPILER_WORKS)
-  PrintTestCompilerStatus("C#" "${CMAKE_CSharp_COMPILER}")
+  # Don't call PrintTestCompilerStatus() because the "C#" we want to pass
+  # as the LANG doesn't match with the variable name "CMAKE_CSharp_COMPILER"
+  message(CHECK_START "Check for working C# compiler: ${CMAKE_CSharp_COMPILER}")
   file(WRITE "${test_compile_file}"
     "namespace Test {"
     "   public class CSharp {"
@@ -38,7 +40,7 @@
 endif()
 
 if(NOT CMAKE_CSharp_COMPILER_WORKS)
-  PrintTestCompilerStatus("C#" "${CMAKE_CSharp_COMPILER} -- broken")
+  PrintTestCompilerResult(CHECK_FAIL "broken")
   file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
     "Determining if the C# compiler works failed with "
     "the following output:\n${__CMAKE_CSharp_COMPILER_OUTPUT}\n\n")
@@ -49,7 +51,7 @@
     "CMake will not be able to correctly generate this project.")
 else()
   if(CSharp_TEST_WAS_RUN)
-    PrintTestCompilerStatus("C#" "${CMAKE_CSharp_COMPILER} -- works")
+    PrintTestCompilerResult(CHECK_PASS "works")
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
       "Determining if the C# compiler works passed with "
       "the following output:\n${__CMAKE_CSharp_COMPILER_OUTPUT}\n\n")
diff --git a/Modules/CMakeTestCUDACompiler.cmake b/Modules/CMakeTestCUDACompiler.cmake
index f0454da..05811a8 100644
--- a/Modules/CMakeTestCUDACompiler.cmake
+++ b/Modules/CMakeTestCUDACompiler.cmake
@@ -20,7 +20,7 @@
 # is set and cmake stops processing commands and will not generate
 # any makefiles or projects.
 if(NOT CMAKE_CUDA_COMPILER_WORKS)
-  PrintTestCompilerStatus("CUDA" "")
+  PrintTestCompilerStatus("CUDA")
   file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/main.cu
     "#ifndef __CUDACC__\n"
     "# error \"The CMAKE_CUDA_COMPILER is set to an invalid CUDA compiler\"\n"
@@ -38,7 +38,7 @@
 endif()
 
 if(NOT CMAKE_CUDA_COMPILER_WORKS)
-  PrintTestCompilerStatus("CUDA" " -- broken")
+  PrintTestCompilerResult(CHECK_FAIL "broken")
   file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
     "Determining if the CUDA compiler works failed with "
     "the following output:\n${__CMAKE_CUDA_COMPILER_OUTPUT}\n\n")
@@ -49,7 +49,7 @@
     "CMake will not be able to correctly generate this project.")
 else()
   if(CUDA_TEST_WAS_RUN)
-    PrintTestCompilerStatus("CUDA" " -- works")
+    PrintTestCompilerResult(CHECK_PASS "works")
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
       "Determining if the CUDA compiler works passed with "
       "the following output:\n${__CMAKE_CUDA_COMPILER_OUTPUT}\n\n")
@@ -58,12 +58,38 @@
   # Try to identify the ABI and configure it into CMakeCUDACompiler.cmake
   include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
   CMAKE_DETERMINE_COMPILER_ABI(CUDA ${CMAKE_ROOT}/Modules/CMakeCUDACompilerABI.cu)
+  # Try to identify the compiler features
+  include(${CMAKE_ROOT}/Modules/CMakeDetermineCompileFeatures.cmake)
+  CMAKE_DETERMINE_COMPILE_FEATURES(CUDA)
 
   if("x${CMAKE_CUDA_SIMULATE_ID}" STREQUAL "xMSVC")
     set(CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES "${CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES}")
     set(CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES "${CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES}")
   endif()
 
+  # Remove the following libraries from CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES and
+  # CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES
+  #
+  # - cudart
+  # - cudart_static
+  # - cudadevrt
+  #
+  # These are controlled by CMAKE_CUDA_RUNTIME_LIBRARY
+  list(REMOVE_ITEM CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES cudart cudart_static cudadevrt)
+  list(REMOVE_ITEM CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES cudart cudart_static cudadevrt)
+
+  # Remove the CUDA Toolkit include directories from the set of
+  # implicit system include directories.
+  # This resolves the issue that NVCC doesn't specify these
+  # includes as SYSTEM includes when compiling device code, and sometimes
+  # they contain headers that generate warnings, so let users mark them
+  # as SYSTEM explicitly
+  if(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES)
+    list(REMOVE_ITEM CMAKE_CUDA_IMPLICIT_INCLUDE_DIRECTORIES
+      ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}
+      )
+  endif()
+
   # Re-configure to save learned information.
   configure_file(
     ${CMAKE_ROOT}/Modules/CMakeCUDACompiler.cmake.in
diff --git a/Modules/CMakeTestCXXCompiler.cmake b/Modules/CMakeTestCXXCompiler.cmake
index 7e595b7..bd42153 100644
--- a/Modules/CMakeTestCXXCompiler.cmake
+++ b/Modules/CMakeTestCXXCompiler.cmake
@@ -27,7 +27,7 @@
 # is set and cmake stops processing commands and will not generate
 # any makefiles or projects.
 if(NOT CMAKE_CXX_COMPILER_WORKS)
-  PrintTestCompilerStatus("CXX" "")
+  PrintTestCompilerStatus("CXX")
   __TestCompiler_setTryCompileTargetType()
   file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testCXXCompiler.cxx
     "#ifndef __cplusplus\n"
@@ -45,7 +45,7 @@
 endif()
 
 if(NOT CMAKE_CXX_COMPILER_WORKS)
-  PrintTestCompilerStatus("CXX" " -- broken")
+  PrintTestCompilerResult(CHECK_FAIL "broken")
   file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
     "Determining if the CXX compiler works failed with "
     "the following output:\n${__CMAKE_CXX_COMPILER_OUTPUT}\n\n")
@@ -56,7 +56,7 @@
     "CMake will not be able to correctly generate this project.")
 else()
   if(CXX_TEST_WAS_RUN)
-    PrintTestCompilerStatus("CXX" " -- works")
+    PrintTestCompilerResult(CHECK_PASS "works")
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
       "Determining if the CXX compiler works passed with "
       "the following output:\n${__CMAKE_CXX_COMPILER_OUTPUT}\n\n")
diff --git a/Modules/CMakeTestCompilerCommon.cmake b/Modules/CMakeTestCompilerCommon.cmake
index 6ee5175..da7c007 100644
--- a/Modules/CMakeTestCompilerCommon.cmake
+++ b/Modules/CMakeTestCompilerCommon.cmake
@@ -2,8 +2,15 @@
 # file Copyright.txt or https://cmake.org/licensing for details.
 
 
-function(PrintTestCompilerStatus LANG MSG)
-  message(STATUS "Check for working ${LANG} compiler: ${CMAKE_${LANG}_COMPILER}${MSG}")
+function(PrintTestCompilerStatus LANG)
+  # ARGN shouldn't be needed now, but it is there to preserve backward
+  # compatibility in case this function is called from project code or
+  # custom toolchains (they shouldn't, but we can easily support it)
+  message(CHECK_START "Check for working ${LANG} compiler: ${CMAKE_${LANG}_COMPILER}${ARGN}")
+endfunction()
+
+function(PrintTestCompilerResult TYPE MSG)
+  message(${TYPE} "${MSG}")
 endfunction()
 
 # if required set the target type if not already explicitly set
diff --git a/Modules/CMakeTestFortranCompiler.cmake b/Modules/CMakeTestFortranCompiler.cmake
index e9860e9..7461f9c 100644
--- a/Modules/CMakeTestFortranCompiler.cmake
+++ b/Modules/CMakeTestFortranCompiler.cmake
@@ -21,7 +21,7 @@
 # is set and cmake stops processing commands and will not generate
 # any makefiles or projects.
 if(NOT CMAKE_Fortran_COMPILER_WORKS)
-  PrintTestCompilerStatus("Fortran" "")
+  PrintTestCompilerStatus("Fortran")
   file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testFortranCompiler.f "
         PROGRAM TESTFortran
         PRINT *, 'Hello'
@@ -37,7 +37,7 @@
 endif()
 
 if(NOT CMAKE_Fortran_COMPILER_WORKS)
-  PrintTestCompilerStatus("Fortran" "  -- broken")
+  PrintTestCompilerResult(CHECK_FAIL "broken")
   file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
     "Determining if the Fortran compiler works failed with "
     "the following output:\n${OUTPUT}\n\n")
@@ -48,7 +48,7 @@
     "CMake will not be able to correctly generate this project.")
 else()
   if(FORTRAN_TEST_WAS_RUN)
-    PrintTestCompilerStatus("Fortran" "  -- works")
+    PrintTestCompilerResult(CHECK_PASS "works")
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
       "Determining if the Fortran compiler works passed with "
       "the following output:\n${OUTPUT}\n\n")
@@ -60,7 +60,7 @@
 
   # Test for Fortran 90 support by using an f90-specific construct.
   if(NOT DEFINED CMAKE_Fortran_COMPILER_SUPPORTS_F90)
-    message(STATUS "Checking whether ${CMAKE_Fortran_COMPILER} supports Fortran 90")
+    message(CHECK_START "Checking whether ${CMAKE_Fortran_COMPILER} supports Fortran 90")
     file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testFortranCompilerF90.f90 "
       PROGRAM TESTFortran90
       integer stop ; stop = 1 ; do while ( stop .eq. 0 ) ; end do
@@ -70,13 +70,13 @@
       ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testFortranCompilerF90.f90
       OUTPUT_VARIABLE OUTPUT)
     if(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
-      message(STATUS "Checking whether ${CMAKE_Fortran_COMPILER} supports Fortran 90 -- yes")
+      message(CHECK_PASS "yes")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Determining if the Fortran compiler supports Fortran 90 passed with "
         "the following output:\n${OUTPUT}\n\n")
       set(CMAKE_Fortran_COMPILER_SUPPORTS_F90 1)
     else()
-      message(STATUS "Checking whether ${CMAKE_Fortran_COMPILER} supports Fortran 90 -- no")
+      message(CHECK_FAIL "no")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Determining if the Fortran compiler supports Fortran 90 failed with "
         "the following output:\n${OUTPUT}\n\n")
diff --git a/Modules/CMakeTestOBJCCompiler.cmake b/Modules/CMakeTestOBJCCompiler.cmake
index 0030683..bcc6fae 100644
--- a/Modules/CMakeTestOBJCCompiler.cmake
+++ b/Modules/CMakeTestOBJCCompiler.cmake
@@ -27,7 +27,7 @@
 # is set and cmake stops processing commands and will not generate
 # any makefiles or projects.
 if(NOT CMAKE_OBJC_COMPILER_WORKS)
-  PrintTestCompilerStatus("OBJC" "")
+  PrintTestCompilerStatus("OBJC")
   __TestCompiler_setTryCompileTargetType()
   file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testOBJCCompiler.m
     "#ifdef __cplusplus\n"
@@ -49,7 +49,7 @@
 endif()
 
 if(NOT CMAKE_OBJC_COMPILER_WORKS)
-  PrintTestCompilerStatus("OBJC" " -- broken")
+  PrintTestCompilerResult(CHECK_FAIL "broken")
   file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
     "Determining if the Objective-C compiler works failed with "
     "the following output:\n${__CMAKE_OBJC_COMPILER_OUTPUT}\n\n")
@@ -60,7 +60,7 @@
     "CMake will not be able to correctly generate this project.")
 else()
   if(OBJC_TEST_WAS_RUN)
-    PrintTestCompilerStatus("OBJC" " -- works")
+    PrintTestCompilerResult(CHECK_PASS "works")
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
       "Determining if the Objective-C compiler works passed with "
       "the following output:\n${__CMAKE_OBJC_COMPILER_OUTPUT}\n\n")
diff --git a/Modules/CMakeTestOBJCXXCompiler.cmake b/Modules/CMakeTestOBJCXXCompiler.cmake
index bcce2f1..83227d5 100644
--- a/Modules/CMakeTestOBJCXXCompiler.cmake
+++ b/Modules/CMakeTestOBJCXXCompiler.cmake
@@ -27,7 +27,7 @@
 # is set and cmake stops processing commands and will not generate
 # any makefiles or projects.
 if(NOT CMAKE_OBJCXX_COMPILER_WORKS)
-  PrintTestCompilerStatus("OBJCXX" "")
+  PrintTestCompilerStatus("OBJCXX")
   __TestCompiler_setTryCompileTargetType()
   file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testOBJCXXCompiler.mm
     "#ifndef __cplusplus\n"
@@ -48,7 +48,7 @@
 endif()
 
 if(NOT CMAKE_OBJCXX_COMPILER_WORKS)
-  PrintTestCompilerStatus("OBJCXX" " -- broken")
+  PrintTestCompilerResult(CHECK_FAIL "broken")
   file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
     "Determining if the Objective-C++ compiler works failed with "
     "the following output:\n${__CMAKE_OBJCXX_COMPILER_OUTPUT}\n\n")
@@ -59,7 +59,7 @@
     "CMake will not be able to correctly generate this project.")
 else()
   if(OBJCXX_TEST_WAS_RUN)
-    PrintTestCompilerStatus("OBJCXX" " -- works")
+    PrintTestCompilerResult(CHECK_PASS "works")
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
       "Determining if the Objective-C++ compiler works passed with "
       "the following output:\n${__CMAKE_OBJCXX_COMPILER_OUTPUT}\n\n")
diff --git a/Modules/CMakeTestSwiftCompiler.cmake b/Modules/CMakeTestSwiftCompiler.cmake
index 841aee6..d98dc9d 100644
--- a/Modules/CMakeTestSwiftCompiler.cmake
+++ b/Modules/CMakeTestSwiftCompiler.cmake
@@ -20,7 +20,7 @@
 # is set and cmake stops processing commands and will not generate
 # any makefiles or projects.
 if(NOT CMAKE_Swift_COMPILER_WORKS)
-  PrintTestCompilerStatus("Swift" "")
+  PrintTestCompilerStatus("Swift")
   file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/main.swift
     "print(\"CMake\")\n")
   try_compile(CMAKE_Swift_COMPILER_WORKS ${CMAKE_BINARY_DIR}
@@ -33,7 +33,7 @@
 endif()
 
 if(NOT CMAKE_Swift_COMPILER_WORKS)
-  PrintTestCompilerStatus("Swift" " -- broken")
+  PrintTestCompilerResult(CHECK_FAIL "broken")
   file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
     "Determining if the Swift compiler works failed with "
     "the following output:\n${__CMAKE_Swift_COMPILER_OUTPUT}\n\n")
@@ -44,12 +44,17 @@
     "CMake will not be able to correctly generate this project.")
 else()
   if(Swift_TEST_WAS_RUN)
-    PrintTestCompilerStatus("Swift" " -- works")
+    PrintTestCompilerResult(CHECK_PASS "works")
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
       "Determining if the Swift compiler works passed with "
       "the following output:\n${__CMAKE_Swift_COMPILER_OUTPUT}\n\n")
   endif()
 
+  # Unlike C and CXX we do not yet detect any information about the Swift ABI.
+  # However, one of the steps done for C and CXX as part of that detection is
+  # to initialize the implicit include directories.  That is relevant here.
+  set(CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES "${_CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES_INIT}")
+
   # Re-configure to save learned information.
   configure_file(${CMAKE_ROOT}/Modules/CMakeSwiftCompiler.cmake.in
                  ${CMAKE_PLATFORM_INFO_DIR}/CMakeSwiftCompiler.cmake @ONLY)
diff --git a/Modules/CPack.cmake b/Modules/CPack.cmake
index c2ed3de..baf7e47 100644
--- a/Modules/CPack.cmake
+++ b/Modules/CPack.cmake
@@ -5,22 +5,23 @@
 CPack
 -----
 
-Build binary and source package installers.
+Configure the binary and source package installers.
 
 Introduction
 ^^^^^^^^^^^^
 
-The CPack module generates a file ``CPackConfig.cmake`` intended for
-use in a subsequent run of  the :manual:`cpack <cpack(1)>` program
-where it steers the generation of installers or/and source packages.
+The CPack module generates the configuration files ``CPackConfig.cmake``
+and ``CPackSourceConfig.cmake``. They are intended for use in a subsequent
+run of  the :manual:`cpack <cpack(1)>` program where they steer the generation
+of installers or/and source packages.
 
-Inclusion of the CPack module adds two new build targets, ``package``
-and ``package_source``, which build the binary and source installers
-respectively.  The generated binary installers contain everything
-installed via CMake's :command:`install` command (and the deprecated
-commands :command:`install_files`, :command:`install_programs`, and
-:command:`install_targets`).
+Depending on the CMake generator, the CPack module may also add two new build
+targets, ``package`` and ``package_source``. See the `packaging targets`_
+section below for details.
 
+The generated binary installers contain everything installed via CMake's
+:command:`install` command (and the deprecated commands :command:`install_files`,
+:command:`install_programs`, and :command:`install_targets`).
 For certain kinds of binary installers (including the graphical
 installers on macOS and Windows), CPack generates installers that
 allow users to select individual application components to install.
@@ -63,6 +64,26 @@
 internally to *the one currently being used* and then include the
 :variable:`CPACK_PROJECT_CONFIG_FILE`.
 
+For a list of available generators, see :manual:`cpack-generators(7)`.
+
+.. _`packaging targets`:
+
+Targets package and package_source
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If CMake is run with the Makefile, Ninja, or Xcode generator, then
+``include(CPack)`` generates a target ``package``. This makes it possible
+to build a binary installer from CMake, Make, or Ninja: Instead of ``cpack``,
+one may call ``cmake --build . --target package`` or ``make package`` or
+``ninja package``. The VS generator creates an uppercase target ``PACKAGE``.
+
+If CMake is run with the Makefile or Ninja generator, then ``include(CPack)``
+also generates a target ``package_source``. To build a source package,
+instead of ``cpack -G TGZ --config CPackConfig.cmake`` one may call
+``cmake --build . --target package_source``, ``make package_source``,
+or ``ninja package_source``.
+
+
 Variables common to all CPack Generators
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -563,11 +584,19 @@
       if(APPLE)
         option(CPACK_BINARY_BUNDLE       "Enable to build OSX bundles"      OFF)
         option(CPACK_BINARY_DRAGNDROP    "Enable to build OSX Drag And Drop package" OFF)
-        option(CPACK_BINARY_OSXX11       "Enable to build OSX X11 packages"      OFF)
-        option(CPACK_BINARY_PACKAGEMAKER "Enable to build PackageMaker packages" OFF)
+        option(CPACK_BINARY_OSXX11       "Enable to build OSX X11 packages (deprecated)" OFF)
+        option(CPACK_BINARY_PACKAGEMAKER "Enable to build PackageMaker packages (deprecated)" 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)
@@ -577,6 +606,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)
@@ -584,8 +623,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)
@@ -615,6 +662,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)
@@ -622,10 +670,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)
@@ -638,38 +698,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;/")
@@ -684,6 +712,8 @@
 # value of CPACK_NSIS_PACKAGE_NAME  instead
 # of CPACK_PACKAGE_INSTALL_DIRECTORY
 _cpack_set_default(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY}")
+# Specify the name of the Uninstall file in NSIS
+_cpack_set_default(CPACK_NSIS_UNINSTALL_NAME "Uninstall")
 
 if(CPACK_NSIS_DISPLAY_NAME_SET)
   _cpack_set_default(CPACK_NSIS_PACKAGE_NAME "${CPACK_NSIS_DISPLAY_NAME}")
diff --git a/Modules/CPackIFW.cmake b/Modules/CPackIFW.cmake
index 42ef8c7..f58f9ef 100644
--- a/Modules/CPackIFW.cmake
+++ b/Modules/CPackIFW.cmake
@@ -5,15 +5,12 @@
 CPackIFW
 --------
 
-The documentation for the CPack IFW generator has moved here: :cpack_gen:`CPack IFW Generator`
-
-.. _QtIFW: http://doc.qt.io/qtinstallerframework/index.html
-
-This module looks for the location of the command line utilities supplied
-with the Qt Installer Framework (QtIFW_).
+This module looks for the location of the command-line utilities supplied with the
+`Qt Installer Framework <http://doc.qt.io/qtinstallerframework/index.html>`_
+(QtIFW).
 
 The module also defines several commands to control the behavior of the
-CPack ``IFW`` generator.
+:cpack_gen:`CPack IFW Generator`.
 
 Commands
 ^^^^^^^^
@@ -102,10 +99,10 @@
 
   ``DEPENDS`` | ``DEPENDENCIES``
     list of dependency component or component group identifiers in
-    QtIFW_ style.
+    QtIFW style.
 
   ``AUTO_DEPEND_ON``
-    list of identifiers of component or component group in QtIFW_ style
+    list of identifiers of component or component group in QtIFW style
     that this component has an automatic dependency on.
 
   ``LICENSES``
@@ -207,10 +204,10 @@
 
   ``DEPENDS`` | ``DEPENDENCIES``
     list of dependency component or component group identifiers in
-    QtIFW_ style.
+    QtIFW style.
 
   ``AUTO_DEPEND_ON``
-    list of identifiers of component or component group in QtIFW_ style
+    list of identifiers of component or component group in QtIFW style
     that this component group has an automatic dependency on.
 
   ``LICENSES``
@@ -242,7 +239,7 @@
 
 .. command:: cpack_ifw_add_repository
 
-  Add QtIFW_ specific remote repository to binary installer.
+  Add QtIFW specific remote repository to binary installer.
 
   ::
 
@@ -273,7 +270,7 @@
 
 .. command:: cpack_ifw_update_repository
 
-  Update QtIFW_ specific repository from remote repository.
+  Update QtIFW specific repository from remote repository.
 
   ::
 
diff --git a/Modules/CTest.cmake b/Modules/CTest.cmake
index 3a111ca..8109108 100644
--- a/Modules/CTest.cmake
+++ b/Modules/CTest.cmake
@@ -174,7 +174,7 @@
     "How many times to retry timed-out CTest submissions.")
 
   find_program(MEMORYCHECK_COMMAND
-    NAMES purify valgrind boundscheck
+    NAMES purify valgrind boundscheck drmemory
     PATHS
     "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Rational Software\\Purify\\Setup;InstallFolder]"
     DOC "Path to the memory checking command, used for memory error detection."
@@ -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/CheckCCompilerFlag.cmake b/Modules/CheckCCompilerFlag.cmake
index a3e2da3..6d65313 100644
--- a/Modules/CheckCCompilerFlag.cmake
+++ b/Modules/CheckCCompilerFlag.cmake
@@ -36,28 +36,23 @@
 include(CheckCSourceCompiles)
 include(CMakeCheckCompilerFlagCommonPatterns)
 
-macro (CHECK_C_COMPILER_FLAG _FLAG _RESULT)
-  set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
-  set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
+function(check_c_compiler_flag _flag _var)
+  set(CMAKE_REQUIRED_DEFINITIONS "${_flag}")
 
-   # Normalize locale during test compilation.
-  set(_CheckCCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG)
-  foreach(v ${_CheckCCompilerFlag_LOCALE_VARS})
-    set(_CheckCCompilerFlag_SAVED_${v} "$ENV{${v}}")
+  # Normalize locale during test compilation.
+  set(_locale_vars LC_ALL LC_MESSAGES LANG)
+  foreach(v IN LISTS _locale_vars)
+    set(_locale_vars_saved_${v} "$ENV{${v}}")
     set(ENV{${v}} C)
   endforeach()
-  CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckCCompilerFlag_COMMON_PATTERNS)
-  CHECK_C_SOURCE_COMPILES("int main(void) { return 0; }" ${_RESULT}
+  check_compiler_flag_common_patterns(_common_patterns)
+  check_c_source_compiles("int main(void) { return 0; }" ${_var}
     # Some compilers do not fail with a bad flag
     FAIL_REGEX "command line option .* is valid for .* but not for C" # GNU
-    ${_CheckCCompilerFlag_COMMON_PATTERNS}
+    ${_common_patterns}
     )
-  foreach(v ${_CheckCCompilerFlag_LOCALE_VARS})
-    set(ENV{${v}} ${_CheckCCompilerFlag_SAVED_${v}})
-    unset(_CheckCCompilerFlag_SAVED_${v})
+  foreach(v IN LISTS _locale_vars)
+    set(ENV{${v}} ${_locale_vars_saved_${v}})
   endforeach()
-  unset(_CheckCCompilerFlag_LOCALE_VARS)
-  unset(_CheckCCompilerFlag_COMMON_PATTERNS)
-
-  set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
-endmacro ()
+  set(${_var} "${${_var}}" PARENT_SCOPE)
+endfunction()
diff --git a/Modules/CheckCSourceCompiles.cmake b/Modules/CheckCSourceCompiles.cmake
index 77ba0cc..67fc993 100644
--- a/Modules/CheckCSourceCompiles.cmake
+++ b/Modules/CheckCSourceCompiles.cmake
@@ -104,7 +104,7 @@
       "${SOURCE}\n")
 
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Performing Test ${VAR}")
+      message(CHECK_START "Performing Test ${VAR}")
     endif()
     try_compile(${VAR}
       ${CMAKE_BINARY_DIR}
@@ -125,7 +125,7 @@
     if(${VAR})
       set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Success")
+        message(CHECK_PASS "Success")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Performing C SOURCE FILE Test ${VAR} succeeded with the following output:\n"
@@ -133,7 +133,7 @@
         "Source file was:\n${SOURCE}\n")
     else()
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Failed")
+        message(CHECK_FAIL "Failed")
       endif()
       set(${VAR} "" CACHE INTERNAL "Test ${VAR}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
diff --git a/Modules/CheckCSourceRuns.cmake b/Modules/CheckCSourceRuns.cmake
index eba70f2..7d116db 100644
--- a/Modules/CheckCSourceRuns.cmake
+++ b/Modules/CheckCSourceRuns.cmake
@@ -92,7 +92,7 @@
       "${SOURCE}\n")
 
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Performing Test ${VAR}")
+      message(CHECK_START "Performing Test ${VAR}")
     endif()
     try_run(${VAR}_EXITCODE ${VAR}_COMPILED
       ${CMAKE_BINARY_DIR}
@@ -113,7 +113,7 @@
     if("${${VAR}_EXITCODE}" EQUAL 0)
       set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Success")
+        message(CHECK_PASS "Success")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Performing C SOURCE FILE Test ${VAR} succeeded with the following compile output:\n"
@@ -130,7 +130,7 @@
       endif()
 
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Failed")
+        message(CHECK_FAIL "Failed")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Performing C SOURCE FILE Test ${VAR} failed with the following compile output:\n"
diff --git a/Modules/CheckCXXCompilerFlag.cmake b/Modules/CheckCXXCompilerFlag.cmake
index 5729843..5e07c25 100644
--- a/Modules/CheckCXXCompilerFlag.cmake
+++ b/Modules/CheckCXXCompilerFlag.cmake
@@ -36,28 +36,23 @@
 include(CheckCXXSourceCompiles)
 include(CMakeCheckCompilerFlagCommonPatterns)
 
-macro (CHECK_CXX_COMPILER_FLAG _FLAG _RESULT)
-  set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
-  set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
+function(check_cxx_compiler_flag _flag _var)
+  set(CMAKE_REQUIRED_DEFINITIONS "${_flag}")
 
   # Normalize locale during test compilation.
-  set(_CheckCXXCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG)
-  foreach(v ${_CheckCXXCompilerFlag_LOCALE_VARS})
-    set(_CheckCXXCompilerFlag_SAVED_${v} "$ENV{${v}}")
+  set(_locale_vars LC_ALL LC_MESSAGES LANG)
+  foreach(v IN LISTS _locale_vars)
+    set(_locale_vars_saved_${v} "$ENV{${v}}")
     set(ENV{${v}} C)
   endforeach()
-  CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckCXXCompilerFlag_COMMON_PATTERNS)
-  CHECK_CXX_SOURCE_COMPILES("int main() { return 0; }" ${_RESULT}
+  check_compiler_flag_common_patterns(_common_patterns)
+  check_cxx_source_compiles("int main() { return 0; }" ${_var}
     # Some compilers do not fail with a bad flag
     FAIL_REGEX "command line option .* is valid for .* but not for C\\\\+\\\\+" # GNU
-    ${_CheckCXXCompilerFlag_COMMON_PATTERNS}
+    ${_common_patterns}
     )
-  foreach(v ${_CheckCXXCompilerFlag_LOCALE_VARS})
-    set(ENV{${v}} ${_CheckCXXCompilerFlag_SAVED_${v}})
-    unset(_CheckCXXCompilerFlag_SAVED_${v})
+  foreach(v IN LISTS _locale_vars)
+    set(ENV{${v}} ${_locale_vars_saved_${v}})
   endforeach()
-  unset(_CheckCXXCompilerFlag_LOCALE_VARS)
-  unset(_CheckCXXCompilerFlag_COMMON_PATTERNS)
-
-  set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
-endmacro ()
+  set(${_var} "${${_var}}" PARENT_SCOPE)
+endfunction()
diff --git a/Modules/CheckCXXSourceCompiles.cmake b/Modules/CheckCXXSourceCompiles.cmake
index cc457a5..c693d32 100644
--- a/Modules/CheckCXXSourceCompiles.cmake
+++ b/Modules/CheckCXXSourceCompiles.cmake
@@ -105,7 +105,7 @@
       "${SOURCE}\n")
 
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Performing Test ${VAR}")
+      message(CHECK_START "Performing Test ${VAR}")
     endif()
     try_compile(${VAR}
       ${CMAKE_BINARY_DIR}
@@ -126,7 +126,7 @@
     if(${VAR})
       set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Success")
+        message(CHECK_PASS "Success")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Performing C++ SOURCE FILE Test ${VAR} succeeded with the following output:\n"
@@ -134,7 +134,7 @@
         "Source file was:\n${SOURCE}\n")
     else()
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Failed")
+        message(CHECK_FAIL "Failed")
       endif()
       set(${VAR} "" CACHE INTERNAL "Test ${VAR}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
diff --git a/Modules/CheckCXXSourceRuns.cmake b/Modules/CheckCXXSourceRuns.cmake
index 5e3f195..408e183 100644
--- a/Modules/CheckCXXSourceRuns.cmake
+++ b/Modules/CheckCXXSourceRuns.cmake
@@ -92,7 +92,7 @@
       "${SOURCE}\n")
 
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Performing Test ${VAR}")
+      message(CHECK_START "Performing Test ${VAR}")
     endif()
     try_run(${VAR}_EXITCODE ${VAR}_COMPILED
       ${CMAKE_BINARY_DIR}
@@ -114,7 +114,7 @@
     if("${${VAR}_EXITCODE}" EQUAL 0)
       set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Success")
+        message(CHECK_PASS "Success")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Performing C++ SOURCE FILE Test ${VAR} succeeded with the following output:\n"
@@ -131,7 +131,7 @@
       endif()
 
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Failed")
+        message(CHECK_FAIL "Failed")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Performing C++ SOURCE FILE Test ${VAR} failed with the following output:\n"
diff --git a/Modules/CheckFortranFunctionExists.cmake b/Modules/CheckFortranFunctionExists.cmake
index 7ca205a..d06203f 100644
--- a/Modules/CheckFortranFunctionExists.cmake
+++ b/Modules/CheckFortranFunctionExists.cmake
@@ -38,7 +38,7 @@
 
 macro(CHECK_FORTRAN_FUNCTION_EXISTS FUNCTION VARIABLE)
   if(NOT DEFINED ${VARIABLE})
-    message(STATUS "Looking for Fortran ${FUNCTION}")
+    message(CHECK_START "Looking for Fortran ${FUNCTION}")
     if(CMAKE_REQUIRED_LINK_OPTIONS)
       set(CHECK_FUNCTION_EXISTS_ADD_LINK_OPTIONS
         LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
@@ -61,21 +61,20 @@
     "
     )
     try_compile(${VARIABLE}
-    ${CMAKE_BINARY_DIR}
-    ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testFortranCompiler.f
-    ${CHECK_FUNCTION_EXISTS_ADD_LINK_OPTIONS}
-    ${CHECK_FUNCTION_EXISTS_ADD_LIBRARIES}
-    OUTPUT_VARIABLE OUTPUT
+      ${CMAKE_BINARY_DIR}
+      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testFortranCompiler.f
+      ${CHECK_FUNCTION_EXISTS_ADD_LINK_OPTIONS}
+      ${CHECK_FUNCTION_EXISTS_ADD_LIBRARIES}
+      OUTPUT_VARIABLE OUTPUT
     )
-#    message(STATUS "${OUTPUT}")
     if(${VARIABLE})
       set(${VARIABLE} 1 CACHE INTERNAL "Have Fortran function ${FUNCTION}")
-      message(STATUS "Looking for Fortran ${FUNCTION} - found")
+      message(CHECK_PASS "found")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Determining if the Fortran ${FUNCTION} exists passed with the following output:\n"
         "${OUTPUT}\n\n")
     else()
-      message(STATUS "Looking for Fortran ${FUNCTION} - not found")
+      message(CHECK_FAIL "not found")
       set(${VARIABLE} "" CACHE INTERNAL "Have Fortran function ${FUNCTION}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Determining if the Fortran ${FUNCTION} exists failed with the following output:\n"
diff --git a/Modules/CheckFortranSourceCompiles.cmake b/Modules/CheckFortranSourceCompiles.cmake
index f94b254..f0fde8d 100644
--- a/Modules/CheckFortranSourceCompiles.cmake
+++ b/Modules/CheckFortranSourceCompiles.cmake
@@ -127,7 +127,7 @@
       "${SOURCE}\n")
 
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Performing Test ${VAR}")
+      message(CHECK_START "Performing Test ${VAR}")
     endif()
     try_compile(${VAR}
       ${CMAKE_BINARY_DIR}
@@ -148,7 +148,7 @@
     if(${VAR})
       set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Success")
+        message(CHECK_PASS "Success")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Performing Fortran SOURCE FILE Test ${VAR} succeeded with the following output:\n"
@@ -156,7 +156,7 @@
         "Source file was:\n${SOURCE}\n")
     else()
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Failed")
+        message(CHECK_FAIL "Failed")
       endif()
       set(${VAR} "" CACHE INTERNAL "Test ${VAR}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
diff --git a/Modules/CheckFortranSourceRuns.cmake b/Modules/CheckFortranSourceRuns.cmake
index a80c13d..a3e5d5d 100644
--- a/Modules/CheckFortranSourceRuns.cmake
+++ b/Modules/CheckFortranSourceRuns.cmake
@@ -122,7 +122,7 @@
       "${SOURCE}\n")
 
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Performing Test ${VAR}")
+      message(CHECK_START "Performing Test ${VAR}")
     endif()
     try_run(${VAR}_EXITCODE ${VAR}_COMPILED
       ${CMAKE_BINARY_DIR}
@@ -144,7 +144,7 @@
     if("${${VAR}_EXITCODE}" EQUAL 0)
       set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Success")
+        message(CHECK_PASS "Success")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Performing Fortran SOURCE FILE Test ${VAR} succeeded with the following output:\n"
@@ -161,7 +161,7 @@
       endif()
 
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Failed")
+        message(CHECK_FAIL "Failed")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Performing Fortran SOURCE FILE Test ${VAR} failed with the following output:\n"
diff --git a/Modules/CheckFunctionExists.cmake b/Modules/CheckFunctionExists.cmake
index c39144f..136da89 100644
--- a/Modules/CheckFunctionExists.cmake
+++ b/Modules/CheckFunctionExists.cmake
@@ -57,7 +57,7 @@
     set(MACRO_CHECK_FUNCTION_DEFINITIONS
       "-DCHECK_FUNCTION_EXISTS=${FUNCTION} ${CMAKE_REQUIRED_FLAGS}")
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Looking for ${FUNCTION}")
+      message(CHECK_START "Looking for ${FUNCTION}")
     endif()
     if(CMAKE_REQUIRED_LINK_OPTIONS)
       set(CHECK_FUNCTION_EXISTS_ADD_LINK_OPTIONS
@@ -101,14 +101,14 @@
     if(${VARIABLE})
       set(${VARIABLE} 1 CACHE INTERNAL "Have function ${FUNCTION}")
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Looking for ${FUNCTION} - found")
+        message(CHECK_PASS "found")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Determining if the function ${FUNCTION} exists passed with the following output:\n"
         "${OUTPUT}\n\n")
     else()
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Looking for ${FUNCTION} - not found")
+        message(CHECK_FAIL "not found")
       endif()
       set(${VARIABLE} "" CACHE INTERNAL "Have function ${FUNCTION}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
diff --git a/Modules/CheckIncludeFile.cmake b/Modules/CheckIncludeFile.cmake
index d7b9481..3a10473 100644
--- a/Modules/CheckIncludeFile.cmake
+++ b/Modules/CheckIncludeFile.cmake
@@ -55,7 +55,7 @@
     configure_file(${CMAKE_ROOT}/Modules/CheckIncludeFile.c.in
       ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFile.c)
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Looking for ${INCLUDE}")
+      message(CHECK_START "Looking for ${INCLUDE}")
     endif()
     if(${ARGC} EQUAL 3)
       set(CMAKE_C_FLAGS_SAVE ${CMAKE_C_FLAGS})
@@ -109,7 +109,7 @@
 
     if(${VARIABLE})
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Looking for ${INCLUDE} - found")
+        message(CHECK_PASS "found")
       endif()
       set(${VARIABLE} 1 CACHE INTERNAL "Have include ${INCLUDE}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
@@ -118,7 +118,7 @@
         "${OUTPUT}\n\n")
     else()
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Looking for ${INCLUDE} - not found")
+        message(CHECK_FAIL "not found")
       endif()
       set(${VARIABLE} "" CACHE INTERNAL "Have include ${INCLUDE}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
diff --git a/Modules/CheckIncludeFileCXX.cmake b/Modules/CheckIncludeFileCXX.cmake
index de5a83b..496550f 100644
--- a/Modules/CheckIncludeFileCXX.cmake
+++ b/Modules/CheckIncludeFileCXX.cmake
@@ -54,7 +54,7 @@
     configure_file(${CMAKE_ROOT}/Modules/CheckIncludeFile.cxx.in
       ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFile.cxx)
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Looking for C++ include ${INCLUDE}")
+      message(CHECK_START "Looking for C++ include ${INCLUDE}")
     endif()
     if(${ARGC} EQUAL 3)
       set(CMAKE_CXX_FLAGS_SAVE ${CMAKE_CXX_FLAGS})
@@ -108,7 +108,7 @@
 
     if(${VARIABLE})
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Looking for C++ include ${INCLUDE} - found")
+        message(CHECK_PASS "found")
       endif()
       set(${VARIABLE} 1 CACHE INTERNAL "Have include ${INCLUDE}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
@@ -117,7 +117,7 @@
         "${OUTPUT}\n\n")
     else()
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Looking for C++ include ${INCLUDE} - not found")
+        message(CHECK_FAIL "not found")
       endif()
       set(${VARIABLE} "" CACHE INTERNAL "Have include ${INCLUDE}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
diff --git a/Modules/CheckIncludeFiles.cmake b/Modules/CheckIncludeFiles.cmake
index f52ab55..8e10cd6 100644
--- a/Modules/CheckIncludeFiles.cmake
+++ b/Modules/CheckIncludeFiles.cmake
@@ -131,7 +131,7 @@
     endif()
 
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Looking for ${_description}")
+      message(CHECK_START "Looking for ${_description}")
     endif()
     try_compile(${VARIABLE}
       ${CMAKE_BINARY_DIR}
@@ -147,7 +147,7 @@
     unset(_CIF_LINK_LIBRARIES)
     if(${VARIABLE})
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Looking for ${_description} - found")
+        message(CHECK_PASS "found")
       endif()
       set(${VARIABLE} 1 CACHE INTERNAL "Have include ${INCLUDE}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
@@ -156,7 +156,7 @@
         "${OUTPUT}\n\n")
     else()
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Looking for ${_description} - not found")
+        message(CHECK_FAIL "not found")
       endif()
       set(${VARIABLE} "" CACHE INTERNAL "Have includes ${INCLUDE}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
diff --git a/Modules/CheckLanguage.cmake b/Modules/CheckLanguage.cmake
index a1a3a7a..997cc8d 100644
--- a/Modules/CheckLanguage.cmake
+++ b/Modules/CheckLanguage.cmake
@@ -39,7 +39,7 @@
 macro(check_language lang)
   if(NOT DEFINED CMAKE_${lang}_COMPILER)
     set(_desc "Looking for a ${lang} compiler")
-    message(STATUS ${_desc})
+    message(CHECK_START "${_desc}")
     file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang})
 
     set(extra_compiler_variables)
@@ -63,12 +63,18 @@
     else()
       set(_D_CMAKE_GENERATOR_INSTANCE "")
     endif()
+    if(CMAKE_GENERATOR MATCHES "^(Xcode$|Green Hills MULTI$|Visual Studio)")
+      set(_D_CMAKE_MAKE_PROGRAM "")
+    else()
+      set(_D_CMAKE_MAKE_PROGRAM "-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}")
+    endif()
     execute_process(
       WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}
       COMMAND ${CMAKE_COMMAND} . -G ${CMAKE_GENERATOR}
                                  -A "${CMAKE_GENERATOR_PLATFORM}"
                                  -T "${CMAKE_GENERATOR_TOOLSET}"
                                  ${_D_CMAKE_GENERATOR_INSTANCE}
+                                 ${_D_CMAKE_MAKE_PROGRAM}
       OUTPUT_VARIABLE output
       ERROR_VARIABLE output
       RESULT_VARIABLE result
@@ -78,13 +84,15 @@
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "${_desc} passed with the following output:\n"
         "${output}\n")
+      set(_CHECK_COMPILER_STATUS CHECK_PASS)
     else()
       set(CMAKE_${lang}_COMPILER NOTFOUND)
+      set(_CHECK_COMPILER_STATUS CHECK_FAIL)
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "${_desc} failed with the following output:\n"
         "${output}\n")
     endif()
-    message(STATUS "${_desc} - ${CMAKE_${lang}_COMPILER}")
+    message(${_CHECK_COMPILER_STATUS} "${CMAKE_${lang}_COMPILER}")
     set(CMAKE_${lang}_COMPILER "${CMAKE_${lang}_COMPILER}" CACHE FILEPATH "${lang} compiler")
     mark_as_advanced(CMAKE_${lang}_COMPILER)
 
diff --git a/Modules/CheckLibraryExists.cmake b/Modules/CheckLibraryExists.cmake
index 6504df5..6470dfd 100644
--- a/Modules/CheckLibraryExists.cmake
+++ b/Modules/CheckLibraryExists.cmake
@@ -42,7 +42,7 @@
     set(MACRO_CHECK_LIBRARY_EXISTS_DEFINITION
       "-DCHECK_FUNCTION_EXISTS=${FUNCTION} ${CMAKE_REQUIRED_FLAGS}")
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Looking for ${FUNCTION} in ${LIBRARY}")
+      message(CHECK_START "Looking for ${FUNCTION} in ${LIBRARY}")
     endif()
     set(CHECK_LIBRARY_EXISTS_LINK_OPTIONS)
     if(CMAKE_REQUIRED_LINK_OPTIONS)
@@ -78,7 +78,7 @@
 
     if(${VARIABLE})
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Looking for ${FUNCTION} in ${LIBRARY} - found")
+        message(CHECK_PASS "found")
       endif()
       set(${VARIABLE} 1 CACHE INTERNAL "Have library ${LIBRARY}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
@@ -87,7 +87,7 @@
         "${OUTPUT}\n\n")
     else()
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Looking for ${FUNCTION} in ${LIBRARY} - not found")
+        message(CHECK_FAIL "not found")
       endif()
       set(${VARIABLE} "" CACHE INTERNAL "Have library ${LIBRARY}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
diff --git a/Modules/CheckOBJCSourceCompiles.cmake b/Modules/CheckOBJCSourceCompiles.cmake
index a4676ad..601f1fa 100644
--- a/Modules/CheckOBJCSourceCompiles.cmake
+++ b/Modules/CheckOBJCSourceCompiles.cmake
@@ -104,7 +104,7 @@
       "${SOURCE}\n")
 
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Performing Test ${VAR}")
+      message(CHECK_START "Performing Test ${VAR}")
     endif()
     try_compile(${VAR}
       ${CMAKE_BINARY_DIR}
@@ -125,7 +125,7 @@
     if(${VAR})
       set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Success")
+        message(CHECK_PASS "Success")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Performing Objective-C SOURCE FILE Test ${VAR} succeeded with the following output:\n"
@@ -133,7 +133,7 @@
         "Source file was:\n${SOURCE}\n")
     else()
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Failed")
+        message(CHECK_FAIL "Failed")
       endif()
       set(${VAR} "" CACHE INTERNAL "Test ${VAR}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
diff --git a/Modules/CheckOBJCSourceRuns.cmake b/Modules/CheckOBJCSourceRuns.cmake
index 00a1ebd..6684693 100644
--- a/Modules/CheckOBJCSourceRuns.cmake
+++ b/Modules/CheckOBJCSourceRuns.cmake
@@ -92,7 +92,7 @@
       "${SOURCE}\n")
 
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Performing Test ${VAR}")
+      message(CHECK_START "Performing Test ${VAR}")
     endif()
     try_run(${VAR}_EXITCODE ${VAR}_COMPILED
       ${CMAKE_BINARY_DIR}
@@ -113,7 +113,7 @@
     if("${${VAR}_EXITCODE}" EQUAL 0)
       set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Success")
+        message(CHECK_PASS "Success")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Performing Objective-C SOURCE FILE Test ${VAR} succeeded with the following compile output:\n"
@@ -130,7 +130,7 @@
       endif()
 
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Failed")
+        message(CHECK_FAIL "Failed")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Performing Objective-C SOURCE FILE Test ${VAR} failed with the following compile output:\n"
diff --git a/Modules/CheckOBJCXXSourceCompiles.cmake b/Modules/CheckOBJCXXSourceCompiles.cmake
index 4c0fdd0..2ee79f4 100644
--- a/Modules/CheckOBJCXXSourceCompiles.cmake
+++ b/Modules/CheckOBJCXXSourceCompiles.cmake
@@ -105,7 +105,7 @@
       "${SOURCE}\n")
 
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Performing Test ${VAR}")
+      message(CHECK_START "Performing Test ${VAR}")
     endif()
     try_compile(${VAR}
       ${CMAKE_BINARY_DIR}
@@ -126,7 +126,7 @@
     if(${VAR})
       set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Success")
+        message(CHECK_PASS "Success")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Performing Objective-C++ SOURCE FILE Test ${VAR} succeeded with the following output:\n"
@@ -134,7 +134,7 @@
         "Source file was:\n${SOURCE}\n")
     else()
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Failed")
+        message(CHECK_FAIL "Failed")
       endif()
       set(${VAR} "" CACHE INTERNAL "Test ${VAR}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
diff --git a/Modules/CheckOBJCXXSourceRuns.cmake b/Modules/CheckOBJCXXSourceRuns.cmake
index a3d5923..7f7e04f 100644
--- a/Modules/CheckOBJCXXSourceRuns.cmake
+++ b/Modules/CheckOBJCXXSourceRuns.cmake
@@ -92,7 +92,7 @@
       "${SOURCE}\n")
 
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Performing Test ${VAR}")
+      message(CHECK_START "Performing Test ${VAR}")
     endif()
     try_run(${VAR}_EXITCODE ${VAR}_COMPILED
       ${CMAKE_BINARY_DIR}
@@ -114,7 +114,7 @@
     if("${${VAR}_EXITCODE}" EQUAL 0)
       set(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Success")
+        message(CHECK_PASS "Success")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Performing Objective-C++ SOURCE FILE Test ${VAR} succeeded with the following output:\n"
@@ -131,7 +131,7 @@
       endif()
 
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Performing Test ${VAR} - Failed")
+        message(CHECK_FAIL "Failed")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Performing Objective-C++ SOURCE FILE Test ${VAR} failed with the following output:\n"
diff --git a/Modules/CheckPrototypeDefinition.cmake b/Modules/CheckPrototypeDefinition.cmake
index a7b020c..8b06403 100644
--- a/Modules/CheckPrototypeDefinition.cmake
+++ b/Modules/CheckPrototypeDefinition.cmake
@@ -54,6 +54,9 @@
 function(check_prototype_definition _FUNCTION _PROTOTYPE _RETURN _HEADER _VARIABLE)
 
   if (NOT DEFINED ${_VARIABLE})
+    if(NOT CMAKE_REQUIRED_QUIET)
+      message(CHECK_START "Checking prototype ${_FUNCTION} for ${_VARIABLE}")
+    endif()
     set(CHECK_PROTOTYPE_DEFINITION_CONTENT "/* */\n")
 
     set(CHECK_PROTOTYPE_DEFINITION_FLAGS ${CMAKE_REQUIRED_FLAGS})
@@ -103,14 +106,14 @@
     if (${_VARIABLE})
       set(${_VARIABLE} 1 CACHE INTERNAL "Have correct prototype for ${_FUNCTION}")
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Checking prototype ${_FUNCTION} for ${_VARIABLE} - True")
+        message(CHECK_PASS "True")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Determining if the prototype ${_FUNCTION} exists for ${_VARIABLE} passed with the following output:\n"
         "${OUTPUT}\n\n")
     else ()
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Checking prototype ${_FUNCTION} for ${_VARIABLE} - False")
+        message(CHECK_FAIL "False")
       endif()
       set(${_VARIABLE} 0 CACHE INTERNAL "Have correct prototype for ${_FUNCTION}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
diff --git a/Modules/CheckSymbolExists.cmake b/Modules/CheckSymbolExists.cmake
index 1053383..4f202c4 100644
--- a/Modules/CheckSymbolExists.cmake
+++ b/Modules/CheckSymbolExists.cmake
@@ -126,7 +126,7 @@
       "${SOURCEFILE}" @ONLY)
 
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Looking for ${SYMBOL}")
+      message(CHECK_START "Looking for ${SYMBOL}")
     endif()
     try_compile(${VARIABLE}
       ${CMAKE_BINARY_DIR}
@@ -140,7 +140,7 @@
       OUTPUT_VARIABLE OUTPUT)
     if(${VARIABLE})
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Looking for ${SYMBOL} - found")
+        message(CHECK_PASS "found")
       endif()
       set(${VARIABLE} 1 CACHE INTERNAL "Have symbol ${SYMBOL}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
@@ -150,7 +150,7 @@
         "${CMAKE_CONFIGURABLE_FILE_CONTENT}\n")
     else()
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Looking for ${SYMBOL} - not found")
+        message(CHECK_FAIL "not found")
       endif()
       set(${VARIABLE} "" CACHE INTERNAL "Have symbol ${SYMBOL}")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
diff --git a/Modules/CheckTypeSize.cmake b/Modules/CheckTypeSize.cmake
index 3727373..2b07b7c 100644
--- a/Modules/CheckTypeSize.cmake
+++ b/Modules/CheckTypeSize.cmake
@@ -86,7 +86,7 @@
 # Helper function.  DO NOT CALL DIRECTLY.
 function(__check_type_size_impl type var map builtin language)
   if(NOT CMAKE_REQUIRED_QUIET)
-    message(STATUS "Check size of ${type}")
+    message(CHECK_START "Check size of ${type}")
   endif()
 
   # Include header files.
@@ -173,7 +173,7 @@
     endif()
 
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Check size of ${type} - done")
+      message(CHECK_PASS "done")
     endif()
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
       "Determining size of ${type} passed with the following output:\n${output}\n\n")
@@ -181,7 +181,7 @@
   else()
     # The check failed to compile.
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Check size of ${type} - failed")
+      message(CHECK_FAIL "failed")
     endif()
     file(READ ${src} content)
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
diff --git a/Modules/CheckVariableExists.cmake b/Modules/CheckVariableExists.cmake
index f4953a3..8a93535 100644
--- a/Modules/CheckVariableExists.cmake
+++ b/Modules/CheckVariableExists.cmake
@@ -42,7 +42,7 @@
     set(MACRO_CHECK_VARIABLE_DEFINITIONS
       "-DCHECK_VARIABLE_EXISTS=${VAR} ${CMAKE_REQUIRED_FLAGS}")
     if(NOT CMAKE_REQUIRED_QUIET)
-      message(STATUS "Looking for ${VAR}")
+      message(CHECK_START "Looking for ${VAR}")
     endif()
     if(CMAKE_REQUIRED_LINK_OPTIONS)
       set(CHECK_VARIABLE_EXISTS_ADD_LINK_OPTIONS
@@ -67,7 +67,7 @@
     if(${VARIABLE})
       set(${VARIABLE} 1 CACHE INTERNAL "Have variable ${VAR}")
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Looking for ${VAR} - found")
+        message(CHECK_PASS "found")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Determining if the variable ${VAR} exists passed with the following output:\n"
@@ -75,7 +75,7 @@
     else()
       set(${VARIABLE} "" CACHE INTERNAL "Have variable ${VAR}")
       if(NOT CMAKE_REQUIRED_QUIET)
-        message(STATUS "Looking for ${VAR} - not found")
+        message(CHECK_FAIL "not found")
       endif()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Determining if the variable ${VAR} exists failed with the following output:\n"
diff --git a/Modules/Compiler/AppleClang-CXX.cmake b/Modules/Compiler/AppleClang-CXX.cmake
index 3fa6990..15edc21 100644
--- a/Modules/Compiler/AppleClang-CXX.cmake
+++ b/Modules/Compiler/AppleClang-CXX.cmake
@@ -25,7 +25,10 @@
   set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
 endif()
 
-if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.1)
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0)
+  set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std=c++17")
+  set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++17")
+elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.1)
   set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std=c++1z")
   set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++1z")
 endif()
diff --git a/Modules/Compiler/AppleClang-OBJCXX.cmake b/Modules/Compiler/AppleClang-OBJCXX.cmake
index 2c084af..409bd4a 100644
--- a/Modules/Compiler/AppleClang-OBJCXX.cmake
+++ b/Modules/Compiler/AppleClang-OBJCXX.cmake
@@ -22,7 +22,10 @@
   set(CMAKE_OBJCXX14_STANDARD__HAS_FULL_SUPPORT ON)
 endif()
 
-if (NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 6.1)
+if (NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 10.0)
+  set(CMAKE_OBJCXX17_STANDARD_COMPILE_OPTION "-std=c++17")
+  set(CMAKE_OBJCXX17_EXTENSION_COMPILE_OPTION "-std=gnu++17")
+elseif (NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 6.1)
   set(CMAKE_OBJCXX17_STANDARD_COMPILE_OPTION "-std=c++1z")
   set(CMAKE_OBJCXX17_EXTENSION_COMPILE_OPTION "-std=gnu++1z")
 endif()
diff --git a/Modules/Compiler/CMakeCommonCompilerMacros.cmake b/Modules/Compiler/CMakeCommonCompilerMacros.cmake
index 96537f8..409b65a 100644
--- a/Modules/Compiler/CMakeCommonCompilerMacros.cmake
+++ b/Modules/Compiler/CMakeCommonCompilerMacros.cmake
@@ -134,3 +134,47 @@
     unset(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT)
   endif()
 endmacro()
+
+macro(cmake_record_cuda_compile_features)
+  set(_result 0)
+  if(_result EQUAL 0 AND DEFINED CMAKE_CUDA20_STANDARD_COMPILE_OPTION)
+    if(CMAKE_CUDA20_STANDARD__HAS_FULL_SUPPORT)
+      _has_compiler_features_cuda(20)
+    else()
+      _record_compiler_features_cuda(20)
+    endif()
+    unset(CMAKE_CUDA20_STANDARD__HAS_FULL_SUPPORT)
+  endif()
+  if(_result EQUAL 0 AND DEFINED CMAKE_CUDA17_STANDARD_COMPILE_OPTION)
+    if(CMAKE_CUDA17_STANDARD__HAS_FULL_SUPPORT)
+      _has_compiler_features_cuda(17)
+    else()
+      _record_compiler_features_cuda(17)
+    endif()
+    unset(CMAKE_CUDA17_STANDARD__HAS_FULL_SUPPORT)
+  endif()
+  if(_result EQUAL 0 AND DEFINED CMAKE_CUDA14_STANDARD_COMPILE_OPTION)
+    if(CMAKE_CUDA14_STANDARD__HAS_FULL_SUPPORT)
+      _has_compiler_features_cuda(14)
+    else()
+      _record_compiler_features_cuda(14)
+    endif()
+    unset(CMAKE_CUDA14_STANDARD__HAS_FULL_SUPPORT)
+  endif()
+  if(_result EQUAL 0 AND DEFINED CMAKE_CUDA11_STANDARD_COMPILE_OPTION)
+    if(CMAKE_CUDA11_STANDARD__HAS_FULL_SUPPORT)
+      _has_compiler_features_cuda(11)
+    else()
+      _record_compiler_features_cuda(11)
+    endif()
+    unset(CMAKE_CUDA11_STANDARD__HAS_FULL_SUPPORT)
+  endif()
+  if(_result EQUAL 0 AND DEFINED CMAKE_CUDA03_STANDARD_COMPILE_OPTION)
+    if(CMAKE_CUDA03_STANDARD__HAS_FULL_SUPPORT)
+      _has_compiler_features_cuda(03)
+    else()
+      _record_compiler_features_cuda(03)
+    endif()
+    unset(CMAKE_CUDA03_STANDARD__HAS_FULL_SUPPORT)
+  endif()
+endmacro()
diff --git a/Modules/Compiler/Clang-C.cmake b/Modules/Compiler/Clang-C.cmake
index 0448965..7c4a263 100644
--- a/Modules/Compiler/Clang-C.cmake
+++ b/Modules/Compiler/Clang-C.cmake
@@ -6,6 +6,10 @@
   return()
 endif()
 
+if("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+  set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
+endif()
+
 if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
   if(NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
     set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
diff --git a/Modules/Compiler/Clang-CXX.cmake b/Modules/Compiler/Clang-CXX.cmake
index 61709f8..cb240f9 100644
--- a/Modules/Compiler/Clang-CXX.cmake
+++ b/Modules/Compiler/Clang-CXX.cmake
@@ -10,6 +10,9 @@
   return()
 endif()
 
+if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
+  set(CMAKE_CXX_CLANG_TIDY_DRIVER_MODE "cl")
+endif()
 
 if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
   if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 2.1)
diff --git a/Modules/Compiler/Clang.cmake b/Modules/Compiler/Clang.cmake
index 5cc9328..f65916f 100644
--- a/Modules/Compiler/Clang.cmake
+++ b/Modules/Compiler/Clang.cmake
@@ -101,7 +101,7 @@
     if (NOT CMAKE_GENERATOR MATCHES "Xcode")
       set(CMAKE_PCH_PROLOGUE "#pragma clang system_header")
     endif()
-    set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang <PCH_FILE>)
+    set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang <PCH_FILE> -Xclang -include -Xclang <PCH_HEADER>)
     set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Xclang -emit-pch -Xclang -include -Xclang <PCH_HEADER>)
   endmacro()
 endif()
diff --git a/Modules/Compiler/Intel-C.cmake b/Modules/Compiler/Intel-C.cmake
index e9e59a2..ec3bfd8 100644
--- a/Modules/Compiler/Intel-C.cmake
+++ b/Modules/Compiler/Intel-C.cmake
@@ -9,6 +9,8 @@
 
 if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
 
+  set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
+
   if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 16.0.0)
     set(CMAKE_C11_STANDARD_COMPILE_OPTION "-Qstd=c11")
     set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-Qstd=c11")
diff --git a/Modules/Compiler/Intel-CXX.cmake b/Modules/Compiler/Intel-CXX.cmake
index b630a6b..1ed1b08 100644
--- a/Modules/Compiler/Intel-CXX.cmake
+++ b/Modules/Compiler/Intel-CXX.cmake
@@ -9,6 +9,8 @@
 
 if("x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
 
+  set(CMAKE_CXX_CLANG_TIDY_DRIVER_MODE "cl")
+
   if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0.0)
     set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-Qstd=c++17")
     set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-Qstd=c++17")
diff --git a/Modules/Compiler/MSVC-C.cmake b/Modules/Compiler/MSVC-C.cmake
index 20787a3..bca9764 100644
--- a/Modules/Compiler/MSVC-C.cmake
+++ b/Modules/Compiler/MSVC-C.cmake
@@ -11,6 +11,8 @@
 # There is no meaningful default for this
 set(CMAKE_C_STANDARD_DEFAULT "")
 
+set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
+
 # There are no C compiler modes so we hard-code the known compiler supported
 # features. Override the default macro for this special case.  Pretend that
 # all language standards are available so that at least compilation
diff --git a/Modules/Compiler/MSVC-CXX.cmake b/Modules/Compiler/MSVC-CXX.cmake
index 915295d..1dfc760 100644
--- a/Modules/Compiler/MSVC-CXX.cmake
+++ b/Modules/Compiler/MSVC-CXX.cmake
@@ -3,6 +3,8 @@
 
 include(Compiler/CMakeCommonCompilerMacros)
 
+set(CMAKE_CXX_CLANG_TIDY_DRIVER_MODE "cl")
+
 if ((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.0.24215.1 AND
      CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) OR
    CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.10.25017)
diff --git a/Modules/Compiler/NAG-Fortran.cmake b/Modules/Compiler/NAG-Fortran.cmake
index edc56fd..2111c65 100644
--- a/Modules/Compiler/NAG-Fortran.cmake
+++ b/Modules/Compiler/NAG-Fortran.cmake
@@ -1,6 +1,6 @@
 # Help CMAKE_PARSE_IMPLICIT_LINK_INFO detect NAG Fortran object files.
 if(NOT CMAKE_Fortran_COMPILER_WORKS AND NOT CMAKE_Fortran_COMPILER_FORCED)
-  message(STATUS "Detecting NAG Fortran directory")
+  message(CHECK_START "Detecting NAG Fortran directory")
   # Run with -dryrun to see sample "link" line.
   execute_process(
     COMMAND ${CMAKE_Fortran_COMPILER} dummy.o -dryrun
@@ -20,11 +20,11 @@
       "  directory: ${_nag_dir}\n"
       "  regex: ${CMAKE_Fortran_IMPLICIT_OBJECT_REGEX}\n"
       "from output:\n${_dryrun}\n\n")
-    message(STATUS "Detecting NAG Fortran directory - ${_nag_dir}")
+    message(CHECK_PASS "${_nag_dir}")
   else()
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
       "Detecting NAG Fortran directory with -dryrun failed:\n${_dryrun}\n\n")
-    message(STATUS "Detecting NAG Fortran directory - failed")
+    message(CHECK_FAIL "failed")
   endif()
 endif()
 
diff --git a/Modules/Compiler/NVIDIA-CUDA.cmake b/Modules/Compiler/NVIDIA-CUDA.cmake
index ae40100..1f4d54d 100644
--- a/Modules/Compiler/NVIDIA-CUDA.cmake
+++ b/Modules/Compiler/NVIDIA-CUDA.cmake
@@ -1,7 +1,32 @@
+include(Compiler/CMakeCommonCompilerMacros)
+
 set(CMAKE_CUDA_COMPILER_HAS_DEVICE_LINK_PHASE True)
 set(CMAKE_CUDA_VERBOSE_FLAG "-v")
 set(CMAKE_CUDA_VERBOSE_COMPILE_FLAG "-Xcompiler=-v")
 
+if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 10.2.89)
+  # The -forward-unknown-to-host-compiler flag was only
+  # added to nvcc in 10.2 so before that we had no good
+  # way to invoke the CUDA compiler and propagate unknown
+  # flags such as -pthread to the host compiler
+  set(_CMAKE_CUDA_EXTRA_FLAGS "-forward-unknown-to-host-compiler")
+else()
+  set(_CMAKE_CUDA_EXTRA_FLAGS "")
+endif()
+
+if(CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "8.0.0")
+  set(_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS "-Wno-deprecated-gpu-targets")
+else()
+  set(_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS "")
+endif()
+
+if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 10.2.89)
+  # The -MD flag was only added to nvcc in 10.2 so
+  # before that we had to invoke the compiler twice
+  # to get header dependency information
+  set(CMAKE_DEPFILE_FLAGS_CUDA "-MD -MT <OBJECT> -MF <DEPFILE>")
+endif()
+
 if(NOT "x${CMAKE_CUDA_SIMULATE_ID}" STREQUAL "xMSVC")
   set(CMAKE_CUDA_COMPILE_OPTIONS_PIE -Xcompiler=-fPIE)
   set(CMAKE_CUDA_COMPILE_OPTIONS_PIC -Xcompiler=-fPIC)
@@ -18,18 +43,32 @@
 set(CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS -shared)
 set(CMAKE_INCLUDE_SYSTEM_FLAG_CUDA -isystem=)
 
+set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "STATIC")
+set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_STATIC  "cudadevrt;cudart_static")
+set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_SHARED  "cudadevrt;cudart")
+set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_NONE    "")
+
 if("x${CMAKE_CUDA_SIMULATE_ID}" STREQUAL "xMSVC")
-  set(CMAKE_CUDA_STANDARD_DEFAULT "")
+  set(CMAKE_CUDA03_STANDARD_COMPILE_OPTION "")
+  set(CMAKE_CUDA03_EXTENSION_COMPILE_OPTION "")
+
+  set(CMAKE_CUDA11_STANDARD_COMPILE_OPTION "")
+  set(CMAKE_CUDA11_EXTENSION_COMPILE_OPTION "")
+
+  if (NOT CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 9.0)
+    set(CMAKE_CUDA14_STANDARD_COMPILE_OPTION "")
+    set(CMAKE_CUDA14_EXTENSION_COMPILE_OPTION "")
+  endif()
 else()
-  set(CMAKE_CUDA_STANDARD_DEFAULT 98)
-  set(CMAKE_CUDA98_STANDARD_COMPILE_OPTION "")
-  set(CMAKE_CUDA98_EXTENSION_COMPILE_OPTION "")
+  set(CMAKE_CUDA03_STANDARD_COMPILE_OPTION "")
+  set(CMAKE_CUDA03_EXTENSION_COMPILE_OPTION "")
+
   set(CMAKE_CUDA11_STANDARD_COMPILE_OPTION "-std=c++11")
   set(CMAKE_CUDA11_EXTENSION_COMPILE_OPTION "-std=c++11")
 
   if (NOT CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 9.0)
-    set(CMAKE_CUDA98_STANDARD_COMPILE_OPTION "-std=c++03")
-    set(CMAKE_CUDA98_EXTENSION_COMPILE_OPTION "-std=c++03")
+    set(CMAKE_CUDA03_STANDARD_COMPILE_OPTION "-std=c++03")
+    set(CMAKE_CUDA03_EXTENSION_COMPILE_OPTION "-std=c++03")
     set(CMAKE_CUDA14_STANDARD_COMPILE_OPTION "-std=c++14")
     set(CMAKE_CUDA14_EXTENSION_COMPILE_OPTION "-std=c++14")
   endif()
@@ -46,3 +85,5 @@
   set(CMAKE_CUDA_RESPONSE_FILE_DEVICE_LINK_FLAG "--options-file ")
   set(CMAKE_CUDA_RESPONSE_FILE_FLAG "--options-file ")
 endif()
+
+__compiler_check_default_language_standard(CUDA 6.0 03)
diff --git a/Modules/Compiler/QCC.cmake b/Modules/Compiler/QCC.cmake
index 9df8269..10e1389 100644
--- a/Modules/Compiler/QCC.cmake
+++ b/Modules/Compiler/QCC.cmake
@@ -10,6 +10,9 @@
   # http://www.qnx.com/developers/docs/6.4.0/neutrino/utilities/q/qcc.html#examples
   set(CMAKE_${lang}_COMPILE_OPTIONS_TARGET "-V")
 
+  set(CMAKE_PREFIX_LIBRARY_ARCHITECTURE "ON")
+
+  set(CMAKE_${lang}_COMPILE_OPTIONS_SYSROOT "-Wc,-isysroot,")
   set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-Wp,-isystem,")
   set(CMAKE_DEPFILE_FLAGS_${lang} "-Wp,-MD,<DEPFILE> -Wp,-MT,<OBJECT> -Wp,-MF,<DEPFILE>")
 
diff --git a/Modules/Compiler/XL-Fortran.cmake b/Modules/Compiler/XL-Fortran.cmake
index c4fb097..1683dff 100644
--- a/Modules/Compiler/XL-Fortran.cmake
+++ b/Modules/Compiler/XL-Fortran.cmake
@@ -18,3 +18,7 @@
 # xlf: 1501-214 (W) command option E reserved for future use - ignored
 set(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE)
 set(CMAKE_Fortran_CREATE_ASSEMBLY_SOURCE)
+
+set(CMAKE_Fortran_PREPROCESS_SOURCE
+  "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -qpreprocess -qnoobject -qsuppress=1517-020 -tF -B \"${CMAKE_CURRENT_LIST_DIR}/XL-Fortran/\" -WF,--cpp,\"${CMAKE_Fortran_XL_CPP}\",--out,<PREPROCESSED_SOURCE> <SOURCE>"
+  )
diff --git a/Modules/Compiler/XL-Fortran/cpp b/Modules/Compiler/XL-Fortran/cpp
new file mode 100755
index 0000000..1fd62c2
--- /dev/null
+++ b/Modules/Compiler/XL-Fortran/cpp
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+# Source file.
+src="$(printf %q "$1")"
+shift
+
+# Output file the compiler expects.
+out="$(printf %q "$1")"
+shift
+
+# Create the file the compiler expects.  It will check syntax.
+>"$out"
+
+cpp='cpp'
+opts=''
+while test "$#" != 0; do
+    case "$1" in
+    # Extract the option for the path to cpp.
+    --cpp) shift; cpp="$(printf %q "$1")" ;;
+    # Extract the option for our own output file.
+    --out) shift; out="$(printf %q "$1")" ;;
+    # Collect the rest of the command line.
+    *) opts="$opts $(printf %q "$1")" ;;
+    esac
+    shift
+done
+
+# Execute the real preprocessor tool.
+eval "exec $cpp $src $out $opts"
diff --git a/Modules/CompilerId/VS-10.vcxproj.in b/Modules/CompilerId/VS-10.vcxproj.in
index d742274..b48a332 100644
--- a/Modules/CompilerId/VS-10.vcxproj.in
+++ b/Modules/CompilerId/VS-10.vcxproj.in
@@ -15,6 +15,8 @@
     @id_WindowsTargetPlatformVersion@
     @id_WindowsSDKDesktopARMSupport@
     @id_CudaToolkitCustomDir@
+    @id_ToolsetVCTargetsDir@
+    @id_CustomGlobals@
   </PropertyGroup>
   @id_toolset_version_props@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
diff --git a/Modules/DartConfiguration.tcl.in b/Modules/DartConfiguration.tcl.in
index e4513b3..086ba07 100644
--- a/Modules/DartConfiguration.tcl.in
+++ b/Modules/DartConfiguration.tcl.in
@@ -69,6 +69,8 @@
 PurifyCommand: @PURIFYCOMMAND@
 ValgrindCommand: @VALGRIND_COMMAND@
 ValgrindCommandOptions: @VALGRIND_COMMAND_OPTIONS@
+DrMemoryCommand: @DRMEMORY_COMMAND@
+DrMemoryCommandOptions: @DRMEMORY_COMMAND_OPTIONS@
 MemoryCheckType: @MEMORYCHECK_TYPE@
 MemoryCheckSanitizerOptions: @MEMORYCHECK_SANITIZER_OPTIONS@
 MemoryCheckCommand: @MEMORYCHECK_COMMAND@
diff --git a/Modules/DeployQt4.cmake b/Modules/DeployQt4.cmake
index 4a18927..9aa4383 100644
--- a/Modules/DeployQt4.cmake
+++ b/Modules/DeployQt4.cmake
@@ -106,7 +106,6 @@
 # The functions defined in this file depend on the fixup_bundle function
 # (and others) found in BundleUtilities.cmake
 
-set(DeployQt4_cmake_dir "${CMAKE_CURRENT_LIST_DIR}")
 set(DeployQt4_apple_plugins_dir "PlugIns")
 
 function(write_qt4_conf qt_conf_dir qt_conf_contents)
@@ -392,7 +391,7 @@
   resolve_qt4_paths(libs "")
 
   install(CODE
-"include(\"${DeployQt4_cmake_dir}/DeployQt4.cmake\")
+"include(\"${CMAKE_CURRENT_FUNCTION_LIST_DIR}/DeployQt4.cmake\")
 set(BU_CHMOD_BUNDLE_ITEMS TRUE)
 FIXUP_QT4_EXECUTABLE(\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${executable}\" \"\" \"${libs}\" \"${dirs}\" \"${plugins_dir}\" \"${request_qt_conf}\")"
           ${component}
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake
index 66061a1..5bac0d8 100644
--- a/Modules/ExternalProject.cmake
+++ b/Modules/ExternalProject.cmake
@@ -265,6 +265,11 @@
         is set to ``NEW`` if this value is set to an empty string then no submodules
         are initialized or updated.
 
+      ``GIT_SUBMODULES_RECURSE <bool>``
+        Specify whether git submodules (if any) should update recursively by
+        passing the ``--recursive`` flag to ``git submodule update``.
+        If not specified, the default is on.
+
       ``GIT_SHALLOW <bool>``
         When this option is enabled, the ``git clone`` operation will be given
         the ``--depth 1`` option. This performs a shallow clone, which avoids
@@ -1065,7 +1070,7 @@
   "ExternalProject module."
   )
 
-function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git_repository git_tag git_remote_name init_submodules git_submodules git_shallow git_progress git_config src_name work_dir gitclone_infofile gitclone_stampfile tls_verify)
+function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git_repository git_tag git_remote_name init_submodules git_submodules_recurse git_submodules git_shallow git_progress git_config src_name work_dir gitclone_infofile gitclone_stampfile tls_verify)
   if(NOT GIT_VERSION_STRING VERSION_LESS 1.8.5)
     # Use `git checkout <tree-ish> --` to avoid ambiguity with a local path.
     set(git_checkout_explicit-- "--")
@@ -1091,7 +1096,7 @@
     list(APPEND git_clone_options --progress)
   endif()
   foreach(config IN LISTS git_config)
-    list(APPEND git_clone_options --config ${config})
+    list(APPEND git_clone_options --config \"${config}\")
   endforeach()
   if(NOT ${git_remote_name} STREQUAL "origin")
     list(APPEND git_clone_options --origin \"${git_remote_name}\")
@@ -1115,7 +1120,7 @@
 endif()
 
 execute_process(
-  COMMAND \${CMAKE_COMMAND} -E remove_directory \"${source_dir}\"
+  COMMAND \${CMAKE_COMMAND} -E rm -rf \"${source_dir}\"
   RESULT_VARIABLE error_code
   )
 if(error_code)
@@ -1153,7 +1158,7 @@
 set(init_submodules ${init_submodules})
 if(init_submodules)
   execute_process(
-    COMMAND \"${git_EXECUTABLE}\" ${git_options} submodule update --recursive --init ${git_submodules}
+    COMMAND \"${git_EXECUTABLE}\" ${git_options} submodule update ${git_submodules_recurse} --init ${git_submodules}
     WORKING_DIRECTORY \"${work_dir}/${src_name}\"
     RESULT_VARIABLE error_code
     )
@@ -1191,7 +1196,7 @@
 endif()
 
 execute_process(
-  COMMAND \${CMAKE_COMMAND} -E remove_directory \"${source_dir}\"
+  COMMAND \${CMAKE_COMMAND} -E rm -rf \"${source_dir}\"
   RESULT_VARIABLE error_code
   )
 if(error_code)
@@ -1234,7 +1239,7 @@
 endfunction()
 
 
-function(_ep_write_gitupdate_script script_filename git_EXECUTABLE git_tag git_remote_name init_submodules git_submodules git_repository work_dir)
+function(_ep_write_gitupdate_script script_filename git_EXECUTABLE git_tag git_remote_name init_submodules git_submodules_recurse git_submodules git_repository work_dir)
   if("${git_tag}" STREQUAL "")
     message(FATAL_ERROR "Tag for git checkout should not be empty.")
   endif()
@@ -1394,7 +1399,7 @@
   set(init_submodules ${init_submodules})
   if(init_submodules)
     execute_process(
-      COMMAND \"${git_EXECUTABLE}\" submodule update --recursive --init ${git_submodules}
+      COMMAND \"${git_EXECUTABLE}\" submodule update ${git_submodules_recurse} --init ${git_submodules}
       WORKING_DIRECTORY \"${work_dir}/${src_name}\"
       RESULT_VARIABLE error_code
       )
@@ -1772,6 +1777,11 @@
   # Replace location tags.
   _ep_replace_location_tags(${target_name} script_initial_cache)
   _ep_replace_location_tags(${target_name} script_filename)
+  # Replace list separators.
+  get_property(sep TARGET ${target_name} PROPERTY _EP_LIST_SEPARATOR)
+  if(sep AND script_initial_cache)
+    string(REPLACE "${sep}" ";" script_initial_cache "${script_initial_cache}")
+  endif()
   # Write out the initial cache file to the location specified.
   file(GENERATE OUTPUT "${script_filename}" CONTENT "${script_initial_cache}")
 endfunction()
@@ -2329,6 +2339,29 @@
   endif()
 endfunction()
 
+function(_ep_get_git_submodules_recurse git_submodules_recurse)
+  # Checks for GIT_SUBMODULES_RECURSE property
+  # Default is ON, which sets git_submodules_recurse output variable to "--recursive"
+  # Otherwise, the output variable is set to an empty value ""
+  get_property(git_submodules_recurse_set TARGET ${name} PROPERTY _EP_GIT_SUBMODULES_RECURSE SET)
+  if(NOT git_submodules_recurse_set)
+    set(recurseFlag "--recursive")
+  else()
+    get_property(git_submodules_recurse_value TARGET ${name} PROPERTY _EP_GIT_SUBMODULES_RECURSE)
+    if(git_submodules_recurse_value)
+      set(recurseFlag "--recursive")
+    else()
+      set(recurseFlag "")
+    endif()
+  endif()
+  set(${git_submodules_recurse} "${recurseFlag}" PARENT_SCOPE)
+
+  # The git submodule update '--recursive' flag requires git >= v1.6.5
+  if(recurseFlag AND GIT_VERSION_STRING VERSION_LESS 1.6.5)
+    message(FATAL_ERROR "error: git version 1.6.5 or later required for --recursive flag with 'git submodule ...': GIT_VERSION_STRING='${GIT_VERSION_STRING}'")
+  endif()
+endfunction()
+
 
 function(_ep_add_download_command name)
   ExternalProject_Get_Property(${name} source_dir stamp_dir download_dir tmp_dir)
@@ -2421,11 +2454,7 @@
       message(FATAL_ERROR "error: could not find git for clone of ${name}")
     endif()
 
-    # The git submodule update '--recursive' flag requires git >= v1.6.5
-    #
-    if(GIT_VERSION_STRING VERSION_LESS 1.6.5)
-      message(FATAL_ERROR "error: git version 1.6.5 or later required for 'git submodule update --recursive': GIT_VERSION_STRING='${GIT_VERSION_STRING}'")
-    endif()
+    _ep_get_git_submodules_recurse(git_submodules_recurse)
 
     get_property(git_tag TARGET ${name} PROPERTY _EP_GIT_TAG)
     if(NOT git_tag)
@@ -2477,7 +2506,7 @@
     # The script will delete the source directory and then call git clone.
     #
     _ep_write_gitclone_script(${tmp_dir}/${name}-gitclone.cmake ${source_dir}
-      ${GIT_EXECUTABLE} ${git_repository} ${git_tag} ${git_remote_name} ${git_init_submodules} "${git_submodules}" "${git_shallow}" "${git_progress}" "${git_config}" ${src_name} ${work_dir}
+      ${GIT_EXECUTABLE} ${git_repository} ${git_tag} ${git_remote_name} ${git_init_submodules} "${git_submodules_recurse}" "${git_submodules}" "${git_shallow}" "${git_progress}" "${git_config}" ${src_name} ${work_dir}
       ${stamp_dir}/${name}-gitinfo.txt ${stamp_dir}/${name}-gitclone-lastrun.txt "${tls_verify}"
       )
     set(comment "Performing download step (git clone) for '${name}'")
@@ -2563,7 +2592,7 @@
     if(IS_DIRECTORY "${url}")
       get_filename_component(abs_dir "${url}" ABSOLUTE)
       set(comment "Performing download step (DIR copy) for '${name}'")
-      set(cmd   ${CMAKE_COMMAND} -E remove_directory ${source_dir}
+      set(cmd   ${CMAKE_COMMAND} -E rm -rf ${source_dir}
         COMMAND ${CMAKE_COMMAND} -E copy_directory ${abs_dir} ${source_dir})
     else()
       get_property(no_extract TARGET "${name}" PROPERTY _EP_DOWNLOAD_NO_EXTRACT SET)
@@ -2752,8 +2781,10 @@
       endif()
     endif()
 
+    _ep_get_git_submodules_recurse(git_submodules_recurse)
+
     _ep_write_gitupdate_script(${tmp_dir}/${name}-gitupdate.cmake
-      ${GIT_EXECUTABLE} ${git_tag} ${git_remote_name} ${git_init_submodules} "${git_submodules}" ${git_repository} ${work_dir}
+      ${GIT_EXECUTABLE} ${git_tag} ${git_remote_name} ${git_init_submodules} "${git_submodules_recurse}" "${git_submodules}" ${git_repository} ${work_dir}
       )
     set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitupdate.cmake)
     set(always 1)
diff --git a/Modules/FetchContent.cmake b/Modules/FetchContent.cmake
index 5716b01..f3e1b51 100644
--- a/Modules/FetchContent.cmake
+++ b/Modules/FetchContent.cmake
@@ -596,9 +596,6 @@
 
 #]=======================================================================]
 
-
-set(__FetchContent_privateDir "${CMAKE_CURRENT_LIST_DIR}/FetchContent")
-
 #=======================================================================
 # Recording and retrieving content details for later population
 #=======================================================================
@@ -888,7 +885,7 @@
   # anything to be updated, so extra rebuilds of the project won't occur.
   # Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project
   # has this set to something not findable on the PATH.
-  configure_file("${__FetchContent_privateDir}/CMakeLists.cmake.in"
+  configure_file("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/FetchContent/CMakeLists.cmake.in"
                  "${ARG_SUBBUILD_DIR}/CMakeLists.txt")
   execute_process(
     COMMAND ${CMAKE_COMMAND} ${generatorOpts} .
diff --git a/Modules/FindBLAS.cmake b/Modules/FindBLAS.cmake
index d3acafc..9b6d09c 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,29 @@
   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)
+  * ``Intel10_64_dyn`` (intel mkl v10+ 64 bit, single dynamic library)
+  * ``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
@@ -75,7 +77,8 @@
 
 .. note::
 
-  C or CXX must be enabled to use Intel Math Kernel Library (MKL)
+  C, CXX or Fortran must be enabled to detect a BLAS library.
+  C or CXX must be enabled to use Intel Math Kernel Library (MKL).
 
   For example, to use Intel MKL libraries and/or Intel compiler:
 
@@ -87,22 +90,15 @@
 Hints
 ^^^^^
 
-Set ``MKLROOT`` environment variable to a directory that contains an MKL
-installation.
+Set the ``MKLROOT`` environment variable to a directory that contains an MKL
+installation, or add the directory to the dynamic library loader environment
+variable for your platform (``LIB``, ``DYLD_LIBRARY_PATH`` or
+``LD_LIBRARY_PATH``).
 
 #]=======================================================================]
 
-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 +107,16 @@
   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})
+
 if(BLA_PREFER_PKGCONFIG)
   find_package(PkgConfig)
   pkg_check_modules(PKGC_BLAS blas)
@@ -121,7 +127,23 @@
   endif()
 endif()
 
-macro(Check_Fortran_Libraries LIBRARIES _prefix _name _flags _list _thread)
+set(_blas_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+if(BLA_STATIC)
+  if(WIN32)
+    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()
+
+# TODO: move this stuff to a separate module
+
+macro(CHECK_BLAS_LIBRARIES LIBRARIES _prefix _name _flags _list _threadlibs _addlibdir _subdirs)
   # This macro checks for the existence of the combination of fortran libraries
   # given by _list.  If the combination is found, this macro checks (using the
   # Check_Fortran_Function_Exists macro) whether can link against that library
@@ -132,59 +154,51 @@
 
   # 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(_libdir ${ARGN})
+  # _addlibdir is a list of additional search paths. _subdirs is a list of path
+  # suffixes to be used by find_library().
 
   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}")
+  set(_extaddlibdir "${_addlibdir}")
+  if(WIN32)
+    list(APPEND _extaddlibdir ENV LIB)
+  elseif(APPLE)
+    list(APPEND _extaddlibdir ENV DYLD_LIBRARY_PATH)
+  else()
+    list(APPEND _extaddlibdir ENV LD_LIBRARY_PATH)
+  endif()
+  list(APPEND _extaddlibdir "${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}")
 
   foreach(_library ${_list})
-    set(_combined_name ${_combined_name}_${_library})
-    if(NOT "${_thread}" STREQUAL "")
-      set(_combined_name ${_combined_name}_thread)
-    endif()
-    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}
+    if(_library MATCHES "^-Wl,--(start|end)-group$")
+      # Respect linker flags like --start/end-group (required by MKL)
+      set(${LIBRARIES} ${${LIBRARIES}} "${_library}")
+    else()
+      set(_combined_name ${_combined_name}_${_library})
+      if(NOT "${_threadlibs}" STREQUAL "")
+        set(_combined_name ${_combined_name}_threadlibs)
+      endif()
+      if(_libraries_work)
+        find_library(${_prefix}_${_library}_LIBRARY
+          NAMES ${_library}
+          PATHS ${_extaddlibdir}
+          PATH_SUFFIXES ${_subdirs}
         )
-      mark_as_advanced(${_prefix}_${_library}_LIBRARY)
-      set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY})
-      set(_libraries_work ${${_prefix}_${_library}_LIBRARY})
+        #message("DEBUG: find_library(${_library}) got ${${_prefix}_${_library}_LIBRARY}")
+        mark_as_advanced(${_prefix}_${_library}_LIBRARY)
+        set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY})
+        set(_libraries_work ${${_prefix}_${_library}_LIBRARY})
+      endif()
     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 +206,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,91 +222,96 @@
 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
       ""
       ""
       ""
+      ""
+      ""
       )
   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")
+        if(BLA_STATIC)
+          set(BLAS_mkl_START_GROUP "-Wl,--start-group")
+          set(BLAS_mkl_END_GROUP "-Wl,--end-group")
+        else()
+          set(BLAS_mkl_START_GROUP "")
+          set(BLAS_mkl_END_GROUP "")
+        endif()
+        # 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")
-            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(BLA_VENDOR MATCHES "^Intel10_64i?lp$" OR BLA_VENDOR STREQUAL "All")
             # old version
             list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
               "libguide40 mkl_intel_thread${BLAS_mkl_DLL_SUFFIX}")
@@ -299,56 +319,60 @@
             list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
               "libiomp5md mkl_intel_thread${BLAS_mkl_DLL_SUFFIX}")
           endif()
+          if(BLA_VENDOR MATCHES "^Intel10_64i?lp_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_blas95 mkl_${BLAS_mkl_INTFACE} mkl_${BLAS_mkl_THREADING}_thread mkl_core guide")
 
             # 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")
+              "${BLAS_mkl_START_GROUP} mkl_blas95 mkl_${BLAS_mkl_INTFACE} mkl_${BLAS_mkl_THREADING}_thread mkl_core ${BLAS_mkl_END_GROUP} ${BLAS_mkl_OMP}")
+          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")
 
             # 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")
+              "${BLAS_mkl_START_GROUP} mkl_blas95_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_THREADING}_thread mkl_core ${BLAS_mkl_END_GROUP} ${BLAS_mkl_OMP}")
+          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 ()
+              "${BLAS_mkl_START_GROUP} mkl_blas95_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_sequential mkl_core ${BLAS_mkl_END_GROUP}")
+          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(BLA_VENDOR MATCHES "^Intel10_64i?lp$" OR BLA_VENDOR STREQUAL "All")
             # old version
             list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
               "libguide40 mkl_intel_thread${BLAS_mkl_DLL_SUFFIX}")
@@ -356,96 +380,118 @@
             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 "^Intel10_64i?lp_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")
 
             # 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")
+              "${BLAS_mkl_START_GROUP} mkl_${BLAS_mkl_INTFACE} mkl_${BLAS_mkl_THREADING}_thread mkl_core ${BLAS_mkl_END_GROUP} ${BLAS_mkl_OMP}")
+          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")
 
             # 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")
+              "${BLAS_mkl_START_GROUP} mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_THREADING}_thread mkl_core ${BLAS_mkl_END_GROUP} ${BLAS_mkl_OMP}")
+          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 ()
+              "${BLAS_mkl_START_GROUP} mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_sequential mkl_core ${BLAS_mkl_END_GROUP}")
+          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")
-          set(_BLAS_MKLROOT_LIB_DIR "$ENV{MKLROOT}/lib/ia32")
-        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)
-          string(APPEND _BLAS_MKLROOT_LIB_DIR "_win")
-        elseif (APPLE)
-          string(APPEND _BLAS_MKLROOT_LIB_DIR "_mac")
-        else ()
-          string(APPEND _BLAS_MKLROOT_LIB_DIR "_lin")
-        endif ()
-      endif ()
+      if(BLA_VENDOR MATCHES "^Intel10_64_dyn$" OR BLA_VENDOR STREQUAL "All")
+        # mkl >= 10.3 with single dynamic library
+        list(APPEND BLAS_SEARCH_LIBS
+          "mkl_rt")
+      endif()
 
-      foreach (IT ${BLAS_SEARCH_LIBS})
+      # MKL uses a multitude of partially platform-specific subdirectories:
+      if(BLA_VENDOR STREQUAL "Intel10_32")
+        set(BLAS_mkl_ARCH_NAME "ia32")
+      else()
+        set(BLAS_mkl_ARCH_NAME "intel64")
+      endif()
+      if(WIN32)
+        set(BLAS_mkl_OS_NAME "win")
+      elseif(APPLE)
+        set(BLAS_mkl_OS_NAME "mac")
+      else()
+        set(BLAS_mkl_OS_NAME "lin")
+      endif()
+      if(DEFINED ENV{MKLROOT})
+        set(BLAS_mkl_MKLROOT "$ENV{MKLROOT}")
+        # If MKLROOT points to the subdirectory 'mkl', use the parent directory instead
+        # so we can better detect other relevant libraries in 'compiler' or 'tbb':
+        get_filename_component(BLAS_mkl_MKLROOT_LAST_DIR "${BLAS_mkl_MKLROOT}" NAME)
+        if(BLAS_mkl_MKLROOT_LAST_DIR STREQUAL "mkl")
+            get_filename_component(BLAS_mkl_MKLROOT "${BLAS_mkl_MKLROOT}" DIRECTORY)
+        endif()
+      endif()
+      set(BLAS_mkl_LIB_PATH_SUFFIXES
+          "compiler/lib" "compiler/lib/${BLAS_mkl_ARCH_NAME}_${BLAS_mkl_OS_NAME}"
+          "mkl/lib" "mkl/lib/${BLAS_mkl_ARCH_NAME}_${BLAS_mkl_OS_NAME}"
+          "lib/${BLAS_mkl_ARCH_NAME}_${BLAS_mkl_OS_NAME}")
+
+      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}
             ""
             "${SEARCH_LIBS}"
             "${CMAKE_THREAD_LIBS_INIT};${BLAS_mkl_LM};${BLAS_mkl_LDL}"
-            "${_BLAS_MKLROOT_LIB_DIR}"
+            "${BLAS_mkl_MKLROOT}"
+            "${BLAS_mkl_LIB_PATH_SUFFIXES}"
             )
-        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)
+      unset(BLAS_mkl_MKLROOT)
+      unset(BLAS_mkl_MKLROOT_LAST_DIR)
+      unset(BLAS_mkl_ARCH_NAME)
+      unset(BLAS_mkl_OS_NAME)
+      unset(BLAS_mkl_LIB_PATH_SUFFIXES)
+    endif()
+  endif()
+endif()
 
 if(BLA_F95)
   find_package_handle_standard_args(BLAS REQUIRED_VARS BLAS95_LIBRARIES)
@@ -455,30 +501,34 @@
   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
       ""
       "goto2"
       ""
+      ""
+      ""
       )
   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
       ""
       "openblas"
       ""
+      ""
+      ""
       )
   endif()
   if(NOT BLAS_LIBRARIES AND (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED))
@@ -487,246 +537,265 @@
     else()
       find_package(Threads REQUIRED)
     endif()
-    # OpenBLAS (http://www.openblas.net)
-    check_fortran_libraries(
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
       ""
       "openblas"
       "${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
       ""
       "blis"
       ""
+      ""
+      ""
       )
   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
       ""
-      "f77blas;atlas"
+      "blas;f77blas;atlas"
+      ""
+      ""
       ""
       )
   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
       ""
       "sgemm;dgemm;blas"
       ""
+      ""
+      ""
       )
   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
       ""
       "cxml"
       ""
+      ""
+      ""
       )
   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
       ""
       "dxml"
       ""
+      ""
+      ""
       )
   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
       "-xlic_lib=sunperf"
       "sunperf;sunmath"
       ""
+      ""
+      ""
       )
     if(BLAS_LIBRARIES)
       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
       ""
       "scsl"
       ""
+      ""
+      ""
       )
   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
       ""
       "complib.sgimath"
       ""
+      ""
+      ""
       )
   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
       ""
       "essl;blas"
       ""
+      ""
+      ""
       )
   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}
+      "" "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}
+      "" "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}
+      "" "acml;acml_mv" "" ${BLAS_ACML_LIB_DIRS} ""
       )
-    if( BLAS_LIBRARIES )
+    if(BLAS_LIBRARIES)
       break()
     endif()
   endforeach()
@@ -734,77 +803,90 @@
 
 # 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
     ""
     "acml;acml_mv"
     ""
+    ""
+    ""
     )
 endif()
 if(NOT BLAS_LIBRARIES)
-  check_fortran_libraries(
+  check_blas_libraries(
     BLAS_LIBRARIES
     BLAS
     sgemm
     ""
     "acml_mp;acml_mv"
     ""
+    ""
+    ""
     )
 endif()
 if(NOT BLAS_LIBRARIES)
-  check_fortran_libraries(
+  check_blas_libraries(
     BLAS_LIBRARIES
     BLAS
     sgemm
     ""
     "acml;acml_mv;CALBLAS"
     ""
+    ""
+    ""
     )
 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
       ""
       "Accelerate"
       ""
+      ""
+      ""
       )
   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
       ""
       "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
       ""
       "blas"
       ""
+      ""
+      ""
       )
   endif()
-endif ()
+endif()
 
 if(NOT BLA_F95)
   find_package_handle_standard_args(BLAS REQUIRED_VARS BLAS_LIBRARIES)
@@ -812,7 +894,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..3c52466 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.
@@ -1467,43 +1470,6 @@
 _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_ADDITIONAL_VERSIONS")
 _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_NO_SYSTEM_PATHS")
 
-# Supply Boost_LIB_DIAGNOSTIC_DEFINITIONS as a convenience target. It
-# will only contain any interface definitions on WIN32, but is created
-# on all platforms to keep end user code free from platform dependent
-# code.  Also provide convenience targets to disable autolinking and
-# enable dynamic linking.
-if(NOT TARGET Boost::diagnostic_definitions)
-  add_library(Boost::diagnostic_definitions INTERFACE IMPORTED)
-  add_library(Boost::disable_autolinking INTERFACE IMPORTED)
-  add_library(Boost::dynamic_linking INTERFACE IMPORTED)
-  set_target_properties(Boost::dynamic_linking PROPERTIES
-    INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_DYN_LINK")
-endif()
-if(WIN32)
-  # In windows, automatic linking is performed, so you do not have
-  # to specify the libraries.  If you are linking to a dynamic
-  # runtime, then you can choose to link to either a static or a
-  # dynamic Boost library, the default is to do a static link.  You
-  # can alter this for a specific library "whatever" by defining
-  # BOOST_WHATEVER_DYN_LINK to force Boost library "whatever" to be
-  # linked dynamically.  Alternatively you can force all Boost
-  # libraries to dynamic link by defining BOOST_ALL_DYN_LINK.
-
-  # This feature can be disabled for Boost library "whatever" by
-  # defining BOOST_WHATEVER_NO_LIB, or for all of Boost by defining
-  # BOOST_ALL_NO_LIB.
-
-  # If you want to observe which libraries are being linked against
-  # then defining BOOST_LIB_DIAGNOSTIC will cause the auto-linking
-  # code to emit a #pragma message each time a library is selected
-  # for linking.
-  set(Boost_LIB_DIAGNOSTIC_DEFINITIONS "-DBOOST_LIB_DIAGNOSTIC")
-  set_target_properties(Boost::diagnostic_definitions PROPERTIES
-    INTERFACE_COMPILE_DEFINITIONS "BOOST_LIB_DIAGNOSTIC")
-  set_target_properties(Boost::disable_autolinking PROPERTIES
-    INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_NO_LIB")
-endif()
-
 cmake_policy(GET CMP0074 _Boost_CMP0074)
 if(NOT "x${_Boost_CMP0074}x" STREQUAL "xNEWx")
   _Boost_CHECK_SPELLING(Boost_ROOT)
@@ -2296,6 +2262,43 @@
       endif()
     endif()
   endforeach()
+
+  # Supply Boost_LIB_DIAGNOSTIC_DEFINITIONS as a convenience target. It
+  # will only contain any interface definitions on WIN32, but is created
+  # on all platforms to keep end user code free from platform dependent
+  # code.  Also provide convenience targets to disable autolinking and
+  # enable dynamic linking.
+  if(NOT TARGET Boost::diagnostic_definitions)
+    add_library(Boost::diagnostic_definitions INTERFACE IMPORTED)
+    add_library(Boost::disable_autolinking INTERFACE IMPORTED)
+    add_library(Boost::dynamic_linking INTERFACE IMPORTED)
+    set_target_properties(Boost::dynamic_linking PROPERTIES
+      INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_DYN_LINK")
+  endif()
+  if(WIN32)
+    # In windows, automatic linking is performed, so you do not have
+    # to specify the libraries.  If you are linking to a dynamic
+    # runtime, then you can choose to link to either a static or a
+    # dynamic Boost library, the default is to do a static link.  You
+    # can alter this for a specific library "whatever" by defining
+    # BOOST_WHATEVER_DYN_LINK to force Boost library "whatever" to be
+    # linked dynamically.  Alternatively you can force all Boost
+    # libraries to dynamic link by defining BOOST_ALL_DYN_LINK.
+
+    # This feature can be disabled for Boost library "whatever" by
+    # defining BOOST_WHATEVER_NO_LIB, or for all of Boost by defining
+    # BOOST_ALL_NO_LIB.
+
+    # If you want to observe which libraries are being linked against
+    # then defining BOOST_LIB_DIAGNOSTIC will cause the auto-linking
+    # code to emit a #pragma message each time a library is selected
+    # for linking.
+    set(Boost_LIB_DIAGNOSTIC_DEFINITIONS "-DBOOST_LIB_DIAGNOSTIC")
+    set_target_properties(Boost::diagnostic_definitions PROPERTIES
+      INTERFACE_COMPILE_DEFINITIONS "BOOST_LIB_DIAGNOSTIC")
+    set_target_properties(Boost::disable_autolinking PROPERTIES
+      INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_NO_LIB")
+  endif()
 endif()
 
 # ------------------------------------------------------------------------
diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake
index b6859aa..e1af2d6 100644
--- a/Modules/FindCUDA.cmake
+++ b/Modules/FindCUDA.cmake
@@ -5,17 +5,22 @@
 .. deprecated:: 3.10
 
   Superseded by first-class support for the CUDA language in CMake.
+  Superseded by the :module:`FindCUDAToolkit` for CUDA toolkit libraries.
 
 Replacement
 ^^^^^^^^^^^
 
-It is no longer necessary to use this module or call ``find_package(CUDA)``.
-Instead, list ``CUDA`` among the languages named in the top-level
-call to the :command:`project` command, or call the
+It is no longer necessary to use this module or call ``find_package(CUDA)``
+for compiling CUDA code. Instead, list ``CUDA`` among the languages named
+in the top-level call to the :command:`project` command, or call the
 :command:`enable_language` command with ``CUDA``.
 Then one can add CUDA (``.cu``) sources to programs directly
 in calls to :command:`add_library` and :command:`add_executable`.
 
+To find and use the CUDA toolkit libraries the :module:`FindCUDAToolkit`
+module has superseded this module.  It works whether or not the ``CUDA``
+language is enabled.
+
 Documentation of Deprecated Usage
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -676,7 +681,7 @@
 # Search for the cuda distribution.
 if(NOT CUDA_TOOLKIT_ROOT_DIR AND NOT CMAKE_CROSSCOMPILING)
   # Search in the CUDA_BIN_PATH first.
-  find_path(CUDA_TOOLKIT_ROOT_DIR
+  find_program(CUDA_TOOLKIT_ROOT_DIR_NVCC
     NAMES nvcc nvcc.exe
     PATHS
       ENV CUDA_TOOLKIT_ROOT
@@ -688,19 +693,22 @@
     )
 
   # Now search default paths
-  find_path(CUDA_TOOLKIT_ROOT_DIR
+  find_program(CUDA_TOOLKIT_ROOT_DIR_NVCC
     NAMES nvcc nvcc.exe
     PATHS /opt/cuda/bin
     PATH_SUFFIXES cuda/bin
     DOC "Toolkit location."
     )
 
-  if (CUDA_TOOLKIT_ROOT_DIR)
+  if (CUDA_TOOLKIT_ROOT_DIR_NVCC)
+    get_filename_component(CUDA_TOOLKIT_ROOT_DIR_NVCC_PAR "${CUDA_TOOLKIT_ROOT_DIR_NVCC}" DIRECTORY)
+    get_filename_component(CUDA_TOOLKIT_ROOT_DIR "${CUDA_TOOLKIT_ROOT_DIR_NVCC_PAR}" DIRECTORY CACHE)
     string(REGEX REPLACE "[/\\\\]?bin[64]*[/\\\\]?$" "" CUDA_TOOLKIT_ROOT_DIR ${CUDA_TOOLKIT_ROOT_DIR})
     # We need to force this back into the cache.
     set(CUDA_TOOLKIT_ROOT_DIR ${CUDA_TOOLKIT_ROOT_DIR} CACHE PATH "Toolkit location." FORCE)
     set(CUDA_TOOLKIT_TARGET_DIR ${CUDA_TOOLKIT_ROOT_DIR})
   endif()
+  unset(CUDA_TOOLKIT_ROOT_DIR_NVCC CACHE)
 
   if (NOT EXISTS ${CUDA_TOOLKIT_ROOT_DIR})
     if(CUDA_FIND_REQUIRED)
@@ -921,7 +929,11 @@
 if(CUDA_BUILD_EMULATION AND CUDA_CUDARTEMU_LIBRARY)
   list(APPEND CUDA_LIBRARIES ${CUDA_CUDARTEMU_LIBRARY})
 elseif(CUDA_USE_STATIC_CUDA_RUNTIME AND CUDA_cudart_static_LIBRARY)
-  list(APPEND CUDA_LIBRARIES ${CUDA_cudart_static_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS})
+  list(APPEND CUDA_LIBRARIES ${CUDA_cudart_static_LIBRARY})
+  if (TARGET Threads::Threads)
+    list(APPEND CUDA_LIBRARIES Threads::Threads)
+  endif()
+  list(APPEND CUDA_LIBRARIES ${CMAKE_DL_LIBS})
   if (CUDA_rt_LIBRARY)
     list(APPEND CUDA_LIBRARIES ${CUDA_rt_LIBRARY})
   endif()
@@ -2003,7 +2015,7 @@
     string(TOUPPER ${cuda_clean_target_name} cuda_clean_target_name)
   endif()
   add_custom_target(${cuda_clean_target_name}
-    COMMAND ${CMAKE_COMMAND} -E remove ${CUDA_ADDITIONAL_CLEAN_FILES})
+    COMMAND ${CMAKE_COMMAND} -E rm -f ${CUDA_ADDITIONAL_CLEAN_FILES})
 
   # Clear out the variable, so the next time we configure it will be empty.
   # This is useful so that the files won't persist in the list after targets
diff --git a/Modules/FindCUDA/run_nvcc.cmake b/Modules/FindCUDA/run_nvcc.cmake
index af15d55..ba35433 100644
--- a/Modules/FindCUDA/run_nvcc.cmake
+++ b/Modules/FindCUDA/run_nvcc.cmake
@@ -174,7 +174,7 @@
 # Delete the target file
 cuda_execute_process(
   "Removing ${generated_file}"
-  COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}"
+  COMMAND "${CMAKE_COMMAND}" -E rm -f "${generated_file}"
   )
 
 # For CUDA 2.3 and below, -G -M doesn't work, so remove the -G flag
@@ -241,7 +241,7 @@
 # Delete the temporary file
 cuda_execute_process(
   "Removing ${cmake_dependency_file}.tmp and ${NVCC_generated_dependency_file}"
-  COMMAND "${CMAKE_COMMAND}" -E remove "${cmake_dependency_file}.tmp" "${NVCC_generated_dependency_file}"
+  COMMAND "${CMAKE_COMMAND}" -E rm -f "${cmake_dependency_file}.tmp" "${NVCC_generated_dependency_file}"
   )
 
 if(CUDA_result)
@@ -267,7 +267,7 @@
   # Since nvcc can sometimes leave half done files make sure that we delete the output file.
   cuda_execute_process(
     "Removing ${generated_file}"
-    COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}"
+    COMMAND "${CMAKE_COMMAND}" -E rm -f "${generated_file}"
     )
   message(FATAL_ERROR "Error generating file ${generated_file}")
 else()
diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake
new file mode 100644
index 0000000..4b14ddc
--- /dev/null
+++ b/Modules/FindCUDAToolkit.cmake
@@ -0,0 +1,870 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindCUDAToolkit
+---------------
+
+This script locates the NVIDIA CUDA toolkit and the associated libraries, but
+does not require the ``CUDA`` language be enabled for a given project. This
+module does not search for the NVIDIA CUDA Samples.
+
+Search Behavior
+^^^^^^^^^^^^^^^
+
+Finding the CUDA Toolkit requires finding the ``nvcc`` executable, which is
+searched for in the following order:
+
+1. If the ``CUDA`` language has been enabled we will use the directory
+   containing the compiler as the first search location for ``nvcc``.
+
+2. If the ``CUDAToolkit_ROOT`` cmake configuration variable (e.g.,
+   ``-DCUDAToolkit_ROOT=/some/path``) *or* environment variable is defined, it
+   will be searched.  If both an environment variable **and** a
+   configuration variable are specified, the *configuration* variable takes
+   precedence.
+
+   The directory specified here must be such that the executable ``nvcc`` can be
+   found underneath the directory specified by ``CUDAToolkit_ROOT``.  If
+   ``CUDAToolkit_ROOT`` is specified, but no ``nvcc`` is found underneath, this
+   package is marked as **not** found.  No subsequent search attempts are
+   performed.
+
+3. If the CUDA_PATH environment variable is defined, it will be searched.
+
+4. The user's path is searched for ``nvcc`` using :command:`find_program`.  If
+   this is found, no subsequent search attempts are performed.  Users are
+   responsible for ensuring that the first ``nvcc`` to show up in the path is
+   the desired path in the event that multiple CUDA Toolkits are installed.
+
+5. On Unix systems, if the symbolic link ``/usr/local/cuda`` exists, this is
+   used.  No subsequent search attempts are performed.  No default symbolic link
+   location exists for the Windows platform.
+
+6. The platform specific default install locations are searched.  If exactly one
+   candidate is found, this is used.  The default CUDA Toolkit install locations
+   searched are:
+
+   +-------------+-------------------------------------------------------------+
+   | Platform    | Search Pattern                                              |
+   +=============+=============================================================+
+   | macOS       | ``/Developer/NVIDIA/CUDA-X.Y``                              |
+   +-------------+-------------------------------------------------------------+
+   | Other Unix  | ``/usr/local/cuda-X.Y``                                     |
+   +-------------+-------------------------------------------------------------+
+   | Windows     | ``C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\vX.Y`` |
+   +-------------+-------------------------------------------------------------+
+
+   Where ``X.Y`` would be a specific version of the CUDA Toolkit, such as
+   ``/usr/local/cuda-9.0`` or
+   ``C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0``
+
+   .. note::
+
+       When multiple CUDA Toolkits are installed in the default location of a
+       system (e.g., both ``/usr/local/cuda-9.0`` and ``/usr/local/cuda-10.0``
+       exist but the ``/usr/local/cuda`` symbolic link does **not** exist), this
+       package is marked as **not** found.
+
+       There are too many factors involved in making an automatic decision in
+       the presence of multiple CUDA Toolkits being installed.  In this
+       situation, users are encouraged to either (1) set ``CUDAToolkit_ROOT`` or
+       (2) ensure that the correct ``nvcc`` executable shows up in ``$PATH`` for
+       :command:`find_program` to find.
+
+Options
+^^^^^^^
+
+``VERSION``
+    If specified, describes the version of the CUDA Toolkit to search for.
+
+``REQUIRED``
+    If specified, configuration will error if a suitable CUDA Toolkit is not
+    found.
+
+``QUIET``
+    If specified, the search for a suitable CUDA Toolkit will not produce any
+    messages.
+
+``EXACT``
+    If specified, the CUDA Toolkit is considered found only if the exact
+    ``VERSION`` specified is recovered.
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+An :ref:`imported target <Imported targets>` named ``CUDA::toolkit`` is provided.
+
+This module defines :prop_tgt:`IMPORTED` targets for each
+of the following libraries that are part of the CUDAToolkit:
+
+- :ref:`CUDA Runtime Library<cuda_toolkit_rt_lib>`
+- :ref:`CUDA Driver Library<cuda_toolkit_driver_lib>`
+- :ref:`cuBLAS<cuda_toolkit_cuBLAS>`
+- :ref:`cuFFT<cuda_toolkit_cuFFT>`
+- :ref:`cuRAND<cuda_toolkit_cuRAND>`
+- :ref:`cuSOLVER<cuda_toolkit_cuSOLVER>`
+- :ref:`cuSPARSE<cuda_toolkit_cuSPARSE>`
+- :ref:`cuPTI<cuda_toolkit_cupti>`
+- :ref:`NPP<cuda_toolkit_NPP>`
+- :ref:`nvBLAS<cuda_toolkit_nvBLAS>`
+- :ref:`nvGRAPH<cuda_toolkit_nvGRAPH>`
+- :ref:`nvJPEG<cuda_toolkit_nvJPEG>`
+- :ref:`nvidia-ML<cuda_toolkit_nvML>`
+- :ref:`nvRTC<cuda_toolkit_nvRTC>`
+- :ref:`nvToolsExt<cuda_toolkit_nvToolsExt>`
+- :ref:`OpenCL<cuda_toolkit_opencl>`
+- :ref:`cuLIBOS<cuda_toolkit_cuLIBOS>`
+
+.. _`cuda_toolkit_rt_lib`:
+
+CUDA Runtime Library
+""""""""""""""""""""
+
+The CUDA Runtime library (cudart) are what most applications will typically
+need to link against to make any calls such as `cudaMalloc`, and `cudaFree`.
+
+Targets Created:
+
+- ``CUDA::cudart``
+- ``CUDA::cudart_static``
+
+.. _`cuda_toolkit_driver_lib`:
+
+CUDA Driver Library
+""""""""""""""""""""
+
+The CUDA Driver library (cuda) are used by applications that use calls
+such as `cuMemAlloc`, and `cuMemFree`. This is generally used by advanced
+
+
+Targets Created:
+
+- ``CUDA::cuda_driver``
+- ``CUDA::cuda_driver``
+
+.. _`cuda_toolkit_cuBLAS`:
+
+cuBLAS
+""""""
+
+The `cuBLAS <https://docs.nvidia.com/cuda/cublas/index.html>`_ library.
+
+Targets Created:
+
+- ``CUDA::cublas``
+- ``CUDA::cublas_static``
+
+.. _`cuda_toolkit_cuFFT`:
+
+cuFFT
+"""""
+
+The `cuFFT <https://docs.nvidia.com/cuda/cufft/index.html>`_ library.
+
+Targets Created:
+
+- ``CUDA::cufft``
+- ``CUDA::cufftw``
+- ``CUDA::cufft_static``
+- ``CUDA::cufftw_static``
+
+cuRAND
+""""""
+
+The `cuRAND <https://docs.nvidia.com/cuda/curand/index.html>`_ library.
+
+Targets Created:
+
+- ``CUDA::curand``
+- ``CUDA::curand_static``
+
+.. _`cuda_toolkit_cuSOLVER`:
+
+cuSOLVER
+""""""""
+
+The `cuSOLVER <https://docs.nvidia.com/cuda/cusolver/index.html>`_ library.
+
+Targets Created:
+
+- ``CUDA::cusolver``
+- ``CUDA::cusolver_static``
+
+.. _`cuda_toolkit_cuSPARSE`:
+
+cuSPARSE
+""""""""
+
+The `cuSPARSE <https://docs.nvidia.com/cuda/cusparse/index.html>`_ library.
+
+Targets Created:
+
+- ``CUDA::cusparse``
+- ``CUDA::cusparse_static``
+
+.. _`cuda_toolkit_cupti`:
+
+cupti
+"""""
+
+The `NVIDIA CUDA Profiling Tools Interface <https://developer.nvidia.com/CUPTI>`_.
+
+Targets Created:
+
+- ``CUDA::cupti``
+- ``CUDA::cupti_static``
+
+.. _`cuda_toolkit_NPP`:
+
+NPP
+"""
+
+The `NPP <https://docs.nvidia.com/cuda/npp/index.html>`_ libraries.
+
+Targets Created:
+
+- `nppc`:
+
+  - ``CUDA::nppc``
+  - ``CUDA::nppc_static``
+
+- `nppial`: Arithmetic and logical operation functions in `nppi_arithmetic_and_logical_operations.h`
+
+  - ``CUDA::nppial``
+  - ``CUDA::nppial_static``
+
+- `nppicc`: Color conversion and sampling functions in `nppi_color_conversion.h`
+
+  - ``CUDA::nppicc``
+  - ``CUDA::nppicc_static``
+
+- `nppicom`: JPEG compression and decompression functions in `nppi_compression_functions.h`
+
+  - ``CUDA::nppicom``
+  - ``CUDA::nppicom_static``
+
+- `nppidei`: Data exchange and initialization functions in `nppi_data_exchange_and_initialization.h`
+
+  - ``CUDA::nppidei``
+  - ``CUDA::nppidei_static``
+
+- `nppif`: Filtering and computer vision functions in `nppi_filter_functions.h`
+
+  - ``CUDA::nppif``
+  - ``CUDA::nppif_static``
+
+- `nppig`: Geometry transformation functions found in `nppi_geometry_transforms.h`
+
+  - ``CUDA::nppig``
+  - ``CUDA::nppig_static``
+
+- `nppim`: Morphological operation functions found in `nppi_morphological_operations.h`
+
+  - ``CUDA::nppim``
+  - ``CUDA::nppim_static``
+
+- `nppist`: Statistics and linear transform in `nppi_statistics_functions.h` and `nppi_linear_transforms.h`
+
+  - ``CUDA::nppist``
+  - ``CUDA::nppist_static``
+
+- `nppisu`: Memory support functions in `nppi_support_functions.h`
+
+  - ``CUDA::nppisu``
+  - ``CUDA::nppisu_static``
+
+- `nppitc`: Threshold and compare operation functions in `nppi_threshold_and_compare_operations.h`
+
+  - ``CUDA::nppitc``
+  - ``CUDA::nppitc_static``
+
+- `npps`:
+
+  - ``CUDA::npps``
+  - ``CUDA::npps_static``
+
+.. _`cuda_toolkit_nvBLAS`:
+
+nvBLAS
+""""""
+
+The `nvBLAS <https://docs.nvidia.com/cuda/nvblas/index.html>`_ libraries.
+This is a shared library only.
+
+Targets Created:
+
+- ``CUDA::nvblas``
+
+.. _`cuda_toolkit_nvGRAPH`:
+
+nvGRAPH
+"""""""
+
+The `nvGRAPH <https://docs.nvidia.com/cuda/nvgraph/index.html>`_ library.
+
+Targets Created:
+
+- ``CUDA::nvgraph``
+- ``CUDA::nvgraph_static``
+
+
+.. _`cuda_toolkit_nvJPEG`:
+
+nvJPEG
+""""""
+
+The `nvJPEG <https://docs.nvidia.com/cuda/nvjpeg/index.html>`_ library.
+Introduced in CUDA 10.
+
+Targets Created:
+
+- ``CUDA::nvjpeg``
+- ``CUDA::nvjpeg_static``
+
+.. _`cuda_toolkit_nvRTC`:
+
+nvRTC
+"""""
+
+The `nvRTC <https://docs.nvidia.com/cuda/nvrtc/index.html>`_ (Runtime Compilation) library.
+This is a shared library only.
+
+Targets Created:
+
+- ``CUDA::nvrtc``
+
+.. _`cuda_toolkit_nvml`:
+
+nvidia-ML
+"""""""""
+
+The `NVIDIA Management Library <https://developer.nvidia.com/nvidia-management-library-nvml>`_.
+This is a shared library only.
+
+Targets Created:
+
+- ``CUDA::nvml``
+
+.. _`cuda_toolkit_nvToolsExt`:
+
+nvToolsExt
+""""""""""
+
+The `NVIDIA Tools Extension <https://docs.nvidia.com/gameworks/content/gameworkslibrary/nvtx/nvidia_tools_extension_library_nvtx.htm>`_.
+This is a shared library only.
+
+Targets Created:
+
+- ``CUDA::nvToolsExt``
+
+.. _`cuda_toolkit_opencl`:
+
+OpenCL
+""""""
+
+The `NVIDIA OpenCL Library <https://developer.nvidia.com/opencl>`_.
+This is a shared library only.
+
+Targets Created:
+
+- ``CUDA::OpenCL``
+
+.. _`cuda_toolkit_cuLIBOS`:
+
+cuLIBOS
+"""""""
+
+The cuLIBOS library is a backend thread abstraction layer library which is
+static only.  The ``CUDA::cublas_static``, ``CUDA::cusparse_static``,
+``CUDA::cufft_static``, ``CUDA::curand_static``, and (when implemented) NPP
+libraries all automatically have this dependency linked.
+
+Target Created:
+
+- ``CUDA::culibos``
+
+**Note**: direct usage of this target by consumers should not be necessary.
+
+.. _`cuda_toolkit_cuRAND`:
+
+
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+``CUDAToolkit_FOUND``
+    A boolean specifying whether or not the CUDA Toolkit was found.
+
+``CUDAToolkit_VERSION``
+    The exact version of the CUDA Toolkit found (as reported by
+    ``nvcc --version``).
+
+``CUDAToolkit_VERSION_MAJOR``
+    The major version of the CUDA Toolkit.
+
+``CUDAToolkit_VERSION_MAJOR``
+    The minor version of the CUDA Toolkit.
+
+``CUDAToolkit_VERSION_PATCH``
+    The patch version of the CUDA Toolkit.
+
+``CUDAToolkit_BIN_DIR``
+    The path to the CUDA Toolkit library directory that contains the CUDA
+    executable ``nvcc``.
+
+``CUDAToolkit_INCLUDE_DIRS``
+    The path to the CUDA Toolkit ``include`` folder containing the header files
+    required to compile a project linking against CUDA.
+
+``CUDAToolkit_LIBRARY_DIR``
+    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
+    :variable:`CMAKE_CUDA_COMPILER <CMAKE_<LANG>_COMPILER>`.  ``nvcc`` must be
+    found to determine the CUDA Toolkit version as well as determining other
+    features of the Toolkit.  This variable is set for the convenience of
+    modules that depend on this one.
+
+
+#]=======================================================================]
+
+# NOTE: much of this was simply extracted from FindCUDA.cmake.
+
+#   James Bigler, NVIDIA Corp (nvidia.com - jbigler)
+#   Abe Stephens, SCI Institute -- http://www.sci.utah.edu/~abe/FindCuda.html
+#
+#   Copyright (c) 2008 - 2009 NVIDIA Corporation.  All rights reserved.
+#
+#   Copyright (c) 2007-2009
+#   Scientific Computing and Imaging Institute, University of Utah
+#
+#   This code is licensed under the MIT License.  See the FindCUDA.cmake script
+#   for the text of the license.
+
+# The MIT License
+#
+# License for the specific language governing rights and limitations under
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+###############################################################################
+
+if(CMAKE_CUDA_COMPILER_LOADED AND NOT CUDAToolkit_BIN_DIR)
+  get_filename_component(cuda_dir "${CMAKE_CUDA_COMPILER}" DIRECTORY)
+  # use the already detected cuda compiler
+  set(CUDAToolkit_BIN_DIR "${cuda_dir}" CACHE PATH "")
+  mark_as_advanced(CUDAToolkit_BIN_DIR)
+  unset(cuda_dir)
+endif()
+
+# Try language- or user-provided path first.
+if(CUDAToolkit_BIN_DIR)
+  find_program(CUDAToolkit_NVCC_EXECUTABLE
+    NAMES nvcc nvcc.exe
+    PATHS ${CUDAToolkit_BIN_DIR}
+    NO_DEFAULT_PATH
+    )
+endif()
+
+# Search using CUDAToolkit_ROOT
+find_program(CUDAToolkit_NVCC_EXECUTABLE
+  NAMES nvcc nvcc.exe
+  PATHS ENV CUDA_PATH
+  PATH_SUFFIXES bin
+)
+
+# If the user specified CUDAToolkit_ROOT but nvcc could not be found, this is an error.
+if (NOT CUDAToolkit_NVCC_EXECUTABLE AND (DEFINED CUDAToolkit_ROOT OR DEFINED ENV{CUDAToolkit_ROOT}))
+  # Declare error messages now, print later depending on find_package args.
+  set(fail_base "Could not find nvcc executable in path specified by")
+  set(cuda_root_fail "${fail_base} CUDAToolkit_ROOT=${CUDAToolkit_ROOT}")
+  set(env_cuda_root_fail "${fail_base} environment variable CUDAToolkit_ROOT=$ENV{CUDAToolkit_ROOT}")
+
+  if (CUDAToolkit_FIND_REQUIRED)
+    if (DEFINED CUDAToolkit_ROOT)
+      message(FATAL_ERROR ${cuda_root_fail})
+    elseif (DEFINED ENV{CUDAToolkit_ROOT})
+      message(FATAL_ERROR ${env_cuda_root_fail})
+    endif()
+  else()
+    if (NOT CUDAToolkit_FIND_QUIETLY)
+      if (DEFINED CUDAToolkit_ROOT)
+        message(STATUS ${cuda_root_fail})
+      elseif (DEFINED ENV{CUDAToolkit_ROOT})
+        message(STATUS ${env_cuda_root_fail})
+      endif()
+    endif()
+    set(CUDAToolkit_FOUND FALSE)
+    unset(fail_base)
+    unset(cuda_root_fail)
+    unset(env_cuda_root_fail)
+    return()
+  endif()
+endif()
+
+# CUDAToolkit_ROOT cmake / env variable not specified, try platform defaults.
+#
+# - Linux: /usr/local/cuda-X.Y
+# - macOS: /Developer/NVIDIA/CUDA-X.Y
+# - Windows: C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\vX.Y
+#
+# We will also search the default symlink location /usr/local/cuda first since
+# if CUDAToolkit_ROOT is not specified, it is assumed that the symlinked
+# directory is the desired location.
+if (NOT CUDAToolkit_NVCC_EXECUTABLE)
+  if (UNIX)
+    if (NOT APPLE)
+      set(platform_base "/usr/local/cuda-")
+    else()
+      set(platform_base "/Developer/NVIDIA/CUDA-")
+    endif()
+  else()
+    set(platform_base "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v")
+  endif()
+
+  # Build out a descending list of possible cuda installations, e.g.
+  file(GLOB possible_paths "${platform_base}*")
+  # Iterate the glob results and create a descending list.
+  set(possible_versions)
+  foreach (p ${possible_paths})
+    # Extract version number from end of string
+    string(REGEX MATCH "[0-9][0-9]?\\.[0-9]$" p_version ${p})
+    if (IS_DIRECTORY ${p} AND p_version)
+      list(APPEND possible_versions ${p_version})
+    endif()
+  endforeach()
+
+  # Cannot use list(SORT) because that is alphabetical, we need numerical.
+  # NOTE: this is not an efficient sorting strategy.  But even if a user had
+  # every possible version of CUDA installed, this wouldn't create any
+  # significant overhead.
+  set(versions)
+  foreach (v ${possible_versions})
+    list(LENGTH versions num_versions)
+    # First version, nothing to compare with so just append.
+    if (num_versions EQUAL 0)
+      list(APPEND versions ${v})
+    else()
+      # Loop through list.  Insert at an index when comparison is
+      # VERSION_GREATER since we want a descending list.  Duplicates will not
+      # happen since this came from a glob list of directories.
+      set(i 0)
+      set(early_terminate FALSE)
+      while (i LESS num_versions)
+        list(GET versions ${i} curr)
+        if (v VERSION_GREATER curr)
+          list(INSERT versions ${i} ${v})
+          set(early_terminate TRUE)
+          break()
+        endif()
+        math(EXPR i "${i} + 1")
+      endwhile()
+      # If it did not get inserted, place it at the end.
+      if (NOT early_terminate)
+        list(APPEND versions ${v})
+      endif()
+    endif()
+  endforeach()
+
+  # With a descending list of versions, populate possible paths to search.
+  set(search_paths)
+  foreach (v ${versions})
+    list(APPEND search_paths "${platform_base}${v}")
+  endforeach()
+
+  # Force the global default /usr/local/cuda to the front on Unix.
+  if (UNIX)
+    list(INSERT search_paths 0 "/usr/local/cuda")
+  endif()
+
+  # Now search for nvcc again using the platform default search paths.
+  find_program(CUDAToolkit_NVCC_EXECUTABLE
+    NAMES nvcc nvcc.exe
+    PATHS ${search_paths}
+    PATH_SUFFIXES bin
+  )
+
+  # We are done with these variables now, cleanup for caller.
+  unset(platform_base)
+  unset(possible_paths)
+  unset(possible_versions)
+  unset(versions)
+  unset(i)
+  unset(early_terminate)
+  unset(search_paths)
+
+  if (NOT CUDAToolkit_NVCC_EXECUTABLE)
+    if (CUDAToolkit_FIND_REQUIRED)
+      message(FATAL_ERROR "Could not find nvcc, please set CUDAToolkit_ROOT.")
+    elseif(NOT CUDAToolkit_FIND_QUIETLY)
+      message(STATUS "Could not find nvcc, please set CUDAToolkit_ROOT.")
+    endif()
+
+    set(CUDAToolkit_FOUND FALSE)
+    return()
+  endif()
+endif()
+
+if(NOT CUDAToolkit_BIN_DIR AND CUDAToolkit_NVCC_EXECUTABLE)
+  get_filename_component(cuda_dir "${CUDAToolkit_NVCC_EXECUTABLE}" DIRECTORY)
+  set(CUDAToolkit_BIN_DIR "${cuda_dir}" CACHE PATH "" FORCE)
+  mark_as_advanced(CUDAToolkit_BIN_DIR)
+  unset(cuda_dir)
+endif()
+
+if(CUDAToolkit_NVCC_EXECUTABLE AND
+   CUDAToolkit_NVCC_EXECUTABLE STREQUAL CMAKE_CUDA_COMPILER)
+  # Need to set these based off the already computed CMAKE_CUDA_COMPILER_VERSION value
+  # This if statement will always match, but is used to provide variables for MATCH 1,2,3...
+  if(CMAKE_CUDA_COMPILER_VERSION MATCHES [=[([0-9]+)\.([0-9]+)\.([0-9]+)]=])
+    set(CUDAToolkit_VERSION_MAJOR "${CMAKE_MATCH_1}")
+    set(CUDAToolkit_VERSION_MINOR "${CMAKE_MATCH_2}")
+    set(CUDAToolkit_VERSION_PATCH "${CMAKE_MATCH_3}")
+    set(CUDAToolkit_VERSION "${CMAKE_CUDA_COMPILER_VERSION}")
+  endif()
+else()
+  # Compute the version by invoking nvcc
+  execute_process (COMMAND ${CUDAToolkit_NVCC_EXECUTABLE} "--version" OUTPUT_VARIABLE NVCC_OUT)
+  if(NVCC_OUT MATCHES [=[ V([0-9]+)\.([0-9]+)\.([0-9]+)]=])
+    set(CUDAToolkit_VERSION_MAJOR "${CMAKE_MATCH_1}")
+    set(CUDAToolkit_VERSION_MINOR "${CMAKE_MATCH_2}")
+    set(CUDAToolkit_VERSION_PATCH "${CMAKE_MATCH_3}")
+    set(CUDAToolkit_VERSION  "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
+  endif()
+  unset(NVCC_OUT)
+endif()
+
+
+get_filename_component(CUDAToolkit_ROOT_DIR ${CUDAToolkit_BIN_DIR} DIRECTORY ABSOLUTE)
+
+# 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(PREPEND CMAKE_FIND_ROOT_PATH "${CUDAToolkit_TARGET_DIR}")
+
+    # Mark that we need to pop the root search path changes after we have
+    # found all cuda libraries so that searches for our cross-compilation
+    # libraries work when another cuda sdk is in CMAKE_PREFIX_PATH or
+    # PATh
+    set(_CUDAToolkit_Pop_ROOT_PATH True)
+  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})
+
+  # Mark that we need to pop the prefix path changes after we have
+  # found the cudart library.
+  set(_CUDAToolkit_Pop_Prefix True)
+endif()
+
+
+# Find the include/ directory
+find_path(CUDAToolkit_INCLUDE_DIR
+  NAMES cuda_runtime.h
+)
+
+# And find the CUDA Runtime Library libcudart
+find_library(CUDA_CUDART
+  NAMES cudart
+  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)
+if(_CUDAToolkit_Pop_Prefix)
+  list(REMOVE_AT CMAKE_PREFIX_PATH -1)
+  unset(_CUDAToolkit_Pop_Prefix)
+endif()
+
+#-----------------------------------------------------------------------------
+# Perform version comparison and validate all required variables are set.
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+find_package_handle_standard_args(CUDAToolkit
+  REQUIRED_VARS
+    CUDAToolkit_INCLUDE_DIR
+    CUDA_CUDART
+    CUDAToolkit_NVCC_EXECUTABLE
+  VERSION_VAR
+    CUDAToolkit_VERSION
+)
+mark_as_advanced(CUDA_CUDART
+                 CUDAToolkit_INCLUDE_DIR
+                 CUDAToolkit_NVCC_EXECUTABLE
+                 )
+
+#-----------------------------------------------------------------------------
+# Construct result variables
+if(CUDAToolkit_FOUND)
+ set(CUDAToolkit_INCLUDE_DIRS ${CUDAToolkit_INCLUDE_DIR})
+ get_filename_component(CUDAToolkit_LIBRARY_DIR ${CUDA_CUDART} DIRECTORY ABSOLUTE)
+endif()
+
+#-----------------------------------------------------------------------------
+# Construct import targets
+if(CUDAToolkit_FOUND)
+
+  function(_CUDAToolkit_find_and_add_import_lib lib_name)
+    cmake_parse_arguments(arg "" "" "ALT;DEPS;EXTRA_PATH_SUFFIXES" ${ARGN})
+
+    set(search_names ${lib_name} ${arg_ALT})
+
+    find_library(CUDA_${lib_name}_LIBRARY
+      NAMES ${search_names}
+      HINTS ${CUDAToolkit_LIBRARY_DIR}
+            ENV CUDA_PATH
+      PATH_SUFFIXES nvidia/current lib64 lib64/stubs lib/x64 lib lib/stubs
+                    ${arg_EXTRA_PATH_SUFFIXES}
+    )
+    mark_as_advanced(CUDA_${lib_name}_LIBRARY)
+
+    if (NOT TARGET CUDA::${lib_name} AND CUDA_${lib_name}_LIBRARY)
+      add_library(CUDA::${lib_name} IMPORTED INTERFACE)
+      target_include_directories(CUDA::${lib_name} SYSTEM INTERFACE "${CUDAToolkit_INCLUDE_DIRS}")
+      target_link_libraries(CUDA::${lib_name} INTERFACE "${CUDA_${lib_name}_LIBRARY}")
+      foreach(dep ${arg_DEPS})
+        if(TARGET CUDA::${dep})
+          target_link_libraries(CUDA::${lib_name} INTERFACE CUDA::${dep})
+        endif()
+      endforeach()
+    endif()
+  endfunction()
+
+  if(NOT TARGET CUDA::toolkit)
+    add_library(CUDA::toolkit IMPORTED INTERFACE)
+    target_include_directories(CUDA::toolkit SYSTEM INTERFACE "${CUDAToolkit_INCLUDE_DIRS}")
+    target_link_directories(CUDA::toolkit INTERFACE "${CUDAToolkit_LIBRARY_DIR}")
+  endif()
+
+  _CUDAToolkit_find_and_add_import_lib(cuda_driver ALT cuda)
+
+  _CUDAToolkit_find_and_add_import_lib(cudart)
+  _CUDAToolkit_find_and_add_import_lib(cudart_static)
+
+  # setup dependencies that are required for cudart_static when building
+  # on linux. These are generally only required when using the CUDA toolkit
+  # when CUDA language is disabled
+  if(NOT TARGET CUDA::cudart_static_deps
+     AND TARGET CUDA::cudart_static)
+
+    add_library(CUDA::cudart_static_deps IMPORTED INTERFACE)
+    target_link_libraries(CUDA::cudart_static INTERFACE CUDA::cudart_static_deps)
+
+    if(UNIX AND (CMAKE_C_COMPILER OR CMAKE_CXX_COMPILER))
+      find_package(Threads REQUIRED)
+      target_link_libraries(CUDA::cudart_static_deps INTERFACE Threads::Threads ${CMAKE_DL_LIBS})
+    endif()
+
+    if(UNIX AND NOT APPLE)
+      # On Linux, you must link against librt when using the static cuda runtime.
+      find_library(CUDAToolkit_rt_LIBRARY rt)
+      mark_as_advanced(CUDAToolkit_rt_LIBRARY)
+      if(NOT CUDAToolkit_rt_LIBRARY)
+        message(WARNING "Could not find librt library, needed by CUDA::cudart_static")
+      else()
+        target_link_libraries(CUDA::cudart_static_deps INTERFACE ${CUDAToolkit_rt_LIBRARY})
+      endif()
+    endif()
+  endif()
+
+  _CUDAToolkit_find_and_add_import_lib(culibos) # it's a static library
+  foreach (cuda_lib cublas cufft curand cusparse nppc nvjpeg)
+    _CUDAToolkit_find_and_add_import_lib(${cuda_lib})
+    _CUDAToolkit_find_and_add_import_lib(${cuda_lib}_static DEPS culibos)
+  endforeach()
+
+  # cuFFTW depends on cuFFT
+  _CUDAToolkit_find_and_add_import_lib(cufftw DEPS cufft)
+  _CUDAToolkit_find_and_add_import_lib(cufftw DEPS cufft_static)
+
+  # cuSOLVER depends on cuBLAS, and cuSPARSE
+  _CUDAToolkit_find_and_add_import_lib(cusolver DEPS cublas cusparse)
+  _CUDAToolkit_find_and_add_import_lib(cusolver_static DEPS cublas_static cusparse_static culibos)
+
+  # nvGRAPH depends on cuRAND, and cuSOLVER.
+  _CUDAToolkit_find_and_add_import_lib(nvgraph DEPS curand cusolver)
+  _CUDAToolkit_find_and_add_import_lib(nvgraph_static DEPS curand_static cusolver_static)
+
+  # Process the majority of the NPP libraries.
+  foreach (cuda_lib nppial nppicc nppidei nppif nppig nppim nppist nppitc npps nppicom nppisu)
+    _CUDAToolkit_find_and_add_import_lib(${cuda_lib} DEPS nppc)
+    _CUDAToolkit_find_and_add_import_lib(${cuda_lib}_static DEPS nppc_static)
+  endforeach()
+
+  _CUDAToolkit_find_and_add_import_lib(cupti
+                                       EXTRA_PATH_SUFFIXES ../extras/CUPTI/lib64/
+                                                           ../extras/CUPTI/lib/)
+  _CUDAToolkit_find_and_add_import_lib(cupti_static
+                                       EXTRA_PATH_SUFFIXES ../extras/CUPTI/lib64/
+                                                           ../extras/CUPTI/lib/)
+
+  _CUDAToolkit_find_and_add_import_lib(nvrtc DEPS cuda_driver)
+
+  _CUDAToolkit_find_and_add_import_lib(nvml ALT nvidia-ml nvml)
+
+  if(WIN32)
+    # nvtools can be installed outside the CUDA toolkit directory
+    # so prefer the NVTOOLSEXT_PATH windows only environment variable
+    # In addition on windows the most common name is nvToolsExt64_1
+    find_library(CUDA_nvToolsExt_LIBRARY
+      NAMES nvToolsExt64_1 nvToolsExt64 nvToolsExt
+      PATHS ENV NVTOOLSEXT_PATH
+            ENV CUDA_PATH
+      PATH_SUFFIXES lib/x64 lib
+    )
+  endif()
+  _CUDAToolkit_find_and_add_import_lib(nvToolsExt ALT nvToolsExt64)
+
+  _CUDAToolkit_find_and_add_import_lib(OpenCL)
+endif()
+
+if(_CUDAToolkit_Pop_ROOT_PATH)
+  list(REMOVE_AT CMAKE_FIND_ROOT_PATH 0)
+  unset(_CUDAToolkit_Pop_ROOT_PATH)
+endif()
diff --git a/Modules/FindCURL.cmake b/Modules/FindCURL.cmake
index aeebc84..919babc 100644
--- a/Modules/FindCURL.cmake
+++ b/Modules/FindCURL.cmake
@@ -37,8 +37,35 @@
 
 ``CURL_VERSION_STRING``
   The version of ``curl`` found.
+
+CURL CMake
+^^^^^^^^^^
+
+If CURL was built using the CMake buildsystem then it provides its own
+``CURLConfig.cmake`` file for use with the :command:`find_package` command's
+config mode. This module looks for this file and, if found,
+returns its results with no further action.
+
+Set ``CURL_NO_CURL_CMAKE`` to ``ON`` to disable this search.
+
 #]=======================================================================]
 
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+if(NOT CURL_NO_CURL_CMAKE)
+  # do a find package call to specifically look for the CMake version
+  # of curl
+  find_package(CURL QUIET NO_MODULE)
+  mark_as_advanced(CURL_DIR)
+
+  # if we found the CURL cmake package then we are done, and
+  # can print what we found and return.
+  if(CURL_FOUND)
+    find_package_handle_standard_args(CURL HANDLE_COMPONENTS CONFIG_MODE)
+    return()
+  endif()
+endif()
+
 find_package(PkgConfig QUIET)
 if(PKG_CONFIG_FOUND)
   pkg_check_modules(PC_CURL QUIET libcurl)
@@ -139,7 +166,6 @@
   endforeach()
 endif()
 
-include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 find_package_handle_standard_args(CURL
                                   REQUIRED_VARS CURL_LIBRARY CURL_INCLUDE_DIR
                                   VERSION_VAR CURL_VERSION_STRING
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/FindDCMTK.cmake b/Modules/FindDCMTK.cmake
index d48de08..b2e00df 100644
--- a/Modules/FindDCMTK.cmake
+++ b/Modules/FindDCMTK.cmake
@@ -102,7 +102,7 @@
 # Step1: Attempt to find a version of DCMTK providing a DCMTKConfig.cmake file.
 #
 if(NOT DCMTK_FIND_QUIETLY)
-  message(STATUS "Trying to find DCMTK expecting DCMTKConfig.cmake")
+  message(CHECK_START "Trying to find DCMTK expecting DCMTKConfig.cmake")
 endif()
 find_package(DCMTK QUIET NO_MODULE)
 if(DCMTK_FOUND
@@ -110,12 +110,12 @@
     AND NOT "x" STREQUAL "x${DCMTK_INCLUDE_DIRS}")
 
   if(NOT DCMTK_FIND_QUIETLY)
-    message(STATUS "Trying to find DCMTK expecting DCMTKConfig.cmake - ok")
+    message(CHECK_PASS "ok")
   endif()
   return()
 else()
   if(NOT DCMTK_FIND_QUIETLY)
-    message(STATUS "Trying to find DCMTK expecting DCMTKConfig.cmake - failed")
+    message(CHECK_FAIL "failed")
   endif()
 endif()
 
diff --git a/Modules/FindFLEX.cmake b/Modules/FindFLEX.cmake
index d22b7ec..90e5f86 100644
--- a/Modules/FindFLEX.cmake
+++ b/Modules/FindFLEX.cmake
@@ -142,8 +142,6 @@
   #============================================================
   #
   macro(FLEX_TARGET Name Input Output)
-    set(FLEX_TARGET_outputs "${Output}")
-    set(FLEX_EXECUTABLE_opts "")
 
     set(FLEX_TARGET_PARAM_OPTIONS)
     set(FLEX_TARGET_PARAM_ONE_VALUE_KEYWORDS
@@ -165,31 +163,68 @@
     if(NOT "${FLEX_TARGET_ARG_UNPARSED_ARGUMENTS}" STREQUAL "")
       message(SEND_ERROR ${FLEX_TARGET_usage})
     else()
-      if(NOT "${FLEX_TARGET_ARG_COMPILE_FLAGS}" STREQUAL "")
-        set(FLEX_EXECUTABLE_opts "${FLEX_TARGET_ARG_COMPILE_FLAGS}")
-        separate_arguments(FLEX_EXECUTABLE_opts)
+
+      cmake_policy(GET CMP0098 _flex_CMP0098
+          PARENT_SCOPE # undocumented, do not use outside of CMake
+        )
+      set(_flex_INPUT "${Input}")
+      if("x${_flex_CMP0098}x" STREQUAL "xNEWx")
+        set(_flex_WORKING_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+        if(NOT IS_ABSOLUTE "${_flex_INPUT}")
+          set(_flex_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/${_flex_INPUT}")
+        endif()
+      else()
+        set(_flex_WORKING_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
       endif()
-      if(NOT "${FLEX_TARGET_ARG_DEFINES_FILE}" STREQUAL "")
-        list(APPEND FLEX_TARGET_outputs "${FLEX_TARGET_ARG_DEFINES_FILE}")
-        list(APPEND FLEX_EXECUTABLE_opts --header-file=${FLEX_TARGET_ARG_DEFINES_FILE})
+      unset(_flex_CMP0098)
+
+      set(_flex_OUTPUT "${Output}")
+      if(NOT IS_ABSOLUTE ${_flex_OUTPUT})
+        set(_flex_OUTPUT "${_flex_WORKING_DIR}/${_flex_OUTPUT}")
+      endif()
+      set(_flex_TARGET_OUTPUTS "${_flex_OUTPUT}")
+
+      set(_flex_EXE_OPTS "")
+      if(NOT "${FLEX_TARGET_ARG_COMPILE_FLAGS}" STREQUAL "")
+        set(_flex_EXE_OPTS "${FLEX_TARGET_ARG_COMPILE_FLAGS}")
+        separate_arguments(_flex_EXE_OPTS)
       endif()
 
-      add_custom_command(OUTPUT ${FLEX_TARGET_outputs}
-        COMMAND ${FLEX_EXECUTABLE} ${FLEX_EXECUTABLE_opts} -o${Output} ${Input}
+      set(_flex_OUTPUT_HEADER "")
+      if(NOT "${FLEX_TARGET_ARG_DEFINES_FILE}" STREQUAL "")
+        set(_flex_OUTPUT_HEADER "${FLEX_TARGET_ARG_DEFINES_FILE}")
+        if(IS_ABSOLUTE "${_flex_OUTPUT_HEADER}")
+          set(_flex_OUTPUT_HEADER_ABS "${_flex_OUTPUT_HEADER}")
+        else()
+          set(_flex_OUTPUT_HEADER_ABS "${_flex_WORKING_DIR}/${_flex_OUTPUT_HEADER}")
+        endif()
+        list(APPEND _flex_TARGET_OUTPUTS "${_flex_OUTPUT_HEADER_ABS}")
+        list(APPEND _flex_EXE_OPTS --header-file=${_flex_OUTPUT_HEADER_ABS})
+      endif()
+
+      get_filename_component(_flex_EXE_NAME_WE "${FLEX_EXECUTABLE}" NAME_WE)
+      add_custom_command(OUTPUT ${_flex_TARGET_OUTPUTS}
+        COMMAND ${FLEX_EXECUTABLE} ${_flex_EXE_OPTS} -o${_flex_OUTPUT} ${_flex_INPUT}
         VERBATIM
-        DEPENDS ${Input}
-        COMMENT "[FLEX][${Name}] Building scanner with flex ${FLEX_VERSION}"
-        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+        DEPENDS ${_flex_INPUT}
+        COMMENT "[FLEX][${Name}] Building scanner with ${_flex_EXE_NAME_WE} ${FLEX_VERSION}"
+        WORKING_DIRECTORY ${_flex_WORKING_DIR})
 
       set(FLEX_${Name}_DEFINED TRUE)
-      set(FLEX_${Name}_OUTPUTS ${Output})
-      set(FLEX_${Name}_INPUT ${Input})
-      set(FLEX_${Name}_COMPILE_FLAGS ${FLEX_EXECUTABLE_opts})
-      if("${FLEX_TARGET_ARG_DEFINES_FILE}" STREQUAL "")
-        set(FLEX_${Name}_OUTPUT_HEADER "")
-      else()
-        set(FLEX_${Name}_OUTPUT_HEADER ${FLEX_TARGET_ARG_DEFINES_FILE})
-      endif()
+      set(FLEX_${Name}_OUTPUTS ${_flex_TARGET_OUTPUTS})
+      set(FLEX_${Name}_INPUT ${_flex_INPUT})
+      set(FLEX_${Name}_COMPILE_FLAGS ${_flex_EXE_OPTS})
+      set(FLEX_${Name}_OUTPUT_HEADER ${_flex_OUTPUT_HEADER})
+
+      unset(_flex_EXE_NAME_WE)
+      unset(_flex_EXE_OPTS)
+      unset(_flex_INPUT)
+      unset(_flex_OUTPUT)
+      unset(_flex_OUTPUT_HEADER)
+      unset(_flex_OUTPUT_HEADER_ABS)
+      unset(_flex_TARGET_OUTPUTS)
+      unset(_flex_WORKING_DIR)
+
     endif()
   endmacro()
   #============================================================
diff --git a/Modules/FindGLEW.cmake b/Modules/FindGLEW.cmake
index bd69819..27ffa13 100644
--- a/Modules/FindGLEW.cmake
+++ b/Modules/FindGLEW.cmake
@@ -10,7 +10,7 @@
 Input Variables
 ^^^^^^^^^^^^^^^
 
-The following variables may be set to influence this module’s behavior:
+The following variables may be set to influence this module's behavior:
 
 ``GLEW_USE_STATIC_LIBS``
   to find and create :prop_tgt:`IMPORTED` target for static linkage.
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/FindGTest.cmake b/Modules/FindGTest.cmake
index e015a98..53cab1a 100644
--- a/Modules/FindGTest.cmake
+++ b/Modules/FindGTest.cmake
@@ -240,4 +240,15 @@
         __gtest_import_library(GTest::Main GTEST_MAIN_LIBRARY "RELEASE")
         __gtest_import_library(GTest::Main GTEST_MAIN_LIBRARY "DEBUG")
     endif()
+
+    # Add targets mapping the same library names as defined in
+    # GTest's CMake package config.
+    if(NOT TARGET GTest::gtest)
+        add_library(GTest::gtest INTERFACE IMPORTED)
+        target_link_libraries(GTest::gtest INTERFACE GTest::GTest)
+    endif()
+    if(NOT TARGET GTest::gtest_main)
+        add_library(GTest::gtest_main INTERFACE IMPORTED)
+        target_link_libraries(GTest::gtest_main INTERFACE GTest::Main)
+    endif()
 endif()
diff --git a/Modules/FindLAPACK.cmake b/Modules/FindLAPACK.cmake
index 3cb3653..c962976 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,22 @@
   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)
+  * ``Intel10_64_dyn`` (intel mkl v10+ 64 bit, single dynamic library)
   * ``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 +51,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 +63,8 @@
 
 .. note::
 
-  C or CXX must be enabled to use Intel MKL
+  C, CXX or Fortran must be enabled to detect a BLAS/LAPACK library.
+  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 +74,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,11 +84,11 @@
   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()
@@ -97,290 +97,344 @@
 set(LAPACK_FOUND FALSE)
 set(LAPACK95_FOUND FALSE)
 
-# TODO: move this stuff to 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.
-
-# 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 ()
-
-list(APPEND _libdir "${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}")
-
-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)
-  # Test this combination of libraries.
-  if(UNIX AND BLA_STATIC)
-    set(CMAKE_REQUIRED_LIBRARIES ${_flags} "-Wl,--start-group" ${${LIBRARIES}} ${_blas} "-Wl,--end-group" ${_threads})
+set(_lapack_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+if(BLA_STATIC)
+  if(WIN32)
+    set(CMAKE_FIND_LIBRARY_SUFFIXES .lib ${CMAKE_FIND_LIBRARY_SUFFIXES})
   else()
-    set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}} ${_blas} ${_threads})
+    set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
   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}}")
+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()
 
- if(_libraries_work)
-   if("${_list}${_blas}" STREQUAL "")
-     set(${LIBRARIES} "${LIBRARIES}-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
-   else()
-     set(${LIBRARIES} ${${LIBRARIES}} ${_blas} ${_threads})
-   endif()
- else()
+# TODO: move this stuff to a separate module
+
+macro(CHECK_LAPACK_LIBRARIES LIBRARIES _prefix _name _flags _list _threadlibs _addlibdir _subdirs _blas)
+  # This macro checks for the existence of the combination of fortran libraries
+  # given by _list.  If the combination is found, this macro checks (using the
+  # Check_Fortran_Function_Exists macro) whether can link against that library
+  # combination using the name of a routine given by _name using the linker
+  # flags given by _flags.  If the combination of libraries is found and passes
+  # the link test, LIBRARIES is set to the list of complete library paths that
+  # have been found.  Otherwise, LIBRARIES is set to FALSE.
+
+  # N.B. _prefix is the prefix applied to the names of all cached variables that
+  # are generated internally and marked advanced by this macro.
+  # _addlibdir is a list of additional search paths. _subdirs is a list of path
+  # suffixes to be used by find_library().
+
+  set(_libraries_work TRUE)
+  set(${LIBRARIES})
+  set(_combined_name)
+
+  set(_extaddlibdir "${_addlibdir}")
+  if(WIN32)
+    list(APPEND _extaddlibdir ENV LIB)
+  elseif(APPLE)
+    list(APPEND _extaddlibdir ENV DYLD_LIBRARY_PATH)
+  else()
+    list(APPEND _extaddlibdir ENV LD_LIBRARY_PATH)
+  endif()
+  list(APPEND _extaddlibdir "${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}")
+
+  foreach(_library ${_list})
+    if(_library MATCHES "^-Wl,--(start|end)-group$")
+      # Respect linker flags like --start/end-group (required by MKL)
+      set(${LIBRARIES} ${${LIBRARIES}} "${_library}")
+    else()
+      set(_combined_name ${_combined_name}_${_library})
+      if(_libraries_work)
+        find_library(${_prefix}_${_library}_LIBRARY
+          NAMES ${_library}
+          PATHS ${_extaddlibdir}
+          PATH_SUFFIXES ${_subdirs}
+        )
+        #message("DEBUG: find_library(${_library}) got ${${_prefix}_${_library}_LIBRARY}")
+        mark_as_advanced(${_prefix}_${_library}_LIBRARY)
+        set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY})
+        set(_libraries_work ${${_prefix}_${_library}_LIBRARY})
+      endif()
+    endif()
+  endforeach()
+
+  if(_libraries_work)
+    # Test this combination of libraries.
+    set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}} ${_blas} ${_threadlibs})
+    #message("DEBUG: CMAKE_REQUIRED_LIBRARIES = ${CMAKE_REQUIRED_LIBRARIES}")
+    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()
+
+  if(_libraries_work)
+    if("${_list}${_blas}" STREQUAL "")
+      set(${LIBRARIES} "${LIBRARIES}-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
+    else()
+      set(${LIBRARIES} ${${LIBRARIES}} ${_blas} ${_threadlibs})
+    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 and new >= 10.3
+          list(APPEND LAPACK_SEARCH_LIBS
+            "mkl_lapack")
+        endif()
+
+        # MKL uses a multitude of partially platform-specific subdirectories:
+        if(BLA_VENDOR STREQUAL "Intel10_32")
+          set(LAPACK_mkl_ARCH_NAME "ia32")
+        else()
+          set(LAPACK_mkl_ARCH_NAME "intel64")
+        endif()
+        if(WIN32)
+          set(LAPACK_mkl_OS_NAME "win")
+        elseif(APPLE)
+          set(LAPACK_mkl_OS_NAME "mac")
+        else()
+          set(LAPACK_mkl_OS_NAME "lin")
+        endif()
+        if(DEFINED ENV{MKLROOT})
+          set(LAPACK_mkl_MKLROOT "$ENV{MKLROOT}")
+          # If MKLROOT points to the subdirectory 'mkl', use the parent directory instead
+          # so we can better detect other relevant libraries in 'compiler' or 'tbb':
+          get_filename_component(LAPACK_mkl_MKLROOT_LAST_DIR "${LAPACK_mkl_MKLROOT}" NAME)
+          if(LAPACK_mkl_MKLROOT_LAST_DIR STREQUAL "mkl")
+              get_filename_component(LAPACK_mkl_MKLROOT "${LAPACK_mkl_MKLROOT}" DIRECTORY)
+          endif()
+        endif()
+        set(LAPACK_mkl_LIB_PATH_SUFFIXES
+            "compiler/lib" "compiler/lib/${LAPACK_mkl_ARCH_NAME}_${LAPACK_mkl_OS_NAME}"
+            "mkl/lib" "mkl/lib/${LAPACK_mkl_ARCH_NAME}_${LAPACK_mkl_OS_NAME}"
+            "lib/${LAPACK_mkl_ARCH_NAME}_${LAPACK_mkl_OS_NAME}")
+
+        # First try empty lapack libs
+        if(NOT ${_LIBRARIES})
+          check_lapack_libraries(
+            ${_LIBRARIES}
+            LAPACK
+            ${LAPACK_mkl_SEARCH_SYMBOL}
+            ""
+            ""
+            "${CMAKE_THREAD_LIBS_INIT};${LAPACK_mkl_LM};${LAPACK_mkl_LDL}"
+            "${LAPACK_mkl_MKLROOT}"
+            "${LAPACK_mkl_LIB_PATH_SUFFIXES}"
+            "${_BLAS_LIBRARIES}"
           )
-      endif ()
-    endforeach ()
+        endif()
 
-    unset(LAPACK_mkl_ILP_MODE)
-    unset(LAPACK_mkl_SEARCH_SYMBOL)
-    unset(LAPACK_mkl_LM)
-    unset(LAPACK_mkl_LDL)
-  endif ()
+        # Then try the search libs
+        foreach(IT ${LAPACK_SEARCH_LIBS})
+          string(REPLACE " " ";" SEARCH_LIBS ${IT})
+          if(NOT ${_LIBRARIES})
+            check_lapack_libraries(
+              ${_LIBRARIES}
+              LAPACK
+              ${LAPACK_mkl_SEARCH_SYMBOL}
+              ""
+              "${SEARCH_LIBS}"
+              "${CMAKE_THREAD_LIBS_INIT};${LAPACK_mkl_LM};${LAPACK_mkl_LDL}"
+              "${LAPACK_mkl_MKLROOT}"
+              "${LAPACK_mkl_LIB_PATH_SUFFIXES}"
+              "${_BLAS_LIBRARIES}"
+            )
+          endif()
+        endforeach()
+
+        unset(LAPACK_mkl_ILP_MODE)
+        unset(LAPACK_mkl_SEARCH_SYMBOL)
+        unset(LAPACK_mkl_LM)
+        unset(LAPACK_mkl_LDL)
+        unset(LAPACK_mkl_MKLROOT)
+        unset(LAPACK_mkl_ARCH_NAME)
+        unset(LAPACK_mkl_OS_NAME)
+        unset(LAPACK_mkl_LIB_PATH_SUFFIXES)
+      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 +451,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 +475,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 +488,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/FindLibArchive.cmake b/Modules/FindLibArchive.cmake
index ef27b7d..ce3c8b8 100644
--- a/Modules/FindLibArchive.cmake
+++ b/Modules/FindLibArchive.cmake
@@ -16,18 +16,26 @@
   LibArchive_INCLUDE_DIRS - include search path
   LibArchive_LIBRARIES    - libraries to link
   LibArchive_VERSION      - libarchive 3-component version number
+
+The module defines the following ``IMPORTED`` targets:
+
+::
+
+  LibArchive::LibArchive  - target for linking against libarchive
 #]=======================================================================]
 
 find_path(LibArchive_INCLUDE_DIR
   NAMES archive.h
   PATHS
   "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\LibArchive;InstallPath]/include"
+  DOC "libarchive include directory"
   )
 
 find_library(LibArchive_LIBRARY
   NAMES archive libarchive
   PATHS
   "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\LibArchive;InstallPath]/lib"
+  DOC "libarchive library"
   )
 
 mark_as_advanced(LibArchive_INCLUDE_DIR LibArchive_LIBRARY)
@@ -58,4 +66,11 @@
 if(LibArchive_FOUND)
   set(LibArchive_INCLUDE_DIRS ${LibArchive_INCLUDE_DIR})
   set(LibArchive_LIBRARIES    ${LibArchive_LIBRARY})
+
+  if (NOT TARGET LibArchive::LibArchive)
+    add_library(LibArchive::LibArchive UNKNOWN IMPORTED)
+    set_target_properties(LibArchive::LibArchive PROPERTIES
+      IMPORTED_LOCATION "${LibArchive_LIBRARY}"
+      INTERFACE_INCLUDE_DIRECTORIES "${LibArchive_INCLUDE_DIR}")
+  endif ()
 endif()
diff --git a/Modules/FindLibXml2.cmake b/Modules/FindLibXml2.cmake
index da8bfe0..f551dfe 100644
--- a/Modules/FindLibXml2.cmake
+++ b/Modules/FindLibXml2.cmake
@@ -10,8 +10,12 @@
 IMPORTED Targets
 ^^^^^^^^^^^^^^^^
 
-This module defines :prop_tgt:`IMPORTED` target ``LibXml2::LibXml2``, if
-libxml2 has been found.
+The following :prop_tgt:`IMPORTED` targets may be defined:
+
+``LibXml2::LibXml2``
+  If the libxml2 library has been found
+``LibXml2::xmllint``
+  If the xmllint command-line executable has been found
 
 Result variables
 ^^^^^^^^^^^^^^^^
@@ -48,7 +52,6 @@
 # in the find_path() and find_library() calls
 find_package(PkgConfig QUIET)
 PKG_CHECK_MODULES(PC_LIBXML QUIET libxml-2.0)
-set(LIBXML2_DEFINITIONS ${PC_LIBXML_CFLAGS_OTHER})
 
 find_path(LIBXML2_INCLUDE_DIR NAMES libxml/xpath.h
    HINTS
@@ -74,9 +77,7 @@
 # for backwards compat. with KDE 4.0.x:
 set(XMLLINT_EXECUTABLE "${LIBXML2_XMLLINT_EXECUTABLE}")
 
-if(PC_LIBXML_VERSION)
-    set(LIBXML2_VERSION_STRING ${PC_LIBXML_VERSION})
-elseif(LIBXML2_INCLUDE_DIR AND EXISTS "${LIBXML2_INCLUDE_DIR}/libxml/xmlversion.h")
+if(LIBXML2_INCLUDE_DIR AND EXISTS "${LIBXML2_INCLUDE_DIR}/libxml/xmlversion.h")
     file(STRINGS "${LIBXML2_INCLUDE_DIR}/libxml/xmlversion.h" libxml2_version_str
          REGEX "^#define[\t ]+LIBXML_DOTTED_VERSION[\t ]+\".*\"")
 
@@ -85,9 +86,20 @@
     unset(libxml2_version_str)
 endif()
 
-set(LIBXML2_INCLUDE_DIRS ${LIBXML2_INCLUDE_DIR} ${PC_LIBXML_INCLUDE_DIRS})
+set(LIBXML2_INCLUDE_DIRS ${LIBXML2_INCLUDE_DIR})
 set(LIBXML2_LIBRARIES ${LIBXML2_LIBRARY})
 
+# Did we find the same installation as pkg-config?
+# If so, use additional information from it.
+unset(LIBXML2_DEFINITIONS)
+foreach(libxml2_pc_lib_dir IN LISTS PC_LIBXML_LIBDIR PC_LIBXML_LIBRARY_DIRS)
+  if (LIBXML2_LIBRARY MATCHES "^${libxml2_pc_lib_dir}")
+    list(APPEND LIBXML2_INCLUDE_DIRS ${PC_LIBXML_INCLUDE_DIRS})
+    set(LIBXML2_DEFINITIONS ${PC_LIBXML_CFLAGS_OTHER})
+    break()
+  endif()
+endforeach()
+
 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2
                                   REQUIRED_VARS LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR
@@ -98,5 +110,11 @@
 if(LibXml2_FOUND AND NOT TARGET LibXml2::LibXml2)
   add_library(LibXml2::LibXml2 UNKNOWN IMPORTED)
   set_target_properties(LibXml2::LibXml2 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LIBXML2_INCLUDE_DIRS}")
+  set_target_properties(LibXml2::LibXml2 PROPERTIES INTERFACE_COMPILE_OPTIONS "${LIBXML2_DEFINITIONS}")
   set_property(TARGET LibXml2::LibXml2 APPEND PROPERTY IMPORTED_LOCATION "${LIBXML2_LIBRARY}")
 endif()
+
+if(LIBXML2_XMLLINT_EXECUTABLE AND NOT TARGET LibXml2::xmllint)
+  add_executable(LibXml2::xmllint IMPORTED)
+  set_target_properties(LibXml2::xmllint PROPERTIES IMPORTED_LOCATION "${LIBXML2_XMLLINT_EXECUTABLE}")
+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/FindMFC.cmake b/Modules/FindMFC.cmake
index e366619..b8ca71b 100644
--- a/Modules/FindMFC.cmake
+++ b/Modules/FindMFC.cmake
@@ -31,7 +31,7 @@
     set(CHECK_INCLUDE_FILE_VAR "afxwin.h")
     configure_file(${CMAKE_ROOT}/Modules/CheckIncludeFile.cxx.in
       ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFile.cxx)
-    message(STATUS "Looking for MFC")
+    message(CHECK_START "Looking for MFC")
     # Try both shared and static as the root project may have set the /MT flag
     try_compile(MFC_HAVE_MFC
       ${CMAKE_BINARY_DIR}
@@ -51,13 +51,13 @@
         OUTPUT_VARIABLE OUTPUT)
     endif()
     if(MFC_HAVE_MFC)
-      message(STATUS "Looking for MFC - found")
+      message(CHECK_PASS "found")
       set(MFC_HAVE_MFC 1 CACHE INTERNAL "Have MFC?")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Determining if MFC exists passed with the following output:\n"
         "${OUTPUT}\n\n")
     else()
-      message(STATUS "Looking for MFC - not found")
+      message(CHECK_FAIL "not found")
       set(MFC_HAVE_MFC 0 CACHE INTERNAL "Have MFC?")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Determining if MFC exists failed with the following output:\n"
diff --git a/Modules/FindMPI.cmake b/Modules/FindMPI.cmake
index d6cd799..41e1d08 100644
--- a/Modules/FindMPI.cmake
+++ b/Modules/FindMPI.cmake
@@ -842,8 +842,8 @@
   if(NOT MPI_${LANG}_COMPILE_DEFINITIONS)
     set(MPI_${LANG}_COMPILE_DEFINITIONS      ${MPI_COMPILE_DEFINITIONS_WORK} CACHE STRING "MPI ${LANG} compilation definitions"        FORCE)
   endif()
-  if(NOT MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS)
-    set(MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS  ${MPI_INCLUDE_DIRS_WORK}        CACHE STRING "MPI ${LANG} additional include directories" FORCE)
+  if(NOT MPI_${LANG}_COMPILER_INCLUDE_DIRS)
+    set(MPI_${LANG}_COMPILER_INCLUDE_DIRS    ${MPI_INCLUDE_DIRS_WORK}        CACHE STRING "MPI ${LANG} compiler wrapper include directories" FORCE)
   endif()
   if(NOT MPI_${LANG}_LINK_FLAGS)
     set(MPI_${LANG}_LINK_FLAGS               ${MPI_LINK_FLAGS_WORK}          CACHE STRING "MPI ${LANG} linker flags"                   FORCE)
@@ -1072,34 +1072,28 @@
 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()
+  set(MPI_${LANG}_INCLUDE_DIRS
+    ${MPI_${LANG}_COMPILER_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()
-    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()
+  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)
+      list(APPEND MPI_${LANG}_INCLUDE_DIRS "${MPI_${LANG}_MODULE_DIR}")
+    endif()
+  endif()
+  if(MPI_${LANG}_INCLUDE_DIRS)
+    list(REMOVE_DUPLICATES MPI_${LANG}_INCLUDE_DIRS)
   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}")
@@ -1109,23 +1103,30 @@
   # For C/C++, we just need to have a look for mpi.h.
   if("${LANG}" MATCHES "(C|CXX)")
     find_path(MPI_${LANG}_HEADER_DIR "mpi.h"
-      HINTS ${MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS}
+      HINTS
+        ${MPI_${LANG}_COMPILER_INCLUDE_DIRS}
+        ${MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS}
     )
     mark_as_advanced(MPI_${LANG}_HEADER_DIR)
     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
   # a Fortran 90 module.
   elseif("${LANG}" STREQUAL "Fortran")
     find_path(MPI_${LANG}_F77_HEADER_DIR "mpif.h"
-      HINTS ${MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS}
+      HINTS
+        ${MPI_${LANG}_COMPILER_INCLUDE_DIRS}
+        ${MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS}
     )
     find_path(MPI_${LANG}_MODULE_DIR
       NAMES "mpi.mod" "mpi_f08.mod"
-      HINTS ${MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS}
+      HINTS
+        ${MPI_${LANG}_COMPILER_INCLUDE_DIRS}
+        ${MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS}
     )
     if(MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS)
       list(REMOVE_ITEM MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS
@@ -1135,6 +1136,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)
@@ -1142,8 +1144,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})
@@ -1403,13 +1406,14 @@
     endif()
   else()
     set(_MPI_FIND_${LANG} FALSE)
+    string(APPEND _MPI_FAIL_REASON "MPI component '${LANG}' was requested, but language ${LANG} is not enabled.  ")
   endif()
   if(_MPI_FIND_${LANG})
     if( ${LANG} STREQUAL CXX AND NOT MPICXX IN_LIST MPI_FIND_COMPONENTS )
       set(MPI_CXX_SKIP_MPICXX FALSE CACHE BOOL "If true, the MPI-2 C++ bindings are disabled using definitions.")
       mark_as_advanced(MPI_CXX_SKIP_MPICXX)
     endif()
-    if(NOT (MPI_${LANG}_LIB_NAMES AND (MPI_${LANG}_INCLUDE_PATH OR MPI_${LANG}_INCLUDE_DIRS OR MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS)))
+    if(NOT (MPI_${LANG}_LIB_NAMES AND (MPI_${LANG}_INCLUDE_PATH OR MPI_${LANG}_INCLUDE_DIRS OR MPI_${LANG}_COMPILER_INCLUDE_DIRS)))
       set(MPI_${LANG}_TRIED_IMPLICIT FALSE)
       set(MPI_${LANG}_WORKS_IMPLICIT FALSE)
       if(NOT MPI_${LANG}_COMPILER AND NOT MPI_ASSUME_NO_BUILTIN_MPI)
@@ -1494,7 +1498,7 @@
             if("${LANG}" STREQUAL "CXX" AND MPI_C_WRAPPER_FOUND)
               set(MPI_${LANG}_COMPILE_OPTIONS          ${MPI_C_COMPILE_OPTIONS}     CACHE STRING "MPI ${LANG} compilation options"           )
               set(MPI_${LANG}_COMPILE_DEFINITIONS      ${MPI_C_COMPILE_DEFINITIONS} CACHE STRING "MPI ${LANG} compilation definitions"       )
-              set(MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS  ${MPI_C_INCLUDE_DIRS}        CACHE STRING "MPI ${LANG} additional include directories")
+              set(MPI_${LANG}_COMPILER_INCLUDE_DIRS    ${MPI_C_INCLUDE_DIRS}        CACHE STRING "MPI ${LANG} compiler wrapper include directories")
               set(MPI_${LANG}_LINK_FLAGS               ${MPI_C_LINK_FLAGS}          CACHE STRING "MPI ${LANG} linker flags"                  )
               set(MPI_${LANG}_LIB_NAMES                ${MPI_C_LIB_NAMES}           CACHE STRING "MPI ${LANG} libraries to link against"     )
             else()
@@ -1505,8 +1509,12 @@
       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})
+      _MPI_assemble_include_dirs(${LANG})
+    else()
+      set(MPI_${LANG}_INCLUDE_DIRS "")
+    endif()
     _MPI_assemble_libraries(${LANG})
 
     _MPI_adjust_compile_definitions(${LANG})
@@ -1520,13 +1528,21 @@
     # Next, we'll initialize the MPI variables that have not been previously set.
     set(MPI_${LANG}_COMPILE_OPTIONS          "" CACHE STRING "MPI ${LANG} compilation flags"             )
     set(MPI_${LANG}_COMPILE_DEFINITIONS      "" CACHE STRING "MPI ${LANG} compilation definitions"       )
+    set(MPI_${LANG}_COMPILER_INCLUDE_DIRS    "" CACHE STRING "MPI ${LANG} compiler wrapper include directories")
     set(MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS  "" CACHE STRING "MPI ${LANG} additional include directories")
     set(MPI_${LANG}_LINK_FLAGS               "" CACHE STRING "MPI ${LANG} linker flags"                  )
     if(NOT MPI_${LANG}_COMPILER STREQUAL CMAKE_${LANG}_COMPILER)
       set(MPI_${LANG}_LIB_NAMES                "" CACHE STRING "MPI ${LANG} libraries to link against"   )
     endif()
-    mark_as_advanced(MPI_${LANG}_COMPILE_OPTIONS MPI_${LANG}_COMPILE_DEFINITIONS MPI_${LANG}_LINK_FLAGS
-      MPI_${LANG}_LIB_NAMES MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS MPI_${LANG}_COMPILER)
+    mark_as_advanced(
+      MPI_${LANG}_COMPILE_OPTIONS
+      MPI_${LANG}_COMPILE_DEFINITIONS
+      MPI_${LANG}_LINK_FLAGS
+      MPI_${LANG}_LIB_NAMES
+      MPI_${LANG}_COMPILER_INCLUDE_DIRS
+      MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS
+      MPI_${LANG}_COMPILER
+      )
 
     # If we've found MPI, then we'll perform additional analysis: Determine the MPI version, MPI library version, supported
     # MPI APIs (i.e. MPI-2 C++ bindings). For Fortran we also need to find specific parameters if we're under MPI-3.
@@ -1675,7 +1691,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)
@@ -1700,6 +1717,7 @@
 find_package_handle_standard_args(MPI
     REQUIRED_VARS ${_MPI_REQ_VARS}
     VERSION_VAR ${_MPI_MIN_VERSION}
+    REASON_FAILURE_MESSAGE "${_MPI_FAIL_REASON}"
     HANDLE_COMPONENTS)
 
 #=============================================================================
diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake
index 92ee729..e42c206 100644
--- a/Modules/FindMatlab.cmake
+++ b/Modules/FindMatlab.cmake
@@ -241,6 +241,7 @@
 endif()
 
 set(MATLAB_VERSIONS_MAPPING
+  "R2020a=9.8"
   "R2019b=9.7"
   "R2019a=9.6"
   "R2018b=9.5"
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..a4b1e1e 100644
--- a/Modules/FindOpenMP.cmake
+++ b/Modules/FindOpenMP.cmake
@@ -96,7 +96,7 @@
     unset(OpenMP_FLAG_CANDIDATES)
 
     set(OMP_FLAG_GNU "-fopenmp")
-    set(OMP_FLAG_Clang "-fopenmp=libomp" "-fopenmp=libiomp5" "-fopenmp")
+    set(OMP_FLAG_Clang "-fopenmp=libomp" "-fopenmp=libiomp5" "-fopenmp" "-Xclang -fopenmp")
     set(OMP_FLAG_AppleClang "-Xclang -fopenmp")
     set(OMP_FLAG_HP "+Oopenmp")
     if(WIN32)
@@ -299,6 +299,25 @@
           break()
         endif()
       endif()
+    elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "Clang" AND WIN32)
+      # Check for separate OpenMP library for Clang on Windows
+      find_library(OpenMP_libomp_LIBRARY
+        NAMES libomp libgomp libiomp5
+        HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES}
+      )
+      mark_as_advanced(OpenMP_libomp_LIBRARY)
+      if(OpenMP_libomp_LIBRARY)
+        try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC}
+          CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
+          LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY}
+          OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
+        )
+        if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG})
+          set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE)
+          set("${OPENMP_LIB_NAMES_VAR}" "libomp" PARENT_SCOPE)
+          break()
+        endif()
+      endif()
     else()
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Detecting ${LANG} OpenMP failed with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n")
@@ -425,13 +444,12 @@
     if(NOT DEFINED OpenMP_${LANG}_FLAGS OR "${OpenMP_${LANG}_FLAGS}" STREQUAL "NOTFOUND"
       OR NOT DEFINED OpenMP_${LANG}_LIB_NAMES OR "${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND")
       _OPENMP_GET_FLAGS("${LANG}" "${LANG}" OpenMP_${LANG}_FLAGS_WORK OpenMP_${LANG}_LIB_NAMES_WORK)
+      set(OpenMP_${LANG}_FLAGS "${OpenMP_${LANG}_FLAGS_WORK}"
+        CACHE STRING "${LANG} compiler flags for OpenMP parallelization" FORCE)
+      set(OpenMP_${LANG}_LIB_NAMES "${OpenMP_${LANG}_LIB_NAMES_WORK}"
+        CACHE STRING "${LANG} compiler libraries for OpenMP parallelization" FORCE)
+      mark_as_advanced(OpenMP_${LANG}_FLAGS OpenMP_${LANG}_LIB_NAMES)
     endif()
-
-    set(OpenMP_${LANG}_FLAGS "${OpenMP_${LANG}_FLAGS_WORK}"
-      CACHE STRING "${LANG} compiler flags for OpenMP parallelization")
-    set(OpenMP_${LANG}_LIB_NAMES "${OpenMP_${LANG}_LIB_NAMES_WORK}"
-      CACHE STRING "${LANG} compiler libraries for OpenMP parallelization")
-    mark_as_advanced(OpenMP_${LANG}_FLAGS OpenMP_${LANG}_LIB_NAMES)
   endif()
 endforeach()
 
@@ -509,6 +527,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 478a592..af713d6 100644
--- a/Modules/FindOpenSSL.cmake
+++ b/Modules/FindOpenSSL.cmake
@@ -131,6 +131,7 @@
   ${_OPENSSL_ROOT_HINTS_AND_PATHS}
   HINTS
     ${_OPENSSL_INCLUDEDIR}
+    ${_OPENSSL_INCLUDE_DIRS}
   PATH_SUFFIXES
     include
 )
@@ -319,6 +320,7 @@
     ${_OPENSSL_ROOT_HINTS_AND_PATHS}
     HINTS
       ${_OPENSSL_LIBDIR}
+      ${_OPENSSL_LIBRARY_DIRS}
     PATH_SUFFIXES
       lib
   )
@@ -330,6 +332,7 @@
     ${_OPENSSL_ROOT_HINTS_AND_PATHS}
     HINTS
       ${_OPENSSL_LIBDIR}
+      ${_OPENSSL_LIBRARY_DIRS}
     PATH_SUFFIXES
       lib
   )
@@ -455,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/FindPNG.cmake b/Modules/FindPNG.cmake
index bd400c7..f1fe89a 100644
--- a/Modules/FindPNG.cmake
+++ b/Modules/FindPNG.cmake
@@ -94,6 +94,10 @@
       set(PNG_INCLUDE_DIRS ${PNG_PNG_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} )
       set(PNG_INCLUDE_DIR ${PNG_INCLUDE_DIRS} ) # for backward compatibility
       set(PNG_LIBRARIES ${PNG_LIBRARY} ${ZLIB_LIBRARY})
+      if((CMAKE_SYSTEM_NAME STREQUAL "Linux") AND
+         ("${PNG_LIBRARY}" MATCHES "\\${CMAKE_STATIC_LIBRARY_SUFFIX}$"))
+        list(APPEND PNG_LIBRARIES m)
+      endif()
 
       if (CYGWIN)
         if(BUILD_SHARED_LIBS)
@@ -110,6 +114,12 @@
           INTERFACE_COMPILE_DEFINITIONS "${_PNG_COMPILE_DEFINITIONS}"
           INTERFACE_INCLUDE_DIRECTORIES "${PNG_INCLUDE_DIRS}"
           INTERFACE_LINK_LIBRARIES ZLIB::ZLIB)
+        if((CMAKE_SYSTEM_NAME STREQUAL "Linux") AND
+           ("${PNG_LIBRARY}" MATCHES "\\${CMAKE_STATIC_LIBRARY_SUFFIX}$"))
+          set_property(TARGET PNG::PNG APPEND PROPERTY
+            INTERFACE_LINK_LIBRARIES m)
+        endif()
+
         if(EXISTS "${PNG_LIBRARY}")
           set_target_properties(PNG::PNG PROPERTIES
             IMPORTED_LINK_INTERFACE_LANGUAGES "C"
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/FindPkgConfig.cmake b/Modules/FindPkgConfig.cmake
index bd1bc7c..c79f20f 100644
--- a/Modules/FindPkgConfig.cmake
+++ b/Modules/FindPkgConfig.cmake
@@ -341,7 +341,7 @@
       # remove empty values from the list
       list(REMOVE_ITEM _pkgconfig_path "")
       file(TO_NATIVE_PATH "${_pkgconfig_path}" _pkgconfig_path)
-      if(UNIX)
+      if(CMAKE_HOST_UNIX)
         string(REPLACE ";" ":" _pkgconfig_path "${_pkgconfig_path}")
         string(REPLACE "\\ " " " _pkgconfig_path "${_pkgconfig_path}")
       endif()
diff --git a/Modules/FindProtobuf.cmake b/Modules/FindProtobuf.cmake
index 2d45965..f35978d 100644
--- a/Modules/FindProtobuf.cmake
+++ b/Modules/FindProtobuf.cmake
@@ -482,22 +482,24 @@
         "${_PROTOBUF_COMMON_HEADER} reveals protobuf ${Protobuf_VERSION}")
   endif()
 
-  # Check Protobuf compiler version to be aligned with libraries version
-  execute_process(COMMAND ${Protobuf_PROTOC_EXECUTABLE} --version
-                  OUTPUT_VARIABLE _PROTOBUF_PROTOC_EXECUTABLE_VERSION)
+  if(Protobuf_PROTOC_EXECUTABLE)
+    # Check Protobuf compiler version to be aligned with libraries version
+    execute_process(COMMAND ${Protobuf_PROTOC_EXECUTABLE} --version
+                    OUTPUT_VARIABLE _PROTOBUF_PROTOC_EXECUTABLE_VERSION)
 
-  if("${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}" MATCHES "libprotoc ([0-9.]+)")
-    set(_PROTOBUF_PROTOC_EXECUTABLE_VERSION "${CMAKE_MATCH_1}")
-  endif()
+    if("${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}" MATCHES "libprotoc ([0-9.]+)")
+      set(_PROTOBUF_PROTOC_EXECUTABLE_VERSION "${CMAKE_MATCH_1}")
+    endif()
 
-  if(Protobuf_DEBUG)
-    message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
-        "${Protobuf_PROTOC_EXECUTABLE} reveals version ${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}")
-  endif()
+    if(Protobuf_DEBUG)
+      message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] "
+          "${Protobuf_PROTOC_EXECUTABLE} reveals version ${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}")
+    endif()
 
-  if(NOT "${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}" VERSION_EQUAL "${Protobuf_VERSION}")
+    if(NOT "${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}" VERSION_EQUAL "${Protobuf_VERSION}")
       message(WARNING "Protobuf compiler version ${_PROTOBUF_PROTOC_EXECUTABLE_VERSION}"
-          " doesn't match library version ${Protobuf_VERSION}")
+        " doesn't match library version ${Protobuf_VERSION}")
+    endif()
   endif()
 
   if(Protobuf_LIBRARY)
diff --git a/Modules/FindPython.cmake b/Modules/FindPython.cmake
index 2bdfaf3..9dfa222 100644
--- a/Modules/FindPython.cmake
+++ b/Modules/FindPython.cmake
@@ -93,6 +93,13 @@
 
   Information returned by
   ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=False)``.
+``Python_SOABI``
+  Extension suffix for modules.
+
+  Information returned by
+  ``distutils.sysconfig.get_config_flag('SOABI')`` or computed from
+  ``distutils.sysconfig.get_config_flag('EXT_SUFFIX')`` or
+  ``python-config --extension-suffix``.
 ``Python_Compiler_FOUND``
   System has the Python compiler.
 ``Python_COMPILER``
@@ -220,12 +227,12 @@
   variable will be used, if any.
 
 ``Python_FIND_VIRTUALENV``
-  This variable defines the handling of virtual environments. It is meaningfull
-  only when a virtual environment is active (i.e. the ``activate`` script has
-  been evaluated). In this case, it takes precedence over
-  ``Python_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK`` variables.
-  The ``Python_FIND_VIRTUALENV`` variable can be set to empty or one of the
-  following:
+  This variable defines the handling of virtual environments managed by
+  ``virtualenv`` or ``conda``. It is meaningful only when a virtual environment
+  is active (i.e. the ``activate`` script has been evaluated). In this case, it
+  takes precedence over ``Python_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK``
+  variables.  The ``Python_FIND_VIRTUALENV`` variable can be set to empty or
+  one of the following:
 
   * ``FIRST``: The virtual environment is used before any other standard
     paths to look-up for the interpreter. This is the default.
@@ -290,9 +297,13 @@
 when library type is ``MODULE``, to target ``Python::Module`` and takes care of
 Python module naming rules::
 
-  Python_add_library (my_module MODULE src1.cpp)
+  Python_add_library (<name> [STATIC | SHARED | MODULE [WITH_SOABI]]
+                      <source1> [<source2> ...])
 
-If library type is not specified, ``MODULE`` is assumed.
+If the library type is not specified, ``MODULE`` is assumed.
+
+For ``MODULE`` library type, if option ``WITH_SOABI`` is specified, the
+module suffix will include the ``Python_SOABI`` value, if any.
 #]=======================================================================]
 
 
diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake
index 67db4d3..ce06458 100644
--- a/Modules/FindPython/Support.cmake
+++ b/Modules/FindPython/Support.cmake
@@ -97,8 +97,9 @@
 macro (_PYTHON_FIND_FRAMEWORKS)
   set (${_PYTHON_PREFIX}_FRAMEWORKS)
   if (CMAKE_HOST_APPLE OR APPLE)
+    file(TO_CMAKE_PATH "$ENV{CMAKE_FRAMEWORK_PATH}" _pff_CMAKE_FRAMEWORK_PATH)
     set (_pff_frameworks ${CMAKE_FRAMEWORK_PATH}
-                    $ENV{CMAKE_FRAMEWORK_PATH}
+                    ${_pff_CMAKE_FRAMEWORK_PATH}
                     ~/Library/Frameworks
                     /usr/local/Frameworks
                     ${CMAKE_SYSTEM_FRAMEWORK_PATH})
@@ -289,12 +290,16 @@
 function (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME)
   unset (${_PYTHON_PGCV_VALUE} PARENT_SCOPE)
 
-  if (NOT NAME MATCHES "^(PREFIX|ABIFLAGS|CONFIGDIR|INCLUDES|LIBS)$")
+  if (NOT NAME MATCHES "^(PREFIX|ABIFLAGS|CONFIGDIR|INCLUDES|LIBS|SOABI)$")
     return()
   endif()
 
   if (_${_PYTHON_PREFIX}_CONFIG)
-    set (config_flag "--${NAME}")
+    if (NAME STREQUAL "SOABI")
+      set (config_flag "--extension-suffix")
+    else()
+      set (config_flag "--${NAME}")
+    endif()
     string (TOLOWER "${config_flag}" config_flag)
     execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" ${config_flag}
                      RESULT_VARIABLE _result
@@ -309,6 +314,9 @@
         string (REGEX MATCHALL "(-I|-iwithsysroot)[ ]*[^ ]+" _values "${_values}")
         string (REGEX REPLACE "(-I|-iwithsysroot)[ ]*" "" _values "${_values}")
         list (REMOVE_DUPLICATES _values)
+      elseif (NAME STREQUAL "SOABI")
+        # clean-up: remove prefix character and suffix
+        string (REGEX REPLACE "^[.-](.+)(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.(so|pyd))$" "\\1" _values "${_values}")
       endif()
     endif()
   endif()
@@ -334,6 +342,25 @@
       if (_result)
         unset (_values)
       endif()
+    elseif (NAME STREQUAL "SOABI")
+      execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; from distutils import sysconfig;sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('EXT_SUFFIX') or '']))"
+                       RESULT_VARIABLE _result
+                       OUTPUT_VARIABLE _soabi
+                       ERROR_QUIET
+                       OUTPUT_STRIP_TRAILING_WHITESPACE)
+      if (_result)
+        unset (_values)
+      else()
+        list (GET _soabi 0 _values)
+        if (NOT _values)
+          # try to compute SOABI from EXT_SUFFIX
+          list (GET _soabi 1 _values)
+          if (_values)
+            # clean-up: remove prefix character and suffix
+            string (REGEX REPLACE "^[.-](.+)(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.(so|pyd))$" "\\1" _values "${_values}")
+          endif()
+        endif()
+      endif()
     else()
       set (config_flag "${NAME}")
       if (NAME STREQUAL "CONFIGDIR")
@@ -454,6 +481,7 @@
 
   if (_PVI_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_EXECUTABLE}")
     # interpreter does not exist anymore
+    set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot find the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
     return()
   endif()
@@ -472,6 +500,7 @@
     endif()
     if (NOT abi IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
       # incompatible ABI
+      set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong ABI for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
       set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
       return()
     endif()
@@ -487,9 +516,27 @@
                      OUTPUT_VARIABLE version
                      ERROR_QUIET
                      OUTPUT_STRIP_TRAILING_WHITESPACE)
-    if (result OR (_PVI_EXACT AND NOT version VERSION_EQUAL expected_version) OR (version VERSION_LESS expected_version))
-      # interpreter not usable or has wrong major version
+    if (result)
+      # interpreter is not usable
+      set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
       set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+    else()
+      if (_PVI_EXACT AND NOT version VERSION_EQUAL expected_version)
+        # interpreter has wrong version
+        set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+        set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+      else()
+        # check that version is OK
+        string(REGEX REPLACE "^([0-9]+)\\..*$" "\\1" major_version "${version}")
+        string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" expected_major_version "${expected_version}")
+        if (NOT major_version VERSION_EQUAL expected_major_version
+            OR NOT version VERSION_GREATER_EQUAL expected_version)
+          set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+          set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+        endif()
+      endif()
+    endif()
+    if (NOT _${_PYTHON_PREFIX}_EXECUTABLE)
       return()
     endif()
   else()
@@ -504,6 +551,11 @@
                        OUTPUT_STRIP_TRAILING_WHITESPACE)
       if (result OR NOT version EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
         # interpreter not usable or has wrong major version
+        if (result)
+          set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+        else()
+          set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong major version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+        endif()
         set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
         return()
       endif()
@@ -521,6 +573,11 @@
                      OUTPUT_STRIP_TRAILING_WHITESPACE)
     if (result OR NOT size EQUAL CMAKE_SIZEOF_VOID_P)
       # interpreter not usable or has wrong architecture
+      if (result)
+        set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+      else()
+        set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong architecture for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+      endif()
       set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
       return()
     endif()
@@ -545,6 +602,7 @@
 
   if (_PVC_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_COMPILER}")
     # Compiler does not exist anymore
+    set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Cannot find the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
     return()
   endif()
@@ -571,6 +629,11 @@
 
   if (result OR (_PVC_EXACT AND NOT version VERSION_EQUAL expected_version) OR (version VERSION_LESS expected_version))
     # Compiler not usable or has wrong version
+    if (result)
+      set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Cannot use the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
+    else()
+      set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
+    endif()
     set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
   endif()
 endfunction()
@@ -590,6 +653,7 @@
 
   if (_PVL_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
     # library does not exist anymore
+    set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
     if (WIN32)
       set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_DEBUG PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_DEBUG-NOTFOUND")
@@ -603,16 +667,19 @@
 
   if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT lib_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
     # incompatible ABI
+    set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong ABI for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
   else()
     if (expected_version)
       if ((_PVL_EXACT AND NOT lib_VERSION VERSION_EQUAL expected_version) OR (lib_VERSION VERSION_LESS expected_version))
         # library has wrong version
+        set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
         set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
       endif()
     else()
       if (NOT lib_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
         # library has wrong major version
+        set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong major version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
         set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
       endif()
     endif()
@@ -643,6 +710,7 @@
 
   if (_PVID_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}")
     # include file does not exist anymore
+    set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
     return()
   endif()
@@ -652,16 +720,19 @@
 
   if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT inc_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
     # incompatible ABI
+    set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong ABI for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
   else()
     if (expected_version)
       if ((_PVID_EXACT AND NOT inc_VERSION VERSION_EQUAL expected_version) OR (inc_VERSION VERSION_LESS expected_version))
         # include dir has wrong version
+        set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
         set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
       endif()
     else()
       if (NOT inc_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
         # include dir has wrong major version
+        set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong major version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
         set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
       endif()
     endif()
@@ -761,6 +832,7 @@
     _python_get_abiflags (_${_PYTHON_PREFIX}_ABIFLAGS)
   endif()
 endif()
+unset (${_PYTHON_PREFIX}_SOABI)
 
 # Define lookup strategy
 if (_${_PYTHON_PREFIX}_LOOKUP_POLICY STREQUAL "NEW")
@@ -850,8 +922,8 @@
   set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST")
 endif()
 
-# virtual environments handling
-if (DEFINED ENV{VIRTUAL_ENV})
+# virtual environments recognition
+if (DEFINED ENV{VIRTUAL_ENV} OR DEFINED ENV{CONDA_PREFIX})
   if (DEFINED ${_PYTHON_PREFIX}_FIND_VIRTUALENV)
     if (NOT ${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY|STANDARD)$")
       message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_VIRTUALENV}: invalid value for '${_PYTHON_PREFIX}_FIND_VIRTUALENV'. 'FIRST', 'ONLY' or 'STANDARD' expected. 'FIRST' will be used instead.")
@@ -883,6 +955,10 @@
 
 unset (_${_PYTHON_PREFIX}_REQUIRED_VARS)
 unset (_${_PYTHON_PREFIX}_CACHED_VARS)
+unset (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE)
+unset (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE)
+unset (_${_PYTHON_PREFIX}_Development_REASON_FAILURE)
+unset (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE)
 
 
 # first step, search for the interpreter
@@ -894,6 +970,10 @@
 
   if (DEFINED ${_PYTHON_PREFIX}_EXECUTABLE
       AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_EXECUTABLE}")
+    if (NOT ${_PYTHON_PREFIX}_EXECUTABLE STREQUAL _${_PYTHON_PREFIX}_EXECUTABLE)
+      # invalidate cache properties
+      unset (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES CACHE)
+    endif()
     set (_${_PYTHON_PREFIX}_EXECUTABLE "${${_PYTHON_PREFIX}_EXECUTABLE}" CACHE INTERNAL "")
   elseif (DEFINED _${_PYTHON_PREFIX}_EXECUTABLE)
     # compute interpreter signature and check validity of definition
@@ -907,7 +987,10 @@
       endif()
     else()
       unset (_${_PYTHON_PREFIX}_EXECUTABLE CACHE)
+    endif()
+    if (NOT _${_PYTHON_PREFIX}_EXECUTABLE)
       unset (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE CACHE)
+      unset (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES CACHE)
     endif()
   endif()
 
@@ -942,7 +1025,7 @@
                         NAMES ${_${_PYTHON_PREFIX}_NAMES}
                         NAMES_PER_DIR
                         HINTS ${_${_PYTHON_PREFIX}_HINTS}
-                        PATHS ENV VIRTUAL_ENV
+                        PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX
                         PATH_SUFFIXES bin Scripts
                         NO_CMAKE_PATH
                         NO_CMAKE_ENVIRONMENT_PATH
@@ -1062,7 +1145,7 @@
                         NAMES ${_${_PYTHON_PREFIX}_NAMES}
                         NAMES_PER_DIR
                         HINTS ${_${_PYTHON_PREFIX}_HINTS}
-                        PATHS ENV VIRTUAL_ENV
+                        PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX
                         PATH_SUFFIXES bin Scripts
                         NO_CMAKE_PATH
                         NO_CMAKE_ENVIRONMENT_PATH
@@ -1200,105 +1283,138 @@
                      OUTPUT_STRIP_TRAILING_WHITESPACE)
     if (NOT _${_PYTHON_PREFIX}_RESULT)
       set (_${_PYTHON_PREFIX}_EXECUTABLE_USABLE TRUE)
-      string (REGEX MATCHALL "[0-9]+" _${_PYTHON_PREFIX}_VERSIONS "${${_PYTHON_PREFIX}_VERSION}")
-      list (GET _${_PYTHON_PREFIX}_VERSIONS 0 ${_PYTHON_PREFIX}_VERSION_MAJOR)
-      list (GET _${_PYTHON_PREFIX}_VERSIONS 1 ${_PYTHON_PREFIX}_VERSION_MINOR)
-      list (GET _${_PYTHON_PREFIX}_VERSIONS 2 ${_PYTHON_PREFIX}_VERSION_PATCH)
     else()
       # Interpreter is not usable
       set (_${_PYTHON_PREFIX}_EXECUTABLE_USABLE FALSE)
       unset (${_PYTHON_PREFIX}_VERSION)
+      set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot run the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
     endif()
   endif()
 
-  if (_${_PYTHON_PREFIX}_EXECUTABLE AND _${_PYTHON_PREFIX}_EXECUTABLE_USABLE
-      AND ${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
-    set (${_PYTHON_PREFIX}_Interpreter_FOUND TRUE)
-    # Use interpreter version and ABI for future searches to ensure consistency
-    set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR})
-    execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; sys.stdout.write(sys.abiflags)"
-                     RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                     OUTPUT_VARIABLE _${_PYTHON_PREFIX}_ABIFLAGS
-                     ERROR_QUIET
-                     OUTPUT_STRIP_TRAILING_WHITESPACE)
-    if (_${_PYTHON_PREFIX}_RESULT)
-      # assunme ABI is not supported
-      set (_${_PYTHON_PREFIX}_ABIFLAGS "")
-    endif()
-  endif()
+  if (_${_PYTHON_PREFIX}_EXECUTABLE AND _${_PYTHON_PREFIX}_EXECUTABLE_USABLE)
+    if (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES)
+      set (${_PYTHON_PREFIX}_Interpreter_FOUND TRUE)
 
-  if (${_PYTHON_PREFIX}_Interpreter_FOUND)
-    # compute and save interpreter signature
-    string (MD5 __${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_EXECUTABLE}")
-    set (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${__${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}" CACHE INTERNAL "")
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 0 ${_PYTHON_PREFIX}_INTERPRETER_ID)
 
-    if (NOT CMAKE_SIZEOF_VOID_P)
-      # determine interpreter architecture
-      execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; print(sys.maxsize > 2**32)"
-                       RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                       OUTPUT_VARIABLE ${_PYTHON_PREFIX}_IS64BIT
-                       ERROR_VARIABLE ${_PYTHON_PREFIX}_IS64BIT)
-      if (NOT _${_PYTHON_PREFIX}_RESULT)
-        if (${_PYTHON_PREFIX}_IS64BIT)
-          set (_${_PYTHON_PREFIX}_ARCH 64)
-          set (_${_PYTHON_PREFIX}_ARCH2 64)
-        else()
-          set (_${_PYTHON_PREFIX}_ARCH 32)
-          set (_${_PYTHON_PREFIX}_ARCH2 32)
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 1 ${_PYTHON_PREFIX}_VERSION_MAJOR)
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 2 ${_PYTHON_PREFIX}_VERSION_MINOR)
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 3 ${_PYTHON_PREFIX}_VERSION_PATH)
+
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 4 _${_PYTHON_PREFIX}_ARCH)
+      set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH})
+
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 5 _${_PYTHON_PREFIX}_ABIFLAGS)
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 6 ${_PYTHON_PREFIX}_SOABI)
+
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 7 ${_PYTHON_PREFIX}_STDLIB)
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 8 ${_PYTHON_PREFIX}_STDARCH)
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 9 ${_PYTHON_PREFIX}_SITELIB)
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 10 ${_PYTHON_PREFIX}_SITEARCH)
+    else()
+      string (REGEX MATCHALL "[0-9]+" _${_PYTHON_PREFIX}_VERSIONS "${${_PYTHON_PREFIX}_VERSION}")
+      list (GET _${_PYTHON_PREFIX}_VERSIONS 0 ${_PYTHON_PREFIX}_VERSION_MAJOR)
+      list (GET _${_PYTHON_PREFIX}_VERSIONS 1 ${_PYTHON_PREFIX}_VERSION_MINOR)
+      list (GET _${_PYTHON_PREFIX}_VERSIONS 2 ${_PYTHON_PREFIX}_VERSION_PATCH)
+
+      if (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+        set (${_PYTHON_PREFIX}_Interpreter_FOUND TRUE)
+
+        # Use interpreter version and ABI for future searches to ensure consistency
+        set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR})
+        execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; sys.stdout.write(sys.abiflags)"
+                         RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                         OUTPUT_VARIABLE _${_PYTHON_PREFIX}_ABIFLAGS
+                         ERROR_QUIET
+                         OUTPUT_STRIP_TRAILING_WHITESPACE)
+        if (_${_PYTHON_PREFIX}_RESULT)
+          # assunme ABI is not supported
+          set (_${_PYTHON_PREFIX}_ABIFLAGS "")
         endif()
       endif()
-    endif()
 
-    # retrieve interpreter identity
-    execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -V
-                     RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                     OUTPUT_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID
-                     ERROR_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID)
-    if (NOT _${_PYTHON_PREFIX}_RESULT)
-      if (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "Anaconda")
-        set (${_PYTHON_PREFIX}_INTERPRETER_ID "Anaconda")
-      elseif (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "Enthought")
-        set (${_PYTHON_PREFIX}_INTERPRETER_ID "Canopy")
-      else()
-        string (REGEX REPLACE "^([^ ]+).*" "\\1" ${_PYTHON_PREFIX}_INTERPRETER_ID "${${_PYTHON_PREFIX}_INTERPRETER_ID}")
-        if (${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "Python")
-          # try to get a more precise ID
-          execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; print(sys.copyright)"
+      if (${_PYTHON_PREFIX}_Interpreter_FOUND)
+        # compute and save interpreter signature
+        string (MD5 __${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_EXECUTABLE}")
+        set (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${__${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}" CACHE INTERNAL "")
+
+        if (NOT CMAKE_SIZEOF_VOID_P)
+          # determine interpreter architecture
+          execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; print(sys.maxsize > 2**32)"
                            RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                           OUTPUT_VARIABLE ${_PYTHON_PREFIX}_COPYRIGHT
-                           ERROR_QUIET)
-          if (${_PYTHON_PREFIX}_COPYRIGHT MATCHES "ActiveState")
-            set (${_PYTHON_PREFIX}_INTERPRETER_ID "ActivePython")
+                           OUTPUT_VARIABLE ${_PYTHON_PREFIX}_IS64BIT
+                           ERROR_VARIABLE ${_PYTHON_PREFIX}_IS64BIT)
+          if (NOT _${_PYTHON_PREFIX}_RESULT)
+            if (${_PYTHON_PREFIX}_IS64BIT)
+              set (_${_PYTHON_PREFIX}_ARCH 64)
+              set (_${_PYTHON_PREFIX}_ARCH2 64)
+            else()
+              set (_${_PYTHON_PREFIX}_ARCH 32)
+              set (_${_PYTHON_PREFIX}_ARCH2 32)
+            endif()
           endif()
         endif()
+
+        # retrieve interpreter identity
+        execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -V
+                         RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                         OUTPUT_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID
+                         ERROR_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID)
+        if (NOT _${_PYTHON_PREFIX}_RESULT)
+          if (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "Anaconda")
+            set (${_PYTHON_PREFIX}_INTERPRETER_ID "Anaconda")
+          elseif (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "Enthought")
+            set (${_PYTHON_PREFIX}_INTERPRETER_ID "Canopy")
+          else()
+            string (REGEX REPLACE "^([^ ]+).*" "\\1" ${_PYTHON_PREFIX}_INTERPRETER_ID "${${_PYTHON_PREFIX}_INTERPRETER_ID}")
+            if (${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "Python")
+              # try to get a more precise ID
+              execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; print(sys.copyright)"
+                               RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                               OUTPUT_VARIABLE ${_PYTHON_PREFIX}_COPYRIGHT
+                               ERROR_QUIET)
+              if (${_PYTHON_PREFIX}_COPYRIGHT MATCHES "ActiveState")
+                set (${_PYTHON_PREFIX}_INTERPRETER_ID "ActivePython")
+              endif()
+            endif()
+          endif()
+        else()
+          set (${_PYTHON_PREFIX}_INTERPRETER_ID Python)
+        endif()
+
+        # retrieve various package installation directories
+        execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; from distutils import sysconfig;sys.stdout.write(';'.join([sysconfig.get_python_lib(plat_specific=False,standard_lib=True),sysconfig.get_python_lib(plat_specific=True,standard_lib=True),sysconfig.get_python_lib(plat_specific=False,standard_lib=False),sysconfig.get_python_lib(plat_specific=True,standard_lib=False)]))"
+                        RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                        OUTPUT_VARIABLE _${_PYTHON_PREFIX}_LIBPATHS
+                        ERROR_QUIET)
+        if (NOT _${_PYTHON_PREFIX}_RESULT)
+          list (GET _${_PYTHON_PREFIX}_LIBPATHS 0 ${_PYTHON_PREFIX}_STDLIB)
+          list (GET _${_PYTHON_PREFIX}_LIBPATHS 1 ${_PYTHON_PREFIX}_STDARCH)
+          list (GET _${_PYTHON_PREFIX}_LIBPATHS 2 ${_PYTHON_PREFIX}_SITELIB)
+          list (GET _${_PYTHON_PREFIX}_LIBPATHS 3 ${_PYTHON_PREFIX}_SITEARCH)
+        else()
+          unset (${_PYTHON_PREFIX}_STDLIB)
+          unset (${_PYTHON_PREFIX}_STDARCH)
+          unset (${_PYTHON_PREFIX}_SITELIB)
+          unset (${_PYTHON_PREFIX}_SITEARCH)
+        endif()
+
+        if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR VERSION_GREATER_EQUAL 3)
+          _python_get_config_var (${_PYTHON_PREFIX}_SOABI SOABI)
+        endif()
+
+        # store properties in the cache to speed-up future searches
+        set (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES
+          "${${_PYTHON_PREFIX}_INTERPRETER_ID};${${_PYTHON_PREFIX}_VERSION_MAJOR};${${_PYTHON_PREFIX}_VERSION_MINOR};${${_PYTHON_PREFIX}_VERSION_PATCH};${_${_PYTHON_PREFIX}_ARCH};${_${_PYTHON_PREFIX}_ABIFLAGS};${${_PYTHON_PREFIX}_SOABI};${${_PYTHON_PREFIX}_STDLIB};${${_PYTHON_PREFIX}_STDARCH};${${_PYTHON_PREFIX}_SITELIB};${${_PYTHON_PREFIX}_SITEARCH}" CACHE INTERNAL "${_PYTHON_PREFIX} Properties")
+      else()
+        unset (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE CACHE)
+        unset (${_PYTHON_PREFIX}_INTERPRETER_ID)
       endif()
-    else()
-      set (${_PYTHON_PREFIX}_INTERPRETER_ID Python)
     endif()
-
-    # retrieve various package installation directories
-    execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; from distutils import sysconfig;sys.stdout.write(';'.join([sysconfig.get_python_lib(plat_specific=False,standard_lib=True),sysconfig.get_python_lib(plat_specific=True,standard_lib=True),sysconfig.get_python_lib(plat_specific=False,standard_lib=False),sysconfig.get_python_lib(plat_specific=True,standard_lib=False)]))"
-
-                     RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                     OUTPUT_VARIABLE _${_PYTHON_PREFIX}_LIBPATHS
-                     ERROR_QUIET)
-    if (NOT _${_PYTHON_PREFIX}_RESULT)
-      list (GET _${_PYTHON_PREFIX}_LIBPATHS 0 ${_PYTHON_PREFIX}_STDLIB)
-      list (GET _${_PYTHON_PREFIX}_LIBPATHS 1 ${_PYTHON_PREFIX}_STDARCH)
-      list (GET _${_PYTHON_PREFIX}_LIBPATHS 2 ${_PYTHON_PREFIX}_SITELIB)
-      list (GET _${_PYTHON_PREFIX}_LIBPATHS 3 ${_PYTHON_PREFIX}_SITEARCH)
-    else()
-      unset (${_PYTHON_PREFIX}_STDLIB)
-      unset (${_PYTHON_PREFIX}_STDARCH)
-      unset (${_PYTHON_PREFIX}_SITELIB)
-      unset (${_PYTHON_PREFIX}_SITEARCH)
-    endif()
-  else()
-    unset (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE CACHE)
-    unset (${_PYTHON_PREFIX}_INTERPRETER_ID)
   endif()
 
   _python_mark_as_internal (_${_PYTHON_PREFIX}_EXECUTABLE
+                            _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES
                             _${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE)
 endif()
 
@@ -1463,6 +1579,7 @@
     else()
       # compiler not usable
       set (_${_PYTHON_PREFIX}_COMPILER_USABLE FALSE)
+      set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Cannot run the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
     endif()
     file (REMOVE_RECURSE "${_${_PYTHON_PREFIX}_VERSION_DIR}")
   endif()
@@ -1532,9 +1649,13 @@
       unset (_${_PYTHON_PREFIX}_LIBRARY_RELEASE CACHE)
       unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG CACHE)
       unset (_${_PYTHON_PREFIX}_INCLUDE_DIR CACHE)
-      unset (_${_PYTHON_PREFIX}_DEVELOPMENT_SIGNATURE CACHE)
     endif()
   endif()
+  if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE OR NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)
+    unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+    unset (_${_PYTHON_PREFIX}_DEVELOPMENT_SIGNATURE CACHE)
+  endif()
+
   if (DEFINED ${_PYTHON_PREFIX}_LIBRARY
       AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_LIBRARY}")
     set (_${_PYTHON_PREFIX}_LIBRARY_RELEASE "${${_PYTHON_PREFIX}_LIBRARY}" CACHE INTERNAL "")
@@ -1565,7 +1686,7 @@
       set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
       unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)
       if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
-        set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV)
+        set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)
       endif()
       unset (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS)
 
@@ -1796,7 +1917,7 @@
 
       unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)
       if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
-        set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV)
+        set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)
       endif()
 
       if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
@@ -1961,6 +2082,7 @@
   set (${_PYTHON_PREFIX}_LIBRARY_RELEASE "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
 
   if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE AND NOT EXISTS "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
+    set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
   endif()
 
@@ -2016,7 +2138,7 @@
     if (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)
       unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)
       if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
-        set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV)
+        set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)
       endif()
       unset (_${_PYTHON_PREFIX}_INCLUDE_HINTS)
 
@@ -2093,6 +2215,7 @@
   set (${_PYTHON_PREFIX}_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}")
 
   if (_${_PYTHON_PREFIX}_INCLUDE_DIR AND NOT EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}")
+    set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
   endif()
 
@@ -2158,6 +2281,11 @@
     endif()
   endif()
 
+  if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR VERSION_GREATER_EQUAL 3
+      AND NOT DEFINED ${_PYTHON_PREFIX}_SOABI)
+    _python_get_config_var (${_PYTHON_PREFIX}_SOABI SOABI)
+  endif()
+
   if (${_PYTHON_PREFIX}_Development_FOUND)
     # compute and save development signature
     string (MD5 __${_PYTHON_PREFIX}_DEVELOPMENT_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}:${_${_PYTHON_PREFIX}_INCLUDE_DIR}")
@@ -2176,6 +2304,7 @@
                             _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
                             _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG
                             _${_PYTHON_PREFIX}_INCLUDE_DIR
+                            _${_PYTHON_PREFIX}_CONFIG
                             _${_PYTHON_PREFIX}_DEVELOPMENT_SIGNATURE)
 endif()
 
@@ -2218,6 +2347,7 @@
   set (${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
 
   if(_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR AND NOT EXISTS "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
+    set (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE "Cannot find the directory \"${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR-NOTFOUND")
   endif()
 
@@ -2257,11 +2387,19 @@
   _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Found unsuitable major version \"${${_PYTHON_PREFIX}_VERSION_MAJOR}\", but required major version is exact version \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"")
 endif()
 
+unset (_${_PYTHON_PREFIX}_REASON_FAILURE)
+foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development NumPy)
+  if (_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE)
+    string (APPEND _${_PYTHON_PREFIX}_REASON_FAILURE "\n        ${_${_PYTHON_PREFIX}_COMPONENT}: ${_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE}")
+  endif()
+endforeach()
+
 include (${CMAKE_CURRENT_LIST_DIR}/../FindPackageHandleStandardArgs.cmake)
 find_package_handle_standard_args (${_PYTHON_PREFIX}
                                    REQUIRED_VARS ${_${_PYTHON_PREFIX}_REQUIRED_VARS}
                                    VERSION_VAR ${_PYTHON_PREFIX}_VERSION
-                                   HANDLE_COMPONENTS)
+                                   HANDLE_COMPONENTS
+                                   REASON_FAILURE_MESSAGE "${_${_PYTHON_PREFIX}_REASON_FAILURE}")
 
 # Create imported targets and helper functions
 if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
@@ -2377,15 +2515,21 @@
     #
     function (__${_PYTHON_PREFIX}_ADD_LIBRARY prefix name)
       cmake_parse_arguments (PARSE_ARGV 2 PYTHON_ADD_LIBRARY
-        "STATIC;SHARED;MODULE" "" "")
+        "STATIC;SHARED;MODULE;WITH_SOABI" "" "")
 
-      unset (type)
-      if (NOT (PYTHON_ADD_LIBRARY_STATIC
-            OR PYTHON_ADD_LIBRARY_SHARED
-            OR PYTHON_ADD_LIBRARY_MODULE))
+      if (prefix STREQUAL "Python2" AND PYTHON_ADD_LIBRARY_WITH_SOABI)
+        message (AUTHOR_WARNING "FindPython2: Option `WITH_SOABI` is not supported for Python2 and will be ignored.")
+        unset (PYTHON_ADD_LIBRARY_WITH_SOABI)
+      endif()
+
+      if (PYTHON_ADD_LIBRARY_STATIC)
+        set (type STATIC)
+      elseif (PYTHON_ADD_LIBRARY_SHARED)
+        set (type SHARED)
+      else()
         set (type MODULE)
       endif()
-      add_library (${name} ${type} ${ARGN})
+      add_library (${name} ${type} ${PYTHON_ADD_LIBRARY_UNPARSED_ARGUMENTS})
 
       get_property (type TARGET ${name} PROPERTY TYPE)
 
@@ -2396,7 +2540,18 @@
         if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
           set_property (TARGET ${name} PROPERTY SUFFIX ".pyd")
         endif()
+
+        if (PYTHON_ADD_LIBRARY_WITH_SOABI AND ${prefix}_SOABI)
+          get_property (suffix TARGET ${name} PROPERTY SUFFIX)
+          if (NOT suffix)
+            set (suffix "${CMAKE_SHARED_MODULE_SUFFIX}")
+          endif()
+          set_property (TARGET ${name} PROPERTY SUFFIX ".${${prefix}_SOABI}${suffix}")
+        endif()
       else()
+        if (PYTHON_ADD_LIBRARY_WITH_SOABI)
+          message (AUTHOR_WARNING "Find${prefix}: Option `WITH_SOABI` is only supported for `MODULE` library type.")
+        endif()
         target_link_libraries (${name} PRIVATE ${prefix}::Python)
       endif()
     endfunction()
@@ -2427,5 +2582,3 @@
 else()
   unset (CMAKE_FIND_FRAMEWORK)
 endif()
-
-unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
diff --git a/Modules/FindPython2.cmake b/Modules/FindPython2.cmake
index 3cc7d56..af8ad39 100644
--- a/Modules/FindPython2.cmake
+++ b/Modules/FindPython2.cmake
@@ -176,12 +176,12 @@
   variable will be used, if any.
 
 ``Python2_FIND_VIRTUALENV``
-  This variable defines the handling of virtual environments. It is meaningfull
-  only when a virtual environment is active (i.e. the ``activate`` script has
-  been evaluated). In this case, it takes precedence over
-  ``Python2_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK`` variables.
-  The ``Python2_FIND_VIRTUALENV`` variable can be set to empty or one of the
-  following:
+  This variable defines the handling of virtual environments managed by
+  ``virtualenv`` or ``conda``. It is meaningful only when a virtual environment
+  is active (i.e. the ``activate`` script has been evaluated). In this case, it
+  takes precedence over ``Python2_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK``
+  variables.  The ``Python2_FIND_VIRTUALENV`` variable can be set to empty or
+  one of the following:
 
   * ``FIRST``: The virtual environment is used before any other standard
     paths to look-up for the interpreter. This is the default.
@@ -240,13 +240,14 @@
 Commands
 ^^^^^^^^
 
-This module defines the command ``Python_add_library`` (when
+This module defines the command ``Python2_add_library`` (when
 :prop_gbl:`CMAKE_ROLE` is ``PROJECT``), which has the same semantics as
 :command:`add_library` and adds a dependency to target ``Python2::Python`` or,
 when library type is ``MODULE``, to target ``Python2::Module`` and takes care
 of Python module naming rules::
 
-  Python2_add_library (my_module MODULE src1.cpp)
+  Python2_add_library (<name> [STATIC | SHARED | MODULE]
+                       <source1> [<source2> ...])
 
 If library type is not specified, ``MODULE`` is assumed.
 #]=======================================================================]
diff --git a/Modules/FindPython3.cmake b/Modules/FindPython3.cmake
index 066d0df..66f4f75 100644
--- a/Modules/FindPython3.cmake
+++ b/Modules/FindPython3.cmake
@@ -94,6 +94,13 @@
 
   Information returned by
   ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=False)``.
+``Python3_SOABI``
+  Extension suffix for modules.
+
+  Information returned by
+  ``distutils.sysconfig.get_config_flag('SOABI')`` or computed from
+  ``distutils.sysconfig.get_config_flag('EXT_SUFFIX')`` or
+  ``python3-config --extension-suffix``.
 ``Python3_Compiler_FOUND``
   System has the Python 3 compiler.
 ``Python3_COMPILER``
@@ -217,12 +224,12 @@
   variable will be used, if any.
 
 ``Python3_FIND_VIRTUALENV``
-  This variable defines the handling of virtual environments. It is meaningfull
-  only when a virtual environment is active (i.e. the ``activate`` script has
-  been evaluated). In this case, it takes precedence over
-  ``Python3_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK`` variables.
-  The ``Python3_FIND_VIRTUALENV`` variable can be set to empty or one of the
-  following:
+  This variable defines the handling of virtual environments managed by
+  ``virtualenv`` or ``conda``. It is meaningful only when a virtual environment
+  is active (i.e. the ``activate`` script has been evaluated). In this case, it
+  takes precedence over ``Python3_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK``
+  variables.  The ``Python3_FIND_VIRTUALENV`` variable can be set to empty or
+  one of the following:
 
   * ``FIRST``: The virtual environment is used before any other standard
     paths to look-up for the interpreter. This is the default.
@@ -281,15 +288,19 @@
 Commands
 ^^^^^^^^
 
-This module defines the command ``Python_add_library`` (when
+This module defines the command ``Python3_add_library`` (when
 :prop_gbl:`CMAKE_ROLE` is ``PROJECT``), which has the same semantics as
 :command:`add_library` and adds a dependency to target ``Python3::Python`` or,
 when library type is ``MODULE``, to target ``Python3::Module`` and takes care
 of Python module naming rules::
 
-  Python3_add_library (my_module MODULE src1.cpp)
+  Python3_add_library (<name> [STATIC | SHARED | MODULE [WITH_SOABI]]
+                       <source1> [<source2> ...])
 
-If library type is not specified, ``MODULE`` is assumed.
+If the library type is not specified, ``MODULE`` is assumed.
+
+For ``MODULE`` library type, if option ``WITH_SOABI`` is specified, the
+module suffix will include the ``Python3_SOABI`` value, if any.
 #]=======================================================================]
 
 
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/FindThreads.cmake b/Modules/FindThreads.cmake
index b0c91b2..f97e5c8 100644
--- a/Modules/FindThreads.cmake
+++ b/Modules/FindThreads.cmake
@@ -7,31 +7,44 @@
 
 This module determines the thread library of the system.
 
-The following variables are set
+Imported Targets
+^^^^^^^^^^^^^^^^
 
-::
+This module defines the following :prop_tgt:`IMPORTED` target:
 
-  CMAKE_THREAD_LIBS_INIT     - the thread library
-  CMAKE_USE_WIN32_THREADS_INIT - using WIN32 threads?
-  CMAKE_USE_PTHREADS_INIT    - are we using pthreads
-  CMAKE_HP_PTHREADS_INIT     - are we using hp pthreads
+``Threads::Threads``
+  The thread library, if found.
 
-The following import target is created
+Result Variables
+^^^^^^^^^^^^^^^^
 
-::
+The following variables are set:
 
-  Threads::Threads
+``Threads_FOUND``
+  If a supported thread library was found.
+``CMAKE_THREAD_LIBS_INIT``
+  The thread library to use. This may be empty if the thread functions
+  are provided by the system libraries and no special flags are needed
+  to use them.
+``CMAKE_USE_WIN32_THREADS_INIT``
+  If the found thread library is the win32 one.
+``CMAKE_USE_PTHREADS_INIT``
+  If the found thread library is pthread compatible.
+``CMAKE_HP_PTHREADS_INIT``
+  If the found thread library is the HP thread library.
 
-If the use of the -pthread compiler and linker flag is preferred then the
-caller can set
+Variables Affecting Behavior
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-::
+.. variable:: THREADS_PREFER_PTHREAD_FLAG
 
-  THREADS_PREFER_PTHREAD_FLAG
+  If the use of the -pthread compiler and linker flag is preferred then
+  the caller can set this variable to TRUE. The compiler flag can only be
+  used with the imported target. Use of both the imported target as well
+  as this switch is highly recommended for new code.
 
-The compiler flag can only be used with the imported
-target. Use of both the imported target as well as this switch is highly
-recommended for new code.
+  This variable has no effect if the system libraries provide the
+  thread functions, i.e. when ``CMAKE_THREAD_LIBS_INIT`` will be empty.
 #]=======================================================================]
 
 include (CheckLibraryExists)
@@ -63,6 +76,7 @@
   pthread_t thread;
   pthread_create(&thread, NULL, test_func, NULL);
   pthread_detach(thread);
+  pthread_cancel(thread);
   pthread_join(thread, NULL);
   pthread_atfork(NULL, NULL, NULL);
   pthread_exit(NULL);
@@ -90,7 +104,7 @@
   if(NOT Threads_FOUND)
     # If we did not found -lpthread, -lpthread, or -lthread, look for -pthread
     if(NOT DEFINED THREADS_HAVE_PTHREAD_ARG)
-      message(STATUS "Check if compiler accepts -pthread")
+      message(CHECK_START "Check if compiler accepts -pthread")
       if(CMAKE_C_COMPILER_LOADED)
         set(_threads_src ${CMAKE_CURRENT_LIST_DIR}/CheckForPthreads.c)
       elseif(CMAKE_CXX_COMPILER_LOADED)
@@ -106,9 +120,9 @@
 
       if(THREADS_HAVE_PTHREAD_ARG)
         set(Threads_FOUND TRUE)
-        message(STATUS "Check if compiler accepts -pthread - yes")
+        message(CHECK_PASS "yes")
       else()
-        message(STATUS "Check if compiler accepts -pthread - no")
+        message(CHECK_FAIL "no")
         file(APPEND
           ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
           "Determining if compiler accepts -pthread failed with the following output:\n${OUTPUT}\n\n")
diff --git a/Modules/FortranCInterface.cmake b/Modules/FortranCInterface.cmake
index 893a96f..547346b 100644
--- a/Modules/FortranCInterface.cmake
+++ b/Modules/FortranCInterface.cmake
@@ -341,7 +341,7 @@
   # Build the verification project if not yet built.
   if(NOT DEFINED FortranCInterface_VERIFIED_${lang})
     set(_desc "Verifying Fortran/${lang} Compiler Compatibility")
-    message(STATUS "${_desc}")
+    message(CHECK_START "${_desc}")
 
     # Build a sample project which reports symbols.
     set(CMAKE_TRY_COMPILE_CONFIGURATION Release)
@@ -363,12 +363,12 @@
 
     # Report results.
     if(FortranCInterface_VERIFY_${lang}_COMPILED)
-      message(STATUS "${_desc} - Success")
+      message(CHECK_PASS "Success")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "${_desc} passed with the following output:\n${_output}\n\n")
       set(FortranCInterface_VERIFIED_${lang} 1 CACHE INTERNAL "Fortran/${lang} compatibility")
     else()
-      message(STATUS "${_desc} - Failed")
+      message(CHECK_FAIL "Failed")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "${_desc} failed with the following output:\n${_output}\n\n")
       set(FortranCInterface_VERIFIED_${lang} 0 CACHE INTERNAL "Fortran/${lang} compatibility")
diff --git a/Modules/FortranCInterface/Detect.cmake b/Modules/FortranCInterface/Detect.cmake
index 7789785..33de6c6 100644
--- a/Modules/FortranCInterface/Detect.cmake
+++ b/Modules/FortranCInterface/Detect.cmake
@@ -15,7 +15,7 @@
     OR ${CMAKE_CURRENT_LIST_FILE}
     IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake
     )
-  message(STATUS "Detecting Fortran/C Interface")
+  message(CHECK_START "Detecting Fortran/C Interface")
 else()
   return()
 endif()
@@ -172,7 +172,9 @@
   else()
     set(_result "Found GLOBAL but not MODULE mangling")
   endif()
+  set(_result_type CHECK_PASS)
 elseif(NOT _result)
   set(_result "Failed to recognize symbols")
+  set(_result_type CHECK_FAIL)
 endif()
-message(STATUS "Detecting Fortran/C Interface - ${_result}")
+message(${_result_type} "${_result}")
diff --git a/Modules/GNUInstallDirs.cmake b/Modules/GNUInstallDirs.cmake
index f95e6e2..9ef22b9 100644
--- a/Modules/GNUInstallDirs.cmake
+++ b/Modules/GNUInstallDirs.cmake
@@ -221,6 +221,11 @@
     # default one. When CMAKE_INSTALL_PREFIX changes, the value is
     # updated to the new default, unless the user explicitly changed it.
   endif()
+  if (NOT DEFINED CMAKE_SYSTEM_NAME OR NOT DEFINED CMAKE_SIZEOF_VOID_P)
+    message(AUTHOR_WARNING
+      "Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
+      "Please enable at least one language before including GNUInstallDirs.")
+  endif()
   if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$"
       AND NOT CMAKE_CROSSCOMPILING
       AND NOT EXISTS "/etc/arch-release")
@@ -235,16 +240,10 @@
         endif()
       endif()
     else() # not debian, rely on CMAKE_SIZEOF_VOID_P:
-      if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
-        message(AUTHOR_WARNING
-          "Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
-          "Please enable at least one language before including GNUInstallDirs.")
-      else()
-        if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
-          set(_LIBDIR_DEFAULT "lib64")
-          if(DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX)
-            set(__LAST_LIBDIR_DEFAULT "lib64")
-          endif()
+      if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
+        set(_LIBDIR_DEFAULT "lib64")
+        if(DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX)
+          set(__LAST_LIBDIR_DEFAULT "lib64")
         endif()
       endif()
     endif()
diff --git a/Modules/GetPrerequisites.cmake b/Modules/GetPrerequisites.cmake
index 57ae446..5c8c196 100644
--- a/Modules/GetPrerequisites.cmake
+++ b/Modules/GetPrerequisites.cmake
@@ -531,7 +531,7 @@
       string(TOLOWER "$ENV{windir}" windir)
       file(TO_CMAKE_PATH "${windir}" windir)
 
-      if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*(msvc|api-ms-win-)[^/]+dll)")
+      if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*(msvc|api-ms-win-|vcruntime)[^/]+dll)")
         set(is_system 1)
       endif()
 
@@ -559,7 +559,7 @@
           string(TOLOWER "${env_windir}" windir)
           string(TOLOWER "${env_sysdir}" sysroot)
 
-          if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*(msvc|api-ms-win-)[^/]+dll)")
+          if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*(msvc|api-ms-win-|vcruntime)[^/]+dll)")
             set(is_system 1)
           endif()
         endif()
@@ -601,7 +601,7 @@
 
   if(NOT is_embedded)
     if(NOT IS_ABSOLUTE "${resolved_file}")
-      if(lower MATCHES "^(msvc|api-ms-win-)[^/]+dll" AND is_system)
+      if(lower MATCHES "^(msvc|api-ms-win-|vcruntime)[^/]+dll" AND is_system)
         message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'")
       else()
         message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect")
diff --git a/Modules/Internal/CPack/CPackDeb.cmake b/Modules/Internal/CPack/CPackDeb.cmake
index 97906ca..14bb104 100644
--- a/Modules/Internal/CPack/CPackDeb.cmake
+++ b/Modules/Internal/CPack/CPackDeb.cmake
@@ -554,8 +554,8 @@
   )
 
   # Homepage: (optional)
-  if(NOT CPACK_DEBIAN_PACKAGE_HOMEPAGE AND CMAKE_PROJECT_HOMEPAGE_URL)
-    set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "${CMAKE_PROJECT_HOMEPAGE_URL}")
+  if(NOT CPACK_DEBIAN_PACKAGE_HOMEPAGE AND CPACK_PACKAGE_HOMEPAGE_URL)
+    set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "${CPACK_PACKAGE_HOMEPAGE_URL}")
   endif()
 
   # Section: (recommended)
diff --git a/Modules/Internal/CPack/CPackFreeBSD.cmake b/Modules/Internal/CPack/CPackFreeBSD.cmake
index 16f906c..ae40532 100644
--- a/Modules/Internal/CPack/CPackFreeBSD.cmake
+++ b/Modules/Internal/CPack/CPackFreeBSD.cmake
@@ -68,7 +68,7 @@
 # There's really only one homepage for a project, so
 # re-use the Debian setting if it's there.
 _cpack_freebsd_fallback_var("CPACK_FREEBSD_PACKAGE_WWW"
-    "CMAKE_PROJECT_HOMEPAGE_URL"
+    "CPACK_PACKAGE_HOMEPAGE_URL"
     "CPACK_DEBIAN_PACKAGE_HOMEPAGE"
     "_cpack_freebsd_fallback_www"
     )
diff --git a/Modules/Internal/CPack/CPackNuGet.cmake b/Modules/Internal/CPack/CPackNuGet.cmake
index 82053b2..1f4bcfd 100644
--- a/Modules/Internal/CPack/CPackNuGet.cmake
+++ b/Modules/Internal/CPack/CPackNuGet.cmake
@@ -230,31 +230,22 @@
     foreach(_dep IN LISTS _deps)
         _cpack_nuget_debug("  checking dependency `${_dep}`")
 
-        string(MAKE_C_IDENTIFIER "${_dep}" _dep_id)
-
-        _cpack_nuget_variable_fallback(_ver DEPENDENCIES_${_dep_id}_VERSION)
+        _cpack_nuget_variable_fallback(_ver DEPENDENCIES_${_dep}_VERSION)
 
         if(NOT _ver)
-            string(TOUPPER "${_dep_id}" _dep_id)
-            _cpack_nuget_variable_fallback(_ver DEPENDENCIES_${_dep_id}_VERSION)
+            string(TOUPPER "${_dep}" _dep_upper)
+            _cpack_nuget_variable_fallback(_ver DEPENDENCIES_${_dep_upper}_VERSION)
         endif()
 
         if(_ver)
             _cpack_nuget_debug("  got `${_dep}` dependency version ${_ver}")
-            list(APPEND _collected_deps "<dependency id=\"${_dep}\" version=\"${_ver}\" />")
+            string(CONCAT _collected_deps "${_collected_deps}" "            <dependency id=\"${_dep}\" version=\"${_ver}\" />\n")
         endif()
     endforeach()
 
     # Render deps into the variable
     if(_collected_deps)
-        set(_CPACK_NUGET_DEPENDENCIES_TAG "<dependencies>\n")
-        foreach(_line IN LISTS _collected_deps)
-            string(
-                APPEND _CPACK_NUGET_DEPENDENCIES_TAG
-                "            ${_line}\n"
-              )
-        endforeach()
-        string(APPEND _CPACK_NUGET_DEPENDENCIES_TAG "        </dependencies>")
+        string(CONCAT _CPACK_NUGET_DEPENDENCIES_TAG "<dependencies>\n" "${_collected_deps}" "        </dependencies>")
     endif()
 
     # Render the spec file
diff --git a/Modules/Internal/CPack/CPackRPM.cmake b/Modules/Internal/CPack/CPackRPM.cmake
index ffb24e2..3485e7d 100644
--- a/Modules/Internal/CPack/CPackRPM.cmake
+++ b/Modules/Internal/CPack/CPackRPM.cmake
@@ -844,8 +844,8 @@
     endif()
   endif()
 
-  if(NOT CPACK_RPM_PACKAGE_URL AND CMAKE_PROJECT_HOMEPAGE_URL)
-    set(CPACK_RPM_PACKAGE_URL "${CMAKE_PROJECT_HOMEPAGE_URL}")
+  if(NOT CPACK_RPM_PACKAGE_URL AND CPACK_PACKAGE_HOMEPAGE_URL)
+    set(CPACK_RPM_PACKAGE_URL "${CPACK_PACKAGE_HOMEPAGE_URL}")
   endif()
 
   # CPACK_RPM_PACKAGE_NAME (mandatory)
diff --git a/Modules/Internal/CPack/NSIS.template.in b/Modules/Internal/CPack/NSIS.template.in
index f75ae78..660bfa3 100644
--- a/Modules/Internal/CPack/NSIS.template.in
+++ b/Modules/Internal/CPack/NSIS.template.in
@@ -524,14 +524,6 @@
 !endif
 
 ;--------------------------------
-; Installation types
-@CPACK_NSIS_INSTALLATION_TYPES@
-
-;--------------------------------
-; Component sections
-@CPACK_NSIS_COMPONENT_SECTIONS@
-
-;--------------------------------
 ; Define some macro setting for the gui
 @CPACK_NSIS_INSTALLER_MUI_ICON_CODE@
 @CPACK_NSIS_INSTALLER_ICON_CODE@
@@ -542,6 +534,8 @@
 
 ;--------------------------------
 ;Pages
+  @CPACK_NSIS_INSTALLER_WELCOME_TITLE_CODE@
+  @CPACK_NSIS_INSTALLER_WELCOME_TITLE_3LINES_CODE@
   !insertmacro MUI_PAGE_WELCOME
 
   !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@"
@@ -557,6 +551,8 @@
   @CPACK_NSIS_PAGE_COMPONENTS@
 
   !insertmacro MUI_PAGE_INSTFILES
+  @CPACK_NSIS_INSTALLER_FINISH_TITLE_CODE@
+  @CPACK_NSIS_INSTALLER_FINISH_TITLE_3LINES_CODE@
   !insertmacro MUI_PAGE_FINISH
 
   !insertmacro MUI_UNPAGE_CONFIRM
@@ -617,7 +613,6 @@
   !insertmacro MUI_LANGUAGE "Ukrainian"
   !insertmacro MUI_LANGUAGE "Welsh"
 
-
 ;--------------------------------
 ;Reserve Files
 
@@ -628,6 +623,17 @@
   ReserveFile "NSIS.InstallOptions.ini"
   !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
 
+  ; for UserInfo::GetName and UserInfo::GetAccountType
+  ReserveFile /plugin 'UserInfo.dll'
+
+;--------------------------------
+; Installation types
+@CPACK_NSIS_INSTALLATION_TYPES@
+
+;--------------------------------
+; Component sections
+@CPACK_NSIS_COMPONENT_SECTIONS@
+
 ;--------------------------------
 ;Installer Sections
 
@@ -642,7 +648,7 @@
   WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR
 
   ;Create uninstaller
-  WriteUninstaller "$INSTDIR\Uninstall.exe"
+  WriteUninstaller "$INSTDIR\@CPACK_NSIS_UNINSTALL_NAME@.exe"
   Push "DisplayName"
   Push "@CPACK_NSIS_DISPLAY_NAME@"
   Call ConditionalAddToRegisty
@@ -653,7 +659,7 @@
   Push "@CPACK_PACKAGE_VENDOR@"
   Call ConditionalAddToRegisty
   Push "UninstallString"
-  Push "$INSTDIR\Uninstall.exe"
+  Push "$INSTDIR\@CPACK_NSIS_UNINSTALL_NAME@.exe"
   Call ConditionalAddToRegisty
   Push "NoRepair"
   Push "1"
@@ -690,7 +696,7 @@
   CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
 @CPACK_NSIS_CREATE_ICONS@
 @CPACK_NSIS_CREATE_ICONS_EXTRA@
-  CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
+  CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\@CPACK_NSIS_UNINSTALL_NAME@.exe"
 
   ;Read a value from an InstallOptions INI file
   !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State"
@@ -829,7 +835,7 @@
 !endif
 
   ;Remove the uninstaller itself.
-  Delete "$INSTDIR\Uninstall.exe"
+  Delete "$INSTDIR\@CPACK_NSIS_UNINSTALL_NAME@.exe"
   DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
 
   ;Remove the installation directory if it is empty.
diff --git a/Modules/Internal/FeatureTesting.cmake b/Modules/Internal/FeatureTesting.cmake
index 75be473..72d96b3 100644
--- a/Modules/Internal/FeatureTesting.cmake
+++ b/Modules/Internal/FeatureTesting.cmake
@@ -89,6 +89,16 @@
   unset(lang_level_has_features)
 endmacro()
 
+macro(_record_compiler_features_cuda std)
+  list(APPEND CMAKE_CUDA${std}_COMPILE_FEATURES cuda_std_${std})
+
+  get_property(lang_level_has_features GLOBAL PROPERTY CMAKE_CUDA${std}_KNOWN_FEATURES)
+  if(lang_level_has_features)
+    _record_compiler_features(CUDA "${CMAKE_CUDA${std}_STANDARD_COMPILE_OPTION}" CMAKE_CUDA${std}_COMPILE_FEATURES)
+  endif()
+  unset(lang_level_has_features)
+endmacro()
+
 macro(_has_compiler_features lang level compile_flags feature_list)
   # presume all known features are supported
   get_property(known_features GLOBAL PROPERTY CMAKE_${lang}${level}_KNOWN_FEATURES)
@@ -103,3 +113,7 @@
   list(APPEND CMAKE_CXX${std}_COMPILE_FEATURES cxx_std_${std})
   _has_compiler_features(CXX ${std} "${CMAKE_CXX${std}_STANDARD_COMPILE_OPTION}" CMAKE_CXX${std}_COMPILE_FEATURES)
 endmacro()
+macro(_has_compiler_features_cuda std)
+  list(APPEND CMAKE_CUDA${std}_COMPILE_FEATURES cuda_std_${std})
+  _has_compiler_features(CUDA ${std} "${CMAKE_CUDA${std}_STANDARD_COMPILE_OPTION}" CMAKE_CUDA${std}_COMPILE_FEATURES)
+endmacro()
diff --git a/Modules/Platform/AIX-GNU.cmake b/Modules/Platform/AIX-GNU.cmake
index 61d213a..5a532c7 100644
--- a/Modules/Platform/AIX-GNU.cmake
+++ b/Modules/Platform/AIX-GNU.cmake
@@ -23,11 +23,11 @@
   # Construct the export list ourselves to pass only the object files so
   # that we export only the symbols actually provided by the sources.
   set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
-    "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/objects.exp <OBJECTS>"
-    "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/objects.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
+    "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/exports.exp <AIX_EXPORTS> <OBJECTS>"
+    "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/exports.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
     )
 
   set(CMAKE_${lang}_LINK_EXECUTABLE_WITH_EXPORTS
-    "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -l . <OBJECTS>"
+    "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -l . <AIX_EXPORTS> <OBJECTS>"
     "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> -Wl,-bE:<TARGET_IMPLIB> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 endmacro()
diff --git a/Modules/Platform/AIX-XL.cmake b/Modules/Platform/AIX-XL.cmake
index 2a67c4f..2a8c159 100644
--- a/Modules/Platform/AIX-XL.cmake
+++ b/Modules/Platform/AIX-XL.cmake
@@ -29,12 +29,12 @@
   # Construct the export list ourselves to pass only the object files so
   # that we export only the symbols actually provided by the sources.
   set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
-    "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/objects.exp${_OBJECTS}"
-    "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/objects.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
+    "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/exports.exp <AIX_EXPORTS>${_OBJECTS}"
+    "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/exports.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
     )
 
   set(CMAKE_${lang}_LINK_EXECUTABLE_WITH_EXPORTS
-    "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -l . <OBJECTS>"
+    "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -l . <AIX_EXPORTS> <OBJECTS>"
     "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> -Wl,-bE:<TARGET_IMPLIB> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 
   unset(_OBJECTS)
diff --git a/Modules/Platform/AIX/ExportImportList b/Modules/Platform/AIX/ExportImportList
index 4f67ef5..891bce7 100755
--- a/Modules/Platform/AIX/ExportImportList
+++ b/Modules/Platform/AIX/ExportImportList
@@ -5,7 +5,7 @@
 # This script is internal to CMake and meant only to be
 # invoked by CMake-generated build systems on AIX.
 
-usage='usage: ExportImportList -o <out-file> [-l <lib>] [--] <objects>...'
+usage='usage: ExportImportList -o <out-file> [-l <lib>] [-n] [--] <objects>...'
 
 die() {
     echo "$@" 1>&2; exit 1
@@ -14,10 +14,12 @@
 # Process command-line arguments.
 out=''
 lib=''
+no_objects=''
 while test "$#" != 0; do
     case "$1" in
     -l) shift; lib="$1" ;;
     -o) shift; out="$1" ;;
+    -n) no_objects='1' ;;
     --) shift; break ;;
     -*) die "$usage" ;;
     *)  break ;;
@@ -26,23 +28,28 @@
 done
 test -n "$out" || die "$usage"
 
-# Collect symbols exported from all object files.
+# Build a temporary file that atomically replaces the output later.
 out_tmp="$out.tmp$$"
 trap 'rm -f "$out_tmp"' EXIT INT TERM
-for f in "$@"; do
-    dump -tov -X 32_64 "$f" |
-    awk '
-        BEGIN {
-            V["EXPORTED"]=" export"
-            V["PROTECTED"]=" protected"
-        }
-        /^\[[0-9]+\]\tm +[^ ]+ +\.(text|data|bss) +[^ ]+ +(extern|weak) +(EXPORTED|PROTECTED| ) / {
-            if (!match($NF,/^(\.|__sinit|__sterm|__[0-9]+__)/)) {
-                print $NF V[$(NF-1)]
+> "$out_tmp"
+
+# Collect symbols exported from all object files.
+if test -z "$no_objects"; then
+    for f in "$@"; do
+        dump -tov -X 32_64 "$f" |
+        awk '
+            BEGIN {
+                V["EXPORTED"]=" export"
+                V["PROTECTED"]=" protected"
             }
-        }
-    '
-done > "$out_tmp"
+            /^\[[0-9]+\]\tm +[^ ]+ +\.(text|data|bss) +[^ ]+ +(extern|weak) +(EXPORTED|PROTECTED| ) / {
+                if (!match($NF,/^(\.|__sinit|__sterm|__[0-9]+__)/)) {
+                    print $NF V[$(NF-1)]
+                }
+            }
+        '
+    done >> "$out_tmp"
+fi
 
 # Generate the export/import file.
 {
diff --git a/Modules/Platform/Android-Clang.cmake b/Modules/Platform/Android-Clang.cmake
index 847178f..759448b 100644
--- a/Modules/Platform/Android-Clang.cmake
+++ b/Modules/Platform/Android-Clang.cmake
@@ -24,6 +24,14 @@
   return()
 endif()
 
+# Natively compiling on an Android host doesn't use the NDK cross-compilation
+# tools.
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Android")
+  macro(__android_compiler_clang lang)
+  endmacro()
+  return()
+endif()
+
 include(Platform/Android-Common)
 
 # The NDK toolchain configuration files at:
diff --git a/Modules/Platform/Android-Determine.cmake b/Modules/Platform/Android-Determine.cmake
index e7c1b48..2225897 100644
--- a/Modules/Platform/Android-Determine.cmake
+++ b/Modules/Platform/Android-Determine.cmake
@@ -18,6 +18,12 @@
   return()
 endif()
 
+# Natively compiling on an Android host doesn't use the NDK cross-compilation
+# tools.
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Android")
+  return()
+endif()
+
 cmake_policy(PUSH)
 cmake_policy(SET CMP0057 NEW) # if IN_LIST
 
diff --git a/Modules/Platform/Android-Initialize.cmake b/Modules/Platform/Android-Initialize.cmake
index a5d2820..b90dd7a 100644
--- a/Modules/Platform/Android-Initialize.cmake
+++ b/Modules/Platform/Android-Initialize.cmake
@@ -24,6 +24,12 @@
   return()
 endif()
 
+# Natively compiling on an Android host doesn't use the NDK cross-compilation
+# tools.
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Android")
+  return()
+endif()
+
 if(NOT CMAKE_SYSROOT)
   if(CMAKE_ANDROID_NDK)
     set(CMAKE_SYSROOT "${CMAKE_ANDROID_NDK}/platforms/android-${CMAKE_SYSTEM_VERSION}/arch-${CMAKE_ANDROID_ARCH}")
diff --git a/Modules/Platform/Android.cmake b/Modules/Platform/Android.cmake
index f08f841..8ffa1b2 100644
--- a/Modules/Platform/Android.cmake
+++ b/Modules/Platform/Android.cmake
@@ -2,6 +2,11 @@
 
 set(ANDROID 1)
 
+# Natively compiling on an Android host doesn't need these flags to be reset.
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Android")
+  return()
+endif()
+
 # Conventionally Android does not use versioned soname
 # But in modern versions it is acceptable
 if(NOT DEFINED CMAKE_PLATFORM_NO_VERSIONED_SONAME)
diff --git a/Modules/Platform/Android/Determine-Compiler.cmake b/Modules/Platform/Android/Determine-Compiler.cmake
index 5c6b97b..f9c2d89 100644
--- a/Modules/Platform/Android/Determine-Compiler.cmake
+++ b/Modules/Platform/Android/Determine-Compiler.cmake
@@ -31,6 +31,16 @@
   set(_ANDROID_HOST_EXT "")
 elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
   set(_ANDROID_HOST_EXT ".exe")
+elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Android")
+  # Natively compiling on an Android host doesn't use the NDK cross-compilation
+  # tools.
+  macro(__android_determine_compiler lang)
+    # Do nothing
+  endmacro()
+  if(NOT CMAKE_CXX_COMPILER_NAMES)
+    set(CMAKE_CXX_COMPILER_NAMES c++)
+  endif()
+  return()
 else()
   message(FATAL_ERROR "Android: Builds hosted on '${CMAKE_HOST_SYSTEM_NAME}' not supported.")
 endif()
diff --git a/Modules/Platform/Apple-GNU.cmake b/Modules/Platform/Apple-GNU.cmake
index 0eb8168..9572736 100644
--- a/Modules/Platform/Apple-GNU.cmake
+++ b/Modules/Platform/Apple-GNU.cmake
@@ -19,17 +19,17 @@
 macro(cmake_gnu_set_sysroot_flag lang)
   if(NOT DEFINED CMAKE_${lang}_SYSROOT_FLAG)
     set(_doc "${lang} compiler has -isysroot")
-    message(STATUS "Checking whether ${_doc}")
+    message(CHECK_START "Checking whether ${_doc}")
     execute_process(
       COMMAND ${CMAKE_${lang}_COMPILER} "-v" "--help"
       OUTPUT_VARIABLE _gcc_help
       ERROR_VARIABLE _gcc_help
       )
     if("${_gcc_help}" MATCHES "isysroot")
-      message(STATUS "Checking whether ${_doc} - yes")
+      message(CHECK_PASS "yes")
       set(CMAKE_${lang}_SYSROOT_FLAG "-isysroot")
     else()
-      message(STATUS "Checking whether ${_doc} - no")
+      message(CHECK_FAIL "no")
       set(CMAKE_${lang}_SYSROOT_FLAG "")
     endif()
     set(CMAKE_${lang}_SYSROOT_FLAG_CODE "set(CMAKE_${lang}_SYSROOT_FLAG \"${CMAKE_${lang}_SYSROOT_FLAG}\")")
@@ -39,17 +39,17 @@
 macro(cmake_gnu_set_osx_deployment_target_flag lang)
   if(NOT DEFINED CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG)
     set(_doc "${lang} compiler supports OSX deployment target flag")
-    message(STATUS "Checking whether ${_doc}")
+    message(CHECK_START "Checking whether ${_doc}")
     execute_process(
       COMMAND ${CMAKE_${lang}_COMPILER} "-v" "--help"
       OUTPUT_VARIABLE _gcc_help
       ERROR_VARIABLE _gcc_help
       )
     if("${_gcc_help}" MATCHES "macosx-version-min")
-      message(STATUS "Checking whether ${_doc} - yes")
+      message(CHECK_PASS "yes")
       set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG "-mmacosx-version-min=")
     else()
-      message(STATUS "Checking whether ${_doc} - no")
+      message(CHECK_FAIL "no")
       set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG "")
     endif()
     set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG_CODE "set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG \"${CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG}\")")
diff --git a/Modules/Platform/Darwin-Initialize.cmake b/Modules/Platform/Darwin-Initialize.cmake
index 2d797f6..729217c 100644
--- a/Modules/Platform/Darwin-Initialize.cmake
+++ b/Modules/Platform/Darwin-Initialize.cmake
@@ -122,7 +122,97 @@
 set(CMAKE_OSX_SYSROOT "${_CMAKE_OSX_SYSROOT_DEFAULT}" CACHE ${_CMAKE_OSX_SYSROOT_TYPE}
   "The product will be built against the headers and libraries located inside the indicated SDK.")
 
-# Transform the cached value to something we can use.
+# Resolves the SDK name into a path
+function(_apple_resolve_sdk_path sdk_name ret)
+  execute_process(
+    COMMAND xcrun -sdk ${sdk_name} --show-sdk-path
+    OUTPUT_VARIABLE _stdout
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+    ERROR_VARIABLE _stderr
+    RESULT_VARIABLE _failed
+  )
+  set(${ret} "${_stdout}" PARENT_SCOPE)
+endfunction()
+# Handle multi-arch sysroots. Do this before CMAKE_OSX_SYSROOT is
+# transformed into a path, so that we know the sysroot name.
+function(_apple_resolve_multi_arch_sysroots)
+  if(CMAKE_APPLE_ARCH_SYSROOTS)
+    return() # Already cached
+  endif()
+
+  list(LENGTH CMAKE_OSX_ARCHITECTURES _num_archs)
+  if(NOT (_num_archs GREATER 1))
+    return() # Only apply to multi-arch
+  endif()
+
+  if(CMAKE_OSX_SYSROOT STREQUAL "macosx")
+    # macOS doesn't have a simulator sdk / sysroot, so there is no need to handle per-sdk arches.
+    return()
+  endif()
+
+  if(IS_DIRECTORY "${CMAKE_OSX_SYSROOT}")
+    if(NOT CMAKE_OSX_SYSROOT STREQUAL _CMAKE_OSX_SYSROOT_DEFAULT)
+      message(WARNING "Can not resolve multi-arch sysroots with CMAKE_OSX_SYSROOT set to path (${CMAKE_OSX_SYSROOT})")
+    endif()
+    return()
+  endif()
+
+  string(REPLACE "os" "simulator" _simulator_sdk ${CMAKE_OSX_SYSROOT})
+  set(_sdks "${CMAKE_OSX_SYSROOT};${_simulator_sdk}")
+  foreach(sdk ${_sdks})
+    _apple_resolve_sdk_path(${sdk} _sdk_path)
+    if(NOT IS_DIRECTORY "${_sdk_path}")
+      message(WARNING "Failed to resolve SDK path for '${sdk}'")
+      continue()
+    endif()
+
+    execute_process(
+      COMMAND plutil -extract SupportedTargets.${sdk}.Archs json ${_sdk_path}/SDKSettings.plist -o -
+      OUTPUT_VARIABLE _sdk_archs_json
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      ERROR_VARIABLE _stderr
+      RESULT_VARIABLE _failed
+      )
+    if(_failed)
+      # Failure to extract supported architectures for an SDK means that the installed SDK is old
+      # and does not provide such information (SDKs that come with Xcode >= 10.x started providing
+      # the information). In such a case, return early, and handle multi-arch builds the old way
+      # (no per-sdk arches).
+      return()
+    endif()
+
+    # Poor man's JSON decoding
+    string(REGEX REPLACE "[]\\[\"]" "" _sdk_archs ${_sdk_archs_json})
+    string(REPLACE "," ";" _sdk_archs ${_sdk_archs})
+
+    set(_sdk_archs_${sdk} ${_sdk_archs})
+    set(_sdk_path_${sdk} ${_sdk_path})
+  endforeach()
+
+  foreach(arch ${CMAKE_OSX_ARCHITECTURES})
+    set(_arch_sysroot "")
+    foreach(sdk ${_sdks})
+      list(FIND _sdk_archs_${sdk} ${arch} arch_index)
+      if(NOT arch_index EQUAL -1)
+        set(_arch_sysroot ${_sdk_path_${sdk}})
+        break()
+      endif()
+    endforeach()
+    if(_arch_sysroot)
+      list(APPEND _arch_sysroots ${_arch_sysroot})
+    else()
+      message(WARNING "No SDK found for architecture '${arch}'")
+      list(APPEND _arch_sysroots "") # Placeholder
+    endif()
+  endforeach()
+
+  set(CMAKE_APPLE_ARCH_SYSROOTS "${_arch_sysroots}" CACHE INTERNAL
+    "Architecture dependent sysroots, one per CMAKE_OSX_ARCHITECTURES")
+endfunction()
+
+_apple_resolve_multi_arch_sysroots()
+
+# Transform CMAKE_OSX_SYSROOT to absolute path
 set(_CMAKE_OSX_SYSROOT_PATH "")
 if(CMAKE_OSX_SYSROOT)
   if("x${CMAKE_OSX_SYSROOT}" MATCHES "/")
@@ -134,16 +224,9 @@
     endif()
     set(_CMAKE_OSX_SYSROOT_PATH "${CMAKE_OSX_SYSROOT}")
   else()
-    # Transform the sdk name into a path.
-    execute_process(
-      COMMAND xcodebuild -sdk ${CMAKE_OSX_SYSROOT} -version Path
-      OUTPUT_VARIABLE _stdout
-      OUTPUT_STRIP_TRAILING_WHITESPACE
-      ERROR_VARIABLE _stderr
-      RESULT_VARIABLE _failed
-      )
-    if(NOT _failed AND IS_DIRECTORY "${_stdout}")
-      set(_CMAKE_OSX_SYSROOT_PATH "${_stdout}")
+    _apple_resolve_sdk_path(${CMAKE_OSX_SYSROOT} _sdk_path)
+    if(IS_DIRECTORY "${_sdk_path}")
+      set(_CMAKE_OSX_SYSROOT_PATH "${_sdk_path}")
       # For non-Xcode generators use the path.
       if(NOT "${CMAKE_GENERATOR}" MATCHES "Xcode")
         set(CMAKE_OSX_SYSROOT "${_CMAKE_OSX_SYSROOT_PATH}")
diff --git a/Modules/Platform/Darwin.cmake b/Modules/Platform/Darwin.cmake
index e5a57b5..0a4d4e1 100644
--- a/Modules/Platform/Darwin.cmake
+++ b/Modules/Platform/Darwin.cmake
@@ -210,7 +210,7 @@
 include(Platform/UnixPaths)
 if(_CMAKE_OSX_SYSROOT_PATH AND EXISTS ${_CMAKE_OSX_SYSROOT_PATH}/usr/include)
   list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${_CMAKE_OSX_SYSROOT_PATH}/usr)
-  foreach(lang C CXX OBJC OBJCXX)
+  foreach(lang C CXX OBJC OBJCXX Swift)
     list(APPEND _CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES_INIT ${_CMAKE_OSX_SYSROOT_PATH}/usr/include)
   endforeach()
 endif()
diff --git a/Modules/Platform/Generic-SDCC-C.cmake b/Modules/Platform/Generic-SDCC-C.cmake
index aef4abf..c3fd186 100644
--- a/Modules/Platform/Generic-SDCC-C.cmake
+++ b/Modules/Platform/Generic-SDCC-C.cmake
@@ -1,4 +1,3 @@
-
 # This file implements basic support for sdcc (http://sdcc.sourceforge.net/)
 # a free C compiler for 8 and 16 bit microcontrollers.
 # To use it either a toolchain file is required or cmake has to be run like this:
@@ -19,22 +18,26 @@
 
 set(CMAKE_C_OUTPUT_EXTENSION ".rel")
 
-# find sdcclib as CMAKE_AR
-# since cmake may already have searched for "ar", sdcclib has to
-# be searched with a different variable name (SDCCLIB_EXECUTABLE)
-# and must then be forced into the cache
+# find sdar/sdcclib as CMAKE_AR
+# since cmake may already have searched for "ar", sdar has to
+# be searched with a different variable name (SDCCAR_EXECUTABLE)
+# and must then be forced into the cache.
+# sdcclib has been deprecated in SDCC 3.2.0 and removed in 3.8.6
+# so we first look for sdar
 get_filename_component(SDCC_LOCATION "${CMAKE_C_COMPILER}" PATH)
-find_program(SDCCLIB_EXECUTABLE sdcclib PATHS "${SDCC_LOCATION}" NO_DEFAULT_PATH)
-find_program(SDCCLIB_EXECUTABLE sdcclib)
-set(CMAKE_AR "${SDCCLIB_EXECUTABLE}" CACHE FILEPATH "The sdcc librarian" FORCE)
-
-# CMAKE_C_FLAGS_INIT and CMAKE_EXE_LINKER_FLAGS_INIT should be set in a CMAKE_SYSTEM_PROCESSOR file
-if(NOT DEFINED CMAKE_C_FLAGS_INIT)
-  string(APPEND CMAKE_C_FLAGS_INIT " -mmcs51 --model-small")
+find_program(SDCCAR_EXECUTABLE sdar NAMES sdcclib PATHS "${SDCC_LOCATION}" NO_DEFAULT_PATH)
+find_program(SDCCAR_EXECUTABLE sdar NAMES sdcclib)
+# for compatibility, in case SDCCLIB_EXECUTABLE is set, we use it
+if(DEFINED SDCCLIB_EXECUTABLE)
+  set(CMAKE_AR "${SDCCLIB_EXECUTABLE}" CACHE FILEPATH "The sdcc librarian" FORCE)
+else()
+  set(CMAKE_AR "${SDCCAR_EXECUTABLE}" CACHE FILEPATH "The sdcc librarian" FORCE)
 endif()
 
-if(NOT DEFINED CMAKE_EXE_LINKER_FLAGS_INIT)
-  set (CMAKE_EXE_LINKER_FLAGS_INIT --model-small)
+if("${SDCCAR_EXECUTABLE}" MATCHES "sdcclib")
+  set(CMAKE_AR_OPTIONS "-a")
+else()
+  set(CMAKE_AR_OPTIONS "-rc")
 endif()
 
 set(CMAKE_C_LINKER_WRAPPER_FLAG "-Wl" ",")
@@ -45,10 +48,10 @@
 # link object files to an executable
 set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <OBJECTS> -o <TARGET> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>")
 
-# needs sdcc 2.7.0 + sddclib from cvs
+# needs sdcc + sdar/sdcclib
 set(CMAKE_C_CREATE_STATIC_LIBRARY
       "\"${CMAKE_COMMAND}\" -E remove <TARGET>"
-      "<CMAKE_AR> -a <TARGET> <LINK_FLAGS> <OBJECTS> ")
+      "<CMAKE_AR> ${CMAKE_AR_OPTIONS} <TARGET> <LINK_FLAGS> <OBJECTS> ")
 
 # not supported by sdcc
 set(CMAKE_C_CREATE_SHARED_LIBRARY "")
diff --git a/Modules/Platform/Windows-Apple-Swift.cmake b/Modules/Platform/Windows-Apple-Swift.cmake
new file mode 100644
index 0000000..1177755
--- /dev/null
+++ b/Modules/Platform/Windows-Apple-Swift.cmake
@@ -0,0 +1 @@
+set(CMAKE_Swift_IMPLIB_LINKER_FLAGS "-Xlinker -implib:<TARGET_IMPLIB>")
diff --git a/Modules/Platform/Windows-Clang-ASM.cmake b/Modules/Platform/Windows-Clang-ASM.cmake
new file mode 100644
index 0000000..345d77d
--- /dev/null
+++ b/Modules/Platform/Windows-Clang-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/Windows-Clang)
+__windows_compiler_clang(ASM)
diff --git a/Modules/Platform/Windows-Clang.cmake b/Modules/Platform/Windows-Clang.cmake
index 02864c6..87ddfcd 100644
--- a/Modules/Platform/Windows-Clang.cmake
+++ b/Modules/Platform/Windows-Clang.cmake
@@ -21,10 +21,12 @@
   set(CMAKE_SHARED_LIBRARY_SUFFIX ".dll")
   set(CMAKE_SHARED_MODULE_SUFFIX  ".dll")
   set(CMAKE_STATIC_LIBRARY_SUFFIX ".lib")
-  set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <OBJECT> -MF <DEPFILE>")
+  if(NOT "${lang}" STREQUAL "ASM")
+    set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <OBJECT> -MF <DEPFILE>")
+  endif()
 
   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:")
 
@@ -61,28 +63,30 @@
   set(CMAKE_${lang}_LINK_EXECUTABLE
     "<CMAKE_${lang}_COMPILER> -fuse-ld=lld-link -nostartfiles -nostdlib <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")
 
-  set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         -Xclang -flto-visibility-public-std -D_MT -Xclang --dependent-lib=libcmt)
-  set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      -D_DLL -D_MT -Xclang --dependent-lib=msvcrt)
-  set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    -D_DEBUG -Xclang -flto-visibility-public-std -D_MT -Xclang --dependent-lib=libcmtd)
-  set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd)
+  if(NOT "${lang}" STREQUAL "ASM")
+    set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         -Xclang -flto-visibility-public-std -D_MT -Xclang --dependent-lib=libcmt)
+    set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      -D_DLL -D_MT -Xclang --dependent-lib=msvcrt)
+    set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    -D_DEBUG -Xclang -flto-visibility-public-std -D_MT -Xclang --dependent-lib=libcmtd)
+    set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd)
 
-  if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
-    set(__ADDED_FLAGS "")
-    set(__ADDED_FLAGS_DEBUG "")
-  else()
-    set(__ADDED_FLAGS_DEBUG "-D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd")
-    set(__ADDED_FLAGS "-D_DLL -D_MT -Xclang --dependent-lib=msvcrt")
+    if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
+      set(__ADDED_FLAGS "")
+      set(__ADDED_FLAGS_DEBUG "")
+    else()
+      set(__ADDED_FLAGS_DEBUG "-D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd")
+      set(__ADDED_FLAGS "-D_DLL -D_MT -Xclang --dependent-lib=msvcrt")
+    endif()
+
+    string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g -Xclang -gcodeview -O0 ${__ADDED_FLAGS_DEBUG}")
+    string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Os -DNDEBUG ${__ADDED_FLAGS}")
+    string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3 -DNDEBUG ${__ADDED_FLAGS}")
+    string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG -Xclang -gcodeview ${__ADDED_FLAGS}")
   endif()
-
-  string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g -Xclang -gcodeview -O0 ${__ADDED_FLAGS_DEBUG}")
-  string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Os -DNDEBUG ${__ADDED_FLAGS}")
-  string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3 -DNDEBUG ${__ADDED_FLAGS}")
-  string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG -Xclang -gcodeview ${__ADDED_FLAGS}")
   set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-isystem ")
 
   set(CMAKE_PCH_EXTENSION .pch)
   set(CMAKE_PCH_PROLOGUE "#pragma clang system_header")
-  set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang <PCH_FILE>)
+  set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang <PCH_FILE> -Xclang -include -Xclang <PCH_HEADER>)
   set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Xclang -emit-pch -Xclang -include -Xclang <PCH_HEADER>)
 
   unset(__ADDED_FLAGS)
@@ -129,6 +133,23 @@
   if ( "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC" OR "x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC" )
     include(Platform/Windows-MSVC)
 
+    # Feed the preprocessed rc file to llvm-rc
+    if(CMAKE_RC_COMPILER_INIT STREQUAL "llvm-rc")
+      if(DEFINED CMAKE_C_COMPILER)
+        set(CMAKE_RC_PREPROCESSOR CMAKE_C_COMPILER)
+      elseif(DEFINED CMAKE_CXX_COMPILER)
+        set(CMAKE_RC_PREPROCESSOR CMAKE_CXX_COMPILER)
+      endif()
+      if(DEFINED CMAKE_RC_PREPROCESSOR)
+        set(CMAKE_RC_COMPILE_OBJECT "${CMAKE_COMMAND} -E cmake_llvm_rc <OBJECT>.pp <${CMAKE_RC_PREPROCESSOR}> <DEFINES> -DRC_INVOKED <INCLUDES> <FLAGS> -clang:-MD -clang:-MF -clang:<SOURCE>.d -E <SOURCE> -- <CMAKE_RC_COMPILER> <DEFINES> /fo <OBJECT> <OBJECT>.pp")
+        if(CMAKE_GENERATOR STREQUAL "Ninja")
+          set(CMAKE_NINJA_CMCLDEPS_RC 0)
+          set(CMAKE_NINJA_DEP_TYPE_RC gcc)
+        endif()
+        unset(CMAKE_RC_PREPROCESSOR)
+      endif()
+    endif()
+
     macro(__windows_compiler_clang lang)
       set(_COMPILE_${lang} "${_COMPILE_${lang}_MSVC}")
       __windows_compiler_msvc(${lang})
diff --git a/Modules/Platform/Windows-Embarcadero.cmake b/Modules/Platform/Windows-Embarcadero.cmake
index 370b56e..0c24739 100644
--- a/Modules/Platform/Windows-Embarcadero.cmake
+++ b/Modules/Platform/Windows-Embarcadero.cmake
@@ -122,7 +122,7 @@
   # Precompile Headers
   if (EMBARCADERO)
     set(CMAKE_PCH_EXTENSION .pch)
-    set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang <PCH_FILE>)
+    set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang <PCH_FILE> -Xclang -include -Xclang <PCH_HEADER>)
     set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Xclang -emit-pch -Xclang -include -Xclang <PCH_HEADER>)
   endif()
 
diff --git a/Modules/Platform/Windows-GNU-ASM.cmake b/Modules/Platform/Windows-GNU-ASM.cmake
new file mode 100644
index 0000000..8600892
--- /dev/null
+++ b/Modules/Platform/Windows-GNU-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/Windows-GNU)
+__windows_compiler_gnu(ASM)
diff --git a/Modules/Platform/Windows-GNU.cmake b/Modules/Platform/Windows-GNU.cmake
index 6bf245c..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()
@@ -124,7 +124,7 @@
       string(REPLACE "<OBJECTS>" "-Wl,--whole-archive <OBJECT_DIR>/objects.a -Wl,--no-whole-archive"
         CMAKE_${lang}_${rule} "${CMAKE_${lang}_${rule}}")
       set(CMAKE_${lang}_${rule}
-        "<CMAKE_COMMAND> -E remove -f <OBJECT_DIR>/objects.a"
+        "<CMAKE_COMMAND> -E rm -f <OBJECT_DIR>/objects.a"
         "<CMAKE_AR> cr <OBJECT_DIR>/objects.a <OBJECTS>"
         "${CMAKE_${lang}_${rule}}"
         )
diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake
index 34f5d03..e1d6733 100644
--- a/Modules/Platform/Windows-MSVC.cmake
+++ b/Modules/Platform/Windows-MSVC.cmake
@@ -217,7 +217,7 @@
 else()
   set(_PLATFORM_DEFINES "/DWIN32")
 
-  if(_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM" OR _MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM" OR _MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM64" OR _MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM64")
+  if(_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM" OR _MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM")
     set(CMAKE_C_STANDARD_LIBRARIES_INIT "kernel32.lib user32.lib")
   elseif(MSVC_VERSION GREATER 1310)
     if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*")
diff --git a/Modules/Platform/Windows-NVIDIA-CUDA.cmake b/Modules/Platform/Windows-NVIDIA-CUDA.cmake
index 94d77b9..f809094 100644
--- a/Modules/Platform/Windows-NVIDIA-CUDA.cmake
+++ b/Modules/Platform/Windows-NVIDIA-CUDA.cmake
@@ -1,11 +1,11 @@
 include(Platform/Windows-MSVC)
 
 set(CMAKE_CUDA_COMPILE_PTX_COMPILATION
-  "<CMAKE_CUDA_COMPILER> ${CMAKE_CUDA_HOST_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -x cu -ptx <SOURCE> -o <OBJECT> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS")
+  "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -x cu -ptx <SOURCE> -o <OBJECT> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS")
 set(CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION
-  "<CMAKE_CUDA_COMPILER> ${CMAKE_CUDA_HOST_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -x cu -dc <SOURCE> -o <OBJECT> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS")
+  "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -x cu -dc <SOURCE> -o <OBJECT> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS")
 set(CMAKE_CUDA_COMPILE_WHOLE_COMPILATION
-  "<CMAKE_CUDA_COMPILER> ${CMAKE_CUDA_HOST_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -x cu -c <SOURCE> -o <OBJECT> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS")
+  "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -x cu -c <SOURCE> -o <OBJECT> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS")
 
 set(__IMPLICT_LINKS )
 foreach(dir ${CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES})
@@ -30,11 +30,6 @@
 unset(_CMAKE_VS_LINK_EXE)
 unset(_CMAKE_VS_LINK_EXE)
 
-if(CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "8.0.0")
-  set(_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS "-Wno-deprecated-gpu-targets")
-else()
-  set(_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS "")
-endif()
 
 # Add implicit host link directories that contain device libraries
 # to the device link line.
@@ -51,11 +46,9 @@
 unset(__IMPLICT_DLINK_DIRS)
 
 set(CMAKE_CUDA_DEVICE_LINK_LIBRARY
-  "<CMAKE_CUDA_COMPILER> <LANGUAGE_COMPILE_FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICT_DLINK_FLAGS}")
+  "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICT_DLINK_FLAGS}")
 set(CMAKE_CUDA_DEVICE_LINK_EXECUTABLE
-  "<CMAKE_CUDA_COMPILER> <FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICT_DLINK_FLAGS}")
-
-unset(_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS)
+  "<CMAKE_CUDA_COMPILER>  ${_CMAKE_CUDA_EXTRA_FLAGS} <FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICT_DLINK_FLAGS}")
 unset(__IMPLICT_DLINK_FLAGS)
 
 string(REPLACE "/D" "-D" _PLATFORM_DEFINES_CUDA "${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_CXX}")
@@ -76,6 +69,11 @@
 endif()
 unset(_cmp0092)
 
+set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "STATIC")
+set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_STATIC  "cudadevrt;cudart_static")
+set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_SHARED  "cudadevrt;cudart")
+set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_NONE    "")
+
 string(APPEND CMAKE_CUDA_FLAGS_INIT " ${PLATFORM_DEFINES_CUDA} -D_WINDOWS -Xcompiler=\"${_W3}${_FLAGS_CXX}\"")
 string(APPEND CMAKE_CUDA_FLAGS_DEBUG_INIT " -Xcompiler=\"${_MDd}-Zi -Ob0 -Od ${_RTC1}\"")
 string(APPEND CMAKE_CUDA_FLAGS_RELEASE_INIT " -Xcompiler=\"${_MD}-O2 -Ob2\" -DNDEBUG")
diff --git a/Modules/Platform/Windows-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/Modules/Platform/WindowsPhone-Clang-ASM.cmake b/Modules/Platform/WindowsPhone-Clang-ASM.cmake
new file mode 100644
index 0000000..94f4ca7
--- /dev/null
+++ b/Modules/Platform/WindowsPhone-Clang-ASM.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-Clang-ASM)
diff --git a/Modules/Platform/WindowsPhone-GNU-ASM.cmake b/Modules/Platform/WindowsPhone-GNU-ASM.cmake
new file mode 100644
index 0000000..140eea7
--- /dev/null
+++ b/Modules/Platform/WindowsPhone-GNU-ASM.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-GNU-ASM)
diff --git a/Modules/Platform/WindowsStore-Clang-ASM.cmake b/Modules/Platform/WindowsStore-Clang-ASM.cmake
new file mode 100644
index 0000000..94f4ca7
--- /dev/null
+++ b/Modules/Platform/WindowsStore-Clang-ASM.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-Clang-ASM)
diff --git a/Modules/Platform/WindowsStore-GNU-ASM.cmake b/Modules/Platform/WindowsStore-GNU-ASM.cmake
new file mode 100644
index 0000000..140eea7
--- /dev/null
+++ b/Modules/Platform/WindowsStore-GNU-ASM.cmake
@@ -0,0 +1 @@
+include(Platform/Windows-GNU-ASM)
diff --git a/Modules/Qt4Macros.cmake b/Modules/Qt4Macros.cmake
index 33cacf1..cb6ae43 100644
--- a/Modules/Qt4Macros.cmake
+++ b/Modules/Qt4Macros.cmake
@@ -436,7 +436,7 @@
     if(_my_sources)
       # make a .pro file to call lupdate on, so we don't make our commands too
       # long for some systems
-      get_filename_component(_ts_name ${_ts_file} NAME_WE)
+      get_filename_component(_ts_name ${_ts_file} NAME)
       set(_ts_pro ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_ts_name}_lupdate.pro)
       set(_pro_srcs)
       foreach(_pro_src ${_my_sources})
@@ -463,13 +463,15 @@
 macro(QT4_ADD_TRANSLATION _qm_files)
   foreach (_current_FILE ${ARGN})
     get_filename_component(_abs_FILE ${_current_FILE} ABSOLUTE)
-    get_filename_component(qm ${_abs_FILE} NAME_WE)
-    get_property(output_location SOURCE ${_abs_FILE} PROPERTY OUTPUT_LOCATION)
+    get_filename_component(qm ${_abs_FILE} NAME)
+    # everything before the last dot has to be considered the file name (including other dots)
+    string(REGEX REPLACE "\\.[^.]*$" "" FILE_NAME ${qm})
+    get_source_file_property(output_location ${_abs_FILE} OUTPUT_LOCATION)
     if(output_location)
       file(MAKE_DIRECTORY "${output_location}")
-      set(qm "${output_location}/${qm}.qm")
+      set(qm "${output_location}/${FILE_NAME}.qm")
     else()
-      set(qm "${CMAKE_CURRENT_BINARY_DIR}/${qm}.qm")
+      set(qm "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}.qm")
     endif()
 
     add_custom_command(OUTPUT ${qm}
diff --git a/Modules/TestBigEndian.cmake b/Modules/TestBigEndian.cmake
index 0c6e188..8a769b7 100644
--- a/Modules/TestBigEndian.cmake
+++ b/Modules/TestBigEndian.cmake
@@ -19,8 +19,8 @@
 
 macro(TEST_BIG_ENDIAN VARIABLE)
   if(NOT DEFINED HAVE_${VARIABLE})
-    message(STATUS "Check if the system is big endian")
-    message(STATUS "Searching 16 bit integer")
+    message(CHECK_START "Check if the system is big endian")
+    message(CHECK_START "Searching 16 bit integer")
 
     if(CMAKE_C_COMPILER_LOADED)
       set(_test_language "C")
@@ -32,19 +32,19 @@
 
     CHECK_TYPE_SIZE("unsigned short" CMAKE_SIZEOF_UNSIGNED_SHORT LANGUAGE ${_test_language})
     if(CMAKE_SIZEOF_UNSIGNED_SHORT EQUAL 2)
-      message(STATUS "Using unsigned short")
+      message(CHECK_PASS "Using unsigned short")
       set(CMAKE_16BIT_TYPE "unsigned short")
     else()
       CHECK_TYPE_SIZE("unsigned int"   CMAKE_SIZEOF_UNSIGNED_INT LANGUAGE ${_test_language})
       if(CMAKE_SIZEOF_UNSIGNED_INT)
-        message(STATUS "Using unsigned int")
+        message(CHECK_PASS "Using unsigned int")
         set(CMAKE_16BIT_TYPE "unsigned int")
 
       else()
 
         CHECK_TYPE_SIZE("unsigned long"  CMAKE_SIZEOF_UNSIGNED_LONG LANGUAGE ${_test_language})
         if(CMAKE_SIZEOF_UNSIGNED_LONG)
-          message(STATUS "Using unsigned long")
+          message(CHECK_PASS "Using unsigned long")
           set(CMAKE_16BIT_TYPE "unsigned long")
         else()
           message(FATAL_ERROR "no suitable type found")
@@ -95,15 +95,16 @@
 
         if(CMAKE_TEST_ENDIANESS_STRINGS_LE)
           set(${VARIABLE} 0 CACHE INTERNAL "Result of TEST_BIG_ENDIAN" FORCE)
-          message(STATUS "Check if the system is big endian - little endian")
+          message(CHECK_PASS "little endian")
         endif()
 
         if(CMAKE_TEST_ENDIANESS_STRINGS_BE)
           set(${VARIABLE} 1 CACHE INTERNAL "Result of TEST_BIG_ENDIAN" FORCE)
-          message(STATUS "Check if the system is big endian - big endian")
+          message(CHECK_PASS "big endian")
         endif()
 
         if(NOT CMAKE_TEST_ENDIANESS_STRINGS_BE  AND  NOT CMAKE_TEST_ENDIANESS_STRINGS_LE)
+          message(CHECK_FAIL "TEST_BIG_ENDIAN found no result!")
           message(SEND_ERROR "TEST_BIG_ENDIAN found no result!")
         endif()
 
@@ -111,7 +112,7 @@
           "Determining if the system is big endian passed with the following output:\n${OUTPUT}\nTestEndianess.c:\n${TEST_ENDIANESS_FILE_CONTENT}\n\n")
 
       else()
-        message(STATUS "Check if the system is big endian - failed")
+        message(CHECK_FAIL "failed")
         file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
           "Determining if the system is big endian failed with the following output:\n${OUTPUT}\nTestEndianess.c:\n${TEST_ENDIANESS_FILE_CONTENT}\n\n")
         set(${VARIABLE})
diff --git a/Modules/TestCXXAcceptsFlag.cmake b/Modules/TestCXXAcceptsFlag.cmake
index 92a362e..ce505f3 100644
--- a/Modules/TestCXXAcceptsFlag.cmake
+++ b/Modules/TestCXXAcceptsFlag.cmake
@@ -23,19 +23,19 @@
 
 macro(CHECK_CXX_ACCEPTS_FLAG FLAGS  VARIABLE)
   if(NOT DEFINED ${VARIABLE})
-    message(STATUS "Checking to see if CXX compiler accepts flag ${FLAGS}")
+    message(CHECK_START "Checking to see if CXX compiler accepts flag ${FLAGS}")
     try_compile(${VARIABLE}
       ${CMAKE_BINARY_DIR}
       ${CMAKE_ROOT}/Modules/DummyCXXFile.cxx
       CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${FLAGS}
       OUTPUT_VARIABLE OUTPUT)
     if(${VARIABLE})
-      message(STATUS "Checking to see if CXX compiler accepts flag ${FLAGS} - yes")
+      message(CHECK_PASS "yes")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Determining if the CXX compiler accepts the flag ${FLAGS} passed with "
         "the following output:\n${OUTPUT}\n\n")
     else()
-      message(STATUS "Checking to see if CXX compiler accepts flag ${FLAGS} - no")
+      message(CHECK_FAIL "no")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Determining if the CXX compiler accepts the flag ${FLAGS} failed with "
         "the following output:\n${OUTPUT}\n\n")
diff --git a/Modules/TestForANSIForScope.cmake b/Modules/TestForANSIForScope.cmake
index 272e4ec..0f2dc01 100644
--- a/Modules/TestForANSIForScope.cmake
+++ b/Modules/TestForANSIForScope.cmake
@@ -16,19 +16,19 @@
 #]=======================================================================]
 
 if(NOT DEFINED CMAKE_ANSI_FOR_SCOPE)
-  message(STATUS "Check for ANSI scope")
+  message(CHECK_START "Check for ANSI scope")
   try_compile(CMAKE_ANSI_FOR_SCOPE  ${CMAKE_BINARY_DIR}
     ${CMAKE_ROOT}/Modules/TestForAnsiForScope.cxx
     OUTPUT_VARIABLE OUTPUT)
   if (CMAKE_ANSI_FOR_SCOPE)
-    message(STATUS "Check for ANSI scope - found")
+    message(CHECK_PASS "found")
     set (CMAKE_NO_ANSI_FOR_SCOPE 0 CACHE INTERNAL
       "Does the compiler support ansi for scope.")
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
       "Determining if the CXX compiler understands ansi for scopes passed with "
       "the following output:\n${OUTPUT}\n\n")
   else ()
-    message(STATUS "Check for ANSI scope - not found")
+    message(CHECK_FAIL "not found")
     set (CMAKE_NO_ANSI_FOR_SCOPE 1 CACHE INTERNAL
       "Does the compiler support ansi for scope.")
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
diff --git a/Modules/TestForSSTREAM.cmake b/Modules/TestForSSTREAM.cmake
index e70df00..545b7ec 100644
--- a/Modules/TestForSSTREAM.cmake
+++ b/Modules/TestForSSTREAM.cmake
@@ -15,19 +15,19 @@
 #]=======================================================================]
 
 if(NOT DEFINED CMAKE_HAS_ANSI_STRING_STREAM)
-  message(STATUS "Check for sstream")
+  message(CHECK_START "Check for sstream")
   try_compile(CMAKE_HAS_ANSI_STRING_STREAM  ${CMAKE_BINARY_DIR}
     ${CMAKE_ROOT}/Modules/TestForSSTREAM.cxx
     OUTPUT_VARIABLE OUTPUT)
   if (CMAKE_HAS_ANSI_STRING_STREAM)
-    message(STATUS "Check for sstream - found")
+    message(CHECK_PASS "found")
     set (CMAKE_NO_ANSI_STRING_STREAM 0 CACHE INTERNAL
          "Does the compiler support sstream")
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
       "Determining if the CXX compiler has sstream passed with "
       "the following output:\n${OUTPUT}\n\n")
   else ()
-    message(STATUS "Check for sstream - not found")
+    message(CHECK_FAIL "not found")
     set (CMAKE_NO_ANSI_STRING_STREAM 1 CACHE INTERNAL
        "Does the compiler support sstream")
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
diff --git a/Modules/TestForSTDNamespace.cmake b/Modules/TestForSTDNamespace.cmake
index 703e631..d101c83 100644
--- a/Modules/TestForSTDNamespace.cmake
+++ b/Modules/TestForSTDNamespace.cmake
@@ -15,19 +15,19 @@
 #]=======================================================================]
 
 if(NOT DEFINED CMAKE_STD_NAMESPACE)
-  message(STATUS "Check for STD namespace")
+  message(CHECK_START "Check for STD namespace")
   try_compile(CMAKE_STD_NAMESPACE  ${CMAKE_BINARY_DIR}
     ${CMAKE_ROOT}/Modules/TestForSTDNamespace.cxx
     OUTPUT_VARIABLE OUTPUT)
   if (CMAKE_STD_NAMESPACE)
-    message(STATUS "Check for STD namespace - found")
+    message(CHECK_PASS "found")
     set (CMAKE_NO_STD_NAMESPACE 0 CACHE INTERNAL
          "Does the compiler support std::.")
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
       "Determining if the CXX compiler has std namespace passed with "
       "the following output:\n${OUTPUT}\n\n")
   else ()
-    message(STATUS "Check for STD namespace - not found")
+    message(CHECK_FAIL "not found")
     set (CMAKE_NO_STD_NAMESPACE 1 CACHE INTERNAL
        "Does the compiler support std::.")
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
diff --git a/Modules/UseJava.cmake b/Modules/UseJava.cmake
index 0798488..b668b9e 100644
--- a/Modules/UseJava.cmake
+++ b/Modules/UseJava.cmake
@@ -405,9 +405,14 @@
 
 # define helper scripts
 set(_JAVA_EXPORT_TARGETS_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/javaTargets.cmake.in)
-set(_JAVA_CLASS_FILELIST_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaClassFilelist.cmake)
 set(_JAVA_SYMLINK_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaSymlinks.cmake)
 
+if (CMAKE_HOST_WIN32 AND NOT CYGWIN AND CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
+    set(_UseJava_PATH_SEP "$<SEMICOLON>")
+else ()
+    set(_UseJava_PATH_SEP ":")
+endif()
+
 function(add_jar _TARGET_NAME)
 
     cmake_parse_arguments(_add_jar
@@ -497,14 +502,8 @@
         ${CMAKE_JAVA_LIBRARY_OUTPUT_PATH}
     )
 
-    if (CMAKE_HOST_WIN32 AND NOT CYGWIN AND CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
-        set(CMAKE_JAVA_INCLUDE_FLAG_SEP ";")
-    else ()
-        set(CMAKE_JAVA_INCLUDE_FLAG_SEP ":")
-    endif()
-
     foreach (JAVA_INCLUDE_DIR IN LISTS CMAKE_JAVA_INCLUDE_PATH)
-       string(APPEND CMAKE_JAVA_INCLUDE_PATH_FINAL "${CMAKE_JAVA_INCLUDE_FLAG_SEP}${JAVA_INCLUDE_DIR}")
+       string(APPEND CMAKE_JAVA_INCLUDE_PATH_FINAL "${_UseJava_PATH_SEP}${JAVA_INCLUDE_DIR}")
     endforeach()
 
     set(CMAKE_JAVA_CLASS_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir")
@@ -576,7 +575,7 @@
         if (TARGET ${_JAVA_INCLUDE_JAR})
             get_target_property(_JAVA_JAR_PATH ${_JAVA_INCLUDE_JAR} JAR_FILE)
             if (_JAVA_JAR_PATH)
-                string(APPEND CMAKE_JAVA_INCLUDE_PATH_FINAL "${CMAKE_JAVA_INCLUDE_FLAG_SEP}${_JAVA_JAR_PATH}")
+                string(APPEND CMAKE_JAVA_INCLUDE_PATH_FINAL "${_UseJava_PATH_SEP}${_JAVA_JAR_PATH}")
                 list(APPEND CMAKE_JAVA_INCLUDE_PATH ${_JAVA_JAR_PATH})
                 list(APPEND _JAVA_DEPENDS ${_JAVA_INCLUDE_JAR})
                 list(APPEND _JAVA_COMPILE_DEPENDS ${_JAVA_JAR_PATH})
@@ -584,7 +583,7 @@
                 message(SEND_ERROR "add_jar: INCLUDE_JARS target ${_JAVA_INCLUDE_JAR} is not a jar")
             endif ()
         else ()
-            string(APPEND CMAKE_JAVA_INCLUDE_PATH_FINAL "${CMAKE_JAVA_INCLUDE_FLAG_SEP}${_JAVA_INCLUDE_JAR}")
+            string(APPEND CMAKE_JAVA_INCLUDE_PATH_FINAL "${_UseJava_PATH_SEP}${_JAVA_INCLUDE_JAR}")
             list(APPEND CMAKE_JAVA_INCLUDE_PATH "${_JAVA_INCLUDE_JAR}")
             list(APPEND _JAVA_DEPENDS "${_JAVA_INCLUDE_JAR}")
             list(APPEND _JAVA_COMPILE_DEPENDS "${_JAVA_INCLUDE_JAR}")
@@ -627,7 +626,7 @@
             COMMAND ${CMAKE_COMMAND}
                 -DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH}
                 -DCMAKE_JAR_CLASSES_PREFIX="${CMAKE_JAR_CLASSES_PREFIX}"
-                -P ${_JAVA_CLASS_FILELIST_SCRIPT}
+                -P ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/UseJavaClassFilelist.cmake
             DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
             WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
         )
@@ -1190,55 +1189,40 @@
     set(_javadoc_options -d ${_javadoc_builddir})
 
     if (_javadoc_sourcepath)
-        set(_start TRUE)
-        foreach(_path IN LISTS _javadoc_sourcepath)
-            if (_start)
-                set(_sourcepath ${_path})
-                set(_start FALSE)
-            else ()
-                set(_sourcepath ${_sourcepath}:${_path})
-            endif ()
-        endforeach()
-        set(_javadoc_options ${_javadoc_options} -sourcepath ${_sourcepath})
+        list(JOIN _javadoc_sourcepath "${_UseJava_PATH_SEP}" _javadoc_sourcepath)
+        list(APPEND _javadoc_options -sourcepath "\"${_javadoc_sourcepath}\"")
     endif ()
 
     if (_javadoc_classpath)
-        set(_start TRUE)
-        foreach(_path IN LISTS _javadoc_classpath)
-            if (_start)
-                set(_classpath ${_path})
-                set(_start FALSE)
-            else ()
-                set(_classpath ${_classpath}:${_path})
-            endif ()
-        endforeach()
-        set(_javadoc_options ${_javadoc_options} -classpath "${_classpath}")
+        list(JOIN _javadoc_classpath "${_UseJava_PATH_SEP}" _javadoc_classpath)
+        list(APPEND _javadoc_options -classpath "\"${_javadoc_classpath}\"")
     endif ()
 
     if (_javadoc_doctitle)
-        set(_javadoc_options ${_javadoc_options} -doctitle '${_javadoc_doctitle}')
+        list(APPEND _javadoc_options -doctitle '${_javadoc_doctitle}')
     endif ()
 
     if (_javadoc_windowtitle)
-        set(_javadoc_options ${_javadoc_options} -windowtitle '${_javadoc_windowtitle}')
+        list(APPEND _javadoc_options -windowtitle '${_javadoc_windowtitle}')
     endif ()
 
     if (_javadoc_author)
-        set(_javadoc_options ${_javadoc_options} -author)
+        list(APPEND _javadoc_options -author)
     endif ()
 
     if (_javadoc_use)
-        set(_javadoc_options ${_javadoc_options} -use)
+        list(APPEND _javadoc_options -use)
     endif ()
 
     if (_javadoc_version)
-        set(_javadoc_options ${_javadoc_options} -version)
+        list(APPEND _javadoc_options -version)
     endif ()
 
     add_custom_target(${_target}_javadoc ALL
-        COMMAND ${Java_JAVADOC_EXECUTABLE} ${_javadoc_options}
-                            ${_javadoc_files}
-                            ${_javadoc_packages}
+        COMMAND ${Java_JAVADOC_EXECUTABLE}
+                ${_javadoc_options}
+                ${_javadoc_files}
+                ${_javadoc_packages}
         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
     )
 
@@ -1274,11 +1258,6 @@
     endif()
 
     set (_output_files)
-    if (WIN32 AND NOT CYGWIN AND CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
-      set(_classpath_sep "$<SEMICOLON>")
-    else ()
-      set(_classpath_sep ":")
-    endif()
 
     # handle javah options
     set (_javah_options)
@@ -1304,7 +1283,7 @@
           message(SEND_ERROR "create_javah: CLASSPATH entry ${_path} does not exist.")
         endif()
       endforeach()
-      string (REPLACE ";" "${_classpath_sep}" _classpath "${_classpath}")
+      string (REPLACE ";" "${_UseJava_PATH_SEP}" _classpath "${_classpath}")
       list (APPEND _javah_options -classpath "${_classpath}")
     endif()
 
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index b1f7b29..c57f713 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -134,6 +134,9 @@
   LexerParser/cmFortranParser.cxx
   LexerParser/cmFortranParserTokens.h
   LexerParser/cmFortranParser.y
+  LexerParser/cmGccDepfileLexer.cxx
+  LexerParser/cmGccDepfileLexer.h
+  LexerParser/cmGccDepfileLexer.in.l
   LexerParser/cmListFileLexer.c
   LexerParser/cmListFileLexer.in.l
 
@@ -270,6 +273,10 @@
   cmFortranParserImpl.cxx
   cmFSPermissions.cxx
   cmFSPermissions.h
+  cmGccDepfileLexerHelper.cxx
+  cmGccDepfileLexerHelper.h
+  cmGccDepfileReader.cxx
+  cmGccDepfileReader.h
   cmGeneratedFileStream.cxx
   cmGeneratorExpressionContext.cxx
   cmGeneratorExpressionContext.h
@@ -289,6 +296,8 @@
   cmGeneratorExpression.h
   cmGeneratorTarget.cxx
   cmGeneratorTarget.h
+  cmLinkItemGraphVisitor.cxx
+  cmLinkItemGraphVisitor.h
   cmGetPipes.cxx
   cmGetPipes.h
   cmGlobalCommonGenerator.cxx
@@ -691,6 +700,8 @@
 
   cmDuration.h
   cmDuration.cxx
+
+  bindexplib.cxx
   )
 
 SET_PROPERTY(SOURCE cmProcessOutput.cxx APPEND PROPERTY COMPILE_DEFINITIONS
@@ -713,7 +724,6 @@
   set(SRCS ${SRCS}
     cmCallVisualStudioMacro.cxx
     cmCallVisualStudioMacro.h
-    bindexplib.cxx
     )
 
   if(NOT UNIX)
@@ -1193,6 +1203,11 @@
   endforeach()
 endif()
 
+if(CMake_JOB_POOL_LINK_BIN)
+  set_property(TARGET ${_tools} PROPERTY JOB_POOL_LINK "link-bin")
+  set_property(GLOBAL APPEND PROPERTY JOB_POOLS "link-bin=${CMake_JOB_POOL_LINK_BIN}")
+endif()
+
 # Install tools
 
 foreach(_tool ${_tools})
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 6a8d2fc..de3f050 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 5)
+set(CMake_VERSION_MINOR 17)
+set(CMake_VERSION_PATCH 0)
 #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..fe7abf4 100644
--- a/Source/CPack/cmCPackDragNDropGenerator.cxx
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -138,11 +138,16 @@
     }
     for (auto const& language : languages) {
       std::string license = slaDirectory + "/" + language + ".license.txt";
-      if (!singleLicense && !cmSystemTools::FileExists(license)) {
-        cmCPackLogger(cmCPackLog::LOG_ERROR,
-                      "Missing license file " << language << ".license.txt"
-                                              << std::endl);
-        return 0;
+      std::string license_rtf = slaDirectory + "/" + language + ".license.rtf";
+      if (!singleLicense) {
+        if (!cmSystemTools::FileExists(license) &&
+            !cmSystemTools::FileExists(license_rtf)) {
+          cmCPackLogger(cmCPackLog::LOG_ERROR,
+                        "Missing license file "
+                          << language << ".license.txt"
+                          << " / " << language << ".license.rtf" << std::endl);
+          return 0;
+        }
       }
       std::string menu = slaDirectory + "/" + language + ".menu.txt";
       if (!cmSystemTools::FileExists(menu)) {
@@ -775,6 +780,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);
 }
 
@@ -788,13 +798,29 @@
     licenseLanguage = "English";
   }
 
+  // License file
+  std::string license_format = "TEXT";
+  std::string actual_license;
+  if (!licenseFile.empty()) {
+    if (cmHasLiteralSuffix(licenseFile, ".rtf")) {
+      license_format = "RTF ";
+    }
+    actual_license = licenseFile;
+  } else {
+    std::string license_wo_ext =
+      slaDirectory + "/" + licenseLanguage + ".license";
+    if (cmSystemTools::FileExists(license_wo_ext + ".txt")) {
+      actual_license = license_wo_ext + ".txt";
+    } else {
+      license_format = "RTF ";
+      actual_license = license_wo_ext + ".rtf";
+    }
+  }
+
   // License header
-  outputStream << "data 'TEXT' (" << licenseNumber << ", \"" << licenseLanguage
-               << "\") {\n";
+  outputStream << "data '" << license_format << "' (" << licenseNumber
+               << ", \"" << licenseLanguage << "\") {\n";
   // License body
-  std::string actual_license = !licenseFile.empty()
-    ? licenseFile
-    : (slaDirectory + "/" + licenseLanguage + ".license.txt");
   cmsys::ifstream license_ifs;
   license_ifs.open(actual_license.c_str());
   if (license_ifs.is_open()) {
@@ -873,8 +899,9 @@
                                               std::string* error)
 {
   const size_t max_line_length = 512;
-  for (size_t i = 0; i < line.size(); i += max_line_length) {
-    size_t line_length = max_line_length;
+  size_t line_length = max_line_length;
+  for (size_t i = 0; i < line.size(); i += line_length) {
+    line_length = max_line_length;
     if (i + line_length > line.size()) {
       line_length = line.size() - i;
     } else {
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index 6698f3c..712eb77 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -621,9 +621,9 @@
         buildConfigs.emplace_back();
       }
 
-      std::unique_ptr<cmGlobalGenerator> globalGenerator(
+      std::unique_ptr<cmGlobalGenerator> globalGenerator =
         this->MakefileMap->GetCMakeInstance()->CreateGlobalGenerator(
-          cmakeGenerator));
+          cmakeGenerator);
       if (!globalGenerator) {
         cmCPackLogger(cmCPackLog::LOG_ERROR,
                       "Specified package generator not found. "
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
index 9bf72df..363f536 100644
--- a/Source/CPack/cmCPackNSISGenerator.cxx
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
@@ -128,22 +128,26 @@
       this->IsSet("CPACK_NSIS_MUI_UNIICON")) {
     std::string installerIconCode;
     if (this->IsSet("CPACK_NSIS_MUI_ICON")) {
-      installerIconCode += "!define MUI_ICON \"";
-      installerIconCode += this->GetOption("CPACK_NSIS_MUI_ICON");
-      installerIconCode += "\"\n";
+      installerIconCode += cmStrCat(
+        "!define MUI_ICON \"", this->GetOption("CPACK_NSIS_MUI_ICON"), "\"\n");
     }
     if (this->IsSet("CPACK_NSIS_MUI_UNIICON")) {
-      installerIconCode += "!define MUI_UNICON \"";
-      installerIconCode += this->GetOption("CPACK_NSIS_MUI_UNIICON");
-      installerIconCode += "\"\n";
+      installerIconCode +=
+        cmStrCat("!define MUI_UNICON \"",
+                 this->GetOption("CPACK_NSIS_MUI_UNIICON"), "\"\n");
     }
     this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_ICON_CODE",
                             installerIconCode.c_str());
   }
-  if (this->IsSet("CPACK_PACKAGE_ICON")) {
-    std::string installerIconCode =
-      cmStrCat("!define MUI_HEADERIMAGE_BITMAP \"",
-               this->GetOption("CPACK_PACKAGE_ICON"), "\"\n");
+  std::string installerHeaderImage;
+  if (this->IsSet("CPACK_NSIS_MUI_HEADERIMAGE")) {
+    installerHeaderImage = this->GetOption("CPACK_NSIS_MUI_HEADERIMAGE");
+  } else if (this->IsSet("CPACK_PACKAGE_ICON")) {
+    installerHeaderImage = this->GetOption("CPACK_PACKAGE_ICON");
+  }
+  if (!installerHeaderImage.empty()) {
+    std::string installerIconCode = cmStrCat(
+      "!define MUI_HEADERIMAGE_BITMAP \"", installerHeaderImage, "\"\n");
     this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_ICON_CODE",
                             installerIconCode.c_str());
   }
@@ -173,6 +177,32 @@
                             installerRunCode.c_str());
   }
 
+  if (this->IsSet("CPACK_NSIS_WELCOME_TITLE")) {
+    std::string welcomeTitleCode =
+      cmStrCat("!define MUI_WELCOMEPAGE_TITLE \"",
+               this->GetOption("CPACK_NSIS_WELCOME_TITLE"), "\"");
+    this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_WELCOME_TITLE_CODE",
+                            welcomeTitleCode.c_str());
+  }
+
+  if (this->IsSet("CPACK_NSIS_WELCOME_TITLE_3LINES")) {
+    this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_WELCOME_TITLE_3LINES_CODE",
+                            "!define MUI_WELCOMEPAGE_TITLE_3LINES");
+  }
+
+  if (this->IsSet("CPACK_NSIS_FINISH_TITLE")) {
+    std::string finishTitleCode =
+      cmStrCat("!define MUI_FINISHPAGE_TITLE \"",
+               this->GetOption("CPACK_NSIS_FINISH_TITLE"), "\"");
+    this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_FINISH_TITLE_CODE",
+                            finishTitleCode.c_str());
+  }
+
+  if (this->IsSet("CPACK_NSIS_FINISH_TITLE_3LINES")) {
+    this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_FINISH_TITLE_3LINES_CODE",
+                            "!define MUI_FINISHPAGE_TITLE_3LINES");
+  }
+
   // Setup all of the component sections
   if (this->Components.empty()) {
     this->SetOptionIfNotSet("CPACK_NSIS_INSTALLATION_TYPES", "");
diff --git a/Source/CPack/cmCPackOSXX11Generator.cxx b/Source/CPack/cmCPackOSXX11Generator.cxx
index 951c65f..5de4a6f 100644
--- a/Source/CPack/cmCPackOSXX11Generator.cxx
+++ b/Source/CPack/cmCPackOSXX11Generator.cxx
@@ -178,6 +178,9 @@
 
 int cmCPackOSXX11Generator::InitializeInternal()
 {
+  cmCPackLogger(cmCPackLog::LOG_WARNING,
+                "The OSXX11 generator is deprecated "
+                "and will be removed in a future version.\n");
   cmCPackLogger(cmCPackLog::LOG_DEBUG,
                 "cmCPackOSXX11Generator::Initialize()" << std::endl);
   std::vector<std::string> path;
diff --git a/Source/CPack/cmCPackPKGGenerator.cxx b/Source/CPack/cmCPackPKGGenerator.cxx
index dae5ec9..ac3d64d 100644
--- a/Source/CPack/cmCPackPKGGenerator.cxx
+++ b/Source/CPack/cmCPackPKGGenerator.cxx
@@ -46,7 +46,66 @@
   return component.ArchiveFile + ".pkg";
 }
 
-void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile)
+void cmCPackPKGGenerator::CreateBackground(const char* themeName,
+                                           const char* metapackageFile,
+                                           cm::string_view genName,
+                                           cmXMLWriter& xout)
+{
+  std::string paramSuffix =
+    (themeName == nullptr) ? "" : cmSystemTools::UpperCase(themeName);
+  std::string opt = (themeName == nullptr)
+    ? cmStrCat("CPACK_", genName, "_BACKGROUND")
+    : cmStrCat("CPACK_", genName, "_BACKGROUND_", paramSuffix);
+  const char* bgFileName = this->GetOption(opt);
+  if (bgFileName == nullptr) {
+    return;
+  }
+
+  std::string bgFilePath = cmStrCat(metapackageFile, "/Contents/", bgFileName);
+
+  if (!cmSystemTools::FileExists(bgFilePath)) {
+    cmCPackLogger(cmCPackLog::LOG_ERROR,
+                  "Background image doesn't exist in the resource directory: "
+                    << bgFileName << std::endl);
+    return;
+  }
+
+  if (themeName == nullptr) {
+    xout.StartElement("background");
+  } else {
+    xout.StartElement(cmStrCat("background-", themeName));
+  }
+
+  xout.Attribute("file", bgFileName);
+
+  const char* param = this->GetOption(cmStrCat(opt, "_ALIGNMENT"));
+  if (param != nullptr) {
+    xout.Attribute("alignment", param);
+  }
+
+  param = this->GetOption(cmStrCat(opt, "_SCALING"));
+  if (param != nullptr) {
+    xout.Attribute("scaling", param);
+  }
+
+  // Apple docs say that you must provide either mime-type or uti
+  // attribute for the background, but I've seen examples that
+  // doesn't have them, so don't make them mandatory.
+  param = this->GetOption(cmStrCat(opt, "_MIME_TYPE"));
+  if (param != nullptr) {
+    xout.Attribute("mime-type", param);
+  }
+
+  param = this->GetOption(cmStrCat(opt, "_UTI"));
+  if (param != nullptr) {
+    xout.Attribute("uti", param);
+  }
+
+  xout.EndElement();
+}
+
+void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile,
+                                                const char* genName)
 {
   std::string distributionTemplate =
     this->FindTemplate("CPack.distribution.dist.in");
@@ -102,6 +161,11 @@
     CreateChoice(PostFlightComponent, xout);
   }
 
+  // default background
+  this->CreateBackground(nullptr, metapackageFile, genName, xout);
+  // Dark Aqua
+  this->CreateBackground("darkAqua", metapackageFile, genName, xout);
+
   this->SetOption("CPACK_PACKAGEMAKER_CHOICES", choiceOut.str().c_str());
 
   // Create the distribution.dist file in the metapackage to turn it
diff --git a/Source/CPack/cmCPackPKGGenerator.h b/Source/CPack/cmCPackPKGGenerator.h
index 69286ff..be730ab 100644
--- a/Source/CPack/cmCPackPKGGenerator.h
+++ b/Source/CPack/cmCPackPKGGenerator.h
@@ -9,6 +9,8 @@
 #include <sstream>
 #include <string>
 
+#include <cm/string_view>
+
 #include "cmCPackComponentGroup.h"
 #include "cmCPackGenerator.h"
 
@@ -57,7 +59,7 @@
   // inter-component dependencies. metapackageFile is the name of the
   // metapackage for the distribution. Only valid for a
   // component-based install.
-  void WriteDistributionFile(const char* metapackageFile);
+  void WriteDistributionFile(const char* metapackageFile, const char* genName);
 
   // Subroutine of WriteDistributionFile that writes out the
   // dependency attributes for inter-component dependencies.
@@ -85,6 +87,10 @@
   /// installer GUI.
   void CreateChoice(const cmCPackComponent& component, cmXMLWriter& xout);
 
+  /// Creates a background in the distribution XML.
+  void CreateBackground(const char* themeName, const char* metapackageFile,
+                        cm::string_view genName, cmXMLWriter& xout);
+
   // The PostFlight component when creating a metapackage
   cmCPackComponent PostFlightComponent;
 };
diff --git a/Source/CPack/cmCPackPackageMakerGenerator.cxx b/Source/CPack/cmCPackPackageMakerGenerator.cxx
index c5ba726..f51ea42 100644
--- a/Source/CPack/cmCPackPackageMakerGenerator.cxx
+++ b/Source/CPack/cmCPackPackageMakerGenerator.cxx
@@ -279,7 +279,7 @@
   } else {
     // We have built the package in place. Generate the
     // distribution.dist file to describe it for the installer.
-    WriteDistributionFile(packageDirFileName.c_str());
+    WriteDistributionFile(packageDirFileName.c_str(), "PACKAGEMAKER");
   }
 
   std::string tmpFile = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
@@ -321,6 +321,9 @@
 
 int cmCPackPackageMakerGenerator::InitializeInternal()
 {
+  cmCPackLogger(cmCPackLog::LOG_WARNING,
+                "The PackageMaker generator is deprecated "
+                "and will be removed in a future version.\n");
   this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
 
   // Starting with Xcode 4.3, PackageMaker is a separate app, and you
diff --git a/Source/CPack/cmCPackProductBuildGenerator.cxx b/Source/CPack/cmCPackProductBuildGenerator.cxx
index dae268c..a3e55de 100644
--- a/Source/CPack/cmCPackProductBuildGenerator.cxx
+++ b/Source/CPack/cmCPackProductBuildGenerator.cxx
@@ -81,7 +81,7 @@
   }
 
   // combine package(s) into a distribution
-  WriteDistributionFile(packageDirFileName.c_str());
+  WriteDistributionFile(packageDirFileName.c_str(), "PRODUCTBUILD");
   std::ostringstream pkgCmd;
 
   std::string version = this->GetOption("CPACK_PACKAGE_VERSION");
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
index 5895652..dc31623 100644
--- a/Source/CPack/cpack.cxx
+++ b/Source/CPack/cpack.cxx
@@ -115,7 +115,6 @@
   argc = args.argc();
   argv = args.argv();
 
-  cmSystemTools::EnableMSVCDebugHook();
   cmSystemTools::InitializeLibUV();
   cmSystemTools::FindCMakeResources(argv[0]);
   cmCPackLog log;
@@ -314,7 +313,7 @@
     else {
       // get a default value (current working directory)
       cpackProjectDirectory = cmsys::SystemTools::GetCurrentWorkingDirectory();
-      // use default value iff no value has been provided by the config file
+      // use default value if no value has been provided by the config file
       if (!globalMF.IsSet("CPACK_PACKAGE_DIRECTORY")) {
         globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY",
                                cpackProjectDirectory);
@@ -324,6 +323,12 @@
       globalMF.AddDefinition(cd.first, cd.second);
     }
 
+    // Force CPACK_PACKAGE_DIRECTORY as absolute path
+    cpackProjectDirectory = globalMF.GetDefinition("CPACK_PACKAGE_DIRECTORY");
+    cpackProjectDirectory =
+      cmSystemTools::CollapseFullPath(cpackProjectDirectory);
+    globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY", cpackProjectDirectory);
+
     const char* cpackModulesPath = globalMF.GetDefinition("CPACK_MODULE_PATH");
     if (cpackModulesPath) {
       globalMF.AddDefinition("CMAKE_MODULE_PATH", cpackModulesPath);
diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx
index 8640c46..c87fb83b 100644
--- a/Source/CTest/cmCTestBZR.cxx
+++ b/Source/CTest/cmCTestBZR.cxx
@@ -8,11 +8,12 @@
 #include <ostream>
 #include <vector>
 
+#include <cmext/algorithm>
+
 #include "cmsys/RegularExpression.hxx"
 
 #include "cm_expat.h"
 
-#include "cmAlgorithms.h"
 #include "cmCTest.h"
 #include "cmCTestVC.h"
 #include "cmProcessTools.h"
@@ -245,7 +246,7 @@
 
   void CharacterDataHandler(const char* data, int length) override
   {
-    cmAppend(this->CData, data, data + length);
+    cm::append(this->CData, data, data + length);
   }
 
   void EndElement(const std::string& name) override
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
index 2ad661c..5e29386 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -215,11 +215,11 @@
 
   if (this->BuildNoCMake) {
     // Make the generator available for the Build call below.
-    cmGlobalGenerator* gen = cm.CreateGlobalGenerator(this->BuildGenerator);
-    cm.SetGlobalGenerator(gen);
+    cm.SetGlobalGenerator(cm.CreateGlobalGenerator(this->BuildGenerator));
     if (!this->BuildGeneratorPlatform.empty()) {
-      cmMakefile mf(gen, cm.GetCurrentSnapshot());
-      if (!gen->SetGeneratorPlatform(this->BuildGeneratorPlatform, &mf)) {
+      cmMakefile mf(cm.GetGlobalGenerator(), cm.GetCurrentSnapshot());
+      if (!cm.GetGlobalGenerator()->SetGeneratorPlatform(
+            this->BuildGeneratorPlatform, &mf)) {
         return 1;
       }
     }
diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx
index 18df214..d1b7701 100644
--- a/Source/CTest/cmCTestBuildCommand.cxx
+++ b/Source/CTest/cmCTestBuildCommand.cxx
@@ -29,13 +29,7 @@
   this->Bind("PROJECT_NAME"_s, this->ProjectName);
 }
 
-cmCTestBuildCommand::~cmCTestBuildCommand()
-{
-  if (this->GlobalGenerator) {
-    delete this->GlobalGenerator;
-    this->GlobalGenerator = nullptr;
-  }
-}
+cmCTestBuildCommand::~cmCTestBuildCommand() = default;
 
 cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
 {
@@ -79,8 +73,7 @@
       }
       if (this->GlobalGenerator) {
         if (this->GlobalGenerator->GetName() != cmakeGeneratorName) {
-          delete this->GlobalGenerator;
-          this->GlobalGenerator = nullptr;
+          this->GlobalGenerator.reset();
         }
       }
       if (!this->GlobalGenerator) {
diff --git a/Source/CTest/cmCTestBuildCommand.h b/Source/CTest/cmCTestBuildCommand.h
index da00a43..0f82817 100644
--- a/Source/CTest/cmCTestBuildCommand.h
+++ b/Source/CTest/cmCTestBuildCommand.h
@@ -48,7 +48,7 @@
   bool InitialPass(std::vector<std::string> const& args,
                    cmExecutionStatus& status) override;
 
-  cmGlobalGenerator* GlobalGenerator = nullptr;
+  std::unique_ptr<cmGlobalGenerator> GlobalGenerator;
 
 protected:
   cmCTestBuildHandler* Handler;
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index 9cb5449..03a3fd3 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -7,11 +7,12 @@
 #include <set>
 #include <utility>
 
+#include <cmext/algorithm>
+
 #include "cmsys/Directory.hxx"
 #include "cmsys/FStream.hxx"
 #include "cmsys/Process.h"
 
-#include "cmAlgorithms.h"
 #include "cmCTest.h"
 #include "cmDuration.h"
 #include "cmFileTimeCache.h"
@@ -969,7 +970,7 @@
     if (it != queue->end()) {
       // Create a contiguous array for the line
       this->CurrentProcessingLine.clear();
-      cmAppend(this->CurrentProcessingLine, queue->begin(), it);
+      cm::append(this->CurrentProcessingLine, queue->begin(), it);
       this->CurrentProcessingLine.push_back(0);
       const char* line = this->CurrentProcessingLine.data();
 
diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx
index f2f42b4..3854710 100644
--- a/Source/CTest/cmCTestConfigureCommand.cxx
+++ b/Source/CTest/cmCTestConfigureCommand.cxx
@@ -69,12 +69,11 @@
       bool multiConfig = false;
       bool cmakeBuildTypeInOptions = false;
 
-      cmGlobalGenerator* gg =
-        this->Makefile->GetCMakeInstance()->CreateGlobalGenerator(
-          cmakeGeneratorName);
+      auto gg = this->Makefile->GetCMakeInstance()->CreateGlobalGenerator(
+        cmakeGeneratorName);
       if (gg) {
         multiConfig = gg->IsMultiConfig();
-        delete gg;
+        gg.reset();
       }
 
       std::string cmakeConfigureCommand =
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index 4cd783f..2c8f119 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -12,12 +12,13 @@
 #include <sstream>
 #include <utility>
 
+#include <cmext/algorithm>
+
 #include "cmsys/FStream.hxx"
 #include "cmsys/Glob.hxx"
 #include "cmsys/Process.h"
 #include "cmsys/RegularExpression.hxx"
 
-#include "cmAlgorithms.h"
 #include "cmCTest.h"
 #include "cmDuration.h"
 #include "cmGeneratedFileStream.h"
@@ -819,7 +820,7 @@
   std::string binaryDir = this->CTest->GetCTestConfiguration("BuildDirectory");
   std::string binCoverageFile = binaryDir + "/*jacoco.xml";
   g2.FindFiles(binCoverageFile);
-  cmAppend(files, g2.GetFiles());
+  cm::append(files, g2.GetFiles());
 
   if (!files.empty()) {
     cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
@@ -1462,7 +1463,7 @@
         "   looking for LCOV files in: " << daGlob << std::endl, this->Quiet);
       gl.FindFiles(daGlob);
       // Keep a list of all LCOV files
-      cmAppend(lcovFiles, gl.GetFiles());
+      cm::append(lcovFiles, gl.GetFiles());
 
       for (std::string const& file : lcovFiles) {
         lcovFile = file;
@@ -1599,10 +1600,10 @@
       "   globbing for coverage in: " << lm.first << std::endl, this->Quiet);
     std::string daGlob = cmStrCat(lm.first, "/*.da");
     gl.FindFiles(daGlob);
-    cmAppend(files, gl.GetFiles());
+    cm::append(files, gl.GetFiles());
     daGlob = cmStrCat(lm.first, "/*.gcda");
     gl.FindFiles(daGlob);
-    cmAppend(files, gl.GetFiles());
+    cm::append(files, gl.GetFiles());
   }
 }
 
@@ -1638,7 +1639,7 @@
                "Error while finding files matching " << daGlob << std::endl);
     return false;
   }
-  cmAppend(files, gl.GetFiles());
+  cm::append(files, gl.GetFiles());
   cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                      "Now searching in: " << daGlob << std::endl, this->Quiet);
   return true;
diff --git a/Source/CTest/cmCTestCurl.cxx b/Source/CTest/cmCTestCurl.cxx
index ccac832..69c5793 100644
--- a/Source/CTest/cmCTestCurl.cxx
+++ b/Source/CTest/cmCTestCurl.cxx
@@ -5,7 +5,8 @@
 #include <cstdio>
 #include <ostream>
 
-#include "cmAlgorithms.h"
+#include <cmext/algorithm>
+
 #include "cmCTest.h"
 #include "cmCurl.h"
 #include "cmStringAlgorithms.h"
@@ -46,15 +47,15 @@
 {
   int realsize = static_cast<int>(size * nmemb);
   const char* chPtr = static_cast<char*>(ptr);
-  cmAppend(*static_cast<std::vector<char>*>(data), chPtr, chPtr + realsize);
+  cm::append(*static_cast<std::vector<char>*>(data), chPtr, chPtr + realsize);
   return realsize;
 }
 
 size_t curlDebugCallback(CURL* /*unused*/, curl_infotype /*unused*/,
                          char* chPtr, size_t size, void* data)
 {
-  cmAppend(*static_cast<std::vector<char>*>(data), chPtr, chPtr + size);
-  return size;
+  cm::append(*static_cast<std::vector<char>*>(data), chPtr, chPtr + size);
+  return 0;
 }
 }
 
diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx
index 3265498..5f4581e 100644
--- a/Source/CTest/cmCTestHG.cxx
+++ b/Source/CTest/cmCTestHG.cxx
@@ -5,9 +5,10 @@
 #include <ostream>
 #include <vector>
 
+#include <cmext/algorithm>
+
 #include "cmsys/RegularExpression.hxx"
 
-#include "cmAlgorithms.h"
 #include "cmCTest.h"
 #include "cmCTestVC.h"
 #include "cmProcessTools.h"
@@ -204,7 +205,7 @@
 
   void CharacterDataHandler(const char* data, int length) override
   {
-    cmAppend(this->CData, data, data + length);
+    cm::append(this->CData, data, data + length);
   }
 
   void EndElement(const std::string& name) override
diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx
index a5ec1ae..c1ecaf1 100644
--- a/Source/CTest/cmCTestMemCheckHandler.cxx
+++ b/Source/CTest/cmCTestMemCheckHandler.cxx
@@ -2,9 +2,11 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCTestMemCheckHandler.h"
 
+#include <algorithm>
 #include <chrono>
 #include <cstring>
 #include <iostream>
+#include <iterator>
 #include <sstream>
 #include <utility>
 
@@ -12,6 +14,7 @@
 #include "cmsys/Glob.hxx"
 #include "cmsys/RegularExpression.hxx"
 
+#include "cmAlgorithms.h"
 #include "cmCTest.h"
 #include "cmDuration.h"
 #include "cmSystemTools.h"
@@ -162,12 +165,13 @@
 void cmCTestMemCheckHandler::GenerateTestCommand(
   std::vector<std::string>& args, int test)
 {
-  std::string index;
-  std::ostringstream stream;
+  std::string index = std::to_string(test);
   std::string memcheckcommand =
     cmSystemTools::ConvertToOutputPath(this->MemoryTester);
-  stream << test;
-  index = stream.str();
+
+  std::vector<std::string> dirs;
+  bool nextArgIsDir = false;
+
   for (std::string arg : this->MemoryTesterDynamicOptions) {
     std::string::size_type pos = arg.find("??");
     if (pos != std::string::npos) {
@@ -177,6 +181,16 @@
     memcheckcommand += " \"";
     memcheckcommand += arg;
     memcheckcommand += "\"";
+
+    if (nextArgIsDir) {
+      nextArgIsDir = false;
+      dirs.push_back(arg);
+    }
+
+    if (this->MemoryTesterStyle == cmCTestMemCheckHandler::DRMEMORY &&
+        (arg == "-logdir" || arg == "-symcache_dir")) {
+      nextArgIsDir = true;
+    }
   }
   // Create a copy of the memory tester environment variable.
   // This is used for memory testing programs that pass options
@@ -208,6 +222,11 @@
     memcheckcommand += " " + memTesterEnvironmentVariable;
     args.push_back(memTesterEnvironmentVariable);
   }
+
+  for (std::string const& dir : dirs) {
+    cmSystemTools::MakeDirectory(dir);
+  }
+
   cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                      "Memory check command: " << memcheckcommand << std::endl,
                      this->Quiet);
@@ -300,6 +319,9 @@
     case cmCTestMemCheckHandler::VALGRIND:
       xml.Attribute("Checker", "Valgrind");
       break;
+    case cmCTestMemCheckHandler::DRMEMORY:
+      xml.Attribute("Checker", "DrMemory");
+      break;
     case cmCTestMemCheckHandler::PURIFY:
       xml.Attribute("Checker", "Purify");
       break;
@@ -387,11 +409,11 @@
   }
   cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
                      "MemCheck log files can be found here: "
-                     "( * corresponds to test number)"
+                     "(<#> corresponds to test number)"
                        << std::endl,
                      this->Quiet);
   std::string output = this->MemoryTesterOutputFile;
-  cmSystemTools::ReplaceString(output, "??", "*");
+  cmSystemTools::ReplaceString(output, "??", "<#>");
   cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, output << std::endl,
                      this->Quiet);
   cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
@@ -437,6 +459,10 @@
     if (testerName.find("valgrind") != std::string::npos ||
         this->CTest->GetCTestConfiguration("MemoryCheckType") == "Valgrind") {
       this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
+    } else if (testerName.find("drmemory") != std::string::npos ||
+               this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+                 "DrMemory") {
+      this->MemoryTesterStyle = cmCTestMemCheckHandler::DRMEMORY;
     } else if (testerName.find("purify") != std::string::npos) {
       this->MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY;
     } else if (testerName.find("BC") != std::string::npos) {
@@ -453,6 +479,10 @@
     this->MemoryTester = this->CTest->GetCTestConfiguration("ValgrindCommand");
     this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
   } else if (cmSystemTools::FileExists(
+               this->CTest->GetCTestConfiguration("DrMemoryCommand"))) {
+    this->MemoryTester = this->CTest->GetCTestConfiguration("DrMemoryCommand");
+    this->MemoryTesterStyle = cmCTestMemCheckHandler::DRMEMORY;
+  } else if (cmSystemTools::FileExists(
                this->CTest->GetCTestConfiguration("BoundsCheckerCommand"))) {
     this->MemoryTester =
       this->CTest->GetCTestConfiguration("BoundsCheckerCommand");
@@ -498,6 +528,8 @@
       this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
     } else if (checkType == "Valgrind") {
       this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
+    } else if (checkType == "DrMemory") {
+      this->MemoryTesterStyle = cmCTestMemCheckHandler::DRMEMORY;
     }
   }
   if (this->MemoryTester.empty()) {
@@ -519,6 +551,10 @@
                 .empty()) {
     memoryTesterOptions =
       this->CTest->GetCTestConfiguration("ValgrindCommandOptions");
+  } else if (!this->CTest->GetCTestConfiguration("DrMemoryCommandOptions")
+                .empty()) {
+    memoryTesterOptions =
+      this->CTest->GetCTestConfiguration("DrMemoryCommandOptions");
   }
   this->MemoryTesterOptions =
     cmSystemTools::ParseArguments(memoryTesterOptions);
@@ -554,6 +590,64 @@
                                                  this->MemoryTesterOutputFile);
       break;
     }
+    case cmCTestMemCheckHandler::DRMEMORY: {
+      std::string tempDrMemoryDir =
+        this->CTest->GetBinaryDir() + "/Testing/Temporary/DrMemory";
+
+      if (!cmContains(this->MemoryTesterOptions, "-quiet")) {
+        this->MemoryTesterOptions.emplace_back("-quiet");
+      }
+
+      if (!cmContains(this->MemoryTesterOptions, "-batch")) {
+        this->MemoryTesterOptions.emplace_back("-batch");
+      }
+
+      this->MemoryTesterDynamicOptions.emplace_back("-logdir");
+      auto logdirOption =
+        std::find(this->MemoryTesterOptions.begin(),
+                  this->MemoryTesterOptions.end(), "-logdir");
+      if (logdirOption == this->MemoryTesterOptions.end()) {
+        // No logdir found in memory tester options
+        std::string drMemoryLogDir = tempDrMemoryDir + "/??";
+        this->MemoryTesterDynamicOptions.push_back(drMemoryLogDir);
+        this->MemoryTesterOutputFile = drMemoryLogDir;
+      } else {
+        // Use logdir found in memory tester options
+        auto logdirLocation = std::next(logdirOption);
+        this->MemoryTesterOutputFile = *logdirLocation;
+        this->MemoryTesterDynamicOptions.push_back(*logdirLocation);
+        this->MemoryTesterOptions.erase(logdirOption, logdirLocation + 1);
+      }
+      this->MemoryTesterOutputFile += "/*/results.txt";
+
+      if (std::find(this->MemoryTesterOptions.begin(),
+                    this->MemoryTesterOptions.end(),
+                    "-symcache_dir") == this->MemoryTesterOptions.end()) {
+        this->MemoryTesterDynamicOptions.emplace_back("-symcache_dir");
+        std::string drMemoryCacheDir = tempDrMemoryDir + "/cache";
+        this->MemoryTesterDynamicOptions.push_back(drMemoryCacheDir);
+      }
+
+      if (!this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")
+             .empty()) {
+        if (!cmSystemTools::FileExists(this->CTest->GetCTestConfiguration(
+              "MemoryCheckSuppressionFile"))) {
+          cmCTestLog(this->CTest, ERROR_MESSAGE,
+                     "Cannot find memory checker suppression file: "
+                       << this->CTest->GetCTestConfiguration(
+                            "MemoryCheckSuppressionFile")
+                       << std::endl);
+          return false;
+        }
+        this->MemoryTesterOptions.emplace_back("-suppress");
+        this->MemoryTesterOptions.push_back(
+          this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile"));
+      }
+
+      this->MemoryTesterOptions.emplace_back("--");
+
+      break;
+    }
     case cmCTestMemCheckHandler::PURIFY: {
       std::string outputFile;
 #ifdef _WIN32
@@ -667,6 +761,8 @@
   switch (this->MemoryTesterStyle) {
     case cmCTestMemCheckHandler::VALGRIND:
       return this->ProcessMemCheckValgrindOutput(str, log, results);
+    case cmCTestMemCheckHandler::DRMEMORY:
+      return this->ProcessMemCheckDrMemoryOutput(str, log, results);
     case cmCTestMemCheckHandler::PURIFY:
       return this->ProcessMemCheckPurifyOutput(str, log, results);
     case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
@@ -932,6 +1028,47 @@
   return defects == 0;
 }
 
+bool cmCTestMemCheckHandler::ProcessMemCheckDrMemoryOutput(
+  const std::string& str, std::string& log, std::vector<int>& results)
+{
+  std::vector<std::string> lines;
+  cmsys::SystemTools::Split(str, lines);
+
+  cmsys::RegularExpression drMemoryError("^Error #[0-9]+");
+
+  cmsys::RegularExpression unaddressableAccess("UNADDRESSABLE ACCESS");
+  cmsys::RegularExpression uninitializedRead("UNINITIALIZED READ");
+  cmsys::RegularExpression invalidHeapArgument("INVALID HEAP ARGUMENT");
+  cmsys::RegularExpression leak("LEAK");
+  cmsys::RegularExpression handleLeak("HANDLE LEAK");
+
+  int defects = 0;
+
+  std::ostringstream ostr;
+  for (const auto& l : lines) {
+    ostr << l << std::endl;
+    if (drMemoryError.find(l)) {
+      defects++;
+      if (unaddressableAccess.find(l)) {
+        results[cmCTestMemCheckHandler::UMR]++;
+      } else if (uninitializedRead.find(l)) {
+        results[cmCTestMemCheckHandler::UMR]++;
+      } else if (leak.find(l)) {
+        results[cmCTestMemCheckHandler::MLK]++;
+      } else if (handleLeak.find(l)) {
+        results[cmCTestMemCheckHandler::MLK]++;
+      } else if (invalidHeapArgument.find(l)) {
+        results[cmCTestMemCheckHandler::FMM]++;
+      }
+    }
+  }
+
+  log = ostr.str();
+
+  this->DefectCount += defects;
+  return defects == 0;
+}
+
 bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput(
   const std::string& str, std::string& log, std::vector<int>& results)
 {
@@ -991,6 +1128,8 @@
                      this->Quiet);
   if (this->MemoryTesterStyle == cmCTestMemCheckHandler::BOUNDS_CHECKER) {
     this->PostProcessBoundsCheckerTest(res, test);
+  } else if (this->MemoryTesterStyle == cmCTestMemCheckHandler::DRMEMORY) {
+    this->PostProcessDrMemoryTest(res, test);
   } else {
     std::vector<std::string> files;
     this->TestOutputFileNames(test, files);
@@ -1045,6 +1184,37 @@
                      this->Quiet);
 }
 
+void cmCTestMemCheckHandler::PostProcessDrMemoryTest(
+  cmCTestTestHandler::cmCTestTestResult& res, int test)
+{
+  std::string drMemoryLogDir = this->MemoryTesterOutputFile.substr(
+    0, this->MemoryTesterOutputFile.find("/*/results.txt"));
+
+  // replace placeholder of test
+  std::string::size_type pos = drMemoryLogDir.find("??");
+  if (pos != std::string::npos) {
+    drMemoryLogDir.replace(pos, 2, std::to_string(test));
+  }
+
+  cmsys::Glob g;
+  g.FindFiles(drMemoryLogDir + "/resfile.*");
+  const std::vector<std::string>& files = g.GetFiles();
+
+  for (const std::string& f : files) {
+    cmsys::ifstream ifs(f.c_str());
+    if (!ifs) {
+      std::string log = "Cannot read memory tester output file: " + f;
+      cmCTestLog(this->CTest, ERROR_MESSAGE, log << std::endl);
+      return;
+    }
+    std::string resultFileLocation;
+    cmSystemTools::GetLineFromStream(ifs, resultFileLocation);
+    this->AppendMemTesterOutput(res, resultFileLocation);
+    ifs.close();
+    cmSystemTools::RemoveFile(f);
+  }
+}
+
 void cmCTestMemCheckHandler::AppendMemTesterOutput(cmCTestTestResult& res,
                                                    std::string const& ofile)
 {
diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h
index eda65f7..52667f8 100644
--- a/Source/CTest/cmCTestMemCheckHandler.h
+++ b/Source/CTest/cmCTestMemCheckHandler.h
@@ -43,6 +43,7 @@
     UNKNOWN = 0,
     VALGRIND,
     PURIFY,
+    DRMEMORY,
     BOUNDS_CHECKER,
     // checkers after here do not use the standard error list
     ADDRESS_SANITIZER,
@@ -132,6 +133,8 @@
                              std::vector<int>& results);
   bool ProcessMemCheckValgrindOutput(const std::string& str, std::string& log,
                                      std::vector<int>& results);
+  bool ProcessMemCheckDrMemoryOutput(const std::string& str, std::string& log,
+                                     std::vector<int>& results);
   bool ProcessMemCheckPurifyOutput(const std::string& str, std::string& log,
                                    std::vector<int>& results);
   bool ProcessMemCheckSanitizerOutput(const std::string& str, std::string& log,
@@ -142,6 +145,7 @@
 
   void PostProcessTest(cmCTestTestResult& res, int test);
   void PostProcessBoundsCheckerTest(cmCTestTestResult& res, int test);
+  void PostProcessDrMemoryTest(cmCTestTestResult& res, int test);
 
   //! append MemoryTesterOutputFile to the test log
   void AppendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res,
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 02d396e..2192843 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -19,6 +19,8 @@
 #include <utility>
 #include <vector>
 
+#include <cmext/algorithm>
+
 #include "cmsys/FStream.hxx"
 #include "cmsys/SystemInformation.hxx"
 
@@ -171,9 +173,9 @@
   this->RunningCount += GetProcessorsUsed(test);
 
   cmCTestRunTest* testRun = new cmCTestRunTest(*this);
-  if (this->CTest->GetRepeatUntilFail()) {
-    testRun->SetRunUntilFailOn();
-    testRun->SetNumberOfRuns(this->CTest->GetTestRepeat());
+  if (this->RepeatMode != cmCTest::Repeat::Never) {
+    testRun->SetRepeatMode(this->RepeatMode);
+    testRun->SetNumberOfRuns(this->RepeatCount);
   }
   testRun->SetIndex(test);
   testRun->SetTestProperties(this->Properties[test]);
@@ -194,8 +196,40 @@
   // working directory because FinishTestProcess() will try to unlock them
   this->LockResources(test);
 
-  if (!this->TestsHaveSufficientResources[test]) {
-    testRun->StartFailure("Insufficient resources");
+  if (!this->ResourceAllocationErrors[test].empty()) {
+    std::ostringstream e;
+    e << "Insufficient resources for test " << this->Properties[test]->Name
+      << ":\n\n";
+    for (auto const& it : this->ResourceAllocationErrors[test]) {
+      switch (it.second) {
+        case ResourceAllocationError::NoResourceType:
+          e << "  Test requested resources of type '" << it.first
+            << "' which does not exist\n";
+          break;
+
+        case ResourceAllocationError::InsufficientResources:
+          e << "  Test requested resources of type '" << it.first
+            << "' in the following amounts:\n";
+          for (auto const& group : this->Properties[test]->ResourceGroups) {
+            for (auto const& requirement : group) {
+              if (requirement.ResourceType == it.first) {
+                e << "    " << requirement.SlotsNeeded
+                  << (requirement.SlotsNeeded == 1 ? " slot\n" : " slots\n");
+              }
+            }
+          }
+          e << "  but only the following units were available:\n";
+          for (auto const& res :
+               this->ResourceAllocator.GetResources().at(it.first)) {
+            e << "    '" << res.first << "': " << res.second.Total
+              << (res.second.Total == 1 ? " slot\n" : " slots\n");
+          }
+          break;
+      }
+      e << "\n";
+    }
+    e << "Resource spec file:\n\n  " << this->TestHandler->ResourceSpecFile;
+    testRun->StartFailure(e.str(), "Insufficient resources");
     this->FinishTestProcess(testRun, false);
     return false;
   }
@@ -203,8 +237,9 @@
   cmWorkingDirectory workdir(this->Properties[test]->Directory);
   if (workdir.Failed()) {
     testRun->StartFailure("Failed to change working directory to " +
-                          this->Properties[test]->Directory + " : " +
-                          std::strerror(workdir.GetLastResult()));
+                            this->Properties[test]->Directory + " : " +
+                            std::strerror(workdir.GetLastResult()),
+                          "Failed to change working directory");
   } else {
     if (testRun->StartTest(this->Completed, this->Total)) {
       // Ownership of 'testRun' has moved to another structure.
@@ -247,7 +282,8 @@
 
 bool cmCTestMultiProcessHandler::TryAllocateResources(
   int index,
-  std::map<std::string, std::vector<cmCTestBinPackerAllocation>>& allocations)
+  std::map<std::string, std::vector<cmCTestBinPackerAllocation>>& allocations,
+  std::map<std::string, ResourceAllocationError>* errors)
 {
   allocations.clear();
 
@@ -262,18 +298,28 @@
     ++processIndex;
   }
 
+  bool result = true;
   auto const& availableResources = this->ResourceAllocator.GetResources();
   for (auto& it : allocations) {
     if (!availableResources.count(it.first)) {
-      return false;
-    }
-    if (!cmAllocateCTestResourcesRoundRobin(availableResources.at(it.first),
-                                            it.second)) {
-      return false;
+      if (errors) {
+        (*errors)[it.first] = ResourceAllocationError::NoResourceType;
+        result = false;
+      } else {
+        return false;
+      }
+    } else if (!cmAllocateCTestResourcesRoundRobin(
+                 availableResources.at(it.first), it.second)) {
+      if (errors) {
+        (*errors)[it.first] = ResourceAllocationError::InsufficientResources;
+        result = false;
+      } else {
+        return false;
+      }
     }
   }
 
-  return true;
+  return result;
 }
 
 void cmCTestMultiProcessHandler::DeallocateResources(int index)
@@ -314,11 +360,13 @@
 
 void cmCTestMultiProcessHandler::CheckResourcesAvailable()
 {
-  for (auto test : this->SortedTests) {
-    std::map<std::string, std::vector<cmCTestBinPackerAllocation>> allocations;
-    this->TestsHaveSufficientResources[test] =
-      !this->TestHandler->UseResourceSpec ||
-      this->TryAllocateResources(test, allocations);
+  if (this->TestHandler->UseResourceSpec) {
+    for (auto test : this->SortedTests) {
+      std::map<std::string, std::vector<cmCTestBinPackerAllocation>>
+        allocations;
+      this->TryAllocateResources(test, allocations,
+                                 &this->ResourceAllocationErrors[test]);
+    }
   }
 }
 
@@ -405,7 +453,7 @@
   }
 
   // Allocate resources
-  if (this->TestsHaveSufficientResources[test] &&
+  if (this->ResourceAllocationErrors[test].empty() &&
       !this->AllocateResources(test)) {
     this->DeallocateResources(test);
     return false;
@@ -788,7 +836,7 @@
   // Sort tests within each level by COST and append them to the cost list.
   for (TestSet const& currentSet : cmReverseRange(priorityStack)) {
     TestList sortedCopy;
-    cmAppend(sortedCopy, currentSet);
+    cm::append(sortedCopy, currentSet);
     std::stable_sort(sortedCopy.begin(), sortedCopy.end(),
                      TestComparator(this));
 
@@ -1154,7 +1202,7 @@
     const std::vector<std::string>& args = testRun.GetArguments();
     if (!args.empty()) {
       commandAndArgs.reserve(args.size() + 1);
-      cmAppend(commandAndArgs, args);
+      cm::append(commandAndArgs, args);
     }
     testInfo["command"] = DumpToJsonArray(commandAndArgs);
   }
diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h
index 1db4bfd..5b429d4 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.h
+++ b/Source/CTest/cmCTestMultiProcessHandler.h
@@ -14,11 +14,11 @@
 
 #include "cm_uv.h"
 
+#include "cmCTest.h"
 #include "cmCTestResourceAllocator.h"
 #include "cmCTestTestHandler.h"
 #include "cmUVHandlePtr.h"
 
-class cmCTest;
 struct cmCTestBinPackerAllocation;
 class cmCTestResourceSpec;
 class cmCTestRunTest;
@@ -85,6 +85,12 @@
 
   cmCTestTestHandler* GetTestHandler() { return this->TestHandler; }
 
+  void SetRepeatMode(cmCTest::Repeat mode, int count)
+  {
+    this->RepeatMode = mode;
+    this->RepeatCount = count;
+  }
+
   void SetQuiet(bool b) { this->Quiet = b; }
 
   void InitResourceAllocator(const cmCTestResourceSpec& spec)
@@ -137,11 +143,18 @@
   void LockResources(int index);
   void UnlockResources(int index);
 
+  enum class ResourceAllocationError
+  {
+    NoResourceType,
+    InsufficientResources,
+  };
+
   bool AllocateResources(int index);
   bool TryAllocateResources(
     int index,
     std::map<std::string, std::vector<cmCTestBinPackerAllocation>>&
-      allocations);
+      allocations,
+    std::map<std::string, ResourceAllocationError>* errors = nullptr);
   void DeallocateResources(int index);
   bool AllResourcesAvailable();
 
@@ -168,7 +181,8 @@
   std::map<int,
            std::vector<std::map<std::string, std::vector<ResourceAllocation>>>>
     AllocatedResources;
-  std::map<int, bool> TestsHaveSufficientResources;
+  std::map<int, std::map<std::string, ResourceAllocationError>>
+    ResourceAllocationErrors;
   cmCTestResourceAllocator ResourceAllocator;
   std::vector<cmCTestTestHandler::cmCTestTestResult>* TestResults;
   size_t ParallelLevel; // max number of process that can be run at once
@@ -179,6 +193,8 @@
   cmCTestTestHandler* TestHandler;
   cmCTest* CTest;
   bool HasCycles;
+  cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never;
+  int RepeatCount = 1;
   bool Quiet;
   bool SerialTestRunning;
 };
diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx
index e2063e1..1375be4 100644
--- a/Source/CTest/cmCTestP4.cxx
+++ b/Source/CTest/cmCTestP4.cxx
@@ -7,9 +7,10 @@
 #include <ostream>
 #include <utility>
 
+#include <cmext/algorithm>
+
 #include "cmsys/RegularExpression.hxx"
 
-#include "cmAlgorithms.h"
 #include "cmCTest.h"
 #include "cmCTestVC.h"
 #include "cmProcessTools.h"
@@ -326,7 +327,7 @@
     // The CTEST_P4_OPTIONS variable adds additional Perforce command line
     // options before the main command
     std::string opts = this->CTest->GetCTestConfiguration("P4Options");
-    cmAppend(P4Options, cmSystemTools::ParseArguments(opts));
+    cm::append(P4Options, cmSystemTools::ParseArguments(opts));
   }
 
   CommandOptions.clear();
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 3091050..ec54960 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -34,9 +34,6 @@
   this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
   this->TestResult.TestCount = 0;
   this->TestResult.Properties = nullptr;
-  this->NumberOfRunsLeft = 1; // default to 1 run of the test
-  this->RunUntilFail = false; // default to run the test once
-  this->RunAgain = false;     // default to not having to run again
 }
 
 void cmCTestRunTest::CheckOutput(std::string const& line)
@@ -310,7 +307,7 @@
   }
   // If the test does not need to rerun push the current TestResult onto the
   // TestHandler vector
-  if (!this->NeedsToRerun()) {
+  if (!this->NeedsToRepeat()) {
     this->TestHandler->TestResults.push_back(this->TestResult);
   }
   this->TestProcess.reset();
@@ -327,8 +324,9 @@
   cmWorkingDirectory workdir(this->TestProperties->Directory);
   if (workdir.Failed()) {
     this->StartFailure("Failed to change working directory to " +
-                       this->TestProperties->Directory + " : " +
-                       std::strerror(workdir.GetLastResult()));
+                         this->TestProperties->Directory + " : " +
+                         std::strerror(workdir.GetLastResult()),
+                       "Failed to change working directory");
     return true;
   }
 
@@ -336,17 +334,21 @@
   return true;
 }
 
-bool cmCTestRunTest::NeedsToRerun()
+bool cmCTestRunTest::NeedsToRepeat()
 {
   this->NumberOfRunsLeft--;
   if (this->NumberOfRunsLeft == 0) {
     return false;
   }
   // if number of runs left is not 0, and we are running until
-  // we find a failed test, then return true so the test can be
+  // we find a failed (or passed) test, then return true so the test can be
   // restarted
-  if (this->RunUntilFail &&
-      this->TestResult.Status == cmCTestTestHandler::COMPLETED) {
+  if ((this->RepeatMode == cmCTest::Repeat::UntilFail &&
+       this->TestResult.Status == cmCTestTestHandler::COMPLETED) ||
+      (this->RepeatMode == cmCTest::Repeat::UntilPass &&
+       this->TestResult.Status != cmCTestTestHandler::COMPLETED) ||
+      (this->RepeatMode == cmCTest::Repeat::AfterTimeout &&
+       this->TestResult.Status == cmCTestTestHandler::TIMEOUT)) {
     this->RunAgain = true;
     return true;
   }
@@ -380,7 +382,8 @@
   handler->PostProcessTest(this->TestResult, this->Index);
 }
 
-void cmCTestRunTest::StartFailure(std::string const& output)
+void cmCTestRunTest::StartFailure(std::string const& output,
+                                  std::string const& detail)
 {
   // Still need to log the Start message so the test summary records our
   // attempt to start this test
@@ -403,7 +406,7 @@
   this->TestResult.ExecutionTime = cmDuration::zero();
   this->TestResult.CompressOutput = false;
   this->TestResult.ReturnValue = -1;
-  this->TestResult.CompletionStatus = "Failed to start";
+  this->TestResult.CompletionStatus = detail;
   this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
   this->TestResult.TestCount = this->TestProperties->Index;
   this->TestResult.Name = this->TestProperties->Name;
@@ -746,7 +749,12 @@
   // then it will never print out the completed / total, same would
   // got for run until pass.  Trick is when this is called we don't
   // yet know if we are passing or failing.
-  if (this->NumberOfRunsLeft == 1 || this->CTest->GetTestProgressOutput()) {
+  bool const progressOnLast =
+    (this->RepeatMode != cmCTest::Repeat::UntilPass &&
+     this->RepeatMode != cmCTest::Repeat::AfterTimeout);
+  if ((progressOnLast && this->NumberOfRunsLeft == 1) ||
+      (!progressOnLast && this->NumberOfRunsLeft == this->NumberOfRunsTotal) ||
+      this->CTest->GetTestProgressOutput()) {
     outputStream << std::setw(getNumWidth(total)) << completed << "/";
     outputStream << std::setw(getNumWidth(total)) << total << " ";
   }
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index f781c7a..4988839 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -13,13 +13,12 @@
 
 #include <stddef.h>
 
+#include "cmCTest.h"
 #include "cmCTestMultiProcessHandler.h"
 #include "cmCTestTestHandler.h"
 #include "cmDuration.h"
 #include "cmProcess.h"
 
-class cmCTest;
-
 /** \class cmRunTest
  * \brief represents a single test to be run
  *
@@ -30,8 +29,13 @@
 public:
   explicit cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler);
 
-  void SetNumberOfRuns(int n) { this->NumberOfRunsLeft = n; }
-  void SetRunUntilFailOn() { this->RunUntilFail = true; }
+  void SetNumberOfRuns(int n)
+  {
+    this->NumberOfRunsLeft = n;
+    this->NumberOfRunsTotal = n;
+  }
+
+  void SetRepeatMode(cmCTest::Repeat r) { this->RepeatMode = r; }
   void SetTestProperties(cmCTestTestHandler::cmCTestTestProperties* prop)
   {
     this->TestProperties = prop;
@@ -72,7 +76,7 @@
 
   bool StartAgain(size_t completed);
 
-  void StartFailure(std::string const& output);
+  void StartFailure(std::string const& output, std::string const& detail);
 
   cmCTest* GetCTest() const { return this->CTest; }
 
@@ -98,7 +102,7 @@
   }
 
 private:
-  bool NeedsToRerun();
+  bool NeedsToRepeat();
   void DartProcessing();
   void ExeNotFound(std::string exe);
   bool ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
@@ -132,9 +136,10 @@
   std::vector<std::map<
     std::string, std::vector<cmCTestMultiProcessHandler::ResourceAllocation>>>
     AllocatedResources;
-  bool RunUntilFail;
-  int NumberOfRunsLeft;
-  bool RunAgain;
+  cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never;
+  int NumberOfRunsLeft = 1;  // default to 1 run of the test
+  int NumberOfRunsTotal = 1; // default to 1 run of the test
+  bool RunAgain = false;     // default to not having to run again
   size_t TotalNumberOfTests;
 };
 
diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx
index 34395c9..44dfab2 100644
--- a/Source/CTest/cmCTestSVN.cxx
+++ b/Source/CTest/cmCTestSVN.cxx
@@ -7,9 +7,10 @@
 #include <map>
 #include <ostream>
 
+#include <cmext/algorithm>
+
 #include "cmsys/RegularExpression.hxx"
 
-#include "cmAlgorithms.h"
 #include "cmCTest.h"
 #include "cmCTestVC.h"
 #include "cmProcessTools.h"
@@ -271,7 +272,7 @@
 
   std::vector<char const*> args;
   args.push_back(this->CommandLineTool.c_str());
-  cmAppend(args, parameters);
+  cm::append(args, parameters);
   args.push_back("--non-interactive");
 
   std::string userOptions = this->CTest->GetCTestConfiguration("SVNOptions");
@@ -344,7 +345,7 @@
 
   void CharacterDataHandler(const char* data, int length) override
   {
-    cmAppend(this->CData, data, data + length);
+    cm::append(this->CData, data, data + length);
   }
 
   void EndElement(const std::string& name) override
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index 60facbd..7803e37 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -340,6 +340,13 @@
   this->SetRunCurrentScript(true);
   this->UpdateElapsedTime();
 
+  // set the CTEST_CONFIGURATION_TYPE variable to the current value of the
+  // the -C argument on the command line.
+  if (!this->CTest->GetConfigType().empty()) {
+    this->Makefile->AddDefinition("CTEST_CONFIGURATION_TYPE",
+                                  this->CTest->GetConfigType());
+  }
+
   // add the script arg if defined
   if (!script_arg.empty()) {
     this->Makefile->AddDefinition("CTEST_SCRIPT_ARG", script_arg);
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/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
index 2ac5af6..22ab48f 100644
--- a/Source/CTest/cmCTestSubmitHandler.cxx
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -7,6 +7,8 @@
 #include <cstdlib>
 #include <sstream>
 
+#include <cmext/algorithm>
+
 #include "cm_curl.h"
 #include "cm_jsoncpp_reader.h"
 #include "cm_jsoncpp_value.h"
@@ -65,7 +67,7 @@
 
   void CharacterDataHandler(const char* data, int length) override
   {
-    cmAppend(this->CurrentValue, data, data + length);
+    cm::append(this->CurrentValue, data, data + length);
   }
 
   void EndElement(const std::string& name) override
@@ -96,8 +98,8 @@
 {
   int realsize = static_cast<int>(size * nmemb);
   const char* chPtr = static_cast<char*>(ptr);
-  cmAppend(*static_cast<cmCTestSubmitHandlerVectorOfChar*>(data), chPtr,
-           chPtr + realsize);
+  cm::append(*static_cast<cmCTestSubmitHandlerVectorOfChar*>(data), chPtr,
+             chPtr + realsize);
   return realsize;
 }
 
@@ -106,9 +108,9 @@
                                                     char* chPtr, size_t size,
                                                     void* data)
 {
-  cmAppend(*static_cast<cmCTestSubmitHandlerVectorOfChar*>(data), chPtr,
-           chPtr + size);
-  return size;
+  cm::append(*static_cast<cmCTestSubmitHandlerVectorOfChar*>(data), chPtr,
+             chPtr + size);
+  return 0;
 }
 
 cmCTestSubmitHandler::cmCTestSubmitHandler()
@@ -768,7 +770,7 @@
 
   if (!this->Files.empty()) {
     // Submit the explicitly selected files:
-    cmAppend(files, this->Files);
+    cm::append(files, this->Files);
   }
 
   // Add to the list of files to submit from any selected, existing parts:
@@ -814,7 +816,7 @@
     }
 
     // Submit files from this part.
-    cmAppend(files, this->CTest->GetSubmitFiles(p));
+    cm::append(files, this->CTest->GetSubmitFiles(p));
   }
 
   // Make sure files are unique, but preserve order.
diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx
index 9784214..0f9b695 100644
--- a/Source/CTest/cmCTestTestCommand.cxx
+++ b/Source/CTest/cmCTestTestCommand.cxx
@@ -29,6 +29,7 @@
   this->Bind("EXCLUDE_FIXTURE_SETUP"_s, this->ExcludeFixtureSetup);
   this->Bind("EXCLUDE_FIXTURE_CLEANUP"_s, this->ExcludeFixtureCleanup);
   this->Bind("PARALLEL_LEVEL"_s, this->ParallelLevel);
+  this->Bind("REPEAT"_s, this->Repeat);
   this->Bind("SCHEDULE_RANDOM"_s, this->ScheduleRandom);
   this->Bind("STOP_TIME"_s, this->StopTime);
   this->Bind("TEST_LOAD"_s, this->TestLoad);
@@ -85,6 +86,9 @@
   if (!this->ParallelLevel.empty()) {
     handler->SetOption("ParallelLevel", this->ParallelLevel.c_str());
   }
+  if (!this->Repeat.empty()) {
+    handler->SetOption("Repeat", this->Repeat.c_str());
+  }
   if (!this->ScheduleRandom.empty()) {
     handler->SetOption("ScheduleRandom", this->ScheduleRandom.c_str());
   }
diff --git a/Source/CTest/cmCTestTestCommand.h b/Source/CTest/cmCTestTestCommand.h
index 4019694..2345afb 100644
--- a/Source/CTest/cmCTestTestCommand.h
+++ b/Source/CTest/cmCTestTestCommand.h
@@ -55,6 +55,7 @@
   std::string ExcludeFixtureSetup;
   std::string ExcludeFixtureCleanup;
   std::string ParallelLevel;
+  std::string Repeat;
   std::string ScheduleRandom;
   std::string StopTime;
   std::string TestLoad;
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index c8bbb0b..4f324ea 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -410,10 +410,15 @@
 
   auto clock_finish = std::chrono::steady_clock::now();
 
+  bool noTestsFoundError = false;
   if (passed.size() + failed.size() == 0) {
-    if (!this->CTest->GetShowOnly() && !this->CTest->ShouldPrintLabels()) {
+    if (!this->CTest->GetShowOnly() && !this->CTest->ShouldPrintLabels() &&
+        this->CTest->GetNoTestsMode() != cmCTest::NoTests::Ignore) {
       cmCTestLog(this->CTest, ERROR_MESSAGE,
                  "No tests were found!!!" << std::endl);
+      if (this->CTest->GetNoTestsMode() == cmCTest::NoTests::Error) {
+        noTestsFoundError = true;
+      }
     }
   } else {
     if (this->HandlerVerbose && !passed.empty() &&
@@ -459,6 +464,12 @@
     this->LogFile = nullptr;
     return -1;
   }
+
+  if (noTestsFoundError) {
+    this->LogFile = nullptr;
+    return -1;
+  }
+
   this->LogFile = nullptr;
   return 0;
 }
@@ -471,6 +482,30 @@
   if (cmIsOn(this->GetOption("ScheduleRandom"))) {
     this->CTest->SetScheduleType("Random");
   }
+  if (const char* repeat = this->GetOption("Repeat")) {
+    cmsys::RegularExpression repeatRegex(
+      "^(UNTIL_FAIL|UNTIL_PASS|AFTER_TIMEOUT):([0-9]+)$");
+    if (repeatRegex.find(repeat)) {
+      std::string const& count = repeatRegex.match(2);
+      unsigned long n = 1;
+      cmStrToULong(count, &n); // regex guarantees success
+      this->RepeatCount = static_cast<int>(n);
+      if (this->RepeatCount > 1) {
+        std::string const& mode = repeatRegex.match(1);
+        if (mode == "UNTIL_FAIL") {
+          this->RepeatMode = cmCTest::Repeat::UntilFail;
+        } else if (mode == "UNTIL_PASS") {
+          this->RepeatMode = cmCTest::Repeat::UntilPass;
+        } else if (mode == "AFTER_TIMEOUT") {
+          this->RepeatMode = cmCTest::Repeat::AfterTimeout;
+        }
+      }
+    } else {
+      cmCTestLog(this->CTest, ERROR_MESSAGE,
+                 "Repeat option invalid value: " << repeat << std::endl);
+      return false;
+    }
+  }
   if (this->GetOption("ParallelLevel")) {
     this->CTest->SetParallelLevel(atoi(this->GetOption("ParallelLevel")));
   }
@@ -513,6 +548,7 @@
   val = this->GetOption("ResourceSpecFile");
   if (val) {
     this->UseResourceSpec = true;
+    this->ResourceSpecFile = val;
     auto result = this->ResourceSpec.ReadFromJSONFile(val);
     if (result != cmCTestResourceSpec::ReadFileResult::READ_OK) {
       cmCTestLog(this->CTest, ERROR_MESSAGE,
@@ -1235,6 +1271,12 @@
   parallel->SetCTest(this->CTest);
   parallel->SetParallelLevel(this->CTest->GetParallelLevel());
   parallel->SetTestHandler(this);
+  if (this->RepeatMode != cmCTest::Repeat::Never) {
+    parallel->SetRepeatMode(this->RepeatMode, this->RepeatCount);
+  } else {
+    parallel->SetRepeatMode(this->CTest->GetRepeatMode(),
+                            this->CTest->GetRepeatCount());
+  }
   parallel->SetQuiet(this->Quiet);
   if (this->TestLoad > 0) {
     parallel->SetTestLoad(this->TestLoad);
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index eab75d0..b1c8755 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -18,12 +18,12 @@
 
 #include "cmsys/RegularExpression.hxx"
 
+#include "cmCTest.h"
 #include "cmCTestGenericHandler.h"
 #include "cmCTestResourceSpec.h"
 #include "cmDuration.h"
 #include "cmListFileCache.h"
 
-class cmCTest;
 class cmMakefile;
 class cmXMLWriter;
 
@@ -338,6 +338,7 @@
 
   bool UseResourceSpec;
   cmCTestResourceSpec ResourceSpec;
+  std::string ResourceSpecFile;
 
   void GenerateRegressionImages(cmXMLWriter& xml, const std::string& dart);
   cmsys::RegularExpression DartStuff1;
@@ -353,6 +354,8 @@
 
   std::ostream* LogFile;
 
+  cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never;
+  int RepeatCount = 1;
   bool RerunFailed;
 };
 
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 87f7147..cdf899c 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -6,9 +6,10 @@
 #include <iostream>
 #include <string>
 
+#include <cmext/algorithm>
+
 #include "cmsys/Process.h"
 
-#include "cmAlgorithms.h"
 #include "cmCTest.h"
 #include "cmCTestRunTest.h"
 #include "cmCTestTestHandler.h"
@@ -218,7 +219,7 @@
   if (nread > 0) {
     std::string strdata;
     this->Conv.DecodeText(buf->base, static_cast<size_t>(nread), strdata);
-    cmAppend(this->Output, strdata);
+    cm::append(this->Output, strdata);
 
     while (this->Output.GetLine(line)) {
       this->Runner.CheckOutput(line);
@@ -277,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/Checks/Curses.cmake b/Source/Checks/Curses.cmake
index 2942b66..d35dd2a 100644
--- a/Source/Checks/Curses.cmake
+++ b/Source/Checks/Curses.cmake
@@ -1,4 +1,7 @@
-message(STATUS "Checking for curses support")
+include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake)
+cm_message_checks_compat(
+  "Checking for curses support" __checkStart __checkPass __checkFail)
+message(${__checkStart})
 
 # Try compiling a simple project using curses.
 # Pass in any cache entries that the user may have set.
@@ -31,11 +34,11 @@
 unset(CMakeCheckCurses_COMPILED CACHE)
 
 if(CMakeCheckCurses_COMPILED)
-  message(STATUS "Checking for curses support - Success")
+  message(${__checkPass} "Success")
   file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
     "Checking for curses support passed with the following output:\n${CMakeCheckCurses_OUTPUT}\n\n")
 else()
-  message(STATUS "Checking for curses support - Failed")
+  message(${__checkFail} "Failed")
   file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
     "Checking for curses support failed with the following output:\n${CMakeCheckCurses_OUTPUT}\n\n")
 endif()
diff --git a/Source/Checks/cm_c11_thread_local.cmake b/Source/Checks/cm_c11_thread_local.cmake
index 6b8d10b..2263be3 100644
--- a/Source/Checks/cm_c11_thread_local.cmake
+++ b/Source/Checks/cm_c11_thread_local.cmake
@@ -1,7 +1,11 @@
 set(CMake_C11_THREAD_LOCAL_BROKEN 0)
 if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_C11_STANDARD_COMPILE_OPTION)
   if(NOT DEFINED CMake_C11_THREAD_LOCAL_WORKS)
-    message(STATUS "Checking if compiler supports C11 _Thread_local")
+    include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake)
+    cm_message_checks_compat(
+      "Checking if compiler supports C11 _Thread_local"
+      __checkStart __checkPass __checkFail)
+    message(${__checkStart})
     try_compile(CMake_C11_THREAD_LOCAL_WORKS
       ${CMAKE_CURRENT_BINARY_DIR}
       ${CMAKE_CURRENT_LIST_DIR}/cm_c11_thread_local.c
@@ -12,14 +16,14 @@
       set_property(CACHE CMake_C11_THREAD_LOCAL_WORKS PROPERTY VALUE 0)
     endif()
     if(CMake_C11_THREAD_LOCAL_WORKS)
-      message(STATUS "Checking if compiler supports C11 _Thread_local - yes")
+      message(${__checkPass} "yes")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Determining if compiler supports C11 _Thread_local passed with the following output:\n"
         "${OUTPUT}\n"
         "\n"
         )
     else()
-      message(STATUS "Checking if compiler supports C11 _Thread_local - no")
+      message(${__checkFail} "no")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Determining if compiler supports C11 _Thread_local failed with the following output:\n"
         "${OUTPUT}\n"
diff --git a/Source/Checks/cm_cxx14_check.cmake b/Source/Checks/cm_cxx14_check.cmake
index 38606b9..e5656bf 100644
--- a/Source/Checks/cm_cxx14_check.cmake
+++ b/Source/Checks/cm_cxx14_check.cmake
@@ -1,10 +1,14 @@
 set(CMake_CXX14_BROKEN 0)
-if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|PGI")
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|PGI|Intel")
   if(NOT CMAKE_CXX14_STANDARD_COMPILE_OPTION)
     set(CMake_CXX14_WORKS 0)
   endif()
   if(NOT DEFINED CMake_CXX14_WORKS)
-    message(STATUS "Checking if compiler supports needed C++14 constructs")
+    include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake)
+    cm_message_checks_compat(
+      "Checking if compiler supports needed C++14 constructs"
+      __checkStart __checkPass __checkFail)
+    message(${__checkStart})
     try_compile(CMake_CXX14_WORKS
       ${CMAKE_CURRENT_BINARY_DIR}
       ${CMAKE_CURRENT_LIST_DIR}/cm_cxx14_check.cpp
@@ -15,14 +19,14 @@
       set_property(CACHE CMake_CXX14_WORKS PROPERTY VALUE 0)
     endif()
     if(CMake_CXX14_WORKS)
-      message(STATUS "Checking if compiler supports needed C++14 constructs - yes")
+      message(${__checkPass} "yes")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Determining if compiler supports needed C++14 constructs passed with the following output:\n"
         "${OUTPUT}\n"
         "\n"
         )
     else()
-      message(STATUS "Checking if compiler supports needed C++14 constructs - no")
+      message(${__checkFail} "no")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Determining if compiler supports needed C++14 constructs failed with the following output:\n"
         "${OUTPUT}\n"
diff --git a/Source/Checks/cm_cxx17_check.cmake b/Source/Checks/cm_cxx17_check.cmake
index 4da2fd7..dba3eaf 100644
--- a/Source/Checks/cm_cxx17_check.cmake
+++ b/Source/Checks/cm_cxx17_check.cmake
@@ -1,10 +1,14 @@
 set(CMake_CXX17_BROKEN 0)
-if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|PGI")
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|PGI|Intel")
   if(NOT CMAKE_CXX17_STANDARD_COMPILE_OPTION)
     set(CMake_CXX17_WORKS 0)
   endif()
   if(NOT DEFINED CMake_CXX17_WORKS)
-    message(STATUS "Checking if compiler supports needed C++17 constructs")
+    include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake)
+    cm_message_checks_compat(
+      "Checking if compiler supports needed C++17 constructs"
+      __checkStart __checkPass __checkFail)
+    message(${__checkStart})
     try_compile(CMake_CXX17_WORKS
       ${CMAKE_CURRENT_BINARY_DIR}
       ${CMAKE_CURRENT_LIST_DIR}/cm_cxx17_check.cpp
@@ -15,14 +19,14 @@
       set_property(CACHE CMake_CXX17_WORKS PROPERTY VALUE 0)
     endif()
     if(CMake_CXX17_WORKS)
-      message(STATUS "Checking if compiler supports needed C++17 constructs - yes")
+      message(${__checkPass} "yes")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Determining if compiler supports needed C++17 constructs passed with the following output:\n"
         "${OUTPUT}\n"
         "\n"
         )
     else()
-      message(STATUS "Checking if compiler supports needed C++17 constructs - no")
+      message(${__checkFail} "no")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Determining if compiler supports needed C++17 constructs failed with the following output:\n"
         "${OUTPUT}\n"
diff --git a/Source/Checks/cm_cxx17_check.cpp b/Source/Checks/cm_cxx17_check.cpp
index 29863b1..abbe22c 100644
--- a/Source/Checks/cm_cxx17_check.cpp
+++ b/Source/Checks/cm_cxx17_check.cpp
@@ -8,6 +8,13 @@
 #  include <comdef.h>
 #endif
 
+template <typename T,
+          typename std::invoke_result<decltype(&T::get), T>::type = nullptr>
+typename T::pointer get_ptr(T& item)
+{
+  return item.get();
+}
+
 int main()
 {
   int a[] = { 0, 1, 2 };
@@ -20,6 +27,9 @@
 
   std::unique_ptr<int> u(new int(0));
 
+  // Intel compiler do not handle correctly 'decltype' inside 'invoke_result'
+  get_ptr(u);
+
 #ifdef _MSC_VER
   // clang-cl has problems instantiating this constructor in C++17 mode
   //  error: indirection requires pointer operand ('const _GUID' invalid)
diff --git a/Source/Checks/cm_cxx_features.cmake b/Source/Checks/cm_cxx_features.cmake
index fb68ed7..c16286c 100644
--- a/Source/Checks/cm_cxx_features.cmake
+++ b/Source/Checks/cm_cxx_features.cmake
@@ -1,8 +1,12 @@
+include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake)
 
 function(cm_check_cxx_feature name)
   string(TOUPPER ${name} FEATURE)
   if(NOT DEFINED CMake_HAVE_CXX_${FEATURE})
-    message(STATUS "Checking if compiler supports C++ ${name}")
+    cm_message_checks_compat(
+      "Checking if compiler supports C++ ${name}"
+      __checkStart __checkPass __checkFail)
+    message(${__checkStart})
     if(CMAKE_CXX_STANDARD)
       set(maybe_cxx_standard -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD})
     else()
@@ -26,19 +30,23 @@
     string(REGEX REPLACE "[^\n]*warning:[^\n]*sprintf\\(\\) is often misused, please use snprintf[^\n]*" "" check_output "${check_output}")
     # Filter out xcodebuild warnings.
     string(REGEX REPLACE "[^\n]* xcodebuild\\[[0-9]*:[0-9]*\\] warning: [^\n]*" "" check_output "${check_output}")
+    # Filter out ld warnings.
+    string(REGEX REPLACE "[^\n]*ld: warning: [^\n]*" "" check_output "${check_output}")
+    # Filter out CUDA installation warnings.
+    string(REGEX REPLACE "[^\n]*clang: warning: Unknown CUDA version[^\n]*" "" check_output "${check_output}")
     # If using the feature causes warnings, treat it as broken/unavailable.
     if(check_output MATCHES "(^|[ :])[Ww][Aa][Rr][Nn][Ii][Nn][Gg]")
       set(CMake_HAVE_CXX_${FEATURE} OFF CACHE INTERNAL "TRY_COMPILE" FORCE)
     endif()
     if(CMake_HAVE_CXX_${FEATURE})
-      message(STATUS "Checking if compiler supports C++ ${name} - yes")
+      message(${__checkPass} "yes")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Determining if compiler supports C++ ${name} passed with the following output:\n"
         "${OUTPUT}\n"
         "\n"
         )
     else()
-      message(STATUS "Checking if compiler supports C++ ${name} - no")
+      message(${__checkFail} "no")
       file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Determining if compiler supports C++ ${name} failed with the following output:\n"
         "${OUTPUT}\n"
diff --git a/Source/Checks/cm_message_checks_compat.cmake b/Source/Checks/cm_message_checks_compat.cmake
new file mode 100644
index 0000000..024c397
--- /dev/null
+++ b/Source/Checks/cm_message_checks_compat.cmake
@@ -0,0 +1,13 @@
+# Supporting using the CHECK_... message modes if available
+# and fall back to the older behavior if not
+macro(cm_message_checks_compat description startVar passVar failVar)
+  if(CMAKE_VERSION VERSION_GREATER 3.16.2019)
+    set(${startVar} CHECK_START "${description}")
+    set(${passVar}  CHECK_PASS)
+    set(${failVar}  CHECK_FAIL)
+  else()
+    set(${startVar} STATUS "${description}")
+    set(${passVar}  STATUS "${description} - ")
+    set(${failVar}  STATUS "${description} - ")
+  endif()
+endmacro()
diff --git a/Source/CursesDialog/CMakeLists.txt b/Source/CursesDialog/CMakeLists.txt
index 7009717..c24ee76 100644
--- a/Source/CursesDialog/CMakeLists.txt
+++ b/Source/CursesDialog/CMakeLists.txt
@@ -5,6 +5,7 @@
   ccmake.cxx
   cmCursesBoolWidget.cxx
   cmCursesCacheEntryComposite.cxx
+  cmCursesColor.cxx
   cmCursesDummyWidget.cxx
   cmCursesFilePathWidget.cxx
   cmCursesForm.cxx
@@ -17,21 +18,45 @@
   cmCursesWidget.cxx
   )
 target_include_directories(ccmake PRIVATE ${CURSES_INCLUDE_PATH})
+set(CMAKE_REQUIRED_INCLUDES ${CURSES_INCLUDE_PATH})
 target_link_libraries(ccmake CMakeLib)
 if(CMAKE_USE_SYSTEM_FORM)
   find_path(CURSES_FORM_INCLUDE_DIR NAMES form.h HINTS ${CURSES_INCLUDE_PATH} ${CURSES_INCLUDE_PATH}/ncurses)
   if(CURSES_FORM_INCLUDE_DIR)
     target_include_directories(ccmake PRIVATE ${CURSES_FORM_INCLUDE_DIR})
+    list(APPEND CMAKE_REQUIRED_INCLUDES ${CURSES_FORM_INCLUDE_DIR})
   endif()
   target_link_libraries(ccmake
     ${CURSES_FORM_LIBRARY}
     ${CURSES_LIBRARY}
   )
+  set(CMAKE_REQUIRED_LIBRARIES
+    ${CURSES_FORM_LIBRARY}
+    ${CURSES_LIBRARY}
+  )
   if(CURSES_EXTRA_LIBRARY)
     target_link_libraries(ccmake ${CURSES_EXTRA_LIBRARY})
+    list(APPEND CMAKE_REQUIRED_LIBRARIES ${CURSES_EXTRA_LIBRARY})
   endif()
 else()
   target_link_libraries(ccmake cmForm)
+  get_target_property(cmFormIncludeDirs cmForm INTERFACE_INCLUDE_DIRECTORIES)
+  list(APPEND CMAKE_REQUIRED_INCLUDES ${cmFormIncludeDirs})
+  get_target_property(cmFormLibraries cmForm INTERFACE_LINK_LIBRARIES)
+  set(CMAKE_REQUIRED_LIBRARIES ${cmFormLibraries})
+endif()
+
+include(CheckSymbolExists)
+check_symbol_exists(use_default_colors
+  "form.h"
+  HAVE_CURSES_USE_DEFAULT_COLORS)
+if(HAVE_CURSES_USE_DEFAULT_COLORS)
+  set_source_files_properties(cmCursesColor.cxx
+    PROPERTIES COMPILE_DEFINITIONS HAVE_CURSES_USE_DEFAULT_COLORS)
+endif()
+
+if(CMake_JOB_POOL_LINK_BIN)
+  set_property(TARGET ccmake PROPERTY JOB_POOL_LINK "link-bin")
 endif()
 
 CMake_OPTIONAL_COMPONENT(ccmake)
diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx
index 9e9dfbd..01fce85 100644
--- a/Source/CursesDialog/ccmake.cxx
+++ b/Source/CursesDialog/ccmake.cxx
@@ -9,6 +9,7 @@
 
 #include "cmsys/Encoding.hxx"
 
+#include "cmCursesColor.h"
 #include "cmCursesForm.h"
 #include "cmCursesMainForm.h"
 #include "cmCursesStandardIncludes.h"
@@ -126,6 +127,7 @@
   noecho();             /* Echo off */
   cbreak();             /* nl- or cr not needed */
   keypad(stdscr, true); /* Use key symbols as KEY_DOWN */
+  cmCursesColor::InitColors();
 
   signal(SIGWINCH, onsig);
 
@@ -153,10 +155,28 @@
     return 1;
   }
 
+  /*
+   * The message is stored in a list by the form which will be
+   * joined by '\n' before display.
+   * Removing any trailing '\n' avoid extra empty lines in the final results
+   */
+  auto cleanMessage = [](const std::string& message) -> std::string {
+    auto msg = message;
+    if (!msg.empty() && msg.back() == '\n') {
+      msg.pop_back();
+    }
+    return msg;
+  };
   cmSystemTools::SetMessageCallback(
-    [myform](const std::string& message, const char* title) {
-      myform->AddError(message, title);
+    [&](const std::string& message, const char* title) {
+      myform->AddError(cleanMessage(message), title);
     });
+  cmSystemTools::SetStderrCallback([&](const std::string& message) {
+    myform->AddError(cleanMessage(message), "");
+  });
+  cmSystemTools::SetStdoutCallback([&](const std::string& message) {
+    myform->UpdateProgress(cleanMessage(message), -1);
+  });
 
   cmCursesForm::CurrentForm = myform;
 
diff --git a/Source/CursesDialog/cmCursesBoolWidget.cxx b/Source/CursesDialog/cmCursesBoolWidget.cxx
index 97b0811..c4dbed8 100644
--- a/Source/CursesDialog/cmCursesBoolWidget.cxx
+++ b/Source/CursesDialog/cmCursesBoolWidget.cxx
@@ -4,6 +4,7 @@
 
 #include <string>
 
+#include "cmCursesColor.h"
 #include "cmCursesWidget.h"
 #include "cmStateTypes.h"
 
@@ -12,8 +13,10 @@
   : cmCursesWidget(width, height, left, top)
 {
   this->Type = cmStateEnums::BOOL;
-  set_field_fore(this->Field, A_NORMAL);
-  set_field_back(this->Field, A_STANDOUT);
+  if (!cmCursesColor::HasColors()) {
+    set_field_fore(this->Field, A_NORMAL);
+    set_field_back(this->Field, A_STANDOUT);
+  }
   field_opts_off(this->Field, O_STATIC);
   this->SetValueAsBool(false);
 }
@@ -42,8 +45,16 @@
 {
   if (value) {
     this->SetValue("ON");
+    if (cmCursesColor::HasColors()) {
+      set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::BoolOn));
+      set_field_back(this->Field, COLOR_PAIR(cmCursesColor::BoolOn));
+    }
   } else {
     this->SetValue("OFF");
+    if (cmCursesColor::HasColors()) {
+      set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::BoolOff));
+      set_field_back(this->Field, COLOR_PAIR(cmCursesColor::BoolOff));
+    }
   }
 }
 
diff --git a/Source/CursesDialog/cmCursesColor.cxx b/Source/CursesDialog/cmCursesColor.cxx
new file mode 100644
index 0000000..641d48c
--- /dev/null
+++ b/Source/CursesDialog/cmCursesColor.cxx
@@ -0,0 +1,29 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmCursesColor.h"
+
+#include "cmCursesStandardIncludes.h"
+
+bool cmCursesColor::HasColors()
+{
+#ifdef HAVE_CURSES_USE_DEFAULT_COLORS
+  return has_colors();
+#else
+  return false;
+#endif
+}
+
+void cmCursesColor::InitColors()
+{
+#ifdef HAVE_CURSES_USE_DEFAULT_COLORS
+  if (HasColors()) {
+    start_color();
+    use_default_colors();
+    init_pair(cmCursesColor::BoolOff, COLOR_RED, -1);
+    init_pair(cmCursesColor::BoolOn, COLOR_GREEN, -1);
+    init_pair(cmCursesColor::String, COLOR_BLUE, -1);
+    init_pair(cmCursesColor::Path, COLOR_YELLOW, -1);
+    init_pair(cmCursesColor::Options, COLOR_MAGENTA, -1);
+  }
+#endif
+}
diff --git a/Source/CursesDialog/cmCursesColor.h b/Source/CursesDialog/cmCursesColor.h
new file mode 100644
index 0000000..78ca52c
--- /dev/null
+++ b/Source/CursesDialog/cmCursesColor.h
@@ -0,0 +1,24 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmCursesColor_h
+#define cmCursesColor_h
+
+class cmCursesColor
+{
+public:
+  enum Color
+  {
+    // Default color is pair 0
+    BoolOff = 1,
+    BoolOn,
+    String,
+    Path,
+    Options
+  };
+
+  static bool HasColors();
+
+  static void InitColors();
+};
+
+#endif // cmCursesColor_h
diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx
index e2d8d06..806e663 100644
--- a/Source/CursesDialog/cmCursesLongMessageForm.cxx
+++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx
@@ -8,6 +8,7 @@
 #include "cmCursesForm.h"
 #include "cmCursesMainForm.h"
 #include "cmCursesStandardIncludes.h"
+#include "cmStringAlgorithms.h"
 #include "cmVersion.h"
 
 inline int ctrl(int z)
@@ -16,14 +17,12 @@
 }
 
 cmCursesLongMessageForm::cmCursesLongMessageForm(
-  std::vector<std::string> const& messages, const char* title)
+  std::vector<std::string> const& messages, const char* title,
+  ScrollBehavior scrollBehavior)
+  : Scrolling(scrollBehavior)
 {
   // Append all messages into on big string
-  for (std::string const& message : messages) {
-    this->Messages += message;
-    // Add one blank line after each message
-    this->Messages += "\n\n";
-  }
+  this->Messages = cmJoin(messages, "\n");
   this->Title = title;
   this->Fields[0] = nullptr;
   this->Fields[1] = nullptr;
@@ -48,7 +47,7 @@
     size = cmCursesMainForm::MAX_WIDTH - 1;
   }
   strncpy(bar, this->Title.c_str(), size);
-  for (size_t i = size - 1; i < cmCursesMainForm::MAX_WIDTH; i++) {
+  for (size_t i = size; i < cmCursesMainForm::MAX_WIDTH; i++) {
     bar[i] = ' ';
   }
   int width;
@@ -89,7 +88,7 @@
     return;
   }
   char firstLine[512];
-  sprintf(firstLine, "Press [e] to exit help");
+  sprintf(firstLine, "Press [e] to exit screen");
 
   char fmt_s[] = "%s";
   curses_move(y - 2, 0);
@@ -112,8 +111,6 @@
 
   const char* msg = this->Messages.c_str();
 
-  curses_clear();
-
   if (this->Fields[0]) {
     free_field(this->Fields[0]);
     this->Fields[0] = nullptr;
@@ -136,10 +133,13 @@
     }
     i++;
   }
-  form_driver(this->Form, REQ_BEG_FIELD);
+  if (this->Scrolling == ScrollBehavior::ScrollDown) {
+    form_driver(this->Form, REQ_END_FIELD);
+  } else {
+    form_driver(this->Form, REQ_BEG_FIELD);
+  }
 
   this->UpdateStatusBar();
-  this->PrintKeys();
   touchwin(stdscr);
   refresh();
 }
@@ -153,6 +153,7 @@
   char debugMessage[128];
 
   for (;;) {
+    this->PrintKeys();
     int key = getch();
 
     sprintf(debugMessage, "Message widget handling input, key: %d", key);
@@ -173,7 +174,6 @@
     }
 
     this->UpdateStatusBar();
-    this->PrintKeys();
     touchwin(stdscr);
     wrefresh(stdscr);
   }
diff --git a/Source/CursesDialog/cmCursesLongMessageForm.h b/Source/CursesDialog/cmCursesLongMessageForm.h
index 42f9c71..88efe62 100644
--- a/Source/CursesDialog/cmCursesLongMessageForm.h
+++ b/Source/CursesDialog/cmCursesLongMessageForm.h
@@ -14,8 +14,14 @@
 class cmCursesLongMessageForm : public cmCursesForm
 {
 public:
+  enum class ScrollBehavior
+  {
+    NoScroll,
+    ScrollDown
+  };
+
   cmCursesLongMessageForm(std::vector<std::string> const& messages,
-                          const char* title);
+                          const char* title, ScrollBehavior scrollBehavior);
   ~cmCursesLongMessageForm() override;
 
   cmCursesLongMessageForm(cmCursesLongMessageForm const&) = delete;
@@ -43,6 +49,7 @@
 protected:
   std::string Messages;
   std::string Title;
+  ScrollBehavior Scrolling;
 
   FIELD* Fields[2];
 };
diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx
index 6b71e8a..2c92835 100644
--- a/Source/CursesDialog/cmCursesMainForm.cxx
+++ b/Source/CursesDialog/cmCursesMainForm.cxx
@@ -34,6 +34,7 @@
   : Args(std::move(args))
   , InitialWidth(initWidth)
 {
+  this->HasNonStatusOutputs = false;
   this->NumberOfPages = 0;
   this->AdvancedMode = false;
   this->NumberOfVisibleEntries = 0;
@@ -321,25 +322,25 @@
     } else {
       if (this->OkToGenerate) {
         sprintf(firstLine,
-                "Press [c] to configure       Press [g] to generate and exit");
+                "      [l] Show log output   [c] Configure"
+                "       [g] Generate        ");
       } else {
         sprintf(firstLine,
-                "Press [c] to configure                                     ");
+                "      [l] Show log output   [c] Configure"
+                "                           ");
       }
       {
         const char* toggleKeyInstruction =
-          "Press [t] to toggle advanced mode (Currently %s)";
+          "      [t] Toggle advanced mode (currently %s)";
         sprintf(thirdLine, toggleKeyInstruction,
-                this->AdvancedMode ? "On" : "Off");
+                this->AdvancedMode ? "on" : "off");
       }
       sprintf(secondLine,
-              "Press [h] for help           "
-              "Press [q] to quit without generating");
+              "      [h] Help              [q] Quit without generating");
     }
 
     curses_move(y - 4, 0);
-    char fmt[512] =
-      "Press [enter] to edit option Press [d] to delete an entry";
+    char fmt[512] = "Keys: [enter] Edit an entry [d] Delete an entry";
     if (process) {
       memset(fmt, ' ', 57);
     }
@@ -364,7 +365,7 @@
 
 // Print the key of the current entry and the CMake version
 // on the status bar. Designed for a width of 80 chars.
-void cmCursesMainForm::UpdateStatusBar(const char* message)
+void cmCursesMainForm::UpdateStatusBar(cm::optional<std::string> message)
 {
   int x;
   int y;
@@ -385,119 +386,91 @@
     return;
   }
 
-  // Get the key of the current entry
-  FIELD* cur = current_field(this->Form);
-  int findex = field_index(cur);
-  cmCursesWidget* lbl = nullptr;
-  if (findex >= 0) {
-    lbl = reinterpret_cast<cmCursesWidget*>(
-      field_userptr(this->Fields[findex - 2]));
-  }
-  char help[128] = "";
-  const char* curField = "";
-  if (lbl) {
-    curField = lbl->GetValue();
+  // Find the current label index
+  // Field are grouped by 3, the label should be 2 less than the current index
+  using size_type = decltype(this->Fields)::size_type;
+  size_type currentLabelIndex = field_index(current_field(this->Form)) - 2;
+
+  // Use the status message if any, otherwise join the key and help string
+  std::string bar;
+  if (message) {
+    bar = *message;
+  } else {
+    // Get the key of the current entry
+    cmCursesWidget* labelWidget = reinterpret_cast<cmCursesWidget*>(
+      field_userptr(this->Fields[currentLabelIndex]));
+    std::string labelValue = labelWidget->GetValue();
+    bar = labelValue + ": ";
 
     // Get the help string of the current entry
     // and add it to the help string
-    const char* existingValue =
-      this->CMakeInstance->GetState()->GetCacheEntryValue(curField);
+    auto cmakeState = this->CMakeInstance->GetState();
+    const char* existingValue = cmakeState->GetCacheEntryValue(labelValue);
     if (existingValue) {
-      const char* hs = this->CMakeInstance->GetState()->GetCacheEntryProperty(
-        curField, "HELPSTRING");
-      if (hs) {
-        strncpy(help, hs, 127);
-        help[127] = '\0';
-      } else {
-        help[0] = 0;
-      }
-    } else {
-      sprintf(help, " ");
-    }
-  }
-
-  // Join the key, help string and pad with spaces
-  // (or truncate) as necessary
-  char bar[cmCursesMainForm::MAX_WIDTH];
-  size_t curFieldLen = strlen(curField);
-  size_t helpLen = strlen(help);
-
-  size_t width = std::min<size_t>(x, cmCursesMainForm::MAX_WIDTH);
-
-  if (message) {
-    curField = message;
-    curFieldLen = strlen(message);
-    strncpy(bar, curField, width);
-    if (curFieldLen < width) {
-      memset(bar + curFieldLen, ' ', width - curFieldLen);
-    }
-  } else {
-    strncpy(bar, curField, width);
-    if (curFieldLen < width) {
-      bar[curFieldLen] = ':';
-      bar[curFieldLen + 1] = ' ';
-      strncpy(bar + curFieldLen + 2, help, width - curFieldLen - 2);
-      if (curFieldLen + helpLen + 2 < width) {
-        memset(bar + curFieldLen + helpLen + 2, ' ',
-               width - (curFieldLen + helpLen + 2));
+      auto help = cmakeState->GetCacheEntryProperty(labelValue, "HELPSTRING");
+      if (help) {
+        bar += help;
       }
     }
   }
-
-  bar[width] = '\0';
-
-  // Display CMake version info on the next line
-  // We want to display this on the right
-  char version[cmCursesMainForm::MAX_WIDTH];
-  char vertmp[128];
-  sprintf(vertmp, "CMake Version %s", cmVersion::GetCMakeVersion());
-  size_t sideSpace = (width - strlen(vertmp));
-  memset(version, ' ', sideSpace);
-  sprintf(version + sideSpace, "%s", vertmp);
-  version[width] = '\0';
-
-  // Now print both lines
-  char fmt_s[] = "%s";
+  // Pad with spaces to erase any previous text,
+  // or truncate as necessary to fit the screen
+  bar.resize(x, ' ');
   curses_move(y - 5, 0);
   attron(A_STANDOUT);
-  printw(fmt_s, bar);
+  char fmt_s[] = "%s";
+  printw(fmt_s, bar.c_str());
   attroff(A_STANDOUT);
-  curses_move(y - 4, 0);
-  printw(fmt_s, version);
+
+  // Highlight the current label, reset others
+  // Fields are grouped by 3, the first one being the label
+  // so start at 0 and move up by 3 avoiding the last null entry
+  for (size_type index = 0; index < this->Fields.size() - 1; index += 3) {
+    bool currentLabel = index == currentLabelIndex;
+    set_field_fore(this->Fields[index], currentLabel ? A_STANDOUT : A_NORMAL);
+  }
+
+  // Display CMake version under the status bar
+  // We want to display this on the right
+  std::string version = "CMake Version ";
+  version += cmVersion::GetCMakeVersion();
+  version.resize(std::min<std::string::size_type>(x, version.size()));
+  curses_move(y - 4, x - static_cast<int>(version.size()));
+  printw(fmt_s, version.c_str());
+
   pos_form_cursor(this->Form);
 }
 
 void cmCursesMainForm::UpdateProgress(const std::string& msg, float prog)
 {
-  char tmp[1024];
-  const char* cmsg = tmp;
   if (prog >= 0) {
-    sprintf(tmp, "%s %i%%", msg.c_str(), static_cast<int>(100 * prog));
+    constexpr int progressBarWidth = 40;
+    int progressBarCompleted = static_cast<int>(progressBarWidth * prog);
+    int percentCompleted = static_cast<int>(100 * prog);
+    this->LastProgress = (percentCompleted < 100 ? " " : "");
+    this->LastProgress += (percentCompleted < 10 ? " " : "");
+    this->LastProgress += std::to_string(percentCompleted) + "% [";
+    this->LastProgress.append(progressBarCompleted, '#');
+    this->LastProgress.append(progressBarWidth - progressBarCompleted, ' ');
+    this->LastProgress += "] " + msg + "...";
   } else {
-    cmsg = msg.c_str();
+    this->Outputs.emplace_back(msg);
   }
-  this->UpdateStatusBar(cmsg);
-  this->PrintKeys(1);
-  curses_move(1, 1);
-  touchwin(stdscr);
-  refresh();
+
+  this->DisplayOutputs();
 }
 
 int cmCursesMainForm::Configure(int noconfigure)
 {
-  int xi;
-  int yi;
-  getmaxyx(stdscr, yi, xi);
+  this->ResetOutputs();
 
-  curses_move(1, 1);
-  this->UpdateStatusBar("Configuring, please wait...");
-  this->PrintKeys(1);
-  touchwin(stdscr);
-  refresh();
-  this->CMakeInstance->SetProgressCallback(
-    [this](const std::string& msg, float prog) {
-      this->UpdateProgress(msg, prog);
-    });
+  if (noconfigure == 0) {
+    this->UpdateProgress("Configuring", 0);
+    this->CMakeInstance->SetProgressCallback(
+      [this](const std::string& msg, float prog) {
+        this->UpdateProgress(msg, prog);
+      });
+  }
 
   // always save the current gui values to disk
   this->FillCacheManagerFromUI();
@@ -505,9 +478,6 @@
     this->CMakeInstance->GetHomeOutputDirectory());
   this->LoadCache(nullptr);
 
-  // Get rid of previous errors
-  this->Errors = std::vector<std::string>();
-
   // run the generate process
   this->OkToGenerate = true;
   int retVal;
@@ -524,7 +494,7 @@
 
   keypad(stdscr, true); /* Use key symbols as KEY_DOWN */
 
-  if (retVal != 0 || !this->Errors.empty()) {
+  if (retVal != 0 || this->HasNonStatusOutputs) {
     // see if there was an error
     if (cmSystemTools::GetErrorOccuredFlag()) {
       this->OkToGenerate = false;
@@ -532,11 +502,13 @@
     int xx;
     int yy;
     getmaxyx(stdscr, yy, xx);
-    cmCursesLongMessageForm* msgs =
-      new cmCursesLongMessageForm(this->Errors,
-                                  cmSystemTools::GetErrorOccuredFlag()
-                                    ? "Errors occurred during the last pass."
-                                    : "CMake produced the following output.");
+    const char* title = "Configure produced the following output";
+    if (cmSystemTools::GetErrorOccuredFlag()) {
+      title = "Configure failed with the following output";
+    }
+    cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm(
+      this->Outputs, title,
+      cmCursesLongMessageForm::ScrollBehavior::ScrollDown);
     // reset error condition
     cmSystemTools::ResetErrorOccuredFlag();
     CurrentForm = msgs;
@@ -547,11 +519,13 @@
     if (retVal == -2) {
       return retVal;
     }
-    CurrentForm = this;
-    this->Render(1, 1, xx, yy);
   }
 
   this->InitializeUI();
+  CurrentForm = this;
+  int xi;
+  int yi;
+  getmaxyx(stdscr, yi, xi);
   this->Render(1, 1, xi, yi);
 
   return 0;
@@ -559,30 +533,21 @@
 
 int cmCursesMainForm::Generate()
 {
-  int xi;
-  int yi;
-  getmaxyx(stdscr, yi, xi);
+  this->ResetOutputs();
 
-  curses_move(1, 1);
-  this->UpdateStatusBar("Generating, please wait...");
-  this->PrintKeys(1);
-  touchwin(stdscr);
-  refresh();
+  this->UpdateProgress("Generating", 0);
   this->CMakeInstance->SetProgressCallback(
     [this](const std::string& msg, float prog) {
       this->UpdateProgress(msg, prog);
     });
 
-  // Get rid of previous errors
-  this->Errors = std::vector<std::string>();
-
   // run the generate process
   int retVal = this->CMakeInstance->Generate();
 
   this->CMakeInstance->SetProgressCallback(nullptr);
   keypad(stdscr, true); /* Use key symbols as KEY_DOWN */
 
-  if (retVal != 0 || !this->Errors.empty()) {
+  if (retVal != 0 || this->HasNonStatusOutputs) {
     // see if there was an error
     if (cmSystemTools::GetErrorOccuredFlag()) {
       this->OkToGenerate = false;
@@ -592,12 +557,13 @@
     int xx;
     int yy;
     getmaxyx(stdscr, yy, xx);
-    const char* title = "Messages during last pass.";
+    const char* title = "Generate produced the following output";
     if (cmSystemTools::GetErrorOccuredFlag()) {
-      title = "Errors occurred during the last pass.";
+      title = "Generate failed with the following output";
     }
-    cmCursesLongMessageForm* msgs =
-      new cmCursesLongMessageForm(this->Errors, title);
+    cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm(
+      this->Outputs, title,
+      cmCursesLongMessageForm::ScrollBehavior::ScrollDown);
     CurrentForm = msgs;
     msgs->Render(1, 1, xx, yy);
     msgs->HandleInput();
@@ -606,11 +572,13 @@
     if (retVal == -2) {
       return retVal;
     }
-    CurrentForm = this;
-    this->Render(1, 1, xx, yy);
   }
 
   this->InitializeUI();
+  CurrentForm = this;
+  int xi;
+  int yi;
+  getmaxyx(stdscr, yi, xi);
   this->Render(1, 1, xi, yi);
 
   return 0;
@@ -619,7 +587,9 @@
 void cmCursesMainForm::AddError(const std::string& message,
                                 const char* /*unused*/)
 {
-  this->Errors.emplace_back(message);
+  this->Outputs.emplace_back(message);
+  this->HasNonStatusOutputs = true;
+  this->DisplayOutputs();
 }
 
 void cmCursesMainForm::RemoveEntry(const char* value)
@@ -704,7 +674,7 @@
     this->PrintKeys();
     if (this->SearchMode) {
       std::string searchstr = "Search: " + this->SearchString;
-      this->UpdateStatusBar(searchstr.c_str());
+      this->UpdateStatusBar(searchstr);
       this->PrintKeys(1);
       curses_move(y - 5, static_cast<unsigned int>(searchstr.size()));
       // curses_move(1,1);
@@ -848,8 +818,9 @@
           this->HelpMessage[1] = "";
         }
 
-        cmCursesLongMessageForm* msgs =
-          new cmCursesLongMessageForm(this->HelpMessage, "Help.");
+        cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm(
+          this->HelpMessage, "Help",
+          cmCursesLongMessageForm::ScrollBehavior::NoScroll);
         CurrentForm = msgs;
         msgs->Render(1, 1, x, y);
         msgs->HandleInput();
@@ -861,7 +832,8 @@
       else if (key == 'l') {
         getmaxyx(stdscr, y, x);
         cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm(
-          this->Errors, "Errors occurred during the last pass.");
+          this->Outputs, "CMake produced the following output",
+          cmCursesLongMessageForm::ScrollBehavior::NoScroll);
         CurrentForm = msgs;
         msgs->Render(1, 1, x, y);
         msgs->HandleInput();
@@ -1007,15 +979,6 @@
     } else {
       form_driver(this->Form, REQ_NEXT_FIELD);
     }
-    /*
-    char buffer[1024];
-    sprintf(buffer, "Line: %d != %d / %d\n", findex, idx,
-    this->NumberOfVisibleEntries);
-    touchwin(stdscr);
-    refresh();
-    this->UpdateStatusBar( buffer );
-    usleep(100000);
-    */
     cur = current_field(this->Form);
     findex = field_index(cur);
     if (findex == start_index) {
@@ -1024,6 +987,28 @@
   }
 }
 
+void cmCursesMainForm::ResetOutputs()
+{
+  this->LogForm.reset();
+  this->Outputs.clear();
+  this->HasNonStatusOutputs = false;
+  this->LastProgress.clear();
+}
+
+void cmCursesMainForm::DisplayOutputs()
+{
+  int xi;
+  int yi;
+  getmaxyx(stdscr, yi, xi);
+
+  auto newLogForm = new cmCursesLongMessageForm(
+    this->Outputs, this->LastProgress.c_str(),
+    cmCursesLongMessageForm::ScrollBehavior::ScrollDown);
+  CurrentForm = newLogForm;
+  this->LogForm.reset(newLogForm);
+  this->LogForm->Render(1, 1, xi, yi);
+}
+
 const char* cmCursesMainForm::s_ConstHelpMessage =
   "CMake is used to configure and generate build files for software projects. "
   "The basic steps for configuring a project with ccmake are as follows:\n\n"
@@ -1080,7 +1065,7 @@
   " c : process the configuration files with the current options\n"
   " g : generate build files and exit, only available when there are no "
   "new options and no errors have been detected during last configuration.\n"
-  " l : shows last errors\n"
+  " l : shows cmake output\n"
   " d : delete an option\n"
   " t : toggles advanced mode. In normal mode, only the most important "
   "options are shown. In advanced mode, all options are shown. We recommend "
diff --git a/Source/CursesDialog/cmCursesMainForm.h b/Source/CursesDialog/cmCursesMainForm.h
index b8769b7..b7c204d 100644
--- a/Source/CursesDialog/cmCursesMainForm.h
+++ b/Source/CursesDialog/cmCursesMainForm.h
@@ -10,12 +10,15 @@
 #include <string>
 #include <vector>
 
+#include <cm/optional>
+
 #include "cmCursesCacheEntryComposite.h"
 #include "cmCursesForm.h"
 #include "cmCursesStandardIncludes.h"
 #include "cmStateTypes.h"
 
 class cmake;
+class cmCursesLongMessageForm;
 
 /** \class cmCursesMainForm
  * \brief The main page of ccmake
@@ -66,8 +69,8 @@
    * exception is during a resize. The optional argument specifies the
    * string to be displayed in the status bar.
    */
-  void UpdateStatusBar() override { this->UpdateStatusBar(nullptr); }
-  virtual void UpdateStatusBar(const char* message);
+  void UpdateStatusBar() override { this->UpdateStatusBar(cm::nullopt); }
+  void UpdateStatusBar(cm::optional<std::string> message);
 
   /**
    * Display current commands and their keys on the toolbar.  This
@@ -122,10 +125,24 @@
   // Jump to the cache entry whose name matches the string.
   void JumpToCacheEntry(const char* str);
 
+  // Clear and reset the output log and state
+  void ResetOutputs();
+
+  // Display the current progress and output
+  void DisplayOutputs();
+
   // Copies of cache entries stored in the user interface
   std::vector<cmCursesCacheEntryComposite> Entries;
-  // Errors produced during last run of cmake
-  std::vector<std::string> Errors;
+
+  // The form used to display logs during processing
+  std::unique_ptr<cmCursesLongMessageForm> LogForm;
+  // Output produced by the last pass
+  std::vector<std::string> Outputs;
+  // Did the last pass produced outputs of interest (errors, warnings, ...)
+  bool HasNonStatusOutputs;
+  // Last progress bar
+  std::string LastProgress;
+
   // Command line arguments to be passed to cmake each time
   // it is run
   std::vector<std::string> Args;
diff --git a/Source/CursesDialog/cmCursesOptionsWidget.cxx b/Source/CursesDialog/cmCursesOptionsWidget.cxx
index eb773ad..a15241f 100644
--- a/Source/CursesDialog/cmCursesOptionsWidget.cxx
+++ b/Source/CursesDialog/cmCursesOptionsWidget.cxx
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCursesOptionsWidget.h"
 
+#include "cmCursesColor.h"
 #include "cmCursesWidget.h"
 #include "cmStateTypes.h"
 
@@ -15,8 +16,13 @@
   // there is no option type, and string type causes ccmake to cast
   // the widget into a string widget at some point.  BOOL is safe for
   // now.
-  set_field_fore(this->Field, A_NORMAL);
-  set_field_back(this->Field, A_STANDOUT);
+  if (cmCursesColor::HasColors()) {
+    set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::Options));
+    set_field_back(this->Field, COLOR_PAIR(cmCursesColor::Options));
+  } else {
+    set_field_fore(this->Field, A_NORMAL);
+    set_field_back(this->Field, A_STANDOUT);
+  }
   field_opts_off(this->Field, O_STATIC);
 }
 
diff --git a/Source/CursesDialog/cmCursesPathWidget.cxx b/Source/CursesDialog/cmCursesPathWidget.cxx
index bb3808e..8ed42de 100644
--- a/Source/CursesDialog/cmCursesPathWidget.cxx
+++ b/Source/CursesDialog/cmCursesPathWidget.cxx
@@ -4,6 +4,7 @@
 
 #include <vector>
 
+#include "cmCursesColor.h"
 #include "cmCursesMainForm.h"
 #include "cmCursesStringWidget.h"
 #include "cmStateTypes.h"
@@ -16,6 +17,13 @@
   this->Type = cmStateEnums::PATH;
   this->Cycle = false;
   this->CurrentIndex = 0;
+  if (cmCursesColor::HasColors()) {
+    set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::Path));
+    set_field_back(this->Field, COLOR_PAIR(cmCursesColor::Path));
+  } else {
+    set_field_fore(this->Field, A_NORMAL);
+    set_field_back(this->Field, A_STANDOUT);
+  }
 }
 
 void cmCursesPathWidget::OnType(int& key, cmCursesMainForm* fm, WINDOW* w)
diff --git a/Source/CursesDialog/cmCursesStringWidget.cxx b/Source/CursesDialog/cmCursesStringWidget.cxx
index 6296af2..c629478 100644
--- a/Source/CursesDialog/cmCursesStringWidget.cxx
+++ b/Source/CursesDialog/cmCursesStringWidget.cxx
@@ -4,6 +4,7 @@
 
 #include <cstdio>
 
+#include "cmCursesColor.h"
 #include "cmCursesForm.h"
 #include "cmCursesMainForm.h"
 #include "cmCursesStandardIncludes.h"
@@ -21,8 +22,13 @@
 {
   this->InEdit = false;
   this->Type = cmStateEnums::STRING;
-  set_field_fore(this->Field, A_NORMAL);
-  set_field_back(this->Field, A_STANDOUT);
+  if (cmCursesColor::HasColors()) {
+    set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::String));
+    set_field_back(this->Field, COLOR_PAIR(cmCursesColor::String));
+  } else {
+    set_field_fore(this->Field, A_NORMAL);
+    set_field_back(this->Field, A_STANDOUT);
+  }
   field_opts_off(this->Field, O_STATIC);
 }
 
diff --git a/Source/LexerParser/.gitattributes b/Source/LexerParser/.gitattributes
index bf70249..63d9afb 100644
--- a/Source/LexerParser/.gitattributes
+++ b/Source/LexerParser/.gitattributes
@@ -16,4 +16,6 @@
 /cmFortranLexer.h                  generated
 /cmFortranParser.cxx               generated
 /cmFortranParserTokens.h           generated
+/cmGccDepfileLexer.cxx             generated
+/cmGccDepfileLexer.h               generated
 /cmListFileLexer.c                 generated
diff --git a/Source/LexerParser/cmCommandArgumentParser.cxx b/Source/LexerParser/cmCommandArgumentParser.cxx
index ae7fb42..34dc8ec 100644
--- a/Source/LexerParser/cmCommandArgumentParser.cxx
+++ b/Source/LexerParser/cmCommandArgumentParser.cxx
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 3.3.2.  */
+/* A Bison parser, made by GNU Bison 3.4.2.  */
 
 /* Bison implementation for Yacc-like parsers in C
 
@@ -48,7 +48,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "3.3.2"
+#define YYBISON_VERSION "3.4.2"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -72,7 +72,7 @@
 
 
 /* First part of user prologue.  */
-#line 1 "cmCommandArgumentParser.y" /* yacc.c:337  */
+#line 1 "cmCommandArgumentParser.y"
 
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
@@ -134,7 +134,8 @@
 # pragma GCC diagnostic ignored "-Wconversion"
 #endif
 
-#line 138 "cmCommandArgumentParser.cxx" /* yacc.c:337  */
+#line 138 "cmCommandArgumentParser.cxx"
+
 # ifndef YY_NULLPTR
 #  if defined __cplusplus
 #   if 201103L <= __cplusplus
@@ -155,8 +156,8 @@
 # define YYERROR_VERBOSE 1
 #endif
 
-/* In a future release of Bison, this section will be replaced
-   by #include "cmCommandArgumentParserTokens.h".  */
+/* Use api.header.include to #include this header
+   instead of duplicating it here.  */
 #ifndef YY_CMCOMMANDARGUMENT_YY_CMCOMMANDARGUMENTPARSERTOKENS_H_INCLUDED
 # define YY_CMCOMMANDARGUMENT_YY_CMCOMMANDARGUMENTPARSERTOKENS_H_INCLUDED
 /* Debug traces.  */
@@ -310,6 +311,8 @@
 #endif
 
 
+#define YY_ASSERT(E) ((void) (0 && (E)))
+
 #if ! defined yyoverflow || YYERROR_VERBOSE
 
 /* The parser invokes alloca or malloc; define the necessary symbols.  */
@@ -700,7 +703,9 @@
   if (yytype < YYNTOKENS)
     YYPRINT (yyo, yytoknum[yytype], *yyvaluep);
 # endif
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   YYUSE (yytype);
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
 }
 
 
@@ -1138,6 +1143,8 @@
 | yynewstate -- set current state (the top of the stack) to yystate.  |
 `--------------------------------------------------------------------*/
 yysetstate:
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+  YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
   *yyssp = (yytype_int16) yystate;
 
   if (yyss + yystacksize - 1 <= yyssp)
@@ -1200,8 +1207,6 @@
     }
 #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
 
-  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
   if (yystate == YYFINAL)
     YYACCEPT;
 
@@ -1269,7 +1274,6 @@
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++yyvsp = yylval;
   YY_IGNORE_MAYBE_UNINITIALIZED_END
-
   goto yynewstate;
 
 
@@ -1304,193 +1308,194 @@
   YY_REDUCE_PRINT (yyn);
   switch (yyn)
     {
-        case 2:
-#line 99 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+  case 2:
+#line 99 "cmCommandArgumentParser.y"
     {
     (yyval.str) = 0;
     yyGetParser->SetResult((yyvsp[0].str));
   }
-#line 1314 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1318 "cmCommandArgumentParser.cxx"
     break;
 
   case 3:
-#line 105 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 105 "cmCommandArgumentParser.y"
     {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1322 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1326 "cmCommandArgumentParser.cxx"
     break;
 
   case 4:
-#line 108 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 108 "cmCommandArgumentParser.y"
     {
     (yyval.str) = yyGetParser->CombineUnions((yyvsp[-1].str), (yyvsp[0].str));
   }
-#line 1330 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1334 "cmCommandArgumentParser.cxx"
     break;
 
   case 5:
-#line 113 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 113 "cmCommandArgumentParser.y"
     {
     (yyval.str) = 0;
   }
-#line 1338 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1342 "cmCommandArgumentParser.cxx"
     break;
 
   case 6:
-#line 116 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 116 "cmCommandArgumentParser.y"
     {
     (yyval.str) = yyGetParser->CombineUnions((yyvsp[-1].str), (yyvsp[0].str));
   }
-#line 1346 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1350 "cmCommandArgumentParser.cxx"
     break;
 
   case 7:
-#line 121 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 121 "cmCommandArgumentParser.y"
     {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1354 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1358 "cmCommandArgumentParser.cxx"
     break;
 
   case 8:
-#line 124 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 124 "cmCommandArgumentParser.y"
     {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1362 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1366 "cmCommandArgumentParser.cxx"
     break;
 
   case 9:
-#line 129 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 129 "cmCommandArgumentParser.y"
     {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1370 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1374 "cmCommandArgumentParser.cxx"
     break;
 
   case 10:
-#line 132 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 132 "cmCommandArgumentParser.y"
     {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1378 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1382 "cmCommandArgumentParser.cxx"
     break;
 
   case 11:
-#line 135 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 135 "cmCommandArgumentParser.y"
     {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1386 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1390 "cmCommandArgumentParser.cxx"
     break;
 
   case 12:
-#line 138 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 138 "cmCommandArgumentParser.y"
     {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1394 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1398 "cmCommandArgumentParser.cxx"
     break;
 
   case 13:
-#line 141 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 141 "cmCommandArgumentParser.y"
     {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1402 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1406 "cmCommandArgumentParser.cxx"
     break;
 
   case 14:
-#line 144 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 144 "cmCommandArgumentParser.y"
     {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1410 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1414 "cmCommandArgumentParser.cxx"
     break;
 
   case 15:
-#line 149 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 149 "cmCommandArgumentParser.y"
     {
     (yyval.str) = yyGetParser->ExpandSpecialVariable((yyvsp[-2].str), (yyvsp[-1].str));
   }
-#line 1418 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1422 "cmCommandArgumentParser.cxx"
     break;
 
   case 16:
-#line 152 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 152 "cmCommandArgumentParser.y"
     {
     (yyval.str) = yyGetParser->ExpandSpecialVariable((yyvsp[-2].str), (yyvsp[-1].str));
   }
-#line 1426 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1430 "cmCommandArgumentParser.cxx"
     break;
 
   case 17:
-#line 155 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 155 "cmCommandArgumentParser.y"
     {
     (yyval.str) = yyGetParser->ExpandVariable((yyvsp[-1].str));
   }
-#line 1434 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1438 "cmCommandArgumentParser.cxx"
     break;
 
   case 18:
-#line 158 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 158 "cmCommandArgumentParser.y"
     {
     (yyval.str) = yyGetParser->ExpandVariableForAt((yyvsp[0].str));
   }
-#line 1442 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1446 "cmCommandArgumentParser.cxx"
     break;
 
   case 19:
-#line 163 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 163 "cmCommandArgumentParser.y"
     {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1450 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1454 "cmCommandArgumentParser.cxx"
     break;
 
   case 20:
-#line 166 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 166 "cmCommandArgumentParser.y"
     {
     (yyval.str) = (yyvsp[-1].str);
   }
-#line 1458 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1462 "cmCommandArgumentParser.cxx"
     break;
 
   case 21:
-#line 171 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 171 "cmCommandArgumentParser.y"
     {
     (yyval.str) = 0;
   }
-#line 1466 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1470 "cmCommandArgumentParser.cxx"
     break;
 
   case 22:
-#line 174 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 174 "cmCommandArgumentParser.y"
     {
     (yyval.str) = yyGetParser->CombineUnions((yyvsp[-1].str), (yyvsp[0].str));
   }
-#line 1474 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1478 "cmCommandArgumentParser.cxx"
     break;
 
   case 23:
-#line 179 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 179 "cmCommandArgumentParser.y"
     {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1482 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1486 "cmCommandArgumentParser.cxx"
     break;
 
   case 24:
-#line 182 "cmCommandArgumentParser.y" /* yacc.c:1652  */
+#line 182 "cmCommandArgumentParser.y"
     {
     (yyval.str) = (yyvsp[0].str);
   }
-#line 1490 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1494 "cmCommandArgumentParser.cxx"
     break;
 
 
-#line 1494 "cmCommandArgumentParser.cxx" /* yacc.c:1652  */
+#line 1498 "cmCommandArgumentParser.cxx"
+
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -1723,7 +1728,7 @@
 #endif
   return yyresult;
 }
-#line 187 "cmCommandArgumentParser.y" /* yacc.c:1918  */
+#line 187 "cmCommandArgumentParser.y"
 
 /* End of grammar */
 
diff --git a/Source/LexerParser/cmCommandArgumentParserTokens.h b/Source/LexerParser/cmCommandArgumentParserTokens.h
index 56c9794..033b899 100644
--- a/Source/LexerParser/cmCommandArgumentParserTokens.h
+++ b/Source/LexerParser/cmCommandArgumentParserTokens.h
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 3.3.2.  */
+/* A Bison parser, made by GNU Bison 3.4.2.  */
 
 /* Bison interface for Yacc-like parsers in C
 
diff --git a/Source/LexerParser/cmDependsJavaParser.cxx b/Source/LexerParser/cmDependsJavaParser.cxx
index 6c1fb2c..b15082d 100644
--- a/Source/LexerParser/cmDependsJavaParser.cxx
+++ b/Source/LexerParser/cmDependsJavaParser.cxx
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 3.3.2.  */
+/* A Bison parser, made by GNU Bison 3.4.2.  */
 
 /* Bison implementation for Yacc-like parsers in C
 
@@ -48,7 +48,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "3.3.2"
+#define YYBISON_VERSION "3.4.2"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -72,7 +72,7 @@
 
 
 /* First part of user prologue.  */
-#line 1 "cmDependsJavaParser.y" /* yacc.c:337  */
+#line 1 "cmDependsJavaParser.y"
 
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
@@ -123,7 +123,8 @@
 # pragma GCC diagnostic ignored "-Wconversion"
 #endif
 
-#line 127 "cmDependsJavaParser.cxx" /* yacc.c:337  */
+#line 127 "cmDependsJavaParser.cxx"
+
 # ifndef YY_NULLPTR
 #  if defined __cplusplus
 #   if 201103L <= __cplusplus
@@ -144,8 +145,8 @@
 # define YYERROR_VERBOSE 1
 #endif
 
-/* In a future release of Bison, this section will be replaced
-   by #include "cmDependsJavaParserTokens.h".  */
+/* Use api.header.include to #include this header
+   instead of duplicating it here.  */
 #ifndef YY_CMDEPENDSJAVA_YY_CMDEPENDSJAVAPARSERTOKENS_H_INCLUDED
 # define YY_CMDEPENDSJAVA_YY_CMDEPENDSJAVAPARSERTOKENS_H_INCLUDED
 /* Debug traces.  */
@@ -481,6 +482,8 @@
 #endif
 
 
+#define YY_ASSERT(E) ((void) (0 && (E)))
+
 #if ! defined yyoverflow || YYERROR_VERBOSE
 
 /* The parser invokes alloca or malloc; define the necessary symbols.  */
@@ -1685,7 +1688,9 @@
   if (yytype < YYNTOKENS)
     YYPRINT (yyo, yytoknum[yytype], *yyvaluep);
 # endif
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   YYUSE (yytype);
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
 }
 
 
@@ -2123,6 +2128,8 @@
 | yynewstate -- set current state (the top of the stack) to yystate.  |
 `--------------------------------------------------------------------*/
 yysetstate:
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+  YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
   *yyssp = (yytype_int16) yystate;
 
   if (yyss + yystacksize - 1 <= yyssp)
@@ -2185,8 +2192,6 @@
     }
 #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
 
-  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
   if (yystate == YYFINAL)
     YYACCEPT;
 
@@ -2254,7 +2259,6 @@
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++yyvsp = yylval;
   YY_IGNORE_MAYBE_UNINITIALIZED_END
-
   goto yynewstate;
 
 
@@ -2289,215 +2293,215 @@
   YY_REDUCE_PRINT (yyn);
   switch (yyn)
     {
-        case 2:
-#line 183 "cmDependsJavaParser.y" /* yacc.c:1652  */
+  case 2:
+#line 183 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2301 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2305 "cmDependsJavaParser.cxx"
     break;
 
   case 3:
-#line 192 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 192 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2312 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2316 "cmDependsJavaParser.cxx"
     break;
 
   case 4:
-#line 200 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 200 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2323 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2327 "cmDependsJavaParser.cxx"
     break;
 
   case 5:
-#line 208 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 208 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2334 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2338 "cmDependsJavaParser.cxx"
     break;
 
   case 6:
-#line 216 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 216 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2345 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2349 "cmDependsJavaParser.cxx"
     break;
 
   case 7:
-#line 224 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 224 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2356 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2360 "cmDependsJavaParser.cxx"
     break;
 
   case 8:
-#line 232 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 232 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2367 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2371 "cmDependsJavaParser.cxx"
     break;
 
   case 9:
-#line 241 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 241 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2378 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2382 "cmDependsJavaParser.cxx"
     break;
 
   case 10:
-#line 249 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 249 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2389 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2393 "cmDependsJavaParser.cxx"
     break;
 
   case 11:
-#line 258 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 258 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2400 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2404 "cmDependsJavaParser.cxx"
     break;
 
   case 12:
-#line 266 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 266 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2411 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2415 "cmDependsJavaParser.cxx"
     break;
 
   case 13:
-#line 275 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 275 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
 }
-#line 2419 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2423 "cmDependsJavaParser.cxx"
     break;
 
   case 14:
-#line 280 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 280 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
 }
-#line 2427 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2431 "cmDependsJavaParser.cxx"
     break;
 
   case 15:
-#line 285 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 285 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
 }
-#line 2435 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2439 "cmDependsJavaParser.cxx"
     break;
 
   case 16:
-#line 290 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 290 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
 }
-#line 2443 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2447 "cmDependsJavaParser.cxx"
     break;
 
   case 17:
-#line 295 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 295 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
 }
-#line 2451 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2455 "cmDependsJavaParser.cxx"
     break;
 
   case 18:
-#line 300 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 300 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
 }
-#line 2459 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2463 "cmDependsJavaParser.cxx"
     break;
 
   case 19:
-#line 305 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 305 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
 }
-#line 2467 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2471 "cmDependsJavaParser.cxx"
     break;
 
   case 20:
-#line 310 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 310 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
 }
-#line 2475 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2479 "cmDependsJavaParser.cxx"
     break;
 
   case 21:
-#line 316 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 316 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2486 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2490 "cmDependsJavaParser.cxx"
     break;
 
   case 22:
-#line 324 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 324 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2497 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2501 "cmDependsJavaParser.cxx"
     break;
 
   case 23:
-#line 333 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 333 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpStoreClass((yyvsp[0].str));
@@ -2505,44 +2509,44 @@
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2509 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2513 "cmDependsJavaParser.cxx"
     break;
 
   case 24:
-#line 343 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 343 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2520 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2524 "cmDependsJavaParser.cxx"
     break;
 
   case 25:
-#line 352 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 352 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2531 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2535 "cmDependsJavaParser.cxx"
     break;
 
   case 26:
-#line 361 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 361 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2542 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2546 "cmDependsJavaParser.cxx"
     break;
 
   case 27:
-#line 369 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 369 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpStoreClass((yyvsp[-1].str));
@@ -2550,56 +2554,56 @@
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2554 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2558 "cmDependsJavaParser.cxx"
     break;
 
   case 28:
-#line 379 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 379 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   (yyval.str) = (yyvsp[0].str);
 }
-#line 2563 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2567 "cmDependsJavaParser.cxx"
     break;
 
   case 29:
-#line 385 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 385 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   (yyval.str) = (yyvsp[0].str);
 }
-#line 2572 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2576 "cmDependsJavaParser.cxx"
     break;
 
   case 30:
-#line 392 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 392 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   (yyval.str) = (yyvsp[0].str);
 }
-#line 2581 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2585 "cmDependsJavaParser.cxx"
     break;
 
   case 31:
-#line 399 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 399 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   (yyval.str) = (yyvsp[0].str);
 }
-#line 2590 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2594 "cmDependsJavaParser.cxx"
     break;
 
   case 32:
-#line 405 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 405 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   (yyval.str) = (yyvsp[0].str);
 }
-#line 2599 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2603 "cmDependsJavaParser.cxx"
     break;
 
   case 33:
-#line 412 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 412 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   yyGetParser->AddClassFound((yyvsp[-2].str));
@@ -2607,11 +2611,11 @@
   yyGetParser->DeallocateParserType(&((yyvsp[-2].str)));
   (yyval.str) = const_cast<char*>(yyGetParser->GetCurrentCombine());
 }
-#line 2611 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2615 "cmDependsJavaParser.cxx"
     break;
 
   case 34:
-#line 421 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 421 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpStoreClass((yyvsp[-2].str));
@@ -2620,11 +2624,11 @@
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2624 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2628 "cmDependsJavaParser.cxx"
     break;
 
   case 35:
-#line 431 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 431 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpStoreClass((yyvsp[-2].str));
@@ -2633,118 +2637,118 @@
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2637 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2641 "cmDependsJavaParser.cxx"
     break;
 
   case 36:
-#line 441 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 441 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2648 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2652 "cmDependsJavaParser.cxx"
     break;
 
   case 37:
-#line 450 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 450 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2659 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2663 "cmDependsJavaParser.cxx"
     break;
 
   case 38:
-#line 458 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 458 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2670 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2674 "cmDependsJavaParser.cxx"
     break;
 
   case 39:
-#line 467 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 467 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2681 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2685 "cmDependsJavaParser.cxx"
     break;
 
   case 40:
-#line 475 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 475 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2691 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2695 "cmDependsJavaParser.cxx"
     break;
 
   case 41:
-#line 482 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 482 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2702 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2706 "cmDependsJavaParser.cxx"
     break;
 
   case 42:
-#line 490 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 490 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2712 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2716 "cmDependsJavaParser.cxx"
     break;
 
   case 43:
-#line 497 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 497 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2723 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2727 "cmDependsJavaParser.cxx"
     break;
 
   case 44:
-#line 505 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 505 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2733 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2737 "cmDependsJavaParser.cxx"
     break;
 
   case 45:
-#line 512 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 512 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2744 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2748 "cmDependsJavaParser.cxx"
     break;
 
   case 46:
-#line 521 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 521 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   yyGetParser->SetCurrentPackage((yyvsp[-1].str));
@@ -2754,33 +2758,33 @@
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2758 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2762 "cmDependsJavaParser.cxx"
     break;
 
   case 47:
-#line 533 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 533 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2769 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2773 "cmDependsJavaParser.cxx"
     break;
 
   case 48:
-#line 541 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 541 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2780 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2784 "cmDependsJavaParser.cxx"
     break;
 
   case 49:
-#line 550 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 550 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   yyGetParser->AddPackagesImport((yyvsp[-1].str));
@@ -2790,11 +2794,11 @@
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2794 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2798 "cmDependsJavaParser.cxx"
     break;
 
   case 50:
-#line 562 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 562 "cmDependsJavaParser.y"
     {
   jpElementStart(5);
   std::string str = (yyvsp[-3].str);
@@ -2805,77 +2809,77 @@
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2809 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2813 "cmDependsJavaParser.cxx"
     break;
 
   case 51:
-#line 575 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 575 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2820 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2824 "cmDependsJavaParser.cxx"
     break;
 
   case 52:
-#line 583 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 583 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2831 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2835 "cmDependsJavaParser.cxx"
     break;
 
   case 53:
-#line 591 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 591 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2842 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2846 "cmDependsJavaParser.cxx"
     break;
 
   case 54:
-#line 600 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 600 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2853 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2857 "cmDependsJavaParser.cxx"
     break;
 
   case 55:
-#line 608 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 608 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2864 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2868 "cmDependsJavaParser.cxx"
     break;
 
   case 67:
-#line 623 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 623 "cmDependsJavaParser.y"
     {
   yyGetParser->StartClass((yyvsp[0].str));
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
   jpCheckEmpty(3);
 }
-#line 2875 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2879 "cmDependsJavaParser.cxx"
     break;
 
   case 68:
-#line 633 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 633 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -2883,11 +2887,11 @@
   yyGetParser->SetCurrentCombine("");
   yyGetParser->EndClass();
 }
-#line 2887 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2891 "cmDependsJavaParser.cxx"
     break;
 
   case 69:
-#line 642 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 642 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(2);
@@ -2895,11 +2899,11 @@
   yyGetParser->SetCurrentCombine("");
   yyGetParser->EndClass();
 }
-#line 2899 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2903 "cmDependsJavaParser.cxx"
     break;
 
   case 70:
-#line 651 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 651 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -2907,11 +2911,11 @@
   yyGetParser->SetCurrentCombine("");
   yyGetParser->EndClass();
 }
-#line 2911 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2915 "cmDependsJavaParser.cxx"
     break;
 
   case 71:
-#line 660 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 660 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   jpCheckEmpty(4);
@@ -2919,226 +2923,226 @@
   yyGetParser->SetCurrentCombine("");
   yyGetParser->EndClass();
 }
-#line 2923 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2927 "cmDependsJavaParser.cxx"
     break;
 
   case 72:
-#line 669 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 669 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2933 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2937 "cmDependsJavaParser.cxx"
     break;
 
   case 73:
-#line 676 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 676 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2944 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2948 "cmDependsJavaParser.cxx"
     break;
 
   case 74:
-#line 685 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 685 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2955 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2959 "cmDependsJavaParser.cxx"
     break;
 
   case 75:
-#line 694 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 694 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2966 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2970 "cmDependsJavaParser.cxx"
     break;
 
   case 76:
-#line 703 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 703 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2977 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2981 "cmDependsJavaParser.cxx"
     break;
 
   case 77:
-#line 711 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 711 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2988 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 2992 "cmDependsJavaParser.cxx"
     break;
 
   case 78:
-#line 720 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 720 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 2999 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3003 "cmDependsJavaParser.cxx"
     break;
 
   case 79:
-#line 728 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 728 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3009 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3013 "cmDependsJavaParser.cxx"
     break;
 
   case 80:
-#line 735 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 735 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3020 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3024 "cmDependsJavaParser.cxx"
     break;
 
   case 81:
-#line 744 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 744 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3031 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3035 "cmDependsJavaParser.cxx"
     break;
 
   case 82:
-#line 752 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 752 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3042 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3046 "cmDependsJavaParser.cxx"
     break;
 
   case 83:
-#line 760 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 760 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3053 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3057 "cmDependsJavaParser.cxx"
     break;
 
   case 84:
-#line 768 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 768 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3064 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3068 "cmDependsJavaParser.cxx"
     break;
 
   case 85:
-#line 777 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 777 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3075 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3079 "cmDependsJavaParser.cxx"
     break;
 
   case 86:
-#line 785 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 785 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3086 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3090 "cmDependsJavaParser.cxx"
     break;
 
   case 87:
-#line 794 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 794 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
 }
-#line 3094 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3098 "cmDependsJavaParser.cxx"
     break;
 
   case 88:
-#line 800 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 800 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3105 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3109 "cmDependsJavaParser.cxx"
     break;
 
   case 89:
-#line 808 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 808 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3116 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3120 "cmDependsJavaParser.cxx"
     break;
 
   case 90:
-#line 817 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 817 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3127 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3131 "cmDependsJavaParser.cxx"
     break;
 
   case 91:
-#line 825 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 825 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3138 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3142 "cmDependsJavaParser.cxx"
     break;
 
   case 92:
-#line 834 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 834 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
@@ -3146,77 +3150,77 @@
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3150 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3154 "cmDependsJavaParser.cxx"
     break;
 
   case 93:
-#line 843 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 843 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3161 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3165 "cmDependsJavaParser.cxx"
     break;
 
   case 94:
-#line 852 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 852 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3172 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3176 "cmDependsJavaParser.cxx"
     break;
 
   case 95:
-#line 860 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 860 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3183 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3187 "cmDependsJavaParser.cxx"
     break;
 
   case 96:
-#line 869 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 869 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3194 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3198 "cmDependsJavaParser.cxx"
     break;
 
   case 97:
-#line 877 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 877 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3205 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3209 "cmDependsJavaParser.cxx"
     break;
 
   case 98:
-#line 885 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 885 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3216 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3220 "cmDependsJavaParser.cxx"
     break;
 
   case 99:
-#line 894 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 894 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   jpCheckEmpty(4);
@@ -3224,11 +3228,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3228 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3232 "cmDependsJavaParser.cxx"
     break;
 
   case 100:
-#line 903 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 903 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   jpCheckEmpty(4);
@@ -3236,22 +3240,22 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3240 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3244 "cmDependsJavaParser.cxx"
     break;
 
   case 101:
-#line 912 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 912 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3251 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3255 "cmDependsJavaParser.cxx"
     break;
 
   case 102:
-#line 920 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 920 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3259,11 +3263,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3263 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3267 "cmDependsJavaParser.cxx"
     break;
 
   case 103:
-#line 930 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 930 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
@@ -3272,40 +3276,40 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3276 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3280 "cmDependsJavaParser.cxx"
     break;
 
   case 104:
-#line 940 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 940 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
 
 }
-#line 3285 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3289 "cmDependsJavaParser.cxx"
     break;
 
   case 105:
-#line 946 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 946 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3296 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3300 "cmDependsJavaParser.cxx"
     break;
 
   case 107:
-#line 957 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 957 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
 
 }
-#line 3305 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3309 "cmDependsJavaParser.cxx"
     break;
 
   case 108:
-#line 963 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 963 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -3313,11 +3317,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3317 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3321 "cmDependsJavaParser.cxx"
     break;
 
   case 109:
-#line 973 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 973 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -3325,11 +3329,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3329 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3333 "cmDependsJavaParser.cxx"
     break;
 
   case 110:
-#line 983 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 983 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -3337,20 +3341,20 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3341 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3345 "cmDependsJavaParser.cxx"
     break;
 
   case 111:
-#line 993 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 993 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
 
 }
-#line 3350 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3354 "cmDependsJavaParser.cxx"
     break;
 
   case 112:
-#line 999 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 999 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -3358,11 +3362,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3362 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3366 "cmDependsJavaParser.cxx"
     break;
 
   case 113:
-#line 1009 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1009 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3370,11 +3374,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3374 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3378 "cmDependsJavaParser.cxx"
     break;
 
   case 114:
-#line 1019 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1019 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -3382,11 +3386,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3386 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3390 "cmDependsJavaParser.cxx"
     break;
 
   case 115:
-#line 1029 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1029 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   jpCheckEmpty(4);
@@ -3394,11 +3398,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3398 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3402 "cmDependsJavaParser.cxx"
     break;
 
   case 116:
-#line 1038 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1038 "cmDependsJavaParser.y"
     {
   jpElementStart(5);
   jpCheckEmpty(5);
@@ -3406,11 +3410,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3410 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3414 "cmDependsJavaParser.cxx"
     break;
 
   case 117:
-#line 1048 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1048 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
@@ -3419,11 +3423,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3423 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3427 "cmDependsJavaParser.cxx"
     break;
 
   case 118:
-#line 1059 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1059 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   jpCheckEmpty(4);
@@ -3431,22 +3435,22 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3435 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3439 "cmDependsJavaParser.cxx"
     break;
 
   case 119:
-#line 1068 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1068 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3446 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3450 "cmDependsJavaParser.cxx"
     break;
 
   case 120:
-#line 1076 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1076 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -3454,11 +3458,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3458 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3462 "cmDependsJavaParser.cxx"
     break;
 
   case 121:
-#line 1086 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1086 "cmDependsJavaParser.y"
     {
   jpElementStart(5);
   jpCheckEmpty(5);
@@ -3466,11 +3470,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3470 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3474 "cmDependsJavaParser.cxx"
     break;
 
   case 122:
-#line 1095 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1095 "cmDependsJavaParser.y"
     {
   jpElementStart(5);
   jpCheckEmpty(5);
@@ -3478,22 +3482,22 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3482 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3486 "cmDependsJavaParser.cxx"
     break;
 
   case 123:
-#line 1105 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1105 "cmDependsJavaParser.y"
     {
   yyGetParser->StartClass((yyvsp[0].str));
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
   jpCheckEmpty(3);
 }
-#line 3493 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3497 "cmDependsJavaParser.cxx"
     break;
 
   case 124:
-#line 1114 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1114 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -3501,21 +3505,21 @@
   yyGetParser->SetCurrentCombine("");
   yyGetParser->EndClass();
 }
-#line 3505 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3509 "cmDependsJavaParser.cxx"
     break;
 
   case 125:
-#line 1123 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1123 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 }
-#line 3515 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3519 "cmDependsJavaParser.cxx"
     break;
 
   case 126:
-#line 1130 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1130 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3523,11 +3527,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3527 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3531 "cmDependsJavaParser.cxx"
     break;
 
   case 127:
-#line 1140 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1140 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -3535,11 +3539,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3539 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3543 "cmDependsJavaParser.cxx"
     break;
 
   case 128:
-#line 1149 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1149 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -3547,11 +3551,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3551 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3555 "cmDependsJavaParser.cxx"
     break;
 
   case 129:
-#line 1159 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1159 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -3559,33 +3563,33 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3563 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3567 "cmDependsJavaParser.cxx"
     break;
 
   case 130:
-#line 1168 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1168 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3574 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3578 "cmDependsJavaParser.cxx"
     break;
 
   case 131:
-#line 1176 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1176 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3585 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3589 "cmDependsJavaParser.cxx"
     break;
 
   case 132:
-#line 1185 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1185 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3593,11 +3597,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3597 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3601 "cmDependsJavaParser.cxx"
     break;
 
   case 133:
-#line 1194 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1194 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3605,11 +3609,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3609 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3613 "cmDependsJavaParser.cxx"
     break;
 
   case 134:
-#line 1203 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1203 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3617,22 +3621,22 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3621 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3625 "cmDependsJavaParser.cxx"
     break;
 
   case 135:
-#line 1212 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1212 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3632 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3636 "cmDependsJavaParser.cxx"
     break;
 
   case 136:
-#line 1220 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1220 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3640,22 +3644,22 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3644 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3648 "cmDependsJavaParser.cxx"
     break;
 
   case 137:
-#line 1229 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1229 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3655 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3659 "cmDependsJavaParser.cxx"
     break;
 
   case 138:
-#line 1238 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1238 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3663,11 +3667,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3667 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3671 "cmDependsJavaParser.cxx"
     break;
 
   case 139:
-#line 1248 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1248 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -3675,11 +3679,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3679 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3683 "cmDependsJavaParser.cxx"
     break;
 
   case 140:
-#line 1258 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1258 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3687,11 +3691,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3691 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3695 "cmDependsJavaParser.cxx"
     break;
 
   case 141:
-#line 1267 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1267 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -3699,11 +3703,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3703 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3707 "cmDependsJavaParser.cxx"
     break;
 
   case 142:
-#line 1277 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1277 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -3711,22 +3715,22 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3715 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3719 "cmDependsJavaParser.cxx"
     break;
 
   case 143:
-#line 1286 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1286 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3726 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3730 "cmDependsJavaParser.cxx"
     break;
 
   case 144:
-#line 1294 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1294 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3734,11 +3738,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3738 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3742 "cmDependsJavaParser.cxx"
     break;
 
   case 145:
-#line 1303 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1303 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -3746,11 +3750,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3750 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3754 "cmDependsJavaParser.cxx"
     break;
 
   case 146:
-#line 1313 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1313 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3758,11 +3762,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3762 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3766 "cmDependsJavaParser.cxx"
     break;
 
   case 147:
-#line 1322 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1322 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -3770,33 +3774,33 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3774 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3778 "cmDependsJavaParser.cxx"
     break;
 
   case 148:
-#line 1332 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1332 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3785 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3789 "cmDependsJavaParser.cxx"
     break;
 
   case 149:
-#line 1340 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1340 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3796 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3800 "cmDependsJavaParser.cxx"
     break;
 
   case 150:
-#line 1348 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1348 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3804,11 +3808,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3808 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3812 "cmDependsJavaParser.cxx"
     break;
 
   case 151:
-#line 1358 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1358 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3816,11 +3820,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3820 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3824 "cmDependsJavaParser.cxx"
     break;
 
   case 152:
-#line 1367 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1367 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(2);
@@ -3828,11 +3832,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3832 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3836 "cmDependsJavaParser.cxx"
     break;
 
   case 153:
-#line 1377 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1377 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3840,11 +3844,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3844 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3848 "cmDependsJavaParser.cxx"
     break;
 
   case 154:
-#line 1386 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1386 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3852,11 +3856,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3856 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3860 "cmDependsJavaParser.cxx"
     break;
 
   case 155:
-#line 1395 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1395 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3864,11 +3868,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3868 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3872 "cmDependsJavaParser.cxx"
     break;
 
   case 156:
-#line 1405 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1405 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(2);
@@ -3876,11 +3880,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3880 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3884 "cmDependsJavaParser.cxx"
     break;
 
   case 157:
-#line 1415 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1415 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(3);
@@ -3888,11 +3892,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3892 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3896 "cmDependsJavaParser.cxx"
     break;
 
   case 158:
-#line 1424 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1424 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(2);
@@ -3900,11 +3904,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3904 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3908 "cmDependsJavaParser.cxx"
     break;
 
   case 159:
-#line 1434 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1434 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3912,11 +3916,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3916 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3920 "cmDependsJavaParser.cxx"
     break;
 
   case 160:
-#line 1443 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1443 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3924,11 +3928,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3928 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3932 "cmDependsJavaParser.cxx"
     break;
 
   case 161:
-#line 1452 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1452 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3936,11 +3940,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3940 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3944 "cmDependsJavaParser.cxx"
     break;
 
   case 162:
-#line 1461 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1461 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3948,11 +3952,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3952 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3956 "cmDependsJavaParser.cxx"
     break;
 
   case 163:
-#line 1470 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1470 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3960,11 +3964,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3964 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3968 "cmDependsJavaParser.cxx"
     break;
 
   case 164:
-#line 1479 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1479 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3972,11 +3976,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3976 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3980 "cmDependsJavaParser.cxx"
     break;
 
   case 165:
-#line 1489 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1489 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3984,11 +3988,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 3988 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 3992 "cmDependsJavaParser.cxx"
     break;
 
   case 166:
-#line 1498 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1498 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -3996,11 +4000,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4000 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4004 "cmDependsJavaParser.cxx"
     break;
 
   case 167:
-#line 1507 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1507 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4008,11 +4012,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4012 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4016 "cmDependsJavaParser.cxx"
     break;
 
   case 168:
-#line 1516 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1516 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4020,11 +4024,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4024 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4028 "cmDependsJavaParser.cxx"
     break;
 
   case 169:
-#line 1525 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1525 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4032,11 +4036,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4036 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4040 "cmDependsJavaParser.cxx"
     break;
 
   case 170:
-#line 1535 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1535 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4044,11 +4048,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4048 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4052 "cmDependsJavaParser.cxx"
     break;
 
   case 171:
-#line 1544 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1544 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4056,11 +4060,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4060 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4064 "cmDependsJavaParser.cxx"
     break;
 
   case 172:
-#line 1553 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1553 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4068,11 +4072,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4072 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4076 "cmDependsJavaParser.cxx"
     break;
 
   case 173:
-#line 1562 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1562 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4080,11 +4084,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4084 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4088 "cmDependsJavaParser.cxx"
     break;
 
   case 174:
-#line 1571 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1571 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4092,11 +4096,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4096 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4100 "cmDependsJavaParser.cxx"
     break;
 
   case 175:
-#line 1580 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1580 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4104,11 +4108,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4108 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4112 "cmDependsJavaParser.cxx"
     break;
 
   case 176:
-#line 1589 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1589 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4116,11 +4120,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4120 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4124 "cmDependsJavaParser.cxx"
     break;
 
   case 177:
-#line 1598 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1598 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4128,11 +4132,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4132 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4136 "cmDependsJavaParser.cxx"
     break;
 
   case 178:
-#line 1607 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1607 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4140,11 +4144,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4144 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4148 "cmDependsJavaParser.cxx"
     break;
 
   case 179:
-#line 1616 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1616 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4152,11 +4156,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4156 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4160 "cmDependsJavaParser.cxx"
     break;
 
   case 180:
-#line 1625 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1625 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4164,11 +4168,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4168 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4172 "cmDependsJavaParser.cxx"
     break;
 
   case 181:
-#line 1634 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1634 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4176,11 +4180,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4180 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4184 "cmDependsJavaParser.cxx"
     break;
 
   case 182:
-#line 1644 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1644 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4188,11 +4192,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4192 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4196 "cmDependsJavaParser.cxx"
     break;
 
   case 183:
-#line 1654 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1654 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[-2].str)));
@@ -4201,11 +4205,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4205 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4209 "cmDependsJavaParser.cxx"
     break;
 
   case 184:
-#line 1665 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1665 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -4213,11 +4217,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4217 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4221 "cmDependsJavaParser.cxx"
     break;
 
   case 185:
-#line 1675 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1675 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -4225,11 +4229,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4229 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4233 "cmDependsJavaParser.cxx"
     break;
 
   case 186:
-#line 1685 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1685 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4237,11 +4241,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4241 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4245 "cmDependsJavaParser.cxx"
     break;
 
   case 187:
-#line 1694 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1694 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4249,11 +4253,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4253 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4257 "cmDependsJavaParser.cxx"
     break;
 
   case 188:
-#line 1703 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1703 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4261,11 +4265,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4265 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4269 "cmDependsJavaParser.cxx"
     break;
 
   case 189:
-#line 1712 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1712 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4273,11 +4277,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4277 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4281 "cmDependsJavaParser.cxx"
     break;
 
   case 190:
-#line 1721 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1721 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4285,11 +4289,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4289 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4293 "cmDependsJavaParser.cxx"
     break;
 
   case 191:
-#line 1730 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1730 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4297,11 +4301,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4301 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4305 "cmDependsJavaParser.cxx"
     break;
 
   case 192:
-#line 1739 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1739 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4309,11 +4313,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4313 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4317 "cmDependsJavaParser.cxx"
     break;
 
   case 193:
-#line 1749 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1749 "cmDependsJavaParser.y"
     {
   jpElementStart(5);
   jpCheckEmpty(5);
@@ -4321,11 +4325,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4325 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4329 "cmDependsJavaParser.cxx"
     break;
 
   case 194:
-#line 1759 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1759 "cmDependsJavaParser.y"
     {
   jpElementStart(7);
   jpCheckEmpty(7);
@@ -4333,11 +4337,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4337 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4341 "cmDependsJavaParser.cxx"
     break;
 
   case 195:
-#line 1769 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1769 "cmDependsJavaParser.y"
     {
   jpElementStart(7);
   jpCheckEmpty(7);
@@ -4345,40 +4349,40 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4349 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4353 "cmDependsJavaParser.cxx"
     break;
 
   case 196:
-#line 1779 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1779 "cmDependsJavaParser.y"
     {
   jpElementStart(5);
 
 }
-#line 4358 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4362 "cmDependsJavaParser.cxx"
     break;
 
   case 197:
-#line 1786 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1786 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
 
 }
-#line 4367 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4371 "cmDependsJavaParser.cxx"
     break;
 
   case 198:
-#line 1792 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1792 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4378 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4382 "cmDependsJavaParser.cxx"
     break;
 
   case 199:
-#line 1800 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1800 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4386,22 +4390,22 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4390 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4394 "cmDependsJavaParser.cxx"
     break;
 
   case 200:
-#line 1809 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1809 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4401 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4405 "cmDependsJavaParser.cxx"
     break;
 
   case 201:
-#line 1817 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1817 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -4409,11 +4413,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4413 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4417 "cmDependsJavaParser.cxx"
     break;
 
   case 202:
-#line 1827 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1827 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -4421,11 +4425,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4425 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4429 "cmDependsJavaParser.cxx"
     break;
 
   case 203:
-#line 1837 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1837 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4433,11 +4437,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4437 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4441 "cmDependsJavaParser.cxx"
     break;
 
   case 204:
-#line 1846 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1846 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -4445,11 +4449,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4449 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4453 "cmDependsJavaParser.cxx"
     break;
 
   case 205:
-#line 1856 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1856 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -4457,11 +4461,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4461 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4465 "cmDependsJavaParser.cxx"
     break;
 
   case 206:
-#line 1865 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1865 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -4469,58 +4473,58 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4473 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4477 "cmDependsJavaParser.cxx"
     break;
 
   case 207:
-#line 1875 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1875 "cmDependsJavaParser.y"
     {
   jpElementStart(5);
 
 }
-#line 4482 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4486 "cmDependsJavaParser.cxx"
     break;
 
   case 208:
-#line 1882 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1882 "cmDependsJavaParser.y"
     {
   jpElementStart(5);
 
 }
-#line 4491 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4495 "cmDependsJavaParser.cxx"
     break;
 
   case 209:
-#line 1889 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1889 "cmDependsJavaParser.y"
     {
   jpElementStart(7);
 
 }
-#line 4500 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4504 "cmDependsJavaParser.cxx"
     break;
 
   case 210:
-#line 1897 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1897 "cmDependsJavaParser.y"
     {
   jpElementStart(9);
 
 }
-#line 4509 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4513 "cmDependsJavaParser.cxx"
     break;
 
   case 211:
-#line 1903 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1903 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4520 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4524 "cmDependsJavaParser.cxx"
     break;
 
   case 212:
-#line 1911 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1911 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4528,22 +4532,22 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4532 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4536 "cmDependsJavaParser.cxx"
     break;
 
   case 213:
-#line 1920 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1920 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4543 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4547 "cmDependsJavaParser.cxx"
     break;
 
   case 214:
-#line 1928 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1928 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4551,33 +4555,33 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4555 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4559 "cmDependsJavaParser.cxx"
     break;
 
   case 215:
-#line 1939 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1939 "cmDependsJavaParser.y"
     {
   jpElementStart(9);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4566 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4570 "cmDependsJavaParser.cxx"
     break;
 
   case 216:
-#line 1947 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1947 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4577 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4581 "cmDependsJavaParser.cxx"
     break;
 
   case 217:
-#line 1955 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1955 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4585,11 +4589,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4589 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4593 "cmDependsJavaParser.cxx"
     break;
 
   case 218:
-#line 1965 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1965 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4597,11 +4601,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4601 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4605 "cmDependsJavaParser.cxx"
     break;
 
   case 219:
-#line 1974 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1974 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4609,11 +4613,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4613 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4617 "cmDependsJavaParser.cxx"
     break;
 
   case 220:
-#line 1984 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1984 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4621,11 +4625,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4625 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4629 "cmDependsJavaParser.cxx"
     break;
 
   case 221:
-#line 1994 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 1994 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4633,11 +4637,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4637 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4641 "cmDependsJavaParser.cxx"
     break;
 
   case 222:
-#line 2003 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2003 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -4645,11 +4649,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4649 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4653 "cmDependsJavaParser.cxx"
     break;
 
   case 223:
-#line 2013 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2013 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -4657,11 +4661,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4661 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4665 "cmDependsJavaParser.cxx"
     break;
 
   case 224:
-#line 2022 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2022 "cmDependsJavaParser.y"
     {
   jpElementStart(5);
   jpCheckEmpty(5);
@@ -4669,11 +4673,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4673 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4677 "cmDependsJavaParser.cxx"
     break;
 
   case 225:
-#line 2032 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2032 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[-1].str)));
@@ -4682,31 +4686,31 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4686 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4690 "cmDependsJavaParser.cxx"
     break;
 
   case 226:
-#line 2042 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2042 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4697 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4701 "cmDependsJavaParser.cxx"
     break;
 
   case 227:
-#line 2050 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2050 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
 
 }
-#line 4706 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4710 "cmDependsJavaParser.cxx"
     break;
 
   case 228:
-#line 2057 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2057 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[-1].str)));
@@ -4715,11 +4719,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4719 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4723 "cmDependsJavaParser.cxx"
     break;
 
   case 229:
-#line 2068 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2068 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -4727,11 +4731,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4731 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4735 "cmDependsJavaParser.cxx"
     break;
 
   case 230:
-#line 2078 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2078 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -4739,11 +4743,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4743 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4747 "cmDependsJavaParser.cxx"
     break;
 
   case 231:
-#line 2088 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2088 "cmDependsJavaParser.y"
     {
   jpElementStart(5);
   jpCheckEmpty(5);
@@ -4751,11 +4755,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4755 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4759 "cmDependsJavaParser.cxx"
     break;
 
   case 232:
-#line 2098 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2098 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -4763,11 +4767,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4767 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4771 "cmDependsJavaParser.cxx"
     break;
 
   case 233:
-#line 2107 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2107 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   jpCheckEmpty(4);
@@ -4775,22 +4779,22 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4779 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4783 "cmDependsJavaParser.cxx"
     break;
 
   case 234:
-#line 2116 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2116 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4790 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4794 "cmDependsJavaParser.cxx"
     break;
 
   case 235:
-#line 2124 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2124 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4798,11 +4802,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4802 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4806 "cmDependsJavaParser.cxx"
     break;
 
   case 236:
-#line 2134 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2134 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4810,11 +4814,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4814 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4818 "cmDependsJavaParser.cxx"
     break;
 
   case 237:
-#line 2143 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2143 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -4822,20 +4826,20 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4826 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4830 "cmDependsJavaParser.cxx"
     break;
 
   case 238:
-#line 2153 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2153 "cmDependsJavaParser.y"
     {
   jpElementStart(5);
 
 }
-#line 4835 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4839 "cmDependsJavaParser.cxx"
     break;
 
   case 239:
-#line 2160 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2160 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -4843,11 +4847,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4847 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4851 "cmDependsJavaParser.cxx"
     break;
 
   case 240:
-#line 2170 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2170 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4855,11 +4859,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4859 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4863 "cmDependsJavaParser.cxx"
     break;
 
   case 241:
-#line 2179 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2179 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4867,11 +4871,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4871 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4875 "cmDependsJavaParser.cxx"
     break;
 
   case 242:
-#line 2189 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2189 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4879,20 +4883,20 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4883 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4887 "cmDependsJavaParser.cxx"
     break;
 
   case 243:
-#line 2198 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2198 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
 
 }
-#line 4892 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4896 "cmDependsJavaParser.cxx"
     break;
 
   case 244:
-#line 2204 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2204 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -4900,11 +4904,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4904 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4908 "cmDependsJavaParser.cxx"
     break;
 
   case 245:
-#line 2213 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2213 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4912,11 +4916,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4916 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4920 "cmDependsJavaParser.cxx"
     break;
 
   case 246:
-#line 2222 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2222 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4924,11 +4928,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4928 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4932 "cmDependsJavaParser.cxx"
     break;
 
   case 247:
-#line 2231 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2231 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4936,11 +4940,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4940 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4944 "cmDependsJavaParser.cxx"
     break;
 
   case 248:
-#line 2240 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2240 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4948,11 +4952,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4952 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4956 "cmDependsJavaParser.cxx"
     break;
 
   case 249:
-#line 2250 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2250 "cmDependsJavaParser.y"
     {
   jpElementStart(6);
   jpCheckEmpty(6);
@@ -4960,22 +4964,22 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4964 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4968 "cmDependsJavaParser.cxx"
     break;
 
   case 250:
-#line 2259 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2259 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4975 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4979 "cmDependsJavaParser.cxx"
     break;
 
   case 251:
-#line 2267 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2267 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -4983,22 +4987,22 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4987 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 4991 "cmDependsJavaParser.cxx"
     break;
 
   case 252:
-#line 2276 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2276 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 4998 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5002 "cmDependsJavaParser.cxx"
     break;
 
   case 253:
-#line 2284 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2284 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5006,11 +5010,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5010 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5014 "cmDependsJavaParser.cxx"
     break;
 
   case 254:
-#line 2294 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2294 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5018,11 +5022,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5022 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5026 "cmDependsJavaParser.cxx"
     break;
 
   case 255:
-#line 2303 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2303 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5030,11 +5034,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5034 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5038 "cmDependsJavaParser.cxx"
     break;
 
   case 256:
-#line 2313 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2313 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   jpCheckEmpty(4);
@@ -5042,11 +5046,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5046 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5050 "cmDependsJavaParser.cxx"
     break;
 
   case 257:
-#line 2322 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2322 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   jpCheckEmpty(4);
@@ -5054,11 +5058,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5058 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5062 "cmDependsJavaParser.cxx"
     break;
 
   case 258:
-#line 2331 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2331 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   jpCheckEmpty(4);
@@ -5066,11 +5070,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5070 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5074 "cmDependsJavaParser.cxx"
     break;
 
   case 259:
-#line 2340 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2340 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   jpCheckEmpty(4);
@@ -5078,22 +5082,22 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5082 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5086 "cmDependsJavaParser.cxx"
     break;
 
   case 260:
-#line 2349 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2349 "cmDependsJavaParser.y"
     {
   jpElementStart(0);
   (yyval.str) = 0;
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5093 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5097 "cmDependsJavaParser.cxx"
     break;
 
   case 261:
-#line 2357 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2357 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5101,11 +5105,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5105 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5109 "cmDependsJavaParser.cxx"
     break;
 
   case 262:
-#line 2367 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2367 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5113,11 +5117,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5117 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5121 "cmDependsJavaParser.cxx"
     break;
 
   case 263:
-#line 2376 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2376 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -5125,11 +5129,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5129 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5133 "cmDependsJavaParser.cxx"
     break;
 
   case 264:
-#line 2386 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2386 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5137,29 +5141,29 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5141 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5145 "cmDependsJavaParser.cxx"
     break;
 
   case 265:
-#line 2396 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2396 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
 
 }
-#line 5150 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5154 "cmDependsJavaParser.cxx"
     break;
 
   case 266:
-#line 2402 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2402 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
 
 }
-#line 5159 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5163 "cmDependsJavaParser.cxx"
     break;
 
   case 267:
-#line 2409 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2409 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
@@ -5168,11 +5172,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5172 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5176 "cmDependsJavaParser.cxx"
     break;
 
   case 268:
-#line 2419 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2419 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
@@ -5181,11 +5185,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5185 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5189 "cmDependsJavaParser.cxx"
     break;
 
   case 269:
-#line 2429 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2429 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
@@ -5194,11 +5198,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5198 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5202 "cmDependsJavaParser.cxx"
     break;
 
   case 270:
-#line 2439 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2439 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
@@ -5207,11 +5211,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5211 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5215 "cmDependsJavaParser.cxx"
     break;
 
   case 271:
-#line 2450 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2450 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
@@ -5220,11 +5224,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5224 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5228 "cmDependsJavaParser.cxx"
     break;
 
   case 272:
-#line 2460 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2460 "cmDependsJavaParser.y"
     {
   jpElementStart(6);
   yyGetParser->DeallocateParserType(&((yyvsp[-5].str)));
@@ -5234,11 +5238,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5238 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5242 "cmDependsJavaParser.cxx"
     break;
 
   case 273:
-#line 2471 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2471 "cmDependsJavaParser.y"
     {
   jpElementStart(6);
   yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
@@ -5247,11 +5251,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5251 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5255 "cmDependsJavaParser.cxx"
     break;
 
   case 274:
-#line 2481 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2481 "cmDependsJavaParser.y"
     {
   jpElementStart(6);
   yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
@@ -5260,11 +5264,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5264 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5268 "cmDependsJavaParser.cxx"
     break;
 
   case 275:
-#line 2492 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2492 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   yyGetParser->DeallocateParserType(&((yyvsp[-3].str)));
@@ -5273,11 +5277,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5277 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5281 "cmDependsJavaParser.cxx"
     break;
 
   case 276:
-#line 2502 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2502 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   jpCheckEmpty(4);
@@ -5285,11 +5289,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5289 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5293 "cmDependsJavaParser.cxx"
     break;
 
   case 277:
-#line 2512 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2512 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5297,11 +5301,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5301 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5305 "cmDependsJavaParser.cxx"
     break;
 
   case 278:
-#line 2521 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2521 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
@@ -5309,11 +5313,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5313 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5317 "cmDependsJavaParser.cxx"
     break;
 
   case 279:
-#line 2530 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2530 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5321,11 +5325,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5325 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5329 "cmDependsJavaParser.cxx"
     break;
 
   case 280:
-#line 2539 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2539 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5333,11 +5337,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5337 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5341 "cmDependsJavaParser.cxx"
     break;
 
   case 281:
-#line 2548 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2548 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5345,11 +5349,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5349 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5353 "cmDependsJavaParser.cxx"
     break;
 
   case 282:
-#line 2558 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2558 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -5357,11 +5361,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5361 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5365 "cmDependsJavaParser.cxx"
     break;
 
   case 283:
-#line 2568 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2568 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -5369,11 +5373,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5373 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5377 "cmDependsJavaParser.cxx"
     break;
 
   case 284:
-#line 2578 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2578 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5381,11 +5385,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5385 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5389 "cmDependsJavaParser.cxx"
     break;
 
   case 285:
-#line 2587 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2587 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5393,11 +5397,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5397 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5401 "cmDependsJavaParser.cxx"
     break;
 
   case 286:
-#line 2596 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2596 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -5405,11 +5409,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5409 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5413 "cmDependsJavaParser.cxx"
     break;
 
   case 287:
-#line 2605 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2605 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -5417,11 +5421,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5421 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5425 "cmDependsJavaParser.cxx"
     break;
 
   case 288:
-#line 2614 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2614 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5429,11 +5433,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5433 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5437 "cmDependsJavaParser.cxx"
     break;
 
   case 289:
-#line 2624 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2624 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -5441,11 +5445,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5445 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5449 "cmDependsJavaParser.cxx"
     break;
 
   case 290:
-#line 2634 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2634 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -5453,11 +5457,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5457 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5461 "cmDependsJavaParser.cxx"
     break;
 
   case 291:
-#line 2644 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2644 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5465,11 +5469,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5469 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5473 "cmDependsJavaParser.cxx"
     break;
 
   case 292:
-#line 2653 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2653 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -5477,11 +5481,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5481 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5485 "cmDependsJavaParser.cxx"
     break;
 
   case 293:
-#line 2662 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2662 "cmDependsJavaParser.y"
     {
   jpElementStart(2);
   jpCheckEmpty(2);
@@ -5489,11 +5493,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5493 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5497 "cmDependsJavaParser.cxx"
     break;
 
   case 294:
-#line 2671 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2671 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5501,11 +5505,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5505 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5509 "cmDependsJavaParser.cxx"
     break;
 
   case 295:
-#line 2681 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2681 "cmDependsJavaParser.y"
     {
   jpElementStart(5);
   jpCheckEmpty(5);
@@ -5513,11 +5517,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5517 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5521 "cmDependsJavaParser.cxx"
     break;
 
   case 296:
-#line 2690 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2690 "cmDependsJavaParser.y"
     {
   jpElementStart(4);
   jpCheckEmpty(4);
@@ -5525,20 +5529,20 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5529 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5533 "cmDependsJavaParser.cxx"
     break;
 
   case 297:
-#line 2699 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2699 "cmDependsJavaParser.y"
     {
   jpElementStart(5);
 
 }
-#line 5538 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5542 "cmDependsJavaParser.cxx"
     break;
 
   case 298:
-#line 2706 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2706 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5546,11 +5550,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5550 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5554 "cmDependsJavaParser.cxx"
     break;
 
   case 299:
-#line 2715 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2715 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5558,11 +5562,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5562 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5566 "cmDependsJavaParser.cxx"
     break;
 
   case 300:
-#line 2724 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2724 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5570,11 +5574,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5574 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5578 "cmDependsJavaParser.cxx"
     break;
 
   case 301:
-#line 2733 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2733 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5582,11 +5586,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5586 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5590 "cmDependsJavaParser.cxx"
     break;
 
   case 302:
-#line 2743 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2743 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5594,11 +5598,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5598 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5602 "cmDependsJavaParser.cxx"
     break;
 
   case 303:
-#line 2752 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2752 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5606,11 +5610,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5610 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5614 "cmDependsJavaParser.cxx"
     break;
 
   case 304:
-#line 2761 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2761 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5618,11 +5622,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5622 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5626 "cmDependsJavaParser.cxx"
     break;
 
   case 305:
-#line 2771 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2771 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5630,11 +5634,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5634 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5638 "cmDependsJavaParser.cxx"
     break;
 
   case 306:
-#line 2780 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2780 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5642,11 +5646,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5646 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5650 "cmDependsJavaParser.cxx"
     break;
 
   case 307:
-#line 2789 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2789 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5654,11 +5658,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5658 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5662 "cmDependsJavaParser.cxx"
     break;
 
   case 308:
-#line 2798 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2798 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5666,11 +5670,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5670 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5674 "cmDependsJavaParser.cxx"
     break;
 
   case 309:
-#line 2808 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2808 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5678,11 +5682,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5682 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5686 "cmDependsJavaParser.cxx"
     break;
 
   case 310:
-#line 2817 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2817 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5690,11 +5694,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5694 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5698 "cmDependsJavaParser.cxx"
     break;
 
   case 311:
-#line 2826 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2826 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5702,11 +5706,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5706 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5710 "cmDependsJavaParser.cxx"
     break;
 
   case 312:
-#line 2835 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2835 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5714,11 +5718,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5718 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5722 "cmDependsJavaParser.cxx"
     break;
 
   case 313:
-#line 2844 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2844 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5726,11 +5730,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5730 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5734 "cmDependsJavaParser.cxx"
     break;
 
   case 314:
-#line 2853 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2853 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5738,11 +5742,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5742 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5746 "cmDependsJavaParser.cxx"
     break;
 
   case 315:
-#line 2863 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2863 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5750,11 +5754,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5754 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5758 "cmDependsJavaParser.cxx"
     break;
 
   case 316:
-#line 2872 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2872 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5762,11 +5766,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5766 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5770 "cmDependsJavaParser.cxx"
     break;
 
   case 317:
-#line 2881 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2881 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5774,11 +5778,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5778 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5782 "cmDependsJavaParser.cxx"
     break;
 
   case 318:
-#line 2891 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2891 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5786,11 +5790,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5790 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5794 "cmDependsJavaParser.cxx"
     break;
 
   case 319:
-#line 2900 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2900 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5798,11 +5802,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5802 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5806 "cmDependsJavaParser.cxx"
     break;
 
   case 320:
-#line 2910 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2910 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5810,11 +5814,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5814 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5818 "cmDependsJavaParser.cxx"
     break;
 
   case 321:
-#line 2919 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2919 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5822,11 +5826,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5826 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5830 "cmDependsJavaParser.cxx"
     break;
 
   case 322:
-#line 2929 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2929 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5834,11 +5838,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5838 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5842 "cmDependsJavaParser.cxx"
     break;
 
   case 323:
-#line 2938 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2938 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5846,11 +5850,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5850 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5854 "cmDependsJavaParser.cxx"
     break;
 
   case 324:
-#line 2948 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2948 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5858,11 +5862,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5862 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5866 "cmDependsJavaParser.cxx"
     break;
 
   case 325:
-#line 2957 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2957 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5870,11 +5874,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5874 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5878 "cmDependsJavaParser.cxx"
     break;
 
   case 326:
-#line 2967 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2967 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5882,11 +5886,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5886 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5890 "cmDependsJavaParser.cxx"
     break;
 
   case 327:
-#line 2976 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2976 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5894,11 +5898,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5898 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5902 "cmDependsJavaParser.cxx"
     break;
 
   case 328:
-#line 2986 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2986 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5906,11 +5910,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5910 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5914 "cmDependsJavaParser.cxx"
     break;
 
   case 329:
-#line 2995 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 2995 "cmDependsJavaParser.y"
     {
   jpElementStart(5);
   jpCheckEmpty(5);
@@ -5918,11 +5922,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5922 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5926 "cmDependsJavaParser.cxx"
     break;
 
   case 330:
-#line 3005 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3005 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5930,11 +5934,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5934 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5938 "cmDependsJavaParser.cxx"
     break;
 
   case 331:
-#line 3014 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3014 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5942,11 +5946,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5946 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5950 "cmDependsJavaParser.cxx"
     break;
 
   case 332:
-#line 3024 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3024 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpCheckEmpty(3);
@@ -5954,11 +5958,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5958 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5962 "cmDependsJavaParser.cxx"
     break;
 
   case 333:
-#line 3034 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3034 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   yyGetParser->DeallocateParserType(&((yyvsp[0].str)));
@@ -5967,11 +5971,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5971 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5975 "cmDependsJavaParser.cxx"
     break;
 
   case 334:
-#line 3044 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3044 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5979,11 +5983,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5983 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5987 "cmDependsJavaParser.cxx"
     break;
 
   case 335:
-#line 3053 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3053 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -5991,11 +5995,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 5995 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 5999 "cmDependsJavaParser.cxx"
     break;
 
   case 336:
-#line 3063 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3063 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -6003,11 +6007,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6007 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6011 "cmDependsJavaParser.cxx"
     break;
 
   case 337:
-#line 3072 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3072 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -6015,11 +6019,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6019 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6023 "cmDependsJavaParser.cxx"
     break;
 
   case 338:
-#line 3081 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3081 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -6027,11 +6031,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6031 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6035 "cmDependsJavaParser.cxx"
     break;
 
   case 339:
-#line 3090 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3090 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -6039,11 +6043,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6043 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6047 "cmDependsJavaParser.cxx"
     break;
 
   case 340:
-#line 3099 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3099 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -6051,11 +6055,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6055 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6059 "cmDependsJavaParser.cxx"
     break;
 
   case 341:
-#line 3108 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3108 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -6063,11 +6067,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6067 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6071 "cmDependsJavaParser.cxx"
     break;
 
   case 342:
-#line 3117 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3117 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -6075,11 +6079,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6079 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6083 "cmDependsJavaParser.cxx"
     break;
 
   case 343:
-#line 3126 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3126 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -6087,11 +6091,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6091 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6095 "cmDependsJavaParser.cxx"
     break;
 
   case 344:
-#line 3135 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3135 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -6099,11 +6103,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6103 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6107 "cmDependsJavaParser.cxx"
     break;
 
   case 345:
-#line 3144 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3144 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -6111,11 +6115,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6115 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6119 "cmDependsJavaParser.cxx"
     break;
 
   case 346:
-#line 3153 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3153 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -6123,11 +6127,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6127 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6131 "cmDependsJavaParser.cxx"
     break;
 
   case 347:
-#line 3162 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3162 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -6135,11 +6139,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6139 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6143 "cmDependsJavaParser.cxx"
     break;
 
   case 348:
-#line 3172 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3172 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -6147,11 +6151,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6151 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6155 "cmDependsJavaParser.cxx"
     break;
 
   case 349:
-#line 3182 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3182 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -6159,11 +6163,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6163 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6167 "cmDependsJavaParser.cxx"
     break;
 
   case 350:
-#line 3192 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3192 "cmDependsJavaParser.y"
     {
   jpElementStart(1);
   jpCheckEmpty(1);
@@ -6171,11 +6175,11 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6175 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6179 "cmDependsJavaParser.cxx"
     break;
 
   case 351:
-#line 3201 "cmDependsJavaParser.y" /* yacc.c:1652  */
+#line 3201 "cmDependsJavaParser.y"
     {
   jpElementStart(3);
   jpStoreClass((yyvsp[-2].str));
@@ -6184,11 +6188,12 @@
   yyGetParser->SetCurrentCombine("");
 
 }
-#line 6188 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6192 "cmDependsJavaParser.cxx"
     break;
 
 
-#line 6192 "cmDependsJavaParser.cxx" /* yacc.c:1652  */
+#line 6196 "cmDependsJavaParser.cxx"
+
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -6421,7 +6426,7 @@
 #endif
   return yyresult;
 }
-#line 3210 "cmDependsJavaParser.y" /* yacc.c:1918  */
+#line 3210 "cmDependsJavaParser.y"
 
 /* End of grammar */
 
diff --git a/Source/LexerParser/cmDependsJavaParserTokens.h b/Source/LexerParser/cmDependsJavaParserTokens.h
index 6bbc084..e0dfa01 100644
--- a/Source/LexerParser/cmDependsJavaParserTokens.h
+++ b/Source/LexerParser/cmDependsJavaParserTokens.h
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 3.3.2.  */
+/* A Bison parser, made by GNU Bison 3.4.2.  */
 
 /* Bison interface for Yacc-like parsers in C
 
diff --git a/Source/LexerParser/cmExprParser.cxx b/Source/LexerParser/cmExprParser.cxx
index 8416e72..562b35b 100644
--- a/Source/LexerParser/cmExprParser.cxx
+++ b/Source/LexerParser/cmExprParser.cxx
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 3.3.2.  */
+/* A Bison parser, made by GNU Bison 3.4.2.  */
 
 /* Bison implementation for Yacc-like parsers in C
 
@@ -48,7 +48,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "3.3.2"
+#define YYBISON_VERSION "3.4.2"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -72,7 +72,7 @@
 
 
 /* First part of user prologue.  */
-#line 1 "cmExprParser.y" /* yacc.c:337  */
+#line 1 "cmExprParser.y"
 
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
@@ -116,7 +116,8 @@
 # pragma GCC diagnostic ignored "-Wconversion"
 #endif
 
-#line 120 "cmExprParser.cxx" /* yacc.c:337  */
+#line 120 "cmExprParser.cxx"
+
 # ifndef YY_NULLPTR
 #  if defined __cplusplus
 #   if 201103L <= __cplusplus
@@ -137,8 +138,8 @@
 # define YYERROR_VERBOSE 1
 #endif
 
-/* In a future release of Bison, this section will be replaced
-   by #include "cmExprParserTokens.h".  */
+/* Use api.header.include to #include this header
+   instead of duplicating it here.  */
 #ifndef YY_CMEXPR_YY_CMEXPRPARSERTOKENS_H_INCLUDED
 # define YY_CMEXPR_YY_CMEXPRPARSERTOKENS_H_INCLUDED
 /* Debug traces.  */
@@ -296,6 +297,8 @@
 #endif
 
 
+#define YY_ASSERT(E) ((void) (0 && (E)))
+
 #if ! defined yyoverflow || YYERROR_VERBOSE
 
 /* The parser invokes alloca or malloc; define the necessary symbols.  */
@@ -688,7 +691,9 @@
   if (yytype < YYNTOKENS)
     YYPRINT (yyo, yytoknum[yytype], *yyvaluep);
 # endif
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   YYUSE (yytype);
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
 }
 
 
@@ -1126,6 +1131,8 @@
 | yynewstate -- set current state (the top of the stack) to yystate.  |
 `--------------------------------------------------------------------*/
 yysetstate:
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+  YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
   *yyssp = (yytype_int16) yystate;
 
   if (yyss + yystacksize - 1 <= yyssp)
@@ -1188,8 +1195,6 @@
     }
 #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
 
-  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
   if (yystate == YYFINAL)
     YYACCEPT;
 
@@ -1257,7 +1262,6 @@
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++yyvsp = yylval;
   YY_IGNORE_MAYBE_UNINITIALIZED_END
-
   goto yynewstate;
 
 
@@ -1292,195 +1296,196 @@
   YY_REDUCE_PRINT (yyn);
   switch (yyn)
     {
-        case 2:
-#line 77 "cmExprParser.y" /* yacc.c:1652  */
+  case 2:
+#line 77 "cmExprParser.y"
     {
     cmExpr_yyget_extra(yyscanner)->SetResult((yyvsp[0].Number));
   }
-#line 1301 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1305 "cmExprParser.cxx"
     break;
 
   case 3:
-#line 82 "cmExprParser.y" /* yacc.c:1652  */
+#line 82 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1309 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1313 "cmExprParser.cxx"
     break;
 
   case 4:
-#line 85 "cmExprParser.y" /* yacc.c:1652  */
+#line 85 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[-2].Number) | (yyvsp[0].Number);
   }
-#line 1317 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1321 "cmExprParser.cxx"
     break;
 
   case 5:
-#line 90 "cmExprParser.y" /* yacc.c:1652  */
+#line 90 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1325 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1329 "cmExprParser.cxx"
     break;
 
   case 6:
-#line 93 "cmExprParser.y" /* yacc.c:1652  */
+#line 93 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[-2].Number) ^ (yyvsp[0].Number);
   }
-#line 1333 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1337 "cmExprParser.cxx"
     break;
 
   case 7:
-#line 98 "cmExprParser.y" /* yacc.c:1652  */
+#line 98 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1341 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1345 "cmExprParser.cxx"
     break;
 
   case 8:
-#line 101 "cmExprParser.y" /* yacc.c:1652  */
+#line 101 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[-2].Number) & (yyvsp[0].Number);
   }
-#line 1349 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1353 "cmExprParser.cxx"
     break;
 
   case 9:
-#line 106 "cmExprParser.y" /* yacc.c:1652  */
+#line 106 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1357 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1361 "cmExprParser.cxx"
     break;
 
   case 10:
-#line 109 "cmExprParser.y" /* yacc.c:1652  */
+#line 109 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[-2].Number) << (yyvsp[0].Number);
   }
-#line 1365 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1369 "cmExprParser.cxx"
     break;
 
   case 11:
-#line 112 "cmExprParser.y" /* yacc.c:1652  */
+#line 112 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[-2].Number) >> (yyvsp[0].Number);
   }
-#line 1373 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1377 "cmExprParser.cxx"
     break;
 
   case 12:
-#line 117 "cmExprParser.y" /* yacc.c:1652  */
+#line 117 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1381 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1385 "cmExprParser.cxx"
     break;
 
   case 13:
-#line 120 "cmExprParser.y" /* yacc.c:1652  */
+#line 120 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[-2].Number) + (yyvsp[0].Number);
   }
-#line 1389 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1393 "cmExprParser.cxx"
     break;
 
   case 14:
-#line 123 "cmExprParser.y" /* yacc.c:1652  */
+#line 123 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[-2].Number) - (yyvsp[0].Number);
   }
-#line 1397 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1401 "cmExprParser.cxx"
     break;
 
   case 15:
-#line 128 "cmExprParser.y" /* yacc.c:1652  */
+#line 128 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1405 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1409 "cmExprParser.cxx"
     break;
 
   case 16:
-#line 131 "cmExprParser.y" /* yacc.c:1652  */
+#line 131 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[-2].Number) * (yyvsp[0].Number);
   }
-#line 1413 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1417 "cmExprParser.cxx"
     break;
 
   case 17:
-#line 134 "cmExprParser.y" /* yacc.c:1652  */
+#line 134 "cmExprParser.y"
     {
     if (yyvsp[0].Number == 0) {
       throw std::overflow_error("divide by zero");
     }
     (yyval.Number) = (yyvsp[-2].Number) / (yyvsp[0].Number);
   }
-#line 1424 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1428 "cmExprParser.cxx"
     break;
 
   case 18:
-#line 140 "cmExprParser.y" /* yacc.c:1652  */
+#line 140 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[-2].Number) % (yyvsp[0].Number);
   }
-#line 1432 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1436 "cmExprParser.cxx"
     break;
 
   case 19:
-#line 145 "cmExprParser.y" /* yacc.c:1652  */
+#line 145 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1440 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1444 "cmExprParser.cxx"
     break;
 
   case 20:
-#line 148 "cmExprParser.y" /* yacc.c:1652  */
+#line 148 "cmExprParser.y"
     {
     (yyval.Number) = + (yyvsp[0].Number);
   }
-#line 1448 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1452 "cmExprParser.cxx"
     break;
 
   case 21:
-#line 151 "cmExprParser.y" /* yacc.c:1652  */
+#line 151 "cmExprParser.y"
     {
     (yyval.Number) = - (yyvsp[0].Number);
   }
-#line 1456 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1460 "cmExprParser.cxx"
     break;
 
   case 22:
-#line 154 "cmExprParser.y" /* yacc.c:1652  */
+#line 154 "cmExprParser.y"
     {
     (yyval.Number) = ~ (yyvsp[0].Number);
   }
-#line 1464 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1468 "cmExprParser.cxx"
     break;
 
   case 23:
-#line 159 "cmExprParser.y" /* yacc.c:1652  */
+#line 159 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1472 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1476 "cmExprParser.cxx"
     break;
 
   case 24:
-#line 162 "cmExprParser.y" /* yacc.c:1652  */
+#line 162 "cmExprParser.y"
     {
     (yyval.Number) = (yyvsp[-1].Number);
   }
-#line 1480 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1484 "cmExprParser.cxx"
     break;
 
 
-#line 1484 "cmExprParser.cxx" /* yacc.c:1652  */
+#line 1488 "cmExprParser.cxx"
+
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -1713,7 +1718,7 @@
 #endif
   return yyresult;
 }
-#line 167 "cmExprParser.y" /* yacc.c:1918  */
+#line 167 "cmExprParser.y"
 
 /* End of grammar */
 
diff --git a/Source/LexerParser/cmExprParserTokens.h b/Source/LexerParser/cmExprParserTokens.h
index 5ffd7c5..e30a832 100644
--- a/Source/LexerParser/cmExprParserTokens.h
+++ b/Source/LexerParser/cmExprParserTokens.h
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 3.3.2.  */
+/* A Bison parser, made by GNU Bison 3.4.2.  */
 
 /* Bison interface for Yacc-like parsers in C
 
diff --git a/Source/LexerParser/cmFortranParser.cxx b/Source/LexerParser/cmFortranParser.cxx
index 2ca7927..2494aad 100644
--- a/Source/LexerParser/cmFortranParser.cxx
+++ b/Source/LexerParser/cmFortranParser.cxx
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 3.3.2.  */
+/* A Bison parser, made by GNU Bison 3.4.2.  */
 
 /* Bison implementation for Yacc-like parsers in C
 
@@ -48,7 +48,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "3.3.2"
+#define YYBISON_VERSION "3.4.2"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -72,7 +72,7 @@
 
 
 /* First part of user prologue.  */
-#line 1 "cmFortranParser.y" /* yacc.c:337  */
+#line 1 "cmFortranParser.y"
 
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
@@ -135,7 +135,8 @@
 # pragma GCC diagnostic ignored "-Wconversion"
 #endif
 
-#line 139 "cmFortranParser.cxx" /* yacc.c:337  */
+#line 139 "cmFortranParser.cxx"
+
 # ifndef YY_NULLPTR
 #  if defined __cplusplus
 #   if 201103L <= __cplusplus
@@ -156,8 +157,8 @@
 # define YYERROR_VERBOSE 1
 #endif
 
-/* In a future release of Bison, this section will be replaced
-   by #include "cmFortranParserTokens.h".  */
+/* Use api.header.include to #include this header
+   instead of duplicating it here.  */
 #ifndef YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED
 # define YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED
 /* Debug traces.  */
@@ -255,16 +256,15 @@
 
 /* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-
 union YYSTYPE
 {
-#line 73 "cmFortranParser.y" /* yacc.c:352  */
+#line 73 "cmFortranParser.y"
 
   char* string;
 
-#line 266 "cmFortranParser.cxx" /* yacc.c:352  */
-};
+#line 266 "cmFortranParser.cxx"
 
+};
 typedef union YYSTYPE YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define YYSTYPE_IS_DECLARED 1
@@ -378,6 +378,8 @@
 #endif
 
 
+#define YY_ASSERT(E) ((void) (0 && (E)))
+
 #if ! defined yyoverflow || YYERROR_VERBOSE
 
 /* The parser invokes alloca or malloc; define the necessary symbols.  */
@@ -509,16 +511,16 @@
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  2
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   593
+#define YYLAST   594
 
 /* YYNTOKENS -- Number of terminals.  */
 #define YYNTOKENS  41
 /* YYNNTS -- Number of nonterminals.  */
 #define YYNNTS  14
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  63
+#define YYNRULES  64
 /* YYNSTATES -- Number of states.  */
-#define YYNSTATES  126
+#define YYNSTATES  127
 
 #define YYUNDEFTOK  2
 #define YYMAXUTOK   295
@@ -574,7 +576,7 @@
      220,   220,   221,   221,   222,   222,   223,   223,   224,   224,
      225,   225,   226,   226,   227,   227,   228,   228,   231,   232,
      233,   234,   235,   236,   237,   238,   239,   240,   241,   242,
-     243,   244,   245,   246
+     243,   244,   245,   246,   247
 };
 #endif
 
@@ -626,16 +628,16 @@
      -39,    21,   -39,     1,   -39,   -20,   -39,   -39,   -39,   -39,
      -39,   -39,   -39,   -39,   -39,   -39,   -39,   -39,   -39,   -39,
      -39,   -39,   -39,   -39,   -39,   -39,   -24,   -18,    20,    -8,
-      -3,    39,   -39,    15,    16,    18,    19,    33,   -39,   -39,
+      -3,    40,   -39,    15,    16,    17,    19,    34,   -39,   -39,
      -39,   -39,   -39,   -39,    59,   -39,   -39,   -39,   -39,   -39,
-      35,    36,    37,   -39,   -39,   -39,   -39,   -39,   -39,    76,
-     114,   129,   167,   182,   -39,   -39,   -39,   -39,   -39,   -39,
+      36,    37,    38,   -39,   -39,   -39,   -39,   -39,   -39,    77,
+     115,   130,   168,   183,   -39,   -39,   -39,   -39,   -39,   -39,
      -39,   -39,   -39,   -39,   -39,   -39,   -39,   -39,   -39,   -39,
-     -39,   -39,   220,   235,   273,   288,   -21,    26,   -39,   326,
-     341,   379,   394,   432,   447,   -39,   -39,   -39,   -39,   -39,
-     -39,   -39,   -39,   -39,    38,    40,    41,   485,   -39,   -39,
-     -39,   -39,   -39,   -39,    45,   -39,   -39,   -39,    43,   500,
-     538,   -39,   -39,   -39,   553,   -39
+     -39,   -39,   -39,   221,   236,   274,   289,   -21,    26,   -39,
+     327,   342,   380,   395,   433,   448,   -39,   -39,   -39,   -39,
+     -39,   -39,   -39,   -39,   -39,    39,    41,    42,   486,   -39,
+     -39,   -39,   -39,   -39,   -39,    18,   -39,   -39,   -39,    43,
+     501,   539,   -39,   -39,   -39,   554,   -39
 };
 
   /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -649,13 +651,13 @@
        0,     0,     3,     0,     0,     0,     0,     0,    46,    46,
       46,    46,    26,    46,     0,    46,    46,     4,    46,    46,
        0,     0,     0,    46,    46,    46,    46,    46,    46,     0,
-       0,     0,     0,     0,    15,    57,    56,    62,    58,    59,
-      60,    61,    63,    55,    48,    49,    50,    51,    52,    53,
-      54,    47,     0,     0,     0,     0,     0,     0,    46,     0,
-       0,     0,     0,     0,     0,    21,    22,    23,    24,    14,
-      10,    13,     9,     6,     0,     0,     0,     0,     5,    16,
-      17,    18,    19,    20,     0,    46,    46,    11,     0,     0,
-       0,    46,     7,    12,     0,     8
+       0,     0,     0,     0,    15,    57,    56,    64,    62,    58,
+      59,    60,    61,    63,    55,    48,    49,    50,    51,    52,
+      53,    54,    47,     0,     0,     0,     0,     0,     0,    46,
+       0,     0,     0,     0,     0,     0,    21,    22,    23,    24,
+      14,    10,    13,     9,     6,     0,     0,     0,     0,     5,
+      16,    17,    18,    19,    20,     0,    46,    46,    11,     0,
+       0,     0,    46,     7,    12,     0,     8
 };
 
   /* YYPGOTO[NTERM-NUM].  */
@@ -669,7 +671,7 @@
 static const yytype_int8 yydefgoto[] =
 {
       -1,     1,    32,    33,    34,    35,    36,    37,    38,    39,
-      40,    41,    44,    81
+      40,    41,    44,    82
 };
 
   /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
@@ -677,66 +679,66 @@
      number is the opposite.  If YYTABLE_NINF, syntax error.  */
 static const yytype_uint8 yytable[] =
 {
-      59,    60,    61,    62,    42,    63,   104,    82,    83,   105,
-      84,    85,    43,    45,    46,    89,    90,    91,    92,    93,
-      94,     2,     3,    47,     4,    49,    50,     5,     6,     7,
+      59,    60,    61,    62,    42,    63,   105,    83,    84,   106,
+      85,    86,    43,    45,    46,    90,    91,    92,    93,    94,
+      95,     2,     3,    47,     4,    49,    50,     5,     6,     7,
        8,     9,    10,    11,    12,    13,    14,    15,    16,    17,
-      18,    19,    20,    21,    22,    23,    24,    54,     0,    55,
-     107,    56,    57,    48,   106,    25,    26,    27,    28,    29,
-      30,    31,    64,    65,    66,    51,    58,    52,    86,    87,
-      88,   114,    53,   115,   116,   118,   121,   119,   120,    95,
-      65,    66,     0,   124,     0,    67,    68,    69,    70,    71,
-      72,    73,    74,     0,    75,    76,    77,    78,    79,    80,
-       0,     0,    67,    68,    69,    70,    71,    72,    73,    74,
-       0,    75,    76,    77,    78,    79,    80,    96,    65,    66,
+      18,    19,    20,    21,    22,    23,    24,    54,   119,    55,
+      56,   108,    57,    48,   107,    25,    26,    27,    28,    29,
+      30,    31,    64,    65,    66,    67,    51,    58,    52,    87,
+      88,    89,   115,    53,   116,   117,   122,     0,   120,   121,
+      96,    65,    66,    67,   125,    68,    69,    70,    71,    72,
+      73,    74,    75,     0,    76,    77,    78,    79,    80,    81,
+       0,     0,     0,    68,    69,    70,    71,    72,    73,    74,
+      75,     0,    76,    77,    78,    79,    80,    81,    97,    65,
+      66,    67,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,    98,    65,    66,    67,     0,     0,     0,
+       0,    68,    69,    70,    71,    72,    73,    74,    75,     0,
+      76,    77,    78,    79,    80,    81,    68,    69,    70,    71,
+      72,    73,    74,    75,     0,    76,    77,    78,    79,    80,
+      81,    99,    65,    66,    67,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,   100,    65,    66,    67,
+       0,     0,     0,     0,    68,    69,    70,    71,    72,    73,
+      74,    75,     0,    76,    77,    78,    79,    80,    81,    68,
+      69,    70,    71,    72,    73,    74,    75,     0,    76,    77,
+      78,    79,    80,    81,   101,    65,    66,    67,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   102,
+      65,    66,    67,     0,     0,     0,     0,    68,    69,    70,
+      71,    72,    73,    74,    75,     0,    76,    77,    78,    79,
+      80,    81,    68,    69,    70,    71,    72,    73,    74,    75,
+       0,    76,    77,    78,    79,    80,    81,   103,    65,    66,
+      67,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,   104,    65,    66,    67,     0,     0,     0,     0,
+      68,    69,    70,    71,    72,    73,    74,    75,     0,    76,
+      77,    78,    79,    80,    81,    68,    69,    70,    71,    72,
+      73,    74,    75,     0,    76,    77,    78,    79,    80,    81,
+     109,    65,    66,    67,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   110,    65,    66,    67,     0,
+       0,     0,     0,    68,    69,    70,    71,    72,    73,    74,
+      75,     0,    76,    77,    78,    79,    80,    81,    68,    69,
+      70,    71,    72,    73,    74,    75,     0,    76,    77,    78,
+      79,    80,    81,   111,    65,    66,    67,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,   112,    65,
+      66,    67,     0,     0,     0,     0,    68,    69,    70,    71,
+      72,    73,    74,    75,     0,    76,    77,    78,    79,    80,
+      81,    68,    69,    70,    71,    72,    73,    74,    75,     0,
+      76,    77,    78,    79,    80,    81,   113,    65,    66,    67,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,    97,    65,    66,     0,     0,     0,     0,     0,
-      67,    68,    69,    70,    71,    72,    73,    74,     0,    75,
-      76,    77,    78,    79,    80,    67,    68,    69,    70,    71,
-      72,    73,    74,     0,    75,    76,    77,    78,    79,    80,
-      98,    65,    66,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,    99,    65,    66,     0,     0,
-       0,     0,     0,    67,    68,    69,    70,    71,    72,    73,
-      74,     0,    75,    76,    77,    78,    79,    80,    67,    68,
-      69,    70,    71,    72,    73,    74,     0,    75,    76,    77,
-      78,    79,    80,   100,    65,    66,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,   101,    65,
-      66,     0,     0,     0,     0,     0,    67,    68,    69,    70,
-      71,    72,    73,    74,     0,    75,    76,    77,    78,    79,
-      80,    67,    68,    69,    70,    71,    72,    73,    74,     0,
-      75,    76,    77,    78,    79,    80,   102,    65,    66,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,   103,    65,    66,     0,     0,     0,     0,     0,    67,
-      68,    69,    70,    71,    72,    73,    74,     0,    75,    76,
-      77,    78,    79,    80,    67,    68,    69,    70,    71,    72,
-      73,    74,     0,    75,    76,    77,    78,    79,    80,   108,
-      65,    66,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,   109,    65,    66,     0,     0,     0,
-       0,     0,    67,    68,    69,    70,    71,    72,    73,    74,
-       0,    75,    76,    77,    78,    79,    80,    67,    68,    69,
-      70,    71,    72,    73,    74,     0,    75,    76,    77,    78,
-      79,    80,   110,    65,    66,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,   111,    65,    66,
-       0,     0,     0,     0,     0,    67,    68,    69,    70,    71,
-      72,    73,    74,     0,    75,    76,    77,    78,    79,    80,
-      67,    68,    69,    70,    71,    72,    73,    74,     0,    75,
-      76,    77,    78,    79,    80,   112,    65,    66,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     113,    65,    66,     0,     0,     0,     0,     0,    67,    68,
-      69,    70,    71,    72,    73,    74,     0,    75,    76,    77,
-      78,    79,    80,    67,    68,    69,    70,    71,    72,    73,
-      74,     0,    75,    76,    77,    78,    79,    80,   117,    65,
-      66,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,   122,    65,    66,     0,     0,     0,     0,
-       0,    67,    68,    69,    70,    71,    72,    73,    74,     0,
-      75,    76,    77,    78,    79,    80,    67,    68,    69,    70,
-      71,    72,    73,    74,     0,    75,    76,    77,    78,    79,
-      80,   123,    65,    66,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,   125,    65,    66,     0,
-       0,     0,     0,     0,    67,    68,    69,    70,    71,    72,
-      73,    74,     0,    75,    76,    77,    78,    79,    80,    67,
-      68,    69,    70,    71,    72,    73,    74,     0,    75,    76,
-      77,    78,    79,    80
+       0,   114,    65,    66,    67,     0,     0,     0,     0,    68,
+      69,    70,    71,    72,    73,    74,    75,     0,    76,    77,
+      78,    79,    80,    81,    68,    69,    70,    71,    72,    73,
+      74,    75,     0,    76,    77,    78,    79,    80,    81,   118,
+      65,    66,    67,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,   123,    65,    66,    67,     0,     0,
+       0,     0,    68,    69,    70,    71,    72,    73,    74,    75,
+       0,    76,    77,    78,    79,    80,    81,    68,    69,    70,
+      71,    72,    73,    74,    75,     0,    76,    77,    78,    79,
+      80,    81,   124,    65,    66,    67,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   126,    65,    66,
+      67,     0,     0,     0,     0,    68,    69,    70,    71,    72,
+      73,    74,    75,     0,    76,    77,    78,    79,    80,    81,
+      68,    69,    70,    71,    72,    73,    74,    75,     0,    76,
+      77,    78,    79,    80,    81
 };
 
 static const yytype_int8 yycheck[] =
@@ -745,62 +747,62 @@
       48,    49,    32,    37,    32,    53,    54,    55,    56,    57,
       58,     0,     1,     3,     3,    33,    29,     6,     7,     8,
        9,    10,    11,    12,    13,    14,    15,    16,    17,    18,
-      19,    20,    21,    22,    23,    24,    25,    32,    -1,    33,
-      88,    33,    33,    33,    28,    34,    35,    36,    37,    38,
-      39,    40,     3,     4,     5,    26,    33,    28,    33,    33,
-      33,    33,    33,    33,    33,    30,    33,   115,   116,     3,
-       4,     5,    -1,   121,    -1,    26,    27,    28,    29,    30,
+      19,    20,    21,    22,    23,    24,    25,    32,    30,    33,
+      33,    89,    33,    33,    28,    34,    35,    36,    37,    38,
+      39,    40,     3,     4,     5,     6,    26,    33,    28,    33,
+      33,    33,    33,    33,    33,    33,    33,    -1,   116,   117,
+       3,     4,     5,     6,   122,    26,    27,    28,    29,    30,
       31,    32,    33,    -1,    35,    36,    37,    38,    39,    40,
-      -1,    -1,    26,    27,    28,    29,    30,    31,    32,    33,
-      -1,    35,    36,    37,    38,    39,    40,     3,     4,     5,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,     3,     4,     5,    -1,    -1,    -1,    -1,    -1,
-      26,    27,    28,    29,    30,    31,    32,    33,    -1,    35,
-      36,    37,    38,    39,    40,    26,    27,    28,    29,    30,
-      31,    32,    33,    -1,    35,    36,    37,    38,    39,    40,
-       3,     4,     5,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,     3,     4,     5,    -1,    -1,
       -1,    -1,    -1,    26,    27,    28,    29,    30,    31,    32,
-      33,    -1,    35,    36,    37,    38,    39,    40,    26,    27,
-      28,    29,    30,    31,    32,    33,    -1,    35,    36,    37,
-      38,    39,    40,     3,     4,     5,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,     3,     4,
-       5,    -1,    -1,    -1,    -1,    -1,    26,    27,    28,    29,
-      30,    31,    32,    33,    -1,    35,    36,    37,    38,    39,
-      40,    26,    27,    28,    29,    30,    31,    32,    33,    -1,
-      35,    36,    37,    38,    39,    40,     3,     4,     5,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,     3,     4,     5,    -1,    -1,    -1,    -1,    -1,    26,
-      27,    28,    29,    30,    31,    32,    33,    -1,    35,    36,
-      37,    38,    39,    40,    26,    27,    28,    29,    30,    31,
-      32,    33,    -1,    35,    36,    37,    38,    39,    40,     3,
-       4,     5,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,     3,     4,     5,    -1,    -1,    -1,
-      -1,    -1,    26,    27,    28,    29,    30,    31,    32,    33,
-      -1,    35,    36,    37,    38,    39,    40,    26,    27,    28,
-      29,    30,    31,    32,    33,    -1,    35,    36,    37,    38,
-      39,    40,     3,     4,     5,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,     3,     4,     5,
-      -1,    -1,    -1,    -1,    -1,    26,    27,    28,    29,    30,
-      31,    32,    33,    -1,    35,    36,    37,    38,    39,    40,
-      26,    27,    28,    29,    30,    31,    32,    33,    -1,    35,
-      36,    37,    38,    39,    40,     3,     4,     5,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-       3,     4,     5,    -1,    -1,    -1,    -1,    -1,    26,    27,
-      28,    29,    30,    31,    32,    33,    -1,    35,    36,    37,
-      38,    39,    40,    26,    27,    28,    29,    30,    31,    32,
       33,    -1,    35,    36,    37,    38,    39,    40,     3,     4,
-       5,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,     3,     4,     5,    -1,    -1,    -1,    -1,
+       5,     6,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,     3,     4,     5,     6,    -1,    -1,    -1,
       -1,    26,    27,    28,    29,    30,    31,    32,    33,    -1,
       35,    36,    37,    38,    39,    40,    26,    27,    28,    29,
       30,    31,    32,    33,    -1,    35,    36,    37,    38,    39,
-      40,     3,     4,     5,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,     3,     4,     5,    -1,
+      40,     3,     4,     5,     6,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,     3,     4,     5,     6,
       -1,    -1,    -1,    -1,    26,    27,    28,    29,    30,    31,
       32,    33,    -1,    35,    36,    37,    38,    39,    40,    26,
       27,    28,    29,    30,    31,    32,    33,    -1,    35,    36,
-      37,    38,    39,    40
+      37,    38,    39,    40,     3,     4,     5,     6,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,     3,
+       4,     5,     6,    -1,    -1,    -1,    -1,    26,    27,    28,
+      29,    30,    31,    32,    33,    -1,    35,    36,    37,    38,
+      39,    40,    26,    27,    28,    29,    30,    31,    32,    33,
+      -1,    35,    36,    37,    38,    39,    40,     3,     4,     5,
+       6,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,     3,     4,     5,     6,    -1,    -1,    -1,    -1,
+      26,    27,    28,    29,    30,    31,    32,    33,    -1,    35,
+      36,    37,    38,    39,    40,    26,    27,    28,    29,    30,
+      31,    32,    33,    -1,    35,    36,    37,    38,    39,    40,
+       3,     4,     5,     6,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,     3,     4,     5,     6,    -1,
+      -1,    -1,    -1,    26,    27,    28,    29,    30,    31,    32,
+      33,    -1,    35,    36,    37,    38,    39,    40,    26,    27,
+      28,    29,    30,    31,    32,    33,    -1,    35,    36,    37,
+      38,    39,    40,     3,     4,     5,     6,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,     3,     4,
+       5,     6,    -1,    -1,    -1,    -1,    26,    27,    28,    29,
+      30,    31,    32,    33,    -1,    35,    36,    37,    38,    39,
+      40,    26,    27,    28,    29,    30,    31,    32,    33,    -1,
+      35,    36,    37,    38,    39,    40,     3,     4,     5,     6,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,     3,     4,     5,     6,    -1,    -1,    -1,    -1,    26,
+      27,    28,    29,    30,    31,    32,    33,    -1,    35,    36,
+      37,    38,    39,    40,    26,    27,    28,    29,    30,    31,
+      32,    33,    -1,    35,    36,    37,    38,    39,    40,     3,
+       4,     5,     6,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,     3,     4,     5,     6,    -1,    -1,
+      -1,    -1,    26,    27,    28,    29,    30,    31,    32,    33,
+      -1,    35,    36,    37,    38,    39,    40,    26,    27,    28,
+      29,    30,    31,    32,    33,    -1,    35,    36,    37,    38,
+      39,    40,     3,     4,     5,     6,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,     3,     4,     5,
+       6,    -1,    -1,    -1,    -1,    26,    27,    28,    29,    30,
+      31,    32,    33,    -1,    35,    36,    37,    38,    39,    40,
+      26,    27,    28,    29,    30,    31,    32,    33,    -1,    35,
+      36,    37,    38,    39,    40
 };
 
   /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -813,13 +815,13 @@
       39,    40,    43,    44,    45,    46,    47,    48,    49,    50,
       51,    52,     3,    32,    53,    37,    32,     3,    33,    33,
       29,    26,    28,    33,    32,    33,    33,    33,    33,    53,
-      53,    53,    53,    53,     3,     4,     5,    26,    27,    28,
-      29,    30,    31,    32,    33,    35,    36,    37,    38,    39,
-      40,    54,    53,    53,    53,    53,    33,    33,    33,    53,
-      53,    53,    53,    53,    53,     3,     3,     3,     3,     3,
-       3,     3,     3,     3,    27,    30,    28,    53,     3,     3,
-       3,     3,     3,     3,    33,    33,    33,     3,    30,    53,
-      53,    33,     3,     3,    53,     3
+      53,    53,    53,    53,     3,     4,     5,     6,    26,    27,
+      28,    29,    30,    31,    32,    33,    35,    36,    37,    38,
+      39,    40,    54,    53,    53,    53,    53,    33,    33,    33,
+      53,    53,    53,    53,    53,    53,     3,     3,     3,     3,
+       3,     3,     3,     3,     3,    27,    30,    28,    53,     3,
+       3,     3,     3,     3,     3,    33,    33,    33,     3,    30,
+      53,    53,    33,     3,     3,    53,     3
 };
 
   /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
@@ -831,7 +833,7 @@
       45,    45,    46,    46,    47,    47,    48,    48,    49,    49,
       50,    50,    51,    51,    52,    52,    53,    53,    54,    54,
       54,    54,    54,    54,    54,    54,    54,    54,    54,    54,
-      54,    54,    54,    54
+      54,    54,    54,    54,    54
 };
 
   /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
@@ -843,7 +845,7 @@
        1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
        1,     1,     1,     1,     1,     1,     0,     2,     1,     1,
        1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
-       1,     1,     1,     1
+       1,     1,     1,     1,     1
 };
 
 
@@ -930,7 +932,9 @@
   if (yytype < YYNTOKENS)
     YYPRINT (yyo, yytoknum[yytype], *yyvaluep);
 # endif
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   YYUSE (yytype);
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
 }
 
 
@@ -1368,6 +1372,8 @@
 | yynewstate -- set current state (the top of the stack) to yystate.  |
 `--------------------------------------------------------------------*/
 yysetstate:
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+  YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
   *yyssp = (yytype_int16) yystate;
 
   if (yyss + yystacksize - 1 <= yyssp)
@@ -1430,8 +1436,6 @@
     }
 #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
 
-  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
   if (yystate == YYFINAL)
     YYACCEPT;
 
@@ -1499,7 +1503,6 @@
   YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++yyvsp = yylval;
   YY_IGNORE_MAYBE_UNINITIALIZED_END
-
   goto yynewstate;
 
 
@@ -1534,27 +1537,27 @@
   YY_REDUCE_PRINT (yyn);
   switch (yyn)
     {
-        case 4:
-#line 104 "cmFortranParser.y" /* yacc.c:1652  */
+  case 4:
+#line 104 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_SetInInterface(parser, true);
   }
-#line 1544 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1547 "cmFortranParser.cxx"
     break;
 
   case 5:
-#line 108 "cmFortranParser.y" /* yacc.c:1652  */
+#line 108 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1554 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1557 "cmFortranParser.cxx"
     break;
 
   case 6:
-#line 113 "cmFortranParser.y" /* yacc.c:1652  */
+#line 113 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     if (cmsysString_strcasecmp((yyvsp[-2].string), "function") != 0 &&
@@ -1564,22 +1567,22 @@
     }
     free((yyvsp[-2].string));
   }
-#line 1568 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1571 "cmFortranParser.cxx"
     break;
 
   case 7:
-#line 122 "cmFortranParser.y" /* yacc.c:1652  */
+#line 122 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleSubmodule(parser, (yyvsp[-4].string), (yyvsp[-2].string));
     free((yyvsp[-4].string));
     free((yyvsp[-2].string));
   }
-#line 1579 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1582 "cmFortranParser.cxx"
     break;
 
   case 8:
-#line 128 "cmFortranParser.y" /* yacc.c:1652  */
+#line 128 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleSubmoduleNested(parser, (yyvsp[-6].string), (yyvsp[-4].string), (yyvsp[-2].string));
@@ -1587,40 +1590,40 @@
     free((yyvsp[-4].string));
     free((yyvsp[-2].string));
   }
-#line 1591 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1594 "cmFortranParser.cxx"
     break;
 
   case 9:
-#line 135 "cmFortranParser.y" /* yacc.c:1652  */
+#line 135 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_SetInInterface(parser, true);
     free((yyvsp[-2].string));
   }
-#line 1601 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1604 "cmFortranParser.cxx"
     break;
 
   case 10:
-#line 140 "cmFortranParser.y" /* yacc.c:1652  */
+#line 140 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_SetInInterface(parser, false);
   }
-#line 1610 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1613 "cmFortranParser.cxx"
     break;
 
   case 11:
-#line 144 "cmFortranParser.y" /* yacc.c:1652  */
+#line 144 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleUse(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1620 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1623 "cmFortranParser.cxx"
     break;
 
   case 12:
-#line 149 "cmFortranParser.y" /* yacc.c:1652  */
+#line 149 "cmFortranParser.y"
     {
     if (cmsysString_strcasecmp((yyvsp[-4].string), "non_intrinsic") == 0) {
       cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
@@ -1629,139 +1632,140 @@
     free((yyvsp[-4].string));
     free((yyvsp[-2].string));
   }
-#line 1633 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1636 "cmFortranParser.cxx"
     break;
 
   case 13:
-#line 157 "cmFortranParser.y" /* yacc.c:1652  */
+#line 157 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1643 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1646 "cmFortranParser.cxx"
     break;
 
   case 14:
-#line 162 "cmFortranParser.y" /* yacc.c:1652  */
+#line 162 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleLineDirective(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1653 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1656 "cmFortranParser.cxx"
     break;
 
   case 15:
-#line 167 "cmFortranParser.y" /* yacc.c:1652  */
+#line 167 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1663 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1666 "cmFortranParser.cxx"
     break;
 
   case 16:
-#line 172 "cmFortranParser.y" /* yacc.c:1652  */
+#line 172 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleInclude(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1673 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1676 "cmFortranParser.cxx"
     break;
 
   case 17:
-#line 177 "cmFortranParser.y" /* yacc.c:1652  */
+#line 177 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleDefine(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1683 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1686 "cmFortranParser.cxx"
     break;
 
   case 18:
-#line 182 "cmFortranParser.y" /* yacc.c:1652  */
+#line 182 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleUndef(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1693 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1696 "cmFortranParser.cxx"
     break;
 
   case 19:
-#line 187 "cmFortranParser.y" /* yacc.c:1652  */
+#line 187 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleIfdef(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1703 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1706 "cmFortranParser.cxx"
     break;
 
   case 20:
-#line 192 "cmFortranParser.y" /* yacc.c:1652  */
+#line 192 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleIfndef(parser, (yyvsp[-2].string));
     free((yyvsp[-2].string));
   }
-#line 1713 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1716 "cmFortranParser.cxx"
     break;
 
   case 21:
-#line 197 "cmFortranParser.y" /* yacc.c:1652  */
+#line 197 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleIf(parser);
   }
-#line 1722 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1725 "cmFortranParser.cxx"
     break;
 
   case 22:
-#line 201 "cmFortranParser.y" /* yacc.c:1652  */
+#line 201 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleElif(parser);
   }
-#line 1731 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1734 "cmFortranParser.cxx"
     break;
 
   case 23:
-#line 205 "cmFortranParser.y" /* yacc.c:1652  */
+#line 205 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleElse(parser);
   }
-#line 1740 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1743 "cmFortranParser.cxx"
     break;
 
   case 24:
-#line 209 "cmFortranParser.y" /* yacc.c:1652  */
+#line 209 "cmFortranParser.y"
     {
     cmFortranParser* parser = cmFortran_yyget_extra(yyscanner);
     cmFortranParser_RuleEndif(parser);
   }
-#line 1749 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1752 "cmFortranParser.cxx"
     break;
 
   case 48:
-#line 231 "cmFortranParser.y" /* yacc.c:1652  */
+#line 231 "cmFortranParser.y"
     { free ((yyvsp[0].string)); }
-#line 1755 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1758 "cmFortranParser.cxx"
     break;
 
   case 55:
-#line 238 "cmFortranParser.y" /* yacc.c:1652  */
+#line 238 "cmFortranParser.y"
     { free ((yyvsp[0].string)); }
-#line 1761 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1764 "cmFortranParser.cxx"
     break;
 
 
-#line 1765 "cmFortranParser.cxx" /* yacc.c:1652  */
+#line 1768 "cmFortranParser.cxx"
+
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -1994,6 +1998,6 @@
 #endif
   return yyresult;
 }
-#line 249 "cmFortranParser.y" /* yacc.c:1918  */
+#line 250 "cmFortranParser.y"
 
 /* End of grammar */
diff --git a/Source/LexerParser/cmFortranParser.y b/Source/LexerParser/cmFortranParser.y
index 87f3e0a..1b54dd9 100644
--- a/Source/LexerParser/cmFortranParser.y
+++ b/Source/LexerParser/cmFortranParser.y
@@ -244,6 +244,7 @@
 | RPAREN
 | COMMA
 | UNTERMINATED_STRING
+| CPP_LINE_DIRECTIVE
 ;
 
 %%
diff --git a/Source/LexerParser/cmFortranParserTokens.h b/Source/LexerParser/cmFortranParserTokens.h
index 0da4c1c..f66a15c 100644
--- a/Source/LexerParser/cmFortranParserTokens.h
+++ b/Source/LexerParser/cmFortranParserTokens.h
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 3.3.2.  */
+/* A Bison parser, made by GNU Bison 3.4.2.  */
 
 /* Bison interface for Yacc-like parsers in C
 
@@ -131,16 +131,15 @@
 
 /* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-
 union YYSTYPE
 {
-#line 73 "cmFortranParser.y" /* yacc.c:1921  */
+#line 73 "cmFortranParser.y"
 
   char* string;
 
-#line 142 "cmFortranParserTokens.h" /* yacc.c:1921  */
-};
+#line 141 "cmFortranParserTokens.h"
 
+};
 typedef union YYSTYPE YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define YYSTYPE_IS_DECLARED 1
diff --git a/Source/LexerParser/cmGccDepfileLexer.cxx b/Source/LexerParser/cmGccDepfileLexer.cxx
new file mode 100644
index 0000000..a98969d
--- /dev/null
+++ b/Source/LexerParser/cmGccDepfileLexer.cxx
@@ -0,0 +1,2210 @@
+#include "cmStandardLexer.h"
+
+#define FLEXINT_H 1
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+#ifdef yy_create_buffer
+#define cmGccDepfile_yy_create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer cmGccDepfile_yy_create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define cmGccDepfile_yy_delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer cmGccDepfile_yy_delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define cmGccDepfile_yy_scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer cmGccDepfile_yy_scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define cmGccDepfile_yy_scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string cmGccDepfile_yy_scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define cmGccDepfile_yy_scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes cmGccDepfile_yy_scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define cmGccDepfile_yy_init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer cmGccDepfile_yy_init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define cmGccDepfile_yy_flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer cmGccDepfile_yy_flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define cmGccDepfile_yy_load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state cmGccDepfile_yy_load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define cmGccDepfile_yy_switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer cmGccDepfile_yy_switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define cmGccDepfile_yypush_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state cmGccDepfile_yypush_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define cmGccDepfile_yypop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state cmGccDepfile_yypop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define cmGccDepfile_yyensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack cmGccDepfile_yyensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define cmGccDepfile_yylex_ALREADY_DEFINED
+#else
+#define yylex cmGccDepfile_yylex
+#endif
+
+#ifdef yyrestart
+#define cmGccDepfile_yyrestart_ALREADY_DEFINED
+#else
+#define yyrestart cmGccDepfile_yyrestart
+#endif
+
+#ifdef yylex_init
+#define cmGccDepfile_yylex_init_ALREADY_DEFINED
+#else
+#define yylex_init cmGccDepfile_yylex_init
+#endif
+
+#ifdef yylex_init_extra
+#define cmGccDepfile_yylex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra cmGccDepfile_yylex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define cmGccDepfile_yylex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy cmGccDepfile_yylex_destroy
+#endif
+
+#ifdef yyget_debug
+#define cmGccDepfile_yyget_debug_ALREADY_DEFINED
+#else
+#define yyget_debug cmGccDepfile_yyget_debug
+#endif
+
+#ifdef yyset_debug
+#define cmGccDepfile_yyset_debug_ALREADY_DEFINED
+#else
+#define yyset_debug cmGccDepfile_yyset_debug
+#endif
+
+#ifdef yyget_extra
+#define cmGccDepfile_yyget_extra_ALREADY_DEFINED
+#else
+#define yyget_extra cmGccDepfile_yyget_extra
+#endif
+
+#ifdef yyset_extra
+#define cmGccDepfile_yyset_extra_ALREADY_DEFINED
+#else
+#define yyset_extra cmGccDepfile_yyset_extra
+#endif
+
+#ifdef yyget_in
+#define cmGccDepfile_yyget_in_ALREADY_DEFINED
+#else
+#define yyget_in cmGccDepfile_yyget_in
+#endif
+
+#ifdef yyset_in
+#define cmGccDepfile_yyset_in_ALREADY_DEFINED
+#else
+#define yyset_in cmGccDepfile_yyset_in
+#endif
+
+#ifdef yyget_out
+#define cmGccDepfile_yyget_out_ALREADY_DEFINED
+#else
+#define yyget_out cmGccDepfile_yyget_out
+#endif
+
+#ifdef yyset_out
+#define cmGccDepfile_yyset_out_ALREADY_DEFINED
+#else
+#define yyset_out cmGccDepfile_yyset_out
+#endif
+
+#ifdef yyget_leng
+#define cmGccDepfile_yyget_leng_ALREADY_DEFINED
+#else
+#define yyget_leng cmGccDepfile_yyget_leng
+#endif
+
+#ifdef yyget_text
+#define cmGccDepfile_yyget_text_ALREADY_DEFINED
+#else
+#define yyget_text cmGccDepfile_yyget_text
+#endif
+
+#ifdef yyget_lineno
+#define cmGccDepfile_yyget_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno cmGccDepfile_yyget_lineno
+#endif
+
+#ifdef yyset_lineno
+#define cmGccDepfile_yyset_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno cmGccDepfile_yyset_lineno
+#endif
+
+#ifdef yyget_column
+#define cmGccDepfile_yyget_column_ALREADY_DEFINED
+#else
+#define yyget_column cmGccDepfile_yyget_column
+#endif
+
+#ifdef yyset_column
+#define cmGccDepfile_yyset_column_ALREADY_DEFINED
+#else
+#define yyset_column cmGccDepfile_yyset_column
+#endif
+
+#ifdef yywrap
+#define cmGccDepfile_yywrap_ALREADY_DEFINED
+#else
+#define yywrap cmGccDepfile_yywrap
+#endif
+
+#ifdef yyalloc
+#define cmGccDepfile_yyalloc_ALREADY_DEFINED
+#else
+#define yyalloc cmGccDepfile_yyalloc
+#endif
+
+#ifdef yyrealloc
+#define cmGccDepfile_yyrealloc_ALREADY_DEFINED
+#else
+#define yyrealloc cmGccDepfile_yyrealloc
+#endif
+
+#ifdef yyfree
+#define cmGccDepfile_yyfree_ALREADY_DEFINED
+#else
+#define yyfree cmGccDepfile_yyfree
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX               (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an
+ *   integer in range [0..255] for use as an array index.
+ */
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+   are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin , yyscanner )
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    #define YY_LINENO_REWIND_TO(ptr)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = yyg->yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	int yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+                          ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+                          : NULL)
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+static void yyensure_buffer_stack ( yyscan_t yyscanner );
+static void yy_load_buffer_state ( yyscan_t yyscanner );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner)
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+#define yy_new_buffer yy_create_buffer
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        yyensure_buffer_stack (yyscanner); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        yyensure_buffer_stack (yyscanner); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define cmGccDepfile_yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+typedef flex_uint8_t YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state ( yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state  , yyscan_t yyscanner);
+static int yy_get_next_buffer ( yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yyg->yytext_ptr = yy_bp; \
+	yyleng = (int) (yy_cp - yy_bp); \
+	yyg->yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yyg->yy_c_buf_p = yy_cp;
+#define YY_NUM_RULES 11
+#define YY_END_OF_BUFFER 12
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static const flex_int16_t yy_accept[26] =
+    {   0,
+        0,    0,   12,   10,    8,    6,   10,    9,   10,   10,
+       10,    8,    0,    6,    9,    1,    7,    5,    0,    3,
+        2,    0,    4,    0,    0
+    } ;
+
+static const YY_CHAR yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    4,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    5,    6,    1,    7,    8,    6,    1,    1,    6,
+        6,    1,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    9,    1,    1,
+        6,    1,    1,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,   10,    6,    1,    6,    1,    6,    6,    6,    6,
+
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    1,    6,    6,    1,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6
+    } ;
+
+static const YY_CHAR yy_meta[11] =
+    {   0,
+        1,    2,    1,    1,    2,    1,    1,    1,    1,    3
+    } ;
+
+static const flex_int16_t yy_base[28] =
+    {   0,
+        0,    0,   29,   35,   18,   35,   22,   18,   15,    0,
+        8,   12,   16,   35,   11,   35,    0,   35,   13,   35,
+       35,   16,   35,   22,   35,   31,   12
+    } ;
+
+static const flex_int16_t yy_def[28] =
+    {   0,
+       25,    1,   25,   25,   26,   25,   25,   25,   25,   27,
+       25,   26,   25,   25,   25,   25,   27,   25,   25,   25,
+       25,   25,   25,   25,    0,   25,   25
+    } ;
+
+static const flex_int16_t yy_nxt[46] =
+    {   0,
+        4,    5,    6,    7,    5,    8,    4,    9,   10,   11,
+       18,   19,   20,   17,   21,   18,   15,   22,   18,   19,
+       23,   13,   16,   15,   14,   24,   20,   13,   25,   25,
+       25,   22,   12,   12,    3,   25,   25,   25,   25,   25,
+       25,   25,   25,   25,   25
+    } ;
+
+static const flex_int16_t yy_chk[46] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+       11,   11,   11,   27,   11,   19,   15,   11,   13,   13,
+       22,   12,    9,    8,    7,   22,   24,    5,    3,    0,
+        0,   24,   26,   26,   25,   25,   25,   25,   25,   25,
+       25,   25,   25,   25,   25
+    } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+/* IWYU pragma: no_forward_declare yyguts_t */
+
+#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */
+
+#include <cmGccDepfileLexerHelper.h>
+#include <string>
+
+#define INITIAL 0
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+    {
+
+    /* User-defined. Not touched by flex. */
+    YY_EXTRA_TYPE yyextra_r;
+
+    /* The rest are the same as the globals declared in the non-reentrant scanner. */
+    FILE *yyin_r, *yyout_r;
+    size_t yy_buffer_stack_top; /**< index of top of stack. */
+    size_t yy_buffer_stack_max; /**< capacity of stack. */
+    YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+    char yy_hold_char;
+    int yy_n_chars;
+    int yyleng_r;
+    char *yy_c_buf_p;
+    int yy_init;
+    int yy_start;
+    int yy_did_buffer_switch_on_eof;
+    int yy_start_stack_ptr;
+    int yy_start_stack_depth;
+    int *yy_start_stack;
+    yy_state_type yy_last_accepting_state;
+    char* yy_last_accepting_cpos;
+
+    int yylineno_r;
+    int yy_flex_debug_r;
+
+    char *yytext_r;
+    int yy_more_flag;
+    int yy_more_len;
+
+    }; /* end struct yyguts_t */
+
+static int yy_init_globals ( yyscan_t yyscanner );
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+int yyget_debug ( yyscan_t yyscanner );
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+void yyset_in  ( FILE * _in_str , yyscan_t yyscanner );
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+void yyset_out  ( FILE * _out_str , yyscan_t yyscanner );
+
+			int yyget_leng ( yyscan_t yyscanner );
+
+char *yyget_text ( yyscan_t yyscanner );
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+int yyget_column  ( yyscan_t yyscanner );
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+
+    static void yyunput ( int c, char *buf_ptr  , yyscan_t yyscanner);
+
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput ( yyscan_t yyscanner );
+#else
+static int input ( yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		int n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(yyin); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (yyscan_t yyscanner);
+
+#define YY_DECL int yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK /*LINTED*/break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	yy_state_type yy_current_state;
+	char *yy_cp, *yy_bp;
+	int yy_act;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( !yyg->yy_init )
+		{
+		yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yyg->yy_start )
+			yyg->yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			yyensure_buffer_stack (yyscanner);
+			YY_CURRENT_BUFFER_LVALUE =
+				yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+		}
+
+		yy_load_buffer_state( yyscanner );
+		}
+
+	{
+
+	while ( /*CONSTCOND*/1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yyg->yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yyg->yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yyg->yy_start;
+yy_match:
+		do
+			{
+			YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+			if ( yy_accept[yy_current_state] )
+				{
+				yyg->yy_last_accepting_state = yy_current_state;
+				yyg->yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 26 )
+					yy_c = yy_meta[yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 35 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yyg->yy_last_accepting_cpos;
+			yy_current_state = yyg->yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yyg->yy_hold_char;
+			yy_cp = yyg->yy_last_accepting_cpos;
+			yy_current_state = yyg->yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+{
+                         // Unescape the dollar sign.
+                         yyextra->addToCurrentPath("$");
+                       }
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+{
+                         // Unescape the hash.
+                         yyextra->addToCurrentPath("#");
+                       }
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+{
+                         // 2N+1 backslashes plus space -> N backslashes plus space.
+                         size_t c = (strlen(yytext) - 1) / 2;
+                         std::string s(c, '\\');
+                         s.push_back(' ');
+                         yyextra->addToCurrentPath(s.c_str());
+                       }
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+{
+                         // 2N backslashes plus space -> 2N backslashes, end of filename.
+                         yytext[strlen(yytext) - 1] = 0;
+                         yyextra->addToCurrentPath(yytext);
+                         yyextra->newDependency();
+                       }
+	YY_BREAK
+case 5:
+/* rule 5 can match eol */
+YY_RULE_SETUP
+{
+                         // A line continuation ends the current file name.
+                         yyextra->newDependency();
+                       }
+	YY_BREAK
+case 6:
+/* rule 6 can match eol */
+YY_RULE_SETUP
+{
+                         // A newline ends the current file name and the current rule.
+                         yyextra->newEntry();
+                       }
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+{
+                         // A colon followed by space ends the rules and starts a new dependency.
+                         yyextra->newDependency();
+                       }
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+{
+                         // Rules and dependencies are separated by blocks of whitespace.
+                         yyextra->newRuleOrDependency();
+                       }
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+{
+                         // Got a span of plain text.
+                         yyextra->addToCurrentPath(yytext);
+                       }
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+{
+                         // Got an otherwise unmatched character.
+                         yyextra->addToCurrentPath(yytext);
+                       }
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+ECHO;
+	YY_BREAK
+case YY_STATE_EOF(INITIAL):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yyg->yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * yylex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state( yyscanner );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+			yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yyg->yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yyg->yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer( yyscanner ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yyg->yy_did_buffer_switch_on_eof = 0;
+
+				if ( yywrap( yyscanner ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yyg->yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yyg->yy_c_buf_p =
+					yyg->yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state( yyscanner );
+
+				yy_cp = yyg->yy_c_buf_p;
+				yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yyg->yy_c_buf_p =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+				yy_current_state = yy_get_previous_state( yyscanner );
+
+				yy_cp = yyg->yy_c_buf_p;
+				yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+	} /* end of user's declarations */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	char *source = yyg->yytext_ptr;
+	int number_to_move, i;
+	int ret_val;
+
+	if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1);
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+	else
+		{
+			int num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+			int yy_c_buf_p_offset =
+				(int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					yyrealloc( (void *) b->yy_ch_buf,
+							 (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = NULL;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			yyg->yy_n_chars, num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	if ( yyg->yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart( yyin  , yyscanner);
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+			(void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+		/* "- 2" to take care of EOB's */
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
+	}
+
+	yyg->yy_n_chars += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+	yy_state_type yy_current_state;
+	char *yy_cp;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	yy_current_state = yyg->yy_start;
+
+	for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+		{
+		YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			yyg->yy_last_accepting_state = yy_current_state;
+			yyg->yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 26 )
+				yy_c = yy_meta[yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+	int yy_is_jam;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+	char *yy_cp = yyg->yy_c_buf_p;
+
+	YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		yyg->yy_last_accepting_state = yy_current_state;
+		yyg->yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 26 )
+			yy_c = yy_meta[yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+	yy_is_jam = (yy_current_state == 25);
+
+	(void)yyg;
+	return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+
+    static void yyunput (int c, char * yy_bp , yyscan_t yyscanner)
+{
+	char *yy_cp;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+    yy_cp = yyg->yy_c_buf_p;
+
+	/* undo effects of setting up yytext */
+	*yy_cp = yyg->yy_hold_char;
+
+	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		int number_to_move = yyg->yy_n_chars + 2;
+		char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+		char *source =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+		while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+			yyg->yy_n_chars = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+		if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+	yyg->yytext_ptr = yy_bp;
+	yyg->yy_hold_char = *yy_cp;
+	yyg->yy_c_buf_p = yy_cp;
+}
+
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (yyscan_t yyscanner)
+#else
+    static int input  (yyscan_t yyscanner)
+#endif
+
+{
+	int c;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	*yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+	if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+			/* This was really a NUL. */
+			*yyg->yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr);
+			++yyg->yy_c_buf_p;
+
+			switch ( yy_get_next_buffer( yyscanner ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					yyrestart( yyin , yyscanner);
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( yywrap( yyscanner ) )
+						return 0;
+
+					if ( ! yyg->yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput(yyscanner);
+#else
+					return input(yyscanner);
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yyg->yy_c_buf_p;	/* cast for 8-bit char's */
+	*yyg->yy_c_buf_p = '\0';	/* preserve yytext */
+	yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void yyrestart  (FILE * input_file , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( ! YY_CURRENT_BUFFER ){
+        yyensure_buffer_stack (yyscanner);
+		YY_CURRENT_BUFFER_LVALUE =
+            yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+	}
+
+	yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner);
+	yy_load_buffer_state( yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+    void yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		yypop_buffer_state();
+	 *		yypush_buffer_state(new_buffer);
+     */
+	yyensure_buffer_stack (yyscanner);
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*yyg->yy_c_buf_p = yyg->yy_hold_char;
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	yy_load_buffer_state( yyscanner );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (yywrap()) processing, but the only time this flag
+	 * is looked at is after yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void yy_load_buffer_state  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE yy_create_buffer  (FILE * file, int  size , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+
+	b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer( b, file , yyscanner);
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+    void yy_delete_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		yyfree( (void *) b->yy_ch_buf , yyscanner );
+
+	yyfree( (void *) b , yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+    static void yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file , yyscan_t yyscanner)
+
+{
+	int oerrno = errno;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	yy_flush_buffer( b , yyscanner);
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then yy_init_buffer was _probably_
+     * called from yyrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+    void yy_flush_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		yy_load_buffer_state( yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  @param yyscanner The scanner object.
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if (new_buffer == NULL)
+		return;
+
+	yyensure_buffer_stack(yyscanner);
+
+	/* This block is copied from yy_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*yyg->yy_c_buf_p = yyg->yy_hold_char;
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		yyg->yy_buffer_stack_top++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from yy_switch_to_buffer. */
+	yy_load_buffer_state( yyscanner );
+	yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  @param yyscanner The scanner object.
+ */
+void yypop_buffer_state (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	if (!YY_CURRENT_BUFFER)
+		return;
+
+	yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner);
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if (yyg->yy_buffer_stack_top > 0)
+		--yyg->yy_buffer_stack_top;
+
+	if (YY_CURRENT_BUFFER) {
+		yy_load_buffer_state( yyscanner );
+		yyg->yy_did_buffer_switch_on_eof = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (yyscan_t yyscanner)
+{
+	yy_size_t num_to_alloc;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+	if (!yyg->yy_buffer_stack) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+      num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								, yyscanner);
+		if ( ! yyg->yy_buffer_stack )
+			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+		memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+		yyg->yy_buffer_stack_max = num_to_alloc;
+		yyg->yy_buffer_stack_top = 0;
+		return;
+	}
+
+	if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		yy_size_t grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+		yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
+								(yyg->yy_buffer_stack,
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								, yyscanner);
+		if ( ! yyg->yy_buffer_stack )
+			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+		yyg->yy_buffer_stack_max = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return NULL;
+
+	b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+	b->yy_buf_size = (int) (size - 2);	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = NULL;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	yy_switch_to_buffer( b , yyscanner );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner)
+{
+
+	return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes  (const char * yybytes, int  _yybytes_len , yyscan_t yyscanner)
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = (yy_size_t) (_yybytes_len + 2);
+	buf = (char *) yyalloc( n , yyscanner );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = yy_scan_buffer( buf, n , yyscanner);
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner)
+{
+	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	(void)yyg;
+	fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		yytext[yyleng] = yyg->yy_hold_char; \
+		yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+		yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+		*yyg->yy_c_buf_p = '\0'; \
+		yyleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE yyget_extra  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_lineno  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+
+    return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_column  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+
+    return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_in  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_out  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int yyget_leng  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *yyget_text  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param _line_number line number
+ * @param yyscanner The scanner object.
+ */
+void yyset_lineno (int  _line_number , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* lineno is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           YY_FATAL_ERROR( "yyset_lineno called with no buffer" );
+
+    yylineno = _line_number;
+}
+
+/** Set the current column.
+ * @param _column_no column number
+ * @param yyscanner The scanner object.
+ */
+void yyset_column (int  _column_no , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* column is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           YY_FATAL_ERROR( "yyset_column called with no buffer" );
+
+    yycolumn = _column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param _in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE *  _in_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyin = _in_str ;
+}
+
+void yyset_out (FILE *  _out_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyout = _out_str ;
+}
+
+int yyget_debug  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yy_flex_debug;
+}
+
+void yyset_debug (int  _bdebug , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yy_flex_debug = _bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+/* User-visible API */
+
+/* yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+int yylex_init(yyscan_t* ptr_yy_globals)
+{
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+
+    *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+
+    /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* yylex_init_extra has the same functionality as yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to yyalloc in
+ * the yyextra field.
+ */
+int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals )
+{
+    struct yyguts_t dummy_yyguts;
+
+    yyset_extra (yy_user_defined, &dummy_yyguts);
+
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+
+    *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+
+    /* By setting to 0xAA, we expose bugs in
+    yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+    yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from yylex_destroy(), so don't allocate here.
+     */
+
+    yyg->yy_buffer_stack = NULL;
+    yyg->yy_buffer_stack_top = 0;
+    yyg->yy_buffer_stack_max = 0;
+    yyg->yy_c_buf_p = NULL;
+    yyg->yy_init = 0;
+    yyg->yy_start = 0;
+
+    yyg->yy_start_stack_ptr = 0;
+    yyg->yy_start_stack_depth = 0;
+    yyg->yy_start_stack =  NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    yyin = stdin;
+    yyout = stdout;
+#else
+    yyin = NULL;
+    yyout = NULL;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * yylex_init()
+     */
+    return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		yypop_buffer_state(yyscanner);
+	}
+
+	/* Destroy the stack itself. */
+	yyfree(yyg->yy_buffer_stack , yyscanner);
+	yyg->yy_buffer_stack = NULL;
+
+    /* Destroy the start condition stack. */
+        yyfree( yyg->yy_start_stack , yyscanner );
+        yyg->yy_start_stack = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * yylex() is called, initialization will occur. */
+    yy_init_globals( yyscanner);
+
+    /* Destroy the main struct (reentrant only). */
+    yyfree ( yyscanner , yyscanner );
+    yyscanner = NULL;
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner)
+{
+	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	(void)yyg;
+
+	int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (const char * s , yyscan_t yyscanner)
+{
+	int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *yyalloc (yy_size_t  size , yyscan_t yyscanner)
+{
+	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	(void)yyg;
+	return malloc(size);
+}
+
+void *yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
+{
+	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	(void)yyg;
+
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return realloc(ptr, size);
+}
+
+void yyfree (void * ptr , yyscan_t yyscanner)
+{
+	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+	(void)yyg;
+	free( (char *) ptr );	/* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+/*--------------------------------------------------------------------------*/
+
+#endif /* __clang_analyzer__ */
diff --git a/Source/LexerParser/cmGccDepfileLexer.h b/Source/LexerParser/cmGccDepfileLexer.h
new file mode 100644
index 0000000..7d34060
--- /dev/null
+++ b/Source/LexerParser/cmGccDepfileLexer.h
@@ -0,0 +1,687 @@
+#ifndef cmGccDepfile_yyHEADER_H
+#define cmGccDepfile_yyHEADER_H 1
+#define cmGccDepfile_yyIN_HEADER 1
+
+#define FLEXINT_H 1
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+#ifdef yy_create_buffer
+#define cmGccDepfile_yy_create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer cmGccDepfile_yy_create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define cmGccDepfile_yy_delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer cmGccDepfile_yy_delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define cmGccDepfile_yy_scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer cmGccDepfile_yy_scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define cmGccDepfile_yy_scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string cmGccDepfile_yy_scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define cmGccDepfile_yy_scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes cmGccDepfile_yy_scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define cmGccDepfile_yy_init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer cmGccDepfile_yy_init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define cmGccDepfile_yy_flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer cmGccDepfile_yy_flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define cmGccDepfile_yy_load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state cmGccDepfile_yy_load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define cmGccDepfile_yy_switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer cmGccDepfile_yy_switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define cmGccDepfile_yypush_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state cmGccDepfile_yypush_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define cmGccDepfile_yypop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state cmGccDepfile_yypop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define cmGccDepfile_yyensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack cmGccDepfile_yyensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define cmGccDepfile_yylex_ALREADY_DEFINED
+#else
+#define yylex cmGccDepfile_yylex
+#endif
+
+#ifdef yyrestart
+#define cmGccDepfile_yyrestart_ALREADY_DEFINED
+#else
+#define yyrestart cmGccDepfile_yyrestart
+#endif
+
+#ifdef yylex_init
+#define cmGccDepfile_yylex_init_ALREADY_DEFINED
+#else
+#define yylex_init cmGccDepfile_yylex_init
+#endif
+
+#ifdef yylex_init_extra
+#define cmGccDepfile_yylex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra cmGccDepfile_yylex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define cmGccDepfile_yylex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy cmGccDepfile_yylex_destroy
+#endif
+
+#ifdef yyget_debug
+#define cmGccDepfile_yyget_debug_ALREADY_DEFINED
+#else
+#define yyget_debug cmGccDepfile_yyget_debug
+#endif
+
+#ifdef yyset_debug
+#define cmGccDepfile_yyset_debug_ALREADY_DEFINED
+#else
+#define yyset_debug cmGccDepfile_yyset_debug
+#endif
+
+#ifdef yyget_extra
+#define cmGccDepfile_yyget_extra_ALREADY_DEFINED
+#else
+#define yyget_extra cmGccDepfile_yyget_extra
+#endif
+
+#ifdef yyset_extra
+#define cmGccDepfile_yyset_extra_ALREADY_DEFINED
+#else
+#define yyset_extra cmGccDepfile_yyset_extra
+#endif
+
+#ifdef yyget_in
+#define cmGccDepfile_yyget_in_ALREADY_DEFINED
+#else
+#define yyget_in cmGccDepfile_yyget_in
+#endif
+
+#ifdef yyset_in
+#define cmGccDepfile_yyset_in_ALREADY_DEFINED
+#else
+#define yyset_in cmGccDepfile_yyset_in
+#endif
+
+#ifdef yyget_out
+#define cmGccDepfile_yyget_out_ALREADY_DEFINED
+#else
+#define yyget_out cmGccDepfile_yyget_out
+#endif
+
+#ifdef yyset_out
+#define cmGccDepfile_yyset_out_ALREADY_DEFINED
+#else
+#define yyset_out cmGccDepfile_yyset_out
+#endif
+
+#ifdef yyget_leng
+#define cmGccDepfile_yyget_leng_ALREADY_DEFINED
+#else
+#define yyget_leng cmGccDepfile_yyget_leng
+#endif
+
+#ifdef yyget_text
+#define cmGccDepfile_yyget_text_ALREADY_DEFINED
+#else
+#define yyget_text cmGccDepfile_yyget_text
+#endif
+
+#ifdef yyget_lineno
+#define cmGccDepfile_yyget_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno cmGccDepfile_yyget_lineno
+#endif
+
+#ifdef yyset_lineno
+#define cmGccDepfile_yyset_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno cmGccDepfile_yyset_lineno
+#endif
+
+#ifdef yyget_column
+#define cmGccDepfile_yyget_column_ALREADY_DEFINED
+#else
+#define yyget_column cmGccDepfile_yyget_column
+#endif
+
+#ifdef yyset_column
+#define cmGccDepfile_yyset_column_ALREADY_DEFINED
+#else
+#define yyset_column cmGccDepfile_yyset_column
+#endif
+
+#ifdef yywrap
+#define cmGccDepfile_yywrap_ALREADY_DEFINED
+#else
+#define yywrap cmGccDepfile_yywrap
+#endif
+
+#ifdef yyalloc
+#define cmGccDepfile_yyalloc_ALREADY_DEFINED
+#else
+#define yyalloc cmGccDepfile_yyalloc
+#endif
+
+#ifdef yyrealloc
+#define cmGccDepfile_yyrealloc_ALREADY_DEFINED
+#else
+#define yyrealloc cmGccDepfile_yyrealloc
+#endif
+
+#ifdef yyfree
+#define cmGccDepfile_yyfree_ALREADY_DEFINED
+#else
+#define yyfree cmGccDepfile_yyfree
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX               (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* begin standard C++ headers. */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+   are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	int yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+/* Begin user sect3 */
+
+#define cmGccDepfile_yywrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+
+#define yytext_ptr yytext_r
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+int yyget_debug ( yyscan_t yyscanner );
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+void yyset_in  ( FILE * _in_str , yyscan_t yyscanner );
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+void yyset_out  ( FILE * _out_str , yyscan_t yyscanner );
+
+			int yyget_leng ( yyscan_t yyscanner );
+
+char *yyget_text ( yyscan_t yyscanner );
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+int yyget_column  ( yyscan_t yyscanner );
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (yyscan_t yyscanner);
+
+#define YY_DECL int yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#ifndef cmGccDepfile_yy_create_buffer_ALREADY_DEFINED
+#undef yy_create_buffer
+#endif
+#ifndef cmGccDepfile_yy_delete_buffer_ALREADY_DEFINED
+#undef yy_delete_buffer
+#endif
+#ifndef cmGccDepfile_yy_scan_buffer_ALREADY_DEFINED
+#undef yy_scan_buffer
+#endif
+#ifndef cmGccDepfile_yy_scan_string_ALREADY_DEFINED
+#undef yy_scan_string
+#endif
+#ifndef cmGccDepfile_yy_scan_bytes_ALREADY_DEFINED
+#undef yy_scan_bytes
+#endif
+#ifndef cmGccDepfile_yy_init_buffer_ALREADY_DEFINED
+#undef yy_init_buffer
+#endif
+#ifndef cmGccDepfile_yy_flush_buffer_ALREADY_DEFINED
+#undef yy_flush_buffer
+#endif
+#ifndef cmGccDepfile_yy_load_buffer_state_ALREADY_DEFINED
+#undef yy_load_buffer_state
+#endif
+#ifndef cmGccDepfile_yy_switch_to_buffer_ALREADY_DEFINED
+#undef yy_switch_to_buffer
+#endif
+#ifndef cmGccDepfile_yypush_buffer_state_ALREADY_DEFINED
+#undef yypush_buffer_state
+#endif
+#ifndef cmGccDepfile_yypop_buffer_state_ALREADY_DEFINED
+#undef yypop_buffer_state
+#endif
+#ifndef cmGccDepfile_yyensure_buffer_stack_ALREADY_DEFINED
+#undef yyensure_buffer_stack
+#endif
+#ifndef cmGccDepfile_yylex_ALREADY_DEFINED
+#undef yylex
+#endif
+#ifndef cmGccDepfile_yyrestart_ALREADY_DEFINED
+#undef yyrestart
+#endif
+#ifndef cmGccDepfile_yylex_init_ALREADY_DEFINED
+#undef yylex_init
+#endif
+#ifndef cmGccDepfile_yylex_init_extra_ALREADY_DEFINED
+#undef yylex_init_extra
+#endif
+#ifndef cmGccDepfile_yylex_destroy_ALREADY_DEFINED
+#undef yylex_destroy
+#endif
+#ifndef cmGccDepfile_yyget_debug_ALREADY_DEFINED
+#undef yyget_debug
+#endif
+#ifndef cmGccDepfile_yyset_debug_ALREADY_DEFINED
+#undef yyset_debug
+#endif
+#ifndef cmGccDepfile_yyget_extra_ALREADY_DEFINED
+#undef yyget_extra
+#endif
+#ifndef cmGccDepfile_yyset_extra_ALREADY_DEFINED
+#undef yyset_extra
+#endif
+#ifndef cmGccDepfile_yyget_in_ALREADY_DEFINED
+#undef yyget_in
+#endif
+#ifndef cmGccDepfile_yyset_in_ALREADY_DEFINED
+#undef yyset_in
+#endif
+#ifndef cmGccDepfile_yyget_out_ALREADY_DEFINED
+#undef yyget_out
+#endif
+#ifndef cmGccDepfile_yyset_out_ALREADY_DEFINED
+#undef yyset_out
+#endif
+#ifndef cmGccDepfile_yyget_leng_ALREADY_DEFINED
+#undef yyget_leng
+#endif
+#ifndef cmGccDepfile_yyget_text_ALREADY_DEFINED
+#undef yyget_text
+#endif
+#ifndef cmGccDepfile_yyget_lineno_ALREADY_DEFINED
+#undef yyget_lineno
+#endif
+#ifndef cmGccDepfile_yyset_lineno_ALREADY_DEFINED
+#undef yyset_lineno
+#endif
+#ifndef cmGccDepfile_yyget_column_ALREADY_DEFINED
+#undef yyget_column
+#endif
+#ifndef cmGccDepfile_yyset_column_ALREADY_DEFINED
+#undef yyset_column
+#endif
+#ifndef cmGccDepfile_yywrap_ALREADY_DEFINED
+#undef yywrap
+#endif
+#ifndef cmGccDepfile_yyget_lval_ALREADY_DEFINED
+#undef yyget_lval
+#endif
+#ifndef cmGccDepfile_yyset_lval_ALREADY_DEFINED
+#undef yyset_lval
+#endif
+#ifndef cmGccDepfile_yyget_lloc_ALREADY_DEFINED
+#undef yyget_lloc
+#endif
+#ifndef cmGccDepfile_yyset_lloc_ALREADY_DEFINED
+#undef yyset_lloc
+#endif
+#ifndef cmGccDepfile_yyalloc_ALREADY_DEFINED
+#undef yyalloc
+#endif
+#ifndef cmGccDepfile_yyrealloc_ALREADY_DEFINED
+#undef yyrealloc
+#endif
+#ifndef cmGccDepfile_yyfree_ALREADY_DEFINED
+#undef yyfree
+#endif
+#ifndef cmGccDepfile_yytext_ALREADY_DEFINED
+#undef yytext
+#endif
+#ifndef cmGccDepfile_yyleng_ALREADY_DEFINED
+#undef yyleng
+#endif
+#ifndef cmGccDepfile_yyin_ALREADY_DEFINED
+#undef yyin
+#endif
+#ifndef cmGccDepfile_yyout_ALREADY_DEFINED
+#undef yyout
+#endif
+#ifndef cmGccDepfile_yy_flex_debug_ALREADY_DEFINED
+#undef yy_flex_debug
+#endif
+#ifndef cmGccDepfile_yylineno_ALREADY_DEFINED
+#undef yylineno
+#endif
+#ifndef cmGccDepfile_yytables_fload_ALREADY_DEFINED
+#undef yytables_fload
+#endif
+#ifndef cmGccDepfile_yytables_destroy_ALREADY_DEFINED
+#undef yytables_destroy
+#endif
+#ifndef cmGccDepfile_yyTABLES_NAME_ALREADY_DEFINED
+#undef yyTABLES_NAME
+#endif
+
+#undef cmGccDepfile_yyIN_HEADER
+#endif /* cmGccDepfile_yyHEADER_H */
diff --git a/Source/LexerParser/cmGccDepfileLexer.in.l b/Source/LexerParser/cmGccDepfileLexer.in.l
new file mode 100644
index 0000000..08f8577
--- /dev/null
+++ b/Source/LexerParser/cmGccDepfileLexer.in.l
@@ -0,0 +1,72 @@
+%{
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+/* IWYU pragma: no_forward_declare yyguts_t */
+
+#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */
+
+#include <cmGccDepfileLexerHelper.h>
+#include <string>
+%}
+
+%option prefix="cmGccDepfile_yy"
+%option noyywrap
+%option reentrant
+%pointer
+
+WSPACE [ \t]
+NEWLINE \r?\n
+
+%%
+\${2}                  {
+                         // Unescape the dollar sign.
+                         yyextra->addToCurrentPath("$");
+                       }
+\\#                    {
+                         // Unescape the hash.
+                         yyextra->addToCurrentPath("#");
+                       }
+(\\\\)*\\[ ]           {
+                         // 2N+1 backslashes plus space -> N backslashes plus space.
+                         size_t c = (strlen(yytext) - 1) / 2;
+                         std::string s(c, '\\');
+                         s.push_back(' ');
+                         yyextra->addToCurrentPath(s.c_str());
+                       }
+(\\\\)+[ ]             {
+                         // 2N backslashes plus space -> 2N backslashes, end of filename.
+                         yytext[strlen(yytext) - 1] = 0;
+                         yyextra->addToCurrentPath(yytext);
+                         yyextra->newDependency();
+                       }
+{WSPACE}*\\{NEWLINE}   {
+                         // A line continuation ends the current file name.
+                         yyextra->newDependency();
+                       }
+{NEWLINE}              {
+                         // A newline ends the current file name and the current rule.
+                         yyextra->newEntry();
+                       }
+:{WSPACE}+             {
+                         // A colon followed by space ends the rules and starts a new dependency.
+                         yyextra->newDependency();
+                       }
+{WSPACE}+              {
+                         // Rules and dependencies are separated by blocks of whitespace.
+                         yyextra->newRuleOrDependency();
+                       }
+[a-zA-Z0-9+,/_.~()}{%=@\x5B\x5D!\x80-\xFF-]+ {
+                         // Got a span of plain text.
+                         yyextra->addToCurrentPath(yytext);
+                       }
+.                      {
+                         // Got an otherwise unmatched character.
+                         yyextra->addToCurrentPath(yytext);
+                       }
+
+%%
+
+/*--------------------------------------------------------------------------*/
+
+#endif /* __clang_analyzer__ */
diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt
index cb89d19..98dd0e2 100644
--- a/Source/QtDialog/CMakeLists.txt
+++ b/Source/QtDialog/CMakeLists.txt
@@ -178,6 +178,10 @@
   target_sources(cmake-gui PRIVATE $<TARGET_OBJECTS:CMakeVersion>)
 endif()
 
+if(CMake_JOB_POOL_LINK_BIN)
+  set_property(TARGET cmake-gui PROPERTY JOB_POOL_LINK "link-bin")
+endif()
+
 # cmake-gui has not been updated for `include-what-you-use`.
 # Block the tool until this is done.
 set_target_properties(cmake-gui PROPERTIES
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
index b608fcb..3b5dc04 100644
--- a/Source/QtDialog/QCMake.cxx
+++ b/Source/QtDialog/QCMake.cxx
@@ -6,6 +6,7 @@
 #include <QDir>
 
 #include "cmExternalMakefileProjectGenerator.h"
+#include "cmGlobalGenerator.h"
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
diff --git a/Source/bindexplib.cxx b/Source/bindexplib.cxx
index b85cc33..0b2750d 100644
--- a/Source/bindexplib.cxx
+++ b/Source/bindexplib.cxx
@@ -64,32 +64,36 @@
  */
 #include "bindexplib.h"
 
-#include <iostream>
+#include <cstddef>
 #include <sstream>
 #include <vector>
 
-#include <windows.h>
+#ifdef _WIN32
+#  include <windows.h>
 
-#include "cmsys/Encoding.hxx"
+#  include "cmsys/Encoding.hxx"
+#endif
+
 #include "cmsys/FStream.hxx"
 
 #include "cmSystemTools.h"
 
-#ifndef IMAGE_FILE_MACHINE_ARM
-#  define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian
-#endif
+#ifdef _WIN32
+#  ifndef IMAGE_FILE_MACHINE_ARM
+#    define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian
+#  endif
 
-#ifndef IMAGE_FILE_MACHINE_THUMB
-#  define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM Thumb/Thumb-2 Little-Endian
-#endif
+#  ifndef IMAGE_FILE_MACHINE_THUMB
+#    define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM Thumb/Thumb-2 Little-Endian
+#  endif
 
-#ifndef IMAGE_FILE_MACHINE_ARMNT
-#  define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian
-#endif
+#  ifndef IMAGE_FILE_MACHINE_ARMNT
+#    define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian
+#  endif
 
-#ifndef IMAGE_FILE_MACHINE_ARM64
-#  define IMAGE_FILE_MACHINE_ARM64 0xaa64 // ARM64 Little-Endian
-#endif
+#  ifndef IMAGE_FILE_MACHINE_ARM64
+#    define IMAGE_FILE_MACHINE_ARM64 0xaa64 // ARM64 Little-Endian
+#  endif
 
 typedef struct cmANON_OBJECT_HEADER_BIGOBJ
 {
@@ -306,6 +310,7 @@
   SymbolTableType* SymbolTable;
   bool IsI386;
 };
+#endif
 
 bool DumpFileWithLlvmNm(std::string const& nmPath, const char* filename,
                         std::set<std::string>& symbols,
@@ -315,15 +320,15 @@
   // break up command line into a vector
   std::vector<std::string> command;
   command.push_back(nmPath);
-  command.push_back("--no-weak");
-  command.push_back("--defined-only");
-  command.push_back("--format=posix");
-  command.push_back(filename);
+  command.emplace_back("--no-weak");
+  command.emplace_back("--defined-only");
+  command.emplace_back("--format=posix");
+  command.emplace_back(filename);
 
   // run the command
   int exit_code = 0;
-  cmSystemTools::RunSingleCommand(command, &output, &output, &exit_code, "",
-                                  cmSystemTools::OUTPUT_NONE);
+  cmSystemTools::RunSingleCommand(command, &output, &output, &exit_code,
+                                  nullptr, cmSystemTools::OUTPUT_NONE);
 
   if (exit_code != 0) {
     fprintf(stderr, "llvm-nm returned an error: %s\n", output.c_str());
@@ -336,7 +341,7 @@
     if (line.empty()) { // last line
       continue;
     }
-    size_t sym_end = line.find(" ");
+    size_t sym_end = line.find(' ');
     if (sym_end == std::string::npos) {
       fprintf(stderr, "Couldn't parse llvm-nm output line: %s\n",
               line.c_str());
@@ -366,6 +371,9 @@
               std::set<std::string>& symbols,
               std::set<std::string>& dataSymbols)
 {
+#ifndef _WIN32
+  return DumpFileWithLlvmNm(nmPath, filename, symbols, dataSymbols);
+#else
   HANDLE hFile;
   HANDLE hFileMapping;
   LPVOID lpFileBase;
@@ -446,6 +454,7 @@
   CloseHandle(hFileMapping);
   CloseHandle(hFile);
   return true;
+#endif
 }
 
 bool bindexplib::AddObjectFile(const char* filename)
diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx
index 6e04ce5..231a2d6 100644
--- a/Source/cmAddCustomCommandCommand.cxx
+++ b/Source/cmAddCustomCommandCommand.cxx
@@ -174,7 +174,7 @@
         doing = doing_comment;
       } else if (copy == keyDEPFILE) {
         doing = doing_depfile;
-        if (mf.GetGlobalGenerator()->GetName() != "Ninja") {
+        if (!mf.GetGlobalGenerator()->SupportsCustomCommandDepfile()) {
           status.SetError("Option DEPFILE not supported by " +
                           mf.GetGlobalGenerator()->GetName());
           return false;
@@ -215,7 +215,8 @@
       }
 
       if (cmSystemTools::FileIsFullPath(filename)) {
-        filename = cmSystemTools::CollapseFullPath(filename);
+        filename = cmSystemTools::CollapseFullPath(
+          filename, status.GetMakefile().GetHomeOutputDirectory());
       }
       switch (doing) {
         case doing_depfile:
@@ -261,9 +262,9 @@
         case doing_target:
           target = copy;
           break;
-        case doing_depends: {
+        case doing_depends:
           depends.push_back(copy);
-        } break;
+          break;
         case doing_outputs:
           outputs.push_back(filename);
           break;
@@ -343,7 +344,7 @@
     // Target is empty, use the output.
     mf.AddCustomCommandToOutput(
       output, byproducts, depends, main_dependency, implicit_depends,
-      commandLines, comment, working.c_str(), false, escapeOldStyle,
+      commandLines, comment, working.c_str(), nullptr, false, escapeOldStyle,
       uses_terminal, command_expand_lists, depfile, job_pool);
   } else if (!byproducts.empty()) {
     status.SetError("BYPRODUCTS may not be specified with SOURCE signatures");
diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx
index e27b126..aa98d89 100644
--- a/Source/cmAddCustomTargetCommand.cxx
+++ b/Source/cmAddCustomTargetCommand.cxx
@@ -6,7 +6,6 @@
 
 #include "cmCheckCustomOutputs.h"
 #include "cmCustomCommandLines.h"
-#include "cmCustomCommandTypes.h"
 #include "cmExecutionStatus.h"
 #include "cmGeneratorExpression.h"
 #include "cmGlobalGenerator.h"
@@ -215,9 +214,9 @@
   // Add the utility target to the makefile.
   bool escapeOldStyle = !verbatim;
   cmTarget* target = mf.AddUtilityCommand(
-    targetName, cmCommandOrigin::Project, excludeFromAll,
-    working_directory.c_str(), byproducts, depends, commandLines,
-    escapeOldStyle, comment, uses_terminal, command_expand_lists, job_pool);
+    targetName, excludeFromAll, working_directory.c_str(), byproducts, depends,
+    commandLines, escapeOldStyle, comment, uses_terminal, command_expand_lists,
+    job_pool);
 
   // Add additional user-specified source files to the target.
   target->AddSources(sources);
diff --git a/Source/cmAddDependenciesCommand.cxx b/Source/cmAddDependenciesCommand.cxx
index b1fc893..2d55a5a 100644
--- a/Source/cmAddDependenciesCommand.cxx
+++ b/Source/cmAddDependenciesCommand.cxx
@@ -29,7 +29,7 @@
 
     // skip over target_name
     for (std::string const& arg : cmMakeRange(args).advance(1)) {
-      target->AddUtility(arg, &mf);
+      target->AddUtility(arg, false, &mf);
     }
   } else {
     mf.IssueMessage(
diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx
index 0439c51..f443fc6 100644
--- a/Source/cmAddLibraryCommand.cxx
+++ b/Source/cmAddLibraryCommand.cxx
@@ -2,7 +2,8 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmAddLibraryCommand.h"
 
-#include "cmAlgorithms.h"
+#include <cmext/algorithm>
+
 #include "cmExecutionStatus.h"
 #include "cmGeneratorExpression.h"
 #include "cmGlobalGenerator.h"
@@ -309,7 +310,7 @@
     return true;
   }
 
-  cmAppend(srclists, s, args.end());
+  cm::append(srclists, s, args.end());
 
   mf.AddLibrary(libName, type, srclists, excludeFromAll);
 
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 e0d27ee..c0ac551 100644
--- a/Source/cmAlgorithms.h
+++ b/Source/cmAlgorithms.h
@@ -8,6 +8,7 @@
 #include <algorithm>
 #include <functional>
 #include <iterator>
+#include <memory>
 #include <unordered_set>
 #include <utility>
 #include <vector>
@@ -36,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))
@@ -72,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)
 {
@@ -138,25 +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 T, typename Range>
-void cmAppend(std::vector<T>& v, Range const& r)
-{
-  v.insert(v.end(), r.begin(), r.end());
-}
-
-template <typename T, typename InputIt>
-void cmAppend(std::vector<T>& v, InputIt first, InputIt last)
-{
-  v.insert(v.end(), first, last);
-}
-
-template <typename Range>
 typename Range::const_iterator cmRemoveN(Range& r, size_t n)
 {
   return ContainerAlgorithms::RemoveN(r.begin(), r.end(), n);
@@ -197,7 +139,7 @@
 ForwardIterator cmRemoveDuplicates(ForwardIterator first, ForwardIterator last)
 {
   using Value = typename std::iterator_traits<ForwardIterator>::value_type;
-  using Hash = struct
+  struct Hash
   {
     std::size_t operator()(ForwardIterator it) const
     {
@@ -205,7 +147,7 @@
     }
   };
 
-  using Equal = struct
+  struct Equal
   {
     bool operator()(ForwardIterator it1, ForwardIterator it2) const
     {
diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx
index e5eea79..d29b2ac 100644
--- a/Source/cmArchiveWrite.cxx
+++ b/Source/cmArchiveWrite.cxx
@@ -200,8 +200,11 @@
 bool cmArchiveWrite::AddPath(const char* path, size_t skip, const char* prefix,
                              bool recursive)
 {
-  if (!this->AddFile(path, skip, prefix)) {
-    return false;
+  if (strcmp(path, ".") != 0 ||
+      (this->Format != "zip" && this->Format != "7zip")) {
+    if (!this->AddFile(path, skip, prefix)) {
+      return false;
+    }
   }
   if ((!cmSystemTools::FileIsDirectory(path) || !recursive) ||
       cmSystemTools::FileIsSymlink(path)) {
@@ -210,6 +213,9 @@
   cmsys::Directory d;
   if (d.Load(path)) {
     std::string next = cmStrCat(path, '/');
+    if (next == "./" && (this->Format == "zip" || this->Format == "7zip")) {
+      next.clear();
+    }
     std::string::size_type end = next.size();
     unsigned long n = d.GetNumberOfFiles();
     for (unsigned long i = 0; i < n; ++i) {
diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx
index 177bca8..b5c7e96 100644
--- a/Source/cmCPluginAPI.cxx
+++ b/Source/cmCPluginAPI.cxx
@@ -221,10 +221,10 @@
 
   // Pass the call to the makefile instance.
   std::vector<std::string> no_byproducts;
-  mf->AddUtilityCommand(utilityName, cmCommandOrigin::Project,
-                        (all ? false : true), nullptr, no_byproducts, depends2,
-                        commandLines);
+  mf->AddUtilityCommand(utilityName, (all ? false : true), nullptr,
+                        no_byproducts, depends2, commandLines);
 }
+
 void CCONV cmAddCustomCommand(void* arg, const char* source,
                               const char* command, int numArgs,
                               const char** args, int numDepends,
diff --git a/Source/cmCPluginAPI.h b/Source/cmCPluginAPI.h
index 6a95148..19626f0 100644
--- a/Source/cmCPluginAPI.h
+++ b/Source/cmCPluginAPI.h
@@ -36,7 +36,7 @@
   of functions are utility functions that are specific to the plugin API
   =========================================================================*/
   /* set/Get the ClientData in the cmLoadedCommandInfo structure, this is how
-     information is passed from the InitialPass to FInalPass for commands
+     information is passed from the InitialPass to FinalPass for commands
      that need a FinalPass and need information from the InitialPass */
   void*(CCONV* GetClientData)(void* info);
   /* return the summed size in characters of all the arguments */
@@ -44,7 +44,7 @@
   /* free all the memory associated with an argc, argv pair */
   void(CCONV* FreeArguments)(int argc, char** argv);
   /* set/Get the ClientData in the cmLoadedCommandInfo structure, this is how
-     information is passed from the InitialPass to FInalPass for commands
+     information is passed from the InitialPass to FinalPass for commands
      that need a FinalPass and need information from the InitialPass */
   void(CCONV* SetClientData)(void* info, void* cd);
   /* when an error occurs, call this function to set the error string */
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index 6eae26e..04f75bd 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -21,6 +21,7 @@
 #include "cmsys/FStream.hxx"
 #include "cmsys/Glob.hxx"
 #include "cmsys/Process.h"
+#include "cmsys/RegularExpression.hxx"
 #include "cmsys/SystemInformation.hxx"
 
 #include "cm_curl.h"
@@ -32,8 +33,8 @@
 #endif
 
 #include <cm/memory>
+#include <cmext/algorithm>
 
-#include "cmAlgorithms.h"
 #include "cmCTestBuildAndTestHandler.h"
 #include "cmCTestBuildHandler.h"
 #include "cmCTestConfigureHandler.h"
@@ -83,8 +84,8 @@
     std::string Name;
   };
 
-  int RepeatTests = 1; // default to run each test once
-  bool RepeatUntilFail = false;
+  int RepeatCount = 1; // default to run each test once
+  cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never;
   std::string ConfigType;
   std::string ScheduleType;
   std::chrono::system_clock::time_point StopTime;
@@ -207,6 +208,8 @@
   bool OutputColorCode = cmCTest::ColoredOutputSupportedByConsole();
 
   std::map<std::string, std::string> Definitions;
+
+  cmCTest::NoTests NoTestsMode = cmCTest::NoTests::Legacy;
 };
 
 struct tm* cmCTest::GetNightlyTime(std::string const& str, bool tomorrowtag)
@@ -1279,7 +1282,7 @@
   while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) {
     processOutput.DecodeText(data, length, strdata);
     if (output) {
-      cmAppend(tempOutput, data, data + length);
+      cm::append(tempOutput, data, data + length);
     }
     cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
                cmCTestLogWrite(strdata.c_str(), strdata.size()));
@@ -1839,11 +1842,16 @@
     this->SetParallelLevel(plevel);
     this->Impl->ParallelLevelSetInCli = true;
   }
+
   if (this->CheckArgument(arg, "--repeat-until-fail")) {
     if (i >= args.size() - 1) {
       errormsg = "'--repeat-until-fail' requires an argument";
       return false;
     }
+    if (this->Impl->RepeatMode != cmCTest::Repeat::Never) {
+      errormsg = "At most one '--repeat' option may be used.";
+      return false;
+    }
     i++;
     long repeat = 1;
     if (!cmStrToLong(args[i], &repeat)) {
@@ -1851,9 +1859,42 @@
         "'--repeat-until-fail' given non-integer value '" + args[i] + "'";
       return false;
     }
-    this->Impl->RepeatTests = static_cast<int>(repeat);
+    this->Impl->RepeatCount = static_cast<int>(repeat);
     if (repeat > 1) {
-      this->Impl->RepeatUntilFail = true;
+      this->Impl->RepeatMode = cmCTest::Repeat::UntilFail;
+    }
+  }
+
+  if (this->CheckArgument(arg, "--repeat")) {
+    if (i >= args.size() - 1) {
+      errormsg = "'--repeat' requires an argument";
+      return false;
+    }
+    if (this->Impl->RepeatMode != cmCTest::Repeat::Never) {
+      errormsg = "At most one '--repeat' option may be used.";
+      return false;
+    }
+    i++;
+    cmsys::RegularExpression repeatRegex(
+      "^(until-fail|until-pass|after-timeout):([0-9]+)$");
+    if (repeatRegex.find(args[i])) {
+      std::string const& count = repeatRegex.match(2);
+      unsigned long n = 1;
+      cmStrToULong(count, &n); // regex guarantees success
+      this->Impl->RepeatCount = static_cast<int>(n);
+      if (this->Impl->RepeatCount > 1) {
+        std::string const& mode = repeatRegex.match(1);
+        if (mode == "until-fail") {
+          this->Impl->RepeatMode = cmCTest::Repeat::UntilFail;
+        } else if (mode == "until-pass") {
+          this->Impl->RepeatMode = cmCTest::Repeat::UntilPass;
+        } else if (mode == "after-timeout") {
+          this->Impl->RepeatMode = cmCTest::Repeat::AfterTimeout;
+        }
+      }
+    } else {
+      errormsg = "'--repeat' given invalid value '" + args[i] + "'";
+      return false;
     }
   }
 
@@ -2020,6 +2061,19 @@
     this->SetNotesFiles(args[i].c_str());
   }
 
+  const std::string noTestsPrefix = "--no-tests=";
+  if (cmHasPrefix(arg, noTestsPrefix)) {
+    const std::string noTestsMode = arg.substr(noTestsPrefix.length());
+    if (noTestsMode == "error") {
+      this->Impl->NoTestsMode = cmCTest::NoTests::Error;
+    } else if (noTestsMode != "ignore") {
+      errormsg = "'--no-tests=' given unknown value '" + noTestsMode + "'";
+      return false;
+    } else {
+      this->Impl->NoTestsMode = cmCTest::NoTests::Ignore;
+    }
+  }
+
   // options that control what tests are run
   if (this->CheckArgument(arg, "-I", "--tests-information") &&
       i < args.size() - 1) {
@@ -2204,7 +2258,7 @@
   bool SRArgumentSpecified = false;
 
   // copy the command line
-  cmAppend(this->Impl->InitialCommandLineArguments, args);
+  cm::append(this->Impl->InitialCommandLineArguments, args);
 
   // process the command line arguments
   for (size_t i = 1; i < args.size(); ++i) {
@@ -2847,14 +2901,19 @@
   return this->Impl->Definitions;
 }
 
-int cmCTest::GetTestRepeat() const
+int cmCTest::GetRepeatCount() const
 {
-  return this->Impl->RepeatTests;
+  return this->Impl->RepeatCount;
 }
 
-bool cmCTest::GetRepeatUntilFail() const
+cmCTest::Repeat cmCTest::GetRepeatMode() const
 {
-  return this->Impl->RepeatUntilFail;
+  return this->Impl->RepeatMode;
+}
+
+cmCTest::NoTests cmCTest::GetNoTestsMode() const
+{
+  return this->Impl->NoTestsMode;
 }
 
 void cmCTest::SetBuildID(const std::string& id)
@@ -2964,10 +3023,10 @@
     res = cmsysProcess_WaitForData(cp, &data, &length, nullptr);
     switch (res) {
       case cmsysProcess_Pipe_STDOUT:
-        cmAppend(tempOutput, data, data + length);
+        cm::append(tempOutput, data, data + length);
         break;
       case cmsysProcess_Pipe_STDERR:
-        cmAppend(tempError, data, data + length);
+        cm::append(tempError, data, data + length);
         break;
       default:
         done = true;
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index 82a6f4c..7f8f913 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -431,10 +431,24 @@
   const std::map<std::string, std::string>& GetDefinitions() const;
 
   /** Return the number of times a test should be run */
-  int GetTestRepeat() const;
+  int GetRepeatCount() const;
 
-  /** Return true if test should run until fail */
-  bool GetRepeatUntilFail() const;
+  enum class Repeat
+  {
+    Never,
+    UntilFail,
+    UntilPass,
+    AfterTimeout,
+  };
+  Repeat GetRepeatMode() const;
+
+  enum class NoTests
+  {
+    Legacy,
+    Error,
+    Ignore
+  };
+  NoTests GetNoTestsMode() const;
 
   void GenerateSubprojectsOutput(cmXMLWriter& xml);
   std::vector<std::string> GetLabelsForSubprojects();
diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx
index d627465..dc9aba1 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(
@@ -617,7 +623,7 @@
   const std::string& prop) const
 {
   if (prop == "TYPE") {
-    return cmState::CacheEntryTypeToString(this->Type);
+    return cmState::CacheEntryTypeToString(this->Type).c_str();
   }
   if (prop == "VALUE") {
     return this->Value.c_str();
@@ -638,14 +644,15 @@
 }
 
 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 : "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;
@@ -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/cmCommands.cxx b/Source/cmCommands.cxx
index 6f19697..896b6a9 100644
--- a/Source/cmCommands.cxx
+++ b/Source/cmCommands.cxx
@@ -198,6 +198,7 @@
 #if !defined(CMAKE_BOOTSTRAP)
   state->AddBuiltinCommand("cmake_host_system_information",
                            cmCMakeHostSystemInformationCommand);
+  state->AddBuiltinCommand("load_cache", cmLoadCacheCommand);
   state->AddBuiltinCommand("remove", cmRemoveCommand);
   state->AddBuiltinCommand("variable_watch", cmVariableWatchCommand);
   state->AddBuiltinCommand("write_file", cmWriteFileCommand);
@@ -279,7 +280,6 @@
   state->AddBuiltinCommand("link_libraries", cmLinkLibrariesCommand);
   state->AddBuiltinCommand("target_link_directories",
                            cmTargetLinkDirectoriesCommand);
-  state->AddBuiltinCommand("load_cache", cmLoadCacheCommand);
   state->AddBuiltinCommand("qt_wrap_cpp", cmQTWrapCPPCommand);
   state->AddBuiltinCommand("qt_wrap_ui", cmQTWrapUICommand);
   state->AddBuiltinCommand("remove_definitions", cmRemoveDefinitionsCommand);
@@ -339,7 +339,6 @@
   CM_UNEXPECTED_PROJECT_COMMAND("install");
   CM_UNEXPECTED_PROJECT_COMMAND("link_directories");
   CM_UNEXPECTED_PROJECT_COMMAND("link_libraries");
-  CM_UNEXPECTED_PROJECT_COMMAND("load_cache");
   CM_UNEXPECTED_PROJECT_COMMAND("project");
   CM_UNEXPECTED_PROJECT_COMMAND("qt_wrap_cpp");
   CM_UNEXPECTED_PROJECT_COMMAND("qt_wrap_ui");
diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx
index 19a096b..033cb60 100644
--- a/Source/cmCommonTargetGenerator.cxx
+++ b/Source/cmCommonTargetGenerator.cxx
@@ -17,6 +17,7 @@
 #include "cmSourceFile.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
+#include "cmTarget.h"
 
 cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt)
   : GeneratorTarget(gt)
@@ -25,27 +26,29 @@
       static_cast<cmLocalCommonGenerator*>(gt->LocalGenerator))
   , GlobalCommonGenerator(static_cast<cmGlobalCommonGenerator*>(
       gt->LocalGenerator->GetGlobalGenerator()))
-  , ConfigName(LocalCommonGenerator->GetConfigName())
+  , ConfigNames(LocalCommonGenerator->GetConfigNames())
 {
 }
 
 cmCommonTargetGenerator::~cmCommonTargetGenerator() = default;
 
-std::string const& cmCommonTargetGenerator::GetConfigName() const
+std::vector<std::string> const& cmCommonTargetGenerator::GetConfigNames() const
 {
-  return this->ConfigName;
+  return this->ConfigNames;
 }
 
-const char* cmCommonTargetGenerator::GetFeature(const std::string& feature)
+const char* cmCommonTargetGenerator::GetFeature(const std::string& feature,
+                                                const std::string& config)
 {
-  return this->GeneratorTarget->GetFeature(feature, this->ConfigName);
+  return this->GeneratorTarget->GetFeature(feature, config);
 }
 
 void cmCommonTargetGenerator::AddModuleDefinitionFlag(
-  cmLinkLineComputer* linkLineComputer, std::string& flags)
+  cmLinkLineComputer* linkLineComputer, std::string& flags,
+  const std::string& config)
 {
   cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
-    this->GeneratorTarget->GetModuleDefinitionInfo(this->GetConfigName());
+    this->GeneratorTarget->GetModuleDefinitionInfo(config);
   if (!mdi || mdi->DefFile.empty()) {
     return;
   }
@@ -94,57 +97,60 @@
   }
 }
 
-std::string cmCommonTargetGenerator::GetFlags(const std::string& l)
+std::string cmCommonTargetGenerator::GetFlags(const std::string& l,
+                                              const std::string& config)
 {
-  auto i = this->FlagsByLanguage.find(l);
-  if (i == this->FlagsByLanguage.end()) {
+  auto i = this->Configs[config].FlagsByLanguage.find(l);
+  if (i == this->Configs[config].FlagsByLanguage.end()) {
     std::string flags;
 
-    this->LocalCommonGenerator->GetTargetCompileFlags(
-      this->GeneratorTarget, this->ConfigName, l, flags);
+    this->LocalCommonGenerator->GetTargetCompileFlags(this->GeneratorTarget,
+                                                      config, l, flags);
 
     ByLanguageMap::value_type entry(l, flags);
-    i = this->FlagsByLanguage.insert(entry).first;
+    i = this->Configs[config].FlagsByLanguage.insert(entry).first;
   }
   return i->second;
 }
 
-std::string cmCommonTargetGenerator::GetDefines(const std::string& l)
+std::string cmCommonTargetGenerator::GetDefines(const std::string& l,
+                                                const std::string& config)
 {
-  auto i = this->DefinesByLanguage.find(l);
-  if (i == this->DefinesByLanguage.end()) {
+  auto i = this->Configs[config].DefinesByLanguage.find(l);
+  if (i == this->Configs[config].DefinesByLanguage.end()) {
     std::set<std::string> defines;
-    this->LocalCommonGenerator->GetTargetDefines(this->GeneratorTarget,
-                                                 this->ConfigName, l, defines);
+    this->LocalCommonGenerator->GetTargetDefines(this->GeneratorTarget, config,
+                                                 l, defines);
 
     std::string definesString;
     this->LocalCommonGenerator->JoinDefines(defines, definesString, l);
 
     ByLanguageMap::value_type entry(l, definesString);
-    i = this->DefinesByLanguage.insert(entry).first;
+    i = this->Configs[config].DefinesByLanguage.insert(entry).first;
   }
   return i->second;
 }
 
-std::string cmCommonTargetGenerator::GetIncludes(std::string const& l)
+std::string cmCommonTargetGenerator::GetIncludes(std::string const& l,
+                                                 const std::string& config)
 {
-  auto i = this->IncludesByLanguage.find(l);
-  if (i == this->IncludesByLanguage.end()) {
+  auto i = this->Configs[config].IncludesByLanguage.find(l);
+  if (i == this->Configs[config].IncludesByLanguage.end()) {
     std::string includes;
-    this->AddIncludeFlags(includes, l);
+    this->AddIncludeFlags(includes, l, config);
     ByLanguageMap::value_type entry(l, includes);
-    i = this->IncludesByLanguage.insert(entry).first;
+    i = this->Configs[config].IncludesByLanguage.insert(entry).first;
   }
   return i->second;
 }
 
-std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories()
-  const
+std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories(
+  const std::string& config) const
 {
   std::vector<std::string> dirs;
   std::set<cmGeneratorTarget const*> emitted;
   if (cmComputeLinkInformation* cli =
-        this->GeneratorTarget->GetLinkInformation(this->ConfigName)) {
+        this->GeneratorTarget->GetLinkInformation(config)) {
     cmComputeLinkInformation::ItemVector const& items = cli->GetItems();
     for (auto const& item : items) {
       cmGeneratorTarget const* linkee = item.Target;
@@ -165,19 +171,24 @@
   return dirs;
 }
 
-std::string cmCommonTargetGenerator::ComputeTargetCompilePDB() const
+std::string cmCommonTargetGenerator::ComputeTargetCompilePDB(
+  const std::string& config) const
 {
   std::string compilePdbPath;
   if (this->GeneratorTarget->GetType() > cmStateEnums::OBJECT_LIBRARY) {
     return compilePdbPath;
   }
 
-  compilePdbPath =
-    this->GeneratorTarget->GetCompilePDBPath(this->GetConfigName());
+  compilePdbPath = this->GeneratorTarget->GetCompilePDBPath(config);
   if (compilePdbPath.empty()) {
     // Match VS default: `$(IntDir)vc$(PlatformToolsetVersion).pdb`.
     // A trailing slash tells the toolchain to add its default file name.
-    compilePdbPath = this->GeneratorTarget->GetSupportDirectory() + "/";
+    compilePdbPath = this->GeneratorTarget->GetSupportDirectory();
+    if (this->GlobalCommonGenerator->IsMultiConfig()) {
+      compilePdbPath += "/";
+      compilePdbPath += config;
+    }
+    compilePdbPath += "/";
     if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) {
       // Match VS default for static libs: `$(IntDir)$(ProjectName).pdb`.
       compilePdbPath += this->GeneratorTarget->GetName();
@@ -188,10 +199,10 @@
   return compilePdbPath;
 }
 
-std::string cmCommonTargetGenerator::GetManifests()
+std::string cmCommonTargetGenerator::GetManifests(const std::string& config)
 {
   std::vector<cmSourceFile const*> manifest_srcs;
-  this->GeneratorTarget->GetManifests(manifest_srcs, this->ConfigName);
+  this->GeneratorTarget->GetManifests(manifest_srcs, config);
 
   std::vector<std::string> manifests;
   manifests.reserve(manifest_srcs.size());
@@ -206,6 +217,20 @@
   return cmJoin(manifests, " ");
 }
 
+std::string cmCommonTargetGenerator::GetAIXExports(std::string const&)
+{
+  std::string aixExports;
+  if (this->GeneratorTarget->Target->IsAIX()) {
+    if (const char* exportAll =
+          this->GeneratorTarget->GetProperty("AIX_EXPORT_ALL_SYMBOLS")) {
+      if (cmIsOff(exportAll)) {
+        aixExports = "-n";
+      }
+    }
+  }
+  return aixExports;
+}
+
 void cmCommonTargetGenerator::AppendOSXVerFlag(std::string& flags,
                                                const std::string& lang,
                                                const char* name, bool so)
@@ -223,7 +248,10 @@
   int major;
   int minor;
   int patch;
-  this->GeneratorTarget->GetTargetVersion(so, major, minor, patch);
+  std::string prop = cmStrCat("MACHO_", name, "_VERSION");
+  std::string fallback_prop = so ? "SOVERSION" : "VERSION";
+  this->GeneratorTarget->GetTargetVersionFallback(prop, fallback_prop, major,
+                                                  minor, patch);
   if (major > 0 || minor > 0 || patch > 0) {
     // Append the flag since a non-zero version is specified.
     std::ostringstream vflag;
diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h
index 17792d6..b40a2ed 100644
--- a/Source/cmCommonTargetGenerator.h
+++ b/Source/cmCommonTargetGenerator.h
@@ -25,42 +25,51 @@
   cmCommonTargetGenerator(cmGeneratorTarget* gt);
   virtual ~cmCommonTargetGenerator();
 
-  std::string const& GetConfigName() const;
+  std::vector<std::string> const& GetConfigNames() const;
 
 protected:
   // Feature query methods.
-  const char* GetFeature(const std::string& feature);
+  const char* GetFeature(const std::string& feature,
+                         const std::string& config);
 
   // Helper to add flag for windows .def file.
   void AddModuleDefinitionFlag(cmLinkLineComputer* linkLineComputer,
-                               std::string& flags);
+                               std::string& flags, const std::string& config);
 
   cmGeneratorTarget* GeneratorTarget;
   cmMakefile* Makefile;
   cmLocalCommonGenerator* LocalCommonGenerator;
   cmGlobalCommonGenerator* GlobalCommonGenerator;
-  std::string ConfigName;
+  std::vector<std::string> ConfigNames;
 
   void AppendFortranFormatFlags(std::string& flags,
                                 cmSourceFile const& source);
 
-  virtual void AddIncludeFlags(std::string& flags,
-                               std::string const& lang) = 0;
+  virtual void AddIncludeFlags(std::string& flags, std::string const& lang,
+                               const std::string& config) = 0;
 
   void AppendOSXVerFlag(std::string& flags, const std::string& lang,
                         const char* name, bool so);
 
-  using ByLanguageMap = std::map<std::string, std::string>;
-  std::string GetFlags(const std::string& l);
-  ByLanguageMap FlagsByLanguage;
-  std::string GetDefines(const std::string& l);
-  ByLanguageMap DefinesByLanguage;
-  std::string GetIncludes(std::string const& l);
-  ByLanguageMap IncludesByLanguage;
-  std::string GetManifests();
+  std::string GetFlags(const std::string& l, const std::string& config);
+  std::string GetDefines(const std::string& l, const std::string& config);
+  std::string GetIncludes(std::string const& l, const std::string& config);
+  std::string GetManifests(const std::string& config);
+  std::string GetAIXExports(std::string const& config);
 
-  std::vector<std::string> GetLinkedTargetDirectories() const;
-  std::string ComputeTargetCompilePDB() const;
+  std::vector<std::string> GetLinkedTargetDirectories(
+    const std::string& config) const;
+  std::string ComputeTargetCompilePDB(const std::string& config) const;
+
+private:
+  using ByLanguageMap = std::map<std::string, std::string>;
+  struct ByConfig
+  {
+    ByLanguageMap FlagsByLanguage;
+    ByLanguageMap DefinesByLanguage;
+    ByLanguageMap IncludesByLanguage;
+  };
+  std::map<std::string, ByConfig> Configs;
 };
 
 #endif
diff --git a/Source/cmComputeComponentGraph.cxx b/Source/cmComputeComponentGraph.cxx
index af257ee..81cd878 100644
--- a/Source/cmComputeComponentGraph.cxx
+++ b/Source/cmComputeComponentGraph.cxx
@@ -123,7 +123,7 @@
         // We do not attempt to combine duplicate edges, but instead
         // store the inter-component edges with suitable multiplicity.
         this->ComponentGraph[i_component].emplace_back(
-          j_component, ni.IsStrong(), ni.GetBacktrace());
+          j_component, ni.IsStrong(), ni.IsCross(), ni.GetBacktrace());
       }
     }
   }
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
index ccef9c8..e9bf5a5 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/Source/cmComputeLinkDepends.cxx
@@ -412,7 +412,7 @@
   // This shared library dependency must follow the item that listed
   // it.
   this->EntryConstraintGraph[dep.DependerIndex].emplace_back(
-    index, true, cmListFileBacktrace());
+    index, true, false, cmListFileBacktrace());
 
   // Target items may have their own dependencies.
   if (entry.Target) {
@@ -514,7 +514,7 @@
     // The dependee must come after the depender.
     if (depender_index >= 0) {
       this->EntryConstraintGraph[depender_index].emplace_back(
-        dependee_index, false, cmListFileBacktrace());
+        dependee_index, false, false, cmListFileBacktrace());
     } else {
       // This is a direct dependency of the target being linked.
       this->OriginalEntries.push_back(dependee_index);
@@ -587,7 +587,7 @@
     cmGraphEdgeList& edges = this->EntryConstraintGraph[depender_index];
     edges.reserve(edges.size() + common.size());
     for (auto const& c : common) {
-      edges.emplace_back(c, true, cmListFileBacktrace());
+      edges.emplace_back(c, true, false, cmListFileBacktrace());
     }
   }
 }
diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h
index 43bfd1d..e806dff 100644
--- a/Source/cmComputeLinkDepends.h
+++ b/Source/cmComputeLinkDepends.h
@@ -7,12 +7,11 @@
 
 #include <map>
 #include <memory>
+#include <queue>
 #include <set>
 #include <string>
 #include <vector>
 
-#include <queue>
-
 #include "cmGraphAdjacencyList.h"
 #include "cmLinkItem.h"
 #include "cmListFileCache.h"
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index f3dd840..11570d6 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -8,8 +8,11 @@
 #include <sstream>
 #include <utility>
 
+#include <cm/memory>
+
 #include "cmAlgorithms.h"
 #include "cmComputeLinkDepends.h"
+#include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
 #include "cmListFileCache.h"
@@ -256,11 +259,10 @@
     "FIND_LIBRARY_USE_OPENBSD_VERSIONING");
 
   // Allocate internals.
-  this->OrderLinkerSearchPath = new cmOrderDirectories(
+  this->OrderLinkerSearchPath = cm::make_unique<cmOrderDirectories>(
     this->GlobalGenerator, target, "linker search path");
-  this->OrderRuntimeSearchPath = new cmOrderDirectories(
+  this->OrderRuntimeSearchPath = cm::make_unique<cmOrderDirectories>(
     this->GlobalGenerator, target, "runtime search path");
-  this->OrderDependentRPath = nullptr;
 
   // Get the language used for linking this target.
   this->LinkLanguage = this->Target->GetLinkerLanguage(config);
@@ -358,7 +360,7 @@
     this->SharedDependencyMode = SharedDepModeLibDir;
   } else if (!this->RPathLinkFlag.empty()) {
     this->SharedDependencyMode = SharedDepModeDir;
-    this->OrderDependentRPath = new cmOrderDirectories(
+    this->OrderDependentRPath = cm::make_unique<cmOrderDirectories>(
       this->GlobalGenerator, target, "dependent library path");
   }
 
@@ -400,12 +402,7 @@
     "CMAKE_POLICY_WARNING_CMP0060");
 }
 
-cmComputeLinkInformation::~cmComputeLinkInformation()
-{
-  delete this->OrderLinkerSearchPath;
-  delete this->OrderRuntimeSearchPath;
-  delete this->OrderDependentRPath;
-}
+cmComputeLinkInformation::~cmComputeLinkInformation() = default;
 
 void cmComputeLinkInformation::AppendValues(
   std::string& result, std::vector<BT<std::string>>& values)
@@ -573,6 +570,15 @@
   cmGeneratorTarget::LinkClosure const* lc =
     this->Target->GetLinkClosure(this->Config);
   for (std::string const& li : lc->Languages) {
+
+    if (li == "CUDA") {
+      // These need to go before the other implicit link information
+      // as they could require symbols from those other library
+      // Currently restricted to CUDA as it is the only language
+      // we have documented runtime behavior controls for
+      this->AddRuntimeLinkLibrary(li);
+    }
+
     // Skip those of the linker language.  They are implicit.
     if (li != this->LinkLanguage) {
       this->AddImplicitLinkInfo(li);
@@ -580,6 +586,39 @@
   }
 }
 
+void cmComputeLinkInformation::AddRuntimeLinkLibrary(std::string const& lang)
+{ // Add the lang runtime library flags. This is activated by the presence
+  // of a default selection whether or not it is overridden by a property.
+  std::string defaultVar =
+    cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARY_DEFAULT");
+  const char* langRuntimeLibraryDefault =
+    this->Makefile->GetDefinition(defaultVar);
+  if (langRuntimeLibraryDefault && *langRuntimeLibraryDefault) {
+    const char* runtimeLibraryValue =
+      this->Target->GetProperty(cmStrCat(lang, "_RUNTIME_LIBRARY"));
+    if (!runtimeLibraryValue) {
+      runtimeLibraryValue = langRuntimeLibraryDefault;
+    }
+
+    std::string runtimeLibrary =
+      cmSystemTools::UpperCase(cmGeneratorExpression::Evaluate(
+        runtimeLibraryValue, this->Target->GetLocalGenerator(), this->Config,
+        this->Target));
+    if (!runtimeLibrary.empty()) {
+      if (const char* runtimeLinkOptions = this->Makefile->GetDefinition(
+            "CMAKE_" + lang + "_RUNTIME_LIBRARY_LINK_OPTIONS_" +
+            runtimeLibrary)) {
+        std::vector<std::string> libsVec = cmExpandedList(runtimeLinkOptions);
+        for (std::string const& i : libsVec) {
+          if (!cmContains(this->ImplicitLinkLibs, i)) {
+            this->AddItem(i, nullptr);
+          }
+        }
+      }
+    }
+  }
+}
+
 void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang)
 {
   // Add libraries for this language that are not implied by the
@@ -749,10 +788,10 @@
   if (this->SharedDependencyMode == SharedDepModeLibDir &&
       !this->LinkWithRuntimePath /* AddLibraryRuntimeInfo adds it */) {
     // Add the item to the linker search path.
-    order = this->OrderLinkerSearchPath;
+    order = this->OrderLinkerSearchPath.get();
   } else if (this->SharedDependencyMode == SharedDepModeDir) {
     // Add the item to the separate dependent library search path.
-    order = this->OrderDependentRPath;
+    order = this->OrderDependentRPath.get();
   }
   if (order) {
     if (tgt) {
diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h
index ee74ccd..e50d369 100644
--- a/Source/cmComputeLinkInformation.h
+++ b/Source/cmComputeLinkInformation.h
@@ -6,6 +6,7 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <iosfwd>
+#include <memory>
 #include <set>
 #include <string>
 #include <utility>
@@ -29,6 +30,9 @@
 public:
   cmComputeLinkInformation(cmGeneratorTarget const* target,
                            const std::string& config);
+  cmComputeLinkInformation(const cmComputeLinkInformation&) = delete;
+  cmComputeLinkInformation& operator=(const cmComputeLinkInformation&) =
+    delete;
   ~cmComputeLinkInformation();
   bool Compute();
 
@@ -166,7 +170,7 @@
   cmsys::RegularExpression SplitFramework;
 
   // Linker search path computation.
-  cmOrderDirectories* OrderLinkerSearchPath;
+  std::unique_ptr<cmOrderDirectories> OrderLinkerSearchPath;
   bool FinishLinkerSearchDirectories();
   void PrintLinkPolicyDiagnosis(std::ostream&);
 
@@ -174,6 +178,7 @@
   void LoadImplicitLinkInfo();
   void AddImplicitLinkInfo();
   void AddImplicitLinkInfo(std::string const& lang);
+  void AddRuntimeLinkLibrary(std::string const& lang);
   std::set<std::string> ImplicitLinkDirs;
   std::set<std::string> ImplicitLinkLibs;
 
@@ -186,9 +191,9 @@
   std::vector<std::string> OldUserFlagItems;
   std::set<std::string> CMP0060WarnItems;
   // Dependent library path computation.
-  cmOrderDirectories* OrderDependentRPath;
+  std::unique_ptr<cmOrderDirectories> OrderDependentRPath;
   // Runtime path computation.
-  cmOrderDirectories* OrderRuntimeSearchPath;
+  std::unique_ptr<cmOrderDirectories> OrderRuntimeSearchPath;
 
   bool OldLinkDirMode;
   bool OpenBSD;
diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx
index 162bab2..a98a608 100644
--- a/Source/cmComputeTargetDepends.cxx
+++ b/Source/cmComputeTargetDepends.cxx
@@ -4,6 +4,7 @@
 
 #include <cassert>
 #include <cstdio>
+#include <memory>
 #include <sstream>
 #include <utility>
 
@@ -150,6 +151,7 @@
     cmGeneratorTarget const* dep = this->Targets[ni];
     auto di = deps.insert(dep).first;
     di->SetType(ni.IsStrong());
+    di->SetCross(ni.IsCross());
     di->SetBacktrace(ni.GetBacktrace());
   }
 }
@@ -157,15 +159,12 @@
 void cmComputeTargetDepends::CollectTargets()
 {
   // Collect all targets from all generators.
-  std::vector<cmLocalGenerator*> const& lgens =
-    this->GlobalGenerator->GetLocalGenerators();
-  for (cmLocalGenerator* lgen : lgens) {
-    const std::vector<cmGeneratorTarget*>& targets =
-      lgen->GetGeneratorTargets();
-    for (cmGeneratorTarget const* ti : targets) {
+  auto const& lgens = this->GlobalGenerator->GetLocalGenerators();
+  for (const auto& lgen : lgens) {
+    for (const auto& ti : lgen->GetGeneratorTargets()) {
       int index = static_cast<int>(this->Targets.size());
-      this->TargetIndex[ti] = index;
-      this->Targets.push_back(ti);
+      this->TargetIndex[ti.get()] = index;
+      this->Targets.push_back(ti.get());
     }
   }
 }
@@ -219,7 +218,7 @@
               return;
             }
             const_cast<cmGeneratorTarget*>(depender)->Target->AddUtility(
-              objLib);
+              objLib, false);
           }
         }
       }
@@ -227,11 +226,12 @@
       cmLinkImplementation const* impl = depender->GetLinkImplementation(it);
 
       // A target should not depend on itself.
-      emitted.insert(cmLinkItem(depender, cmListFileBacktrace()));
+      emitted.insert(cmLinkItem(depender, false, cmListFileBacktrace()));
+      emitted.insert(cmLinkItem(depender, true, cmListFileBacktrace()));
       for (cmLinkImplItem const& lib : impl->Libraries) {
         // Don't emit the same library twice for this target.
         if (emitted.insert(lib).second) {
-          this->AddTargetDepend(depender_index, lib, true);
+          this->AddTargetDepend(depender_index, lib, true, false);
           this->AddInterfaceDepends(depender_index, lib, it, emitted);
         }
       }
@@ -243,11 +243,12 @@
     std::set<cmLinkItem> const& tutils = depender->GetUtilityItems();
     std::set<cmLinkItem> emitted;
     // A target should not depend on itself.
-    emitted.insert(cmLinkItem(depender, cmListFileBacktrace()));
+    emitted.insert(cmLinkItem(depender, false, cmListFileBacktrace()));
+    emitted.insert(cmLinkItem(depender, true, cmListFileBacktrace()));
     for (cmLinkItem const& litem : tutils) {
       // Don't emit the same utility twice for this target.
       if (emitted.insert(litem).second) {
-        this->AddTargetDepend(depender_index, litem, false);
+        this->AddTargetDepend(depender_index, litem, false, litem.Cross);
       }
     }
   }
@@ -269,7 +270,7 @@
         // code in the project that caused this dependency to be added.
         cmLinkItem libBT = lib;
         libBT.Backtrace = dependee_backtrace;
-        this->AddTargetDepend(depender_index, libBT, true);
+        this->AddTargetDepend(depender_index, libBT, true, false);
         this->AddInterfaceDepends(depender_index, libBT, config, emitted);
       }
     }
@@ -292,7 +293,8 @@
 
   if (dependee) {
     // A target should not depend on itself.
-    emitted.insert(cmLinkItem(depender, cmListFileBacktrace()));
+    emitted.insert(cmLinkItem(depender, false, cmListFileBacktrace()));
+    emitted.insert(cmLinkItem(depender, true, cmListFileBacktrace()));
     this->AddInterfaceDepends(depender_index, dependee,
                               dependee_name.Backtrace, config, emitted);
   }
@@ -300,7 +302,7 @@
 
 void cmComputeTargetDepends::AddTargetDepend(int depender_index,
                                              cmLinkItem const& dependee_name,
-                                             bool linking)
+                                             bool linking, bool cross)
 {
   // Get the depender.
   cmGeneratorTarget const* depender = this->Targets[depender_index];
@@ -345,13 +347,13 @@
 
   if (dependee) {
     this->AddTargetDepend(depender_index, dependee, dependee_name.Backtrace,
-                          linking);
+                          linking, cross);
   }
 }
 
 void cmComputeTargetDepends::AddTargetDepend(
   int depender_index, cmGeneratorTarget const* dependee,
-  cmListFileBacktrace const& dependee_backtrace, bool linking)
+  cmListFileBacktrace const& dependee_backtrace, bool linking, bool cross)
 {
   if (dependee->IsImported() ||
       dependee->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
@@ -361,7 +363,7 @@
     for (cmLinkItem const& i : utils) {
       if (cmGeneratorTarget const* transitive_dependee = i.Target) {
         this->AddTargetDepend(depender_index, transitive_dependee, i.Backtrace,
-                              false);
+                              false, i.Cross);
       }
     }
   } else {
@@ -373,7 +375,7 @@
 
     // Add this entry to the dependency graph.
     this->InitialGraph[depender_index].emplace_back(dependee_index, !linking,
-                                                    dependee_backtrace);
+                                                    cross, dependee_backtrace);
   }
 }
 
@@ -507,7 +509,8 @@
     for (cmGraphEdge const& edge : el) {
       int j = edge;
       if (cmap[j] == c && edge.IsStrong()) {
-        this->FinalGraph[i].emplace_back(j, true, edge.GetBacktrace());
+        this->FinalGraph[i].emplace_back(j, true, edge.IsCross(),
+                                         edge.GetBacktrace());
         if (!this->IntraComponent(cmap, c, j, head, emitted, visited)) {
           return false;
         }
@@ -516,7 +519,8 @@
 
     // Prepend to a linear linked-list of intra-component edges.
     if (*head >= 0) {
-      this->FinalGraph[i].emplace_back(*head, false, cmListFileBacktrace());
+      this->FinalGraph[i].emplace_back(*head, false, false,
+                                       cmListFileBacktrace());
     } else {
       this->ComponentTail[c] = i;
     }
@@ -566,7 +570,8 @@
       int dependee_component = ni;
       int dependee_component_head = this->ComponentHead[dependee_component];
       this->FinalGraph[depender_component_tail].emplace_back(
-        dependee_component_head, ni.IsStrong(), ni.GetBacktrace());
+        dependee_component_head, ni.IsStrong(), ni.IsCross(),
+        ni.GetBacktrace());
     }
   }
   return true;
diff --git a/Source/cmComputeTargetDepends.h b/Source/cmComputeTargetDepends.h
index d8060ae..e0d625f 100644
--- a/Source/cmComputeTargetDepends.h
+++ b/Source/cmComputeTargetDepends.h
@@ -46,10 +46,10 @@
   void CollectDepends();
   void CollectTargetDepends(int depender_index);
   void AddTargetDepend(int depender_index, cmLinkItem const& dependee_name,
-                       bool linking);
+                       bool linking, bool cross);
   void AddTargetDepend(int depender_index, cmGeneratorTarget const* dependee,
                        cmListFileBacktrace const& dependee_backtrace,
-                       bool linking);
+                       bool linking, bool cross);
   bool ComputeFinalDepends(cmComputeComponentGraph const& ccg);
   void AddInterfaceDepends(int depender_index, cmLinkItem const& dependee_name,
                            const std::string& config,
diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx
index 003e60d..fda687f 100644
--- a/Source/cmConditionEvaluator.cxx
+++ b/Source/cmConditionEvaluator.cxx
@@ -9,6 +9,8 @@
 #include <sstream>
 #include <utility>
 
+#include <cmext/algorithm>
+
 #include "cmsys/RegularExpression.hxx"
 
 #include "cmAlgorithms.h"
@@ -396,7 +398,7 @@
         // copy to the list structure
         auto argP1 = arg;
         argP1++;
-        cmAppend(newArgs2, argP1, argClose);
+        cm::append(newArgs2, argP1, argClose);
         newArgs2.pop_back();
         // now recursively invoke IsTrue to handle the values inside the
         // parenthetical expression
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index 5711cae..da04396 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -51,6 +51,8 @@
 static std::string const kCMAKE_OSX_DEPLOYMENT_TARGET =
   "CMAKE_OSX_DEPLOYMENT_TARGET";
 static std::string const kCMAKE_OSX_SYSROOT = "CMAKE_OSX_SYSROOT";
+static std::string const kCMAKE_APPLE_ARCH_SYSROOTS =
+  "CMAKE_APPLE_ARCH_SYSROOTS";
 static std::string const kCMAKE_POSITION_INDEPENDENT_CODE =
   "CMAKE_POSITION_INDEPENDENT_CODE";
 static std::string const kCMAKE_SYSROOT = "CMAKE_SYSROOT";
@@ -723,6 +725,7 @@
       vars.insert(kCMAKE_OSX_ARCHITECTURES);
       vars.insert(kCMAKE_OSX_DEPLOYMENT_TARGET);
       vars.insert(kCMAKE_OSX_SYSROOT);
+      vars.insert(kCMAKE_APPLE_ARCH_SYSROOTS);
       vars.insert(kCMAKE_POSITION_INDEPENDENT_CODE);
       vars.insert(kCMAKE_SYSROOT);
       vars.insert(kCMAKE_SYSROOT_COMPILE);
@@ -1042,7 +1045,9 @@
       if (deletedFiles.insert(fileName).second) {
         std::string const fullPath =
           std::string(binDir).append("/").append(fileName);
-        if (cmSystemTools::FileIsDirectory(fullPath)) {
+        if (cmSystemTools::FileIsSymlink(fullPath)) {
+          cmSystemTools::RemoveFile(fullPath);
+        } else if (cmSystemTools::FileIsDirectory(fullPath)) {
           this->CleanupFiles(fullPath);
           cmSystemTools::RemoveADirectory(fullPath);
         } else {
diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx
index 09d269b..0dd8722 100644
--- a/Source/cmCustomCommand.cxx
+++ b/Source/cmCustomCommand.cxx
@@ -4,27 +4,23 @@
 
 #include <utility>
 
-#include "cmAlgorithms.h"
-#include "cmMakefile.h"
+#include <cmext/algorithm>
 
-cmCustomCommand::cmCustomCommand(cmMakefile const* mf,
-                                 std::vector<std::string> outputs,
+cmCustomCommand::cmCustomCommand(std::vector<std::string> outputs,
                                  std::vector<std::string> byproducts,
                                  std::vector<std::string> depends,
                                  cmCustomCommandLines commandLines,
-                                 const char* comment,
+                                 cmListFileBacktrace lfbt, const char* comment,
                                  const char* workingDirectory)
   : Outputs(std::move(outputs))
   , Byproducts(std::move(byproducts))
   , Depends(std::move(depends))
   , CommandLines(std::move(commandLines))
+  , Backtrace(std::move(lfbt))
   , Comment(comment ? comment : "")
   , WorkingDirectory(workingDirectory ? workingDirectory : "")
   , HaveComment(comment != nullptr)
 {
-  if (mf) {
-    this->Backtrace = mf->GetBacktrace();
-  }
 }
 
 const std::vector<std::string>& cmCustomCommand::GetOutputs() const
@@ -55,12 +51,12 @@
 
 void cmCustomCommand::AppendCommands(const cmCustomCommandLines& commandLines)
 {
-  cmAppend(this->CommandLines, commandLines);
+  cm::append(this->CommandLines, commandLines);
 }
 
 void cmCustomCommand::AppendDepends(const std::vector<std::string>& depends)
 {
-  cmAppend(this->Depends, depends);
+  cm::append(this->Depends, depends);
 }
 
 bool cmCustomCommand::GetEscapeOldStyle() const
@@ -100,7 +96,7 @@
 
 void cmCustomCommand::AppendImplicitDepends(cmImplicitDependsList const& l)
 {
-  cmAppend(this->ImplicitDepends, l);
+  cm::append(this->ImplicitDepends, l);
 }
 
 bool cmCustomCommand::GetUsesTerminal() const
diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h
index 4689ace..d300fa5 100644
--- a/Source/cmCustomCommand.h
+++ b/Source/cmCustomCommand.h
@@ -12,8 +12,6 @@
 #include "cmCustomCommandLines.h"
 #include "cmListFileCache.h"
 
-class cmMakefile;
-
 class cmImplicitDependsList
   : public std::vector<std::pair<std::string, std::string>>
 {
@@ -28,11 +26,11 @@
 {
 public:
   /** Main constructor specifies all information for the command.  */
-  cmCustomCommand(cmMakefile const* mf, std::vector<std::string> outputs,
+  cmCustomCommand(std::vector<std::string> outputs,
                   std::vector<std::string> byproducts,
                   std::vector<std::string> depends,
-                  cmCustomCommandLines commandLines, const char* comment,
-                  const char* workingDirectory);
+                  cmCustomCommandLines commandLines, cmListFileBacktrace lfbt,
+                  const char* comment, const char* workingDirectory);
 
   /** Get the output file produced by the command.  */
   const std::vector<std::string>& GetOutputs() const;
diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx
index c1f412d..2432d2b 100644
--- a/Source/cmCustomCommandGenerator.cxx
+++ b/Source/cmCustomCommandGenerator.cxx
@@ -6,7 +6,8 @@
 #include <memory>
 #include <utility>
 
-#include "cmAlgorithms.h"
+#include <cmext/algorithm>
+
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
 #include "cmGeneratorExpression.h"
@@ -29,10 +30,11 @@
     for (std::string& it : result) {
       cmSystemTools::ConvertToUnixSlashes(it);
       if (cmSystemTools::FileIsFullPath(it)) {
-        it = cmSystemTools::CollapseFullPath(it);
+        it = cmSystemTools::CollapseFullPath(
+          it, lg->GetMakefile()->GetHomeOutputDirectory());
       }
     }
-    cmAppend(output, result);
+    cm::append(output, result);
   }
 }
 }
@@ -56,7 +58,7 @@
       std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(clarg);
       std::string parsed_arg = cge->Evaluate(this->LG, this->Config);
       if (this->CC.GetCommandExpandLists()) {
-        cmAppend(argv, cmExpandedList(parsed_arg));
+        cm::append(argv, cmExpandedList(parsed_arg));
       } else {
         argv.push_back(std::move(parsed_arg));
       }
@@ -137,7 +139,7 @@
       (target->IsImported() ||
        target->GetProperty("CROSSCOMPILING_EMULATOR") ||
        !this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING"))) {
-    return target->GetLocation(this->Config);
+    return target->GetLocation(this->Config).c_str();
   }
   return nullptr;
 }
@@ -201,7 +203,9 @@
       if (this->OldStyle) {
         cmd += escapeForShellOldStyle(emulator[j]);
       } else {
-        cmd += this->LG->EscapeForShell(emulator[j], this->MakeVars);
+        cmd +=
+          this->LG->EscapeForShell(emulator[j], this->MakeVars, false, false,
+                                   this->MakeVars && this->LG->IsNinjaMulti());
       }
     }
 
@@ -222,7 +226,9 @@
     if (this->OldStyle) {
       cmd += escapeForShellOldStyle(arg);
     } else {
-      cmd += this->LG->EscapeForShell(arg, this->MakeVars);
+      cmd +=
+        this->LG->EscapeForShell(arg, this->MakeVars, false, false,
+                                 this->MakeVars && this->LG->IsNinjaMulti());
     }
   }
 }
diff --git a/Source/cmDependsC.h b/Source/cmDependsC.h
index 3bb6e36..868c94a 100644
--- a/Source/cmDependsC.h
+++ b/Source/cmDependsC.h
@@ -7,12 +7,11 @@
 
 #include <iosfwd>
 #include <map>
+#include <queue>
 #include <set>
 #include <string>
 #include <vector>
 
-#include <queue>
-
 #include "cmsys/RegularExpression.hxx"
 
 #include "cmDepends.h"
diff --git a/Source/cmDocumentationSection.h b/Source/cmDocumentationSection.h
index 15cada6..641263d 100644
--- a/Source/cmDocumentationSection.h
+++ b/Source/cmDocumentationSection.h
@@ -8,7 +8,8 @@
 #include <string>
 #include <vector>
 
-#include "cmAlgorithms.h"
+#include <cmext/algorithm>
+
 #include "cmDocumentationEntry.h"
 
 // Low-level interface for custom documents:
@@ -47,7 +48,7 @@
   }
   void Append(const std::vector<cmDocumentationEntry>& entries)
   {
-    cmAppend(this->Entries, entries);
+    cm::append(this->Entries, entries);
   }
 
   /** Append an entry to this section using NULL terminated chars */
diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx
index 5976b2f..202b205 100644
--- a/Source/cmELF.cxx
+++ b/Source/cmELF.cxx
@@ -10,13 +10,12 @@
 #include <vector>
 
 #include <cm/memory>
+#include <cmext/algorithm>
 
 #include "cmsys/FStream.hxx"
 
 #include "cm_kwiml.h"
 
-#include "cmAlgorithms.h"
-
 // Include the ELF format information system header.
 #if defined(__OpenBSD__)
 #  include <elf_abi.h>
@@ -578,7 +577,7 @@
     }
 
     char* pdyn = reinterpret_cast<char*>(&dyn);
-    cmAppend(result, pdyn, pdyn + sizeof(ELF_Dyn));
+    cm::append(result, pdyn, pdyn + sizeof(ELF_Dyn));
   }
 
   return result;
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index 80e4bcd..5be5bce 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -9,11 +9,12 @@
 #include <memory>
 #include <vector>
 
+#include <cmext/algorithm>
+
 #include "cmsys/Process.h"
 
 #include "cm_static_string_view.hxx"
 
-#include "cmAlgorithms.h"
 #include "cmArgumentParser.h"
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
@@ -402,6 +403,6 @@
     --length;
   }
 #endif
-  cmAppend(output, data, data + length);
+  cm::append(output, data, data + length);
 }
 }
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index 7e9a987..d22bd48 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -8,6 +8,7 @@
 #include <sstream>
 #include <utility>
 
+#include "cmAlgorithms.h"
 #include "cmExportSet.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
@@ -300,11 +301,10 @@
   std::vector<std::string> exportFiles;
   std::string ns;
 
-  std::map<std::string, cmExportBuildFileGenerator*>& exportSets =
-    gg->GetBuildExportSets();
+  auto& exportSets = gg->GetBuildExportSets();
 
   for (auto const& exp : exportSets) {
-    const cmExportBuildFileGenerator* exportSet = exp.second;
+    const auto& exportSet = exp.second;
     std::vector<std::string> targets;
     exportSet->GetTargets(targets);
     if (cmContains(targets, name)) {
diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h
index 11fbd02..66e8cbb 100644
--- a/Source/cmExportBuildFileGenerator.h
+++ b/Source/cmExportBuildFileGenerator.h
@@ -10,7 +10,8 @@
 #include <utility>
 #include <vector>
 
-#include "cmAlgorithms.h"
+#include <cmext/algorithm>
+
 #include "cmExportFileGenerator.h"
 #include "cmStateTypes.h"
 
@@ -41,7 +42,7 @@
   void GetTargets(std::vector<std::string>& targets) const;
   void AppendTargets(std::vector<std::string> const& targets)
   {
-    cmAppend(this->Targets, targets);
+    cm::append(this->Targets, targets);
   }
   void SetExportSet(cmExportSet*);
 
diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx
index 2a6bf5d..e49c174 100644
--- a/Source/cmExportCommand.cxx
+++ b/Source/cmExportCommand.cxx
@@ -6,6 +6,8 @@
 #include <sstream>
 #include <utility>
 
+#include <cm/memory>
+
 #include "cmsys/RegularExpression.hxx"
 
 #include "cm_static_string_view.hxx"
@@ -182,11 +184,11 @@
   }
 
   // Setup export file generation.
-  cmExportBuildFileGenerator* ebfg = nullptr;
+  std::unique_ptr<cmExportBuildFileGenerator> ebfg = nullptr;
   if (android) {
-    ebfg = new cmExportBuildAndroidMKGenerator;
+    ebfg = cm::make_unique<cmExportBuildAndroidMKGenerator>();
   } else {
-    ebfg = new cmExportBuildFileGenerator;
+    ebfg = cm::make_unique<cmExportBuildFileGenerator>();
   }
   ebfg->SetExportFile(fname.c_str());
   ebfg->SetNamespace(arguments.Namespace);
@@ -196,7 +198,6 @@
   } else {
     ebfg->SetTargets(targets);
   }
-  mf.AddExportBuildFileGenerator(ebfg);
   ebfg->SetExportOld(arguments.ExportOld);
 
   // Compute the set of configurations exported.
@@ -209,10 +210,11 @@
     ebfg->AddConfiguration(ct);
   }
   if (exportSet != nullptr) {
-    gg->AddBuildExportExportSet(ebfg);
+    gg->AddBuildExportExportSet(ebfg.get());
   } else {
-    gg->AddBuildExportSet(ebfg);
+    gg->AddBuildExportSet(ebfg.get());
   }
+  mf.AddExportBuildFileGenerator(std::move(ebfg));
 
   return true;
 }
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index aeef602..6441e6f 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"
@@ -60,9 +61,9 @@
     cmSystemTools::GetFilenameLastExtension(this->MainImportFile);
 }
 
-const char* cmExportFileGenerator::GetMainExportFileName() const
+const std::string& cmExportFileGenerator::GetMainExportFileName() const
 {
-  return this->MainImportFile.c_str();
+  return this->MainImportFile;
 }
 
 bool cmExportFileGenerator::GenerateImportFile()
@@ -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 {
@@ -1062,6 +1066,12 @@
   if (target->IsCFBundleOnApple()) {
     os << "set_property(TARGET " << targetName << " PROPERTY BUNDLE 1)\n";
   }
+
+  // generate DEPRECATION
+  if (target->IsDeprecated()) {
+    os << "set_property(TARGET " << targetName << " PROPERTY DEPRECATION "
+       << cmExportFileGeneratorEscape(target->GetDeprecation()) << ")\n";
+  }
   os << "\n";
 }
 
diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h
index 0d69779..e9d0da7 100644
--- a/Source/cmExportFileGenerator.h
+++ b/Source/cmExportFileGenerator.h
@@ -46,7 +46,7 @@
 
   /** Set the full path to the export file to generate.  */
   void SetExportFile(const char* mainFile);
-  const char* GetMainExportFileName() const;
+  const std::string& GetMainExportFileName() const;
 
   /** Set the namespace in which to place exported target names.  */
   void SetNamespace(const std::string& ns) { this->Namespace = ns; }
diff --git a/Source/cmExportInstallAndroidMKGenerator.cxx b/Source/cmExportInstallAndroidMKGenerator.cxx
index 2d732c1..9702e0e 100644
--- a/Source/cmExportInstallAndroidMKGenerator.cxx
+++ b/Source/cmExportInstallAndroidMKGenerator.cxx
@@ -49,7 +49,7 @@
     if (te->ArchiveGenerator) {
       dest = te->ArchiveGenerator->GetDestination("");
     }
-    te->Target->Target->SetProperty("__dest", dest.c_str());
+    te->Target->Target->SetProperty("__dest", dest);
   }
 }
 
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index 6d29c99..987ec9e 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -258,15 +258,7 @@
 
 void cmExportInstallFileGenerator::ReplaceInstallPrefix(std::string& input)
 {
-  std::string::size_type pos = 0;
-  std::string::size_type lastPos = pos;
-
-  while ((pos = input.find("$<INSTALL_PREFIX>", lastPos)) !=
-         std::string::npos) {
-    std::string::size_type endPos = pos + sizeof("$<INSTALL_PREFIX>") - 1;
-    input.replace(pos, endPos - pos, "${_IMPORT_PREFIX}");
-    lastPos = endPos;
-  }
+  cmGeneratorExpression::ReplaceInstallPrefix(input, "${_IMPORT_PREFIX}");
 }
 
 bool cmExportInstallFileGenerator::GenerateImportFileConfig(
@@ -525,13 +517,14 @@
 }
 
 std::string cmExportInstallFileGenerator::InstallNameDir(
-  cmGeneratorTarget* target, const std::string& /*config*/)
+  cmGeneratorTarget* target, const std::string& config)
 {
   std::string install_name_dir;
 
   cmMakefile* mf = target->Target->GetMakefile();
   if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
-    install_name_dir = target->GetInstallNameDirForInstallTree();
+    install_name_dir =
+      target->GetInstallNameDirForInstallTree(config, "${_IMPORT_PREFIX}");
   }
 
   return install_name_dir;
diff --git a/Source/cmExportLibraryDependenciesCommand.cxx b/Source/cmExportLibraryDependenciesCommand.cxx
index 89093e9..6011ba4 100644
--- a/Source/cmExportLibraryDependenciesCommand.cxx
+++ b/Source/cmExportLibraryDependenciesCommand.cxx
@@ -12,6 +12,7 @@
 #include "cmExecutionStatus.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
@@ -20,6 +21,8 @@
 #include "cmTargetLinkLibraryType.h"
 #include "cmake.h"
 
+class cmListFileBacktrace;
+
 static void FinalAction(cmMakefile& makefile, std::string const& filename,
                         bool append)
 {
@@ -46,11 +49,11 @@
   // the project.
   cmake* cm = makefile.GetCMakeInstance();
   cmGlobalGenerator* global = cm->GetGlobalGenerator();
-  const std::vector<cmMakefile*>& locals = global->GetMakefiles();
+  const auto& locals = global->GetMakefiles();
   std::map<std::string, std::string> libDepsOld;
   std::map<std::string, std::string> libDepsNew;
   std::map<std::string, std::string> libTypes;
-  for (cmMakefile* local : locals) {
+  for (const auto& local : locals) {
     for (auto const& tgt : local->GetTargets()) {
       // Get the current target.
       cmTarget const& target = tgt.second;
@@ -150,9 +153,9 @@
 
   std::string const& filename = args[0];
   bool const append = args.size() > 1 && args[1] == "APPEND";
-  status.GetMakefile().AddFinalAction(
-    [filename, append](cmMakefile& makefile) {
-      FinalAction(makefile, filename, append);
+  status.GetMakefile().AddGeneratorAction(
+    [filename, append](cmLocalGenerator& lg, const cmListFileBacktrace&) {
+      FinalAction(*lg.GetMakefile(), filename, append);
     });
 
   return true;
diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx
index fafa51b..3df6a5c 100644
--- a/Source/cmExportTryCompileFileGenerator.cxx
+++ b/Source/cmExportTryCompileFileGenerator.cxx
@@ -70,7 +70,8 @@
   std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
 
   cmTarget dummyHead("try_compile_dummy_exe", cmStateEnums::EXECUTABLE,
-                     cmTarget::VisibilityNormal, tgt->Target->GetMakefile());
+                     cmTarget::VisibilityNormal, tgt->Target->GetMakefile(),
+                     true);
 
   cmGeneratorTarget gDummyHead(&dummyHead, tgt->GetLocalGenerator());
 
diff --git a/Source/cmExternalMakefileProjectGenerator.h b/Source/cmExternalMakefileProjectGenerator.h
index a472a06..2b8d505 100644
--- a/Source/cmExternalMakefileProjectGenerator.h
+++ b/Source/cmExternalMakefileProjectGenerator.h
@@ -5,6 +5,7 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -78,7 +79,7 @@
   std::vector<std::string> GetSupportedGlobalGenerators() const;
   std::vector<std::string> Aliases;
 
-  virtual cmExternalMakefileProjectGenerator*
+  virtual std::unique_ptr<cmExternalMakefileProjectGenerator>
   CreateExternalMakefileProjectGenerator() const = 0;
 
   void AddSupportedGlobalGenerator(const std::string& base);
@@ -100,10 +101,10 @@
   {
   }
 
-  cmExternalMakefileProjectGenerator* CreateExternalMakefileProjectGenerator()
-    const override
+  std::unique_ptr<cmExternalMakefileProjectGenerator>
+  CreateExternalMakefileProjectGenerator() const override
   {
-    T* p = new T;
+    std::unique_ptr<cmExternalMakefileProjectGenerator> p(new T);
     p->SetName(GetName());
     return p;
   }
diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx
index 5a5d959..b710467 100644
--- a/Source/cmExtraCodeBlocksGenerator.cxx
+++ b/Source/cmExtraCodeBlocksGenerator.cxx
@@ -3,10 +3,13 @@
 #include "cmExtraCodeBlocksGenerator.h"
 
 #include <map>
+#include <memory>
 #include <ostream>
 #include <set>
 #include <utility>
 
+#include <cmext/algorithm>
+
 #include "cmAlgorithms.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
@@ -209,7 +212,7 @@
     // Collect all files
     std::vector<std::string> listFiles;
     for (cmLocalGenerator* lg : it.second) {
-      cmAppend(listFiles, lg->GetMakefile()->GetListFiles());
+      cm::append(listFiles, lg->GetMakefile()->GetListFiles());
     }
 
     // Convert
@@ -283,8 +286,8 @@
   // add all executable and library targets and some of the GLOBAL
   // and UTILITY targets
   for (cmLocalGenerator* lg : lgs) {
-    const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
-    for (cmGeneratorTarget* target : targets) {
+    const auto& targets = lg->GetGeneratorTargets();
+    for (const auto& target : targets) {
       std::string targetName = target->GetName();
       switch (target->GetType()) {
         case cmStateEnums::GLOBAL_TARGET: {
@@ -315,7 +318,7 @@
         case cmStateEnums::SHARED_LIBRARY:
         case cmStateEnums::MODULE_LIBRARY:
         case cmStateEnums::OBJECT_LIBRARY: {
-          cmGeneratorTarget* gt = target;
+          cmGeneratorTarget* gt = target.get();
           this->AppendTarget(xml, targetName, gt, make, lg, compiler,
                              makeArgs);
           std::string fastTarget = cmStrCat(targetName, "/fast");
@@ -341,8 +344,8 @@
 
   for (cmLocalGenerator* lg : lgs) {
     cmMakefile* makefile = lg->GetMakefile();
-    const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
-    for (cmGeneratorTarget* target : targets) {
+    const auto& targets = lg->GetGeneratorTargets();
+    for (const auto& target : targets) {
       switch (target->GetType()) {
         case cmStateEnums::EXECUTABLE:
         case cmStateEnums::STATIC_LIBRARY:
@@ -352,13 +355,12 @@
         case cmStateEnums::UTILITY: // can have sources since 2.6.3
         {
           std::vector<cmSourceFile*> sources;
-          cmGeneratorTarget* gt = target;
-          gt->GetSourceFiles(sources,
-                             makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+          target->GetSourceFiles(
+            sources, makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
           for (cmSourceFile* s : sources) {
             // don't add source files from UTILITY target which have the
             // GENERATED property set:
-            if (gt->GetType() == cmStateEnums::UTILITY &&
+            if (target->GetType() == cmStateEnums::UTILITY &&
                 s->GetIsGenerated()) {
               continue;
             }
@@ -391,7 +393,7 @@
             }
 
             CbpUnit& cbpUnit = allFiles[fullPath];
-            cbpUnit.Targets.push_back(target);
+            cbpUnit.Targets.push_back(target.get());
           }
         }
         default: // intended fallthrough
@@ -558,19 +560,19 @@
     {
       std::vector<std::string> includes;
       lg->GetIncludeDirectories(includes, target, "C", buildType);
-      cmAppend(allIncludeDirs, includes);
+      cm::append(allIncludeDirs, includes);
     }
 
     std::string systemIncludeDirs = makefile->GetSafeDefinition(
       "CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS");
     if (!systemIncludeDirs.empty()) {
-      cmAppend(allIncludeDirs, cmExpandedList(systemIncludeDirs));
+      cm::append(allIncludeDirs, cmExpandedList(systemIncludeDirs));
     }
 
     systemIncludeDirs = makefile->GetSafeDefinition(
       "CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS");
     if (!systemIncludeDirs.empty()) {
-      cmAppend(allIncludeDirs, cmExpandedList(systemIncludeDirs));
+      cm::append(allIncludeDirs, cmExpandedList(systemIncludeDirs));
     }
 
     auto end = cmRemoveDuplicates(allIncludeDirs);
diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx
index c7b7457..de40c77 100644
--- a/Source/cmExtraCodeLiteGenerator.cxx
+++ b/Source/cmExtraCodeLiteGenerator.cxx
@@ -4,6 +4,7 @@
 
 #include <cstring>
 #include <map>
+#include <memory>
 #include <set>
 #include <sstream>
 #include <utility>
@@ -116,10 +117,9 @@
 {
   std::vector<std::string> retval;
   // for each target in the workspace create a codelite project
-  const std::vector<cmLocalGenerator*>& lgs =
-    this->GlobalGenerator->GetLocalGenerators();
-  for (cmLocalGenerator* lg : lgs) {
-    for (cmGeneratorTarget* lt : lg->GetGeneratorTargets()) {
+  const auto& lgs = this->GlobalGenerator->GetLocalGenerators();
+  for (const auto& lg : lgs) {
+    for (const auto& lt : lg->GetGeneratorTargets()) {
       cmStateEnums::TargetType type = lt->GetType();
       std::string const& outputDir = lg->GetCurrentBinaryDirectory();
       std::string targetName = lt->GetName();
@@ -142,7 +142,7 @@
           xml->Attribute("Active", "No");
           xml->EndElement();
 
-          CreateNewProjectFile(lt, filename);
+          CreateNewProjectFile(lt.get(), filename);
           break;
         default:
           break;
@@ -269,9 +269,9 @@
 
   for (cmLocalGenerator* lg : lgs) {
     cmMakefile* makefile = lg->GetMakefile();
-    const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
-    for (cmGeneratorTarget* target : targets) {
-      projectType = CollectSourceFiles(makefile, target, cFiles, otherFiles);
+    for (const auto& target : lg->GetGeneratorTargets()) {
+      projectType =
+        CollectSourceFiles(makefile, target.get(), cFiles, otherFiles);
     }
   }
 
@@ -634,7 +634,10 @@
   if (generator == "NMake Makefiles" || generator == "Ninja") {
     ss << make;
   } else if (generator == "MinGW Makefiles" || generator == "Unix Makefiles") {
-    ss << make << " -f$(ProjectPath)/Makefile -j " << this->CpuCount;
+    ss << make << " -f$(ProjectPath)/Makefile";
+    if (this->CpuCount > 0) {
+      ss << " -j " << this->CpuCount;
+    }
   }
   if (!targetName.empty()) {
     ss << " " << targetName;
diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx
index b286acf..78cabce 100644
--- a/Source/cmExtraEclipseCDT4Generator.cxx
+++ b/Source/cmExtraEclipseCDT4Generator.cxx
@@ -6,6 +6,7 @@
 #include <cassert>
 #include <cstdio>
 #include <map>
+#include <memory>
 #include <sstream>
 #include <utility>
 
@@ -98,7 +99,7 @@
 
 void cmExtraEclipseCDT4Generator::Generate()
 {
-  cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0];
+  const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0];
   const cmMakefile* mf = lg->GetMakefile();
 
   std::string eclipseVersion = mf->GetSafeDefinition("CMAKE_ECLIPSE_VERSION");
@@ -175,7 +176,7 @@
 
 void cmExtraEclipseCDT4Generator::CreateSettingsResourcePrefsFile()
 {
-  cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0];
+  const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0];
   cmMakefile* mf = lg->GetMakefile();
 
   const std::string filename =
@@ -198,7 +199,7 @@
   assert(this->HomeDirectory != this->HomeOutputDirectory);
 
   // set up the project name: <project>-Source@<baseSourcePathName>
-  cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0];
+  const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0];
   std::string name = cmExtraEclipseCDT4Generator::GenerateProjectName(
     lg->GetProjectName(), "Source",
     cmExtraEclipseCDT4Generator::GetPathBasename(this->HomeDirectory));
@@ -231,9 +232,9 @@
 
 void cmExtraEclipseCDT4Generator::AddEnvVar(std::ostream& out,
                                             const char* envVar,
-                                            cmLocalGenerator* lg)
+                                            cmLocalGenerator& lg)
 {
-  cmMakefile* mf = lg->GetMakefile();
+  cmMakefile* mf = lg.GetMakefile();
 
   // get the variables from the environment and from the cache and then
   // figure out which one to use:
@@ -243,7 +244,7 @@
 
   std::string cacheEntryName = cmStrCat("CMAKE_ECLIPSE_ENVVAR_", envVar);
   const std::string* cacheValue =
-    lg->GetState()->GetInitializedCacheValue(cacheEntryName);
+    lg.GetState()->GetInitializedCacheValue(cacheEntryName);
 
   // now we have both, decide which one to use
   std::string valueToUse;
@@ -256,7 +257,7 @@
     valueToUse = envVarValue;
     mf->AddCacheDefinition(cacheEntryName, valueToUse.c_str(),
                            cacheEntryName.c_str(), cmStateEnums::STRING, true);
-    mf->GetCMakeInstance()->SaveCache(lg->GetBinaryDirectory());
+    mf->GetCMakeInstance()->SaveCache(lg.GetBinaryDirectory());
   } else if (!envVarSet && cacheValue != nullptr) {
     // It is already in the cache, but not in the env, so use it from the cache
     valueToUse = *cacheValue;
@@ -272,7 +273,7 @@
       mf->AddCacheDefinition(cacheEntryName, valueToUse.c_str(),
                              cacheEntryName.c_str(), cmStateEnums::STRING,
                              true);
-      mf->GetCMakeInstance()->SaveCache(lg->GetBinaryDirectory());
+      mf->GetCMakeInstance()->SaveCache(lg.GetBinaryDirectory());
     }
   }
 
@@ -283,7 +284,7 @@
 
 void cmExtraEclipseCDT4Generator::CreateProjectFile()
 {
-  cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0];
+  const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0];
   cmMakefile* mf = lg->GetMakefile();
 
   const std::string filename = this->HomeOutputDirectory + "/.project";
@@ -350,15 +351,15 @@
   // set vsvars32.bat environment available at CMake time,
   //   but not necessarily when eclipse is open
   if (compilerId == "MSVC") {
-    AddEnvVar(environment, "PATH", lg);
-    AddEnvVar(environment, "INCLUDE", lg);
-    AddEnvVar(environment, "LIB", lg);
-    AddEnvVar(environment, "LIBPATH", lg);
+    AddEnvVar(environment, "PATH", *lg);
+    AddEnvVar(environment, "INCLUDE", *lg);
+    AddEnvVar(environment, "LIB", *lg);
+    AddEnvVar(environment, "LIBPATH", *lg);
   } else if (compilerId == "Intel") {
     // if the env.var is set, use this one and put it in the cache
     // if the env.var is not set, but the value is in the cache,
     // use it from the cache:
-    AddEnvVar(environment, "INTEL_LICENSE_FILE", lg);
+    AddEnvVar(environment, "INTEL_LICENSE_FILE", *lg);
   }
   AppendDictionary(xml, "org.eclipse.cdt.make.core.environment",
                    environment.str());
@@ -494,11 +495,11 @@
   cmExtraEclipseCDT4Generator::AppendLinkedResource(
     xml, linkName, "virtual:/virtual", VirtualFolder);
 
-  for (cmLocalGenerator* lg : this->GlobalGenerator->GetLocalGenerators()) {
+  for (const auto& lg : this->GlobalGenerator->GetLocalGenerators()) {
     cmMakefile* makefile = lg->GetMakefile();
-    const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
+    const auto& targets = lg->GetGeneratorTargets();
 
-    for (cmGeneratorTarget* target : targets) {
+    for (const auto& target : targets) {
       std::string linkName2 = cmStrCat(linkName, '/');
       switch (target->GetType()) {
         case cmStateEnums::EXECUTABLE:
@@ -519,10 +520,9 @@
           std::vector<cmSourceGroup> sourceGroups =
             makefile->GetSourceGroups();
           // get the files from the source lists then add them to the groups
-          cmGeneratorTarget* gt = const_cast<cmGeneratorTarget*>(target);
           std::vector<cmSourceFile*> files;
-          gt->GetSourceFiles(files,
-                             makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+          target->GetSourceFiles(
+            files, makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
           for (cmSourceFile* sf : files) {
             // Add the file to the list of sources.
             std::string const& source = sf->ResolveFullPath();
@@ -606,7 +606,7 @@
 {
   std::set<std::string> emmited;
 
-  cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0];
+  const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0];
   const cmMakefile* mf = lg->GetMakefile();
 
   const std::string filename = this->HomeOutputDirectory + "/.cproject";
@@ -752,7 +752,7 @@
 
   // add pre-processor definitions to allow eclipse to gray out sections
   emmited.clear();
-  for (cmLocalGenerator* lgen : this->GlobalGenerator->GetLocalGenerators()) {
+  for (const auto& lgen : this->GlobalGenerator->GetLocalGenerators()) {
 
     if (const char* cdefs =
           lgen->GetMakefile()->GetProperty("COMPILE_DEFINITIONS")) {
@@ -859,16 +859,15 @@
 
   // include dirs
   emmited.clear();
-  for (cmLocalGenerator* lgen : this->GlobalGenerator->GetLocalGenerators()) {
-    const std::vector<cmGeneratorTarget*>& targets =
-      lgen->GetGeneratorTargets();
-    for (cmGeneratorTarget* target : targets) {
+  for (const auto& lgen : this->GlobalGenerator->GetLocalGenerators()) {
+    const auto& targets = lgen->GetGeneratorTargets();
+    for (const auto& target : targets) {
       if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
         continue;
       }
       std::vector<std::string> includeDirs;
       std::string config = mf->GetSafeDefinition("CMAKE_BUILD_TYPE");
-      lgen->GetIncludeDirectories(includeDirs, target, "C", config);
+      lgen->GetIncludeDirectories(includeDirs, target.get(), "C", config);
       this->AppendIncludeDirectories(xml, includeDirs, emmited);
     }
   }
@@ -915,16 +914,15 @@
 
   // add all executable and library targets and some of the GLOBAL
   // and UTILITY targets
-  for (cmLocalGenerator* lgen : this->GlobalGenerator->GetLocalGenerators()) {
-    const std::vector<cmGeneratorTarget*>& targets =
-      lgen->GetGeneratorTargets();
+  for (const auto& lgen : this->GlobalGenerator->GetLocalGenerators()) {
+    const auto& targets = lgen->GetGeneratorTargets();
     std::string subdir = lgen->MaybeConvertToRelativePath(
       this->HomeOutputDirectory, lgen->GetCurrentBinaryDirectory());
     if (subdir == ".") {
       subdir.clear();
     }
 
-    for (cmGeneratorTarget* target : targets) {
+    for (const auto& target : targets) {
       std::string targetName = target->GetName();
       switch (target->GetType()) {
         case cmStateEnums::GLOBAL_TARGET: {
@@ -975,8 +973,7 @@
             std::string cleanArgs =
               cmStrCat("-E chdir \"", lgen->GetCurrentBinaryDirectory(),
                        "\" \"", cmSystemTools::GetCMakeCommand(), "\" -P \"");
-            cmGeneratorTarget* gt = target;
-            cleanArgs += lgen->GetTargetDirectory(gt);
+            cleanArgs += lgen->GetTargetDirectory(target.get());
             cleanArgs += "/cmake_clean.cmake\"";
             cmExtraEclipseCDT4Generator::AppendTarget(
               xml, "Clean", cmSystemTools::GetCMakeCommand(), cleanArgs,
diff --git a/Source/cmExtraEclipseCDT4Generator.h b/Source/cmExtraEclipseCDT4Generator.h
index ff4c59e..a7aa549 100644
--- a/Source/cmExtraEclipseCDT4Generator.h
+++ b/Source/cmExtraEclipseCDT4Generator.h
@@ -86,7 +86,7 @@
     std::set<std::string>& emittedDirs);
 
   static void AddEnvVar(std::ostream& out, const char* envVar,
-                        cmLocalGenerator* lg);
+                        cmLocalGenerator& lg);
 
   void WriteGroups(std::vector<cmSourceGroup> const& sourceGroups,
                    std::string& linkName, cmXMLWriter& xml);
diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx
index e8c9dd0..3a22846 100644
--- a/Source/cmExtraKateGenerator.cxx
+++ b/Source/cmExtraKateGenerator.cxx
@@ -3,6 +3,7 @@
 #include "cmExtraKateGenerator.h"
 
 #include <cstring>
+#include <memory>
 #include <ostream>
 #include <set>
 #include <vector>
@@ -40,21 +41,21 @@
 
 void cmExtraKateGenerator::Generate()
 {
-  cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0];
+  const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0];
   const cmMakefile* mf = lg->GetMakefile();
   this->ProjectName = this->GenerateProjectName(
     lg->GetProjectName(), mf->GetSafeDefinition("CMAKE_BUILD_TYPE"),
     this->GetPathBasename(lg->GetBinaryDirectory()));
   this->UseNinja = (this->GlobalGenerator->GetName() == "Ninja");
 
-  this->CreateKateProjectFile(lg);
-  this->CreateDummyKateProjectFile(lg);
+  this->CreateKateProjectFile(*lg);
+  this->CreateDummyKateProjectFile(*lg);
 }
 
 void cmExtraKateGenerator::CreateKateProjectFile(
-  const cmLocalGenerator* lg) const
+  const cmLocalGenerator& lg) const
 {
-  std::string filename = cmStrCat(lg->GetBinaryDirectory(), "/.kateproject");
+  std::string filename = cmStrCat(lg.GetBinaryDirectory(), "/.kateproject");
   cmGeneratedFileStream fout(filename);
   if (!fout) {
     return;
@@ -64,21 +65,21 @@
   fout <<
     "{\n"
     "\t\"name\": \"" << this->ProjectName << "\",\n"
-    "\t\"directory\": \"" << lg->GetSourceDirectory() << "\",\n"
+    "\t\"directory\": \"" << lg.GetSourceDirectory() << "\",\n"
     "\t\"files\": [ { " << this->GenerateFilesString(lg) << "} ],\n";
   /* clang-format on */
   this->WriteTargets(lg, fout);
   fout << "}\n";
 }
 
-void cmExtraKateGenerator::WriteTargets(const cmLocalGenerator* lg,
+void cmExtraKateGenerator::WriteTargets(const cmLocalGenerator& lg,
                                         cmGeneratedFileStream& fout) const
 {
-  cmMakefile const* mf = lg->GetMakefile();
+  cmMakefile const* mf = lg.GetMakefile();
   const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
   const std::string& makeArgs =
     mf->GetSafeDefinition("CMAKE_KATE_MAKE_ARGUMENTS");
-  std::string const& homeOutputDir = lg->GetBinaryDirectory();
+  std::string const& homeOutputDir = lg.GetBinaryDirectory();
 
   /* clang-format off */
   fout <<
@@ -109,14 +110,12 @@
 
   // add all executable and library targets and some of the GLOBAL
   // and UTILITY targets
-  for (cmLocalGenerator* localGen :
-       this->GlobalGenerator->GetLocalGenerators()) {
-    const std::vector<cmGeneratorTarget*>& targets =
-      localGen->GetGeneratorTargets();
+  for (const auto& localGen : this->GlobalGenerator->GetLocalGenerators()) {
+    const auto& targets = localGen->GetGeneratorTargets();
     std::string currentDir = localGen->GetCurrentBinaryDirectory();
     bool topLevel = (currentDir == localGen->GetBinaryDirectory());
 
-    for (cmGeneratorTarget* target : targets) {
+    for (const auto& target : targets) {
       std::string const& targetName = target->GetName();
       switch (target->GetType()) {
         case cmStateEnums::GLOBAL_TARGET: {
@@ -205,10 +204,10 @@
 }
 
 void cmExtraKateGenerator::CreateDummyKateProjectFile(
-  const cmLocalGenerator* lg) const
+  const cmLocalGenerator& lg) const
 {
   std::string filename =
-    cmStrCat(lg->GetBinaryDirectory(), '/', this->ProjectName, ".kateproject");
+    cmStrCat(lg.GetBinaryDirectory(), '/', this->ProjectName, ".kateproject");
   cmGeneratedFileStream fout(filename);
   if (!fout) {
     return;
@@ -219,26 +218,25 @@
 }
 
 std::string cmExtraKateGenerator::GenerateFilesString(
-  const cmLocalGenerator* lg) const
+  const cmLocalGenerator& lg) const
 {
-  std::string s = cmStrCat(lg->GetSourceDirectory(), "/.git");
+  std::string s = cmStrCat(lg.GetSourceDirectory(), "/.git");
   if (cmSystemTools::FileExists(s)) {
     return "\"git\": 1 ";
   }
 
-  s = cmStrCat(lg->GetSourceDirectory(), "/.svn");
+  s = cmStrCat(lg.GetSourceDirectory(), "/.svn");
   if (cmSystemTools::FileExists(s)) {
     return "\"svn\": 1 ";
   }
 
-  s = cmStrCat(lg->GetSourceDirectory(), '/');
+  s = cmStrCat(lg.GetSourceDirectory(), '/');
 
   std::set<std::string> files;
   std::string tmp;
-  const std::vector<cmLocalGenerator*>& lgs =
-    this->GlobalGenerator->GetLocalGenerators();
+  const auto& lgs = this->GlobalGenerator->GetLocalGenerators();
 
-  for (cmLocalGenerator* lgen : lgs) {
+  for (const auto& lgen : lgs) {
     cmMakefile* makefile = lgen->GetMakefile();
     const std::vector<std::string>& listFiles = makefile->GetListFiles();
     for (std::string const& listFile : listFiles) {
@@ -248,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/cmExtraKateGenerator.h b/Source/cmExtraKateGenerator.h
index be1376a..1fb81b4 100644
--- a/Source/cmExtraKateGenerator.h
+++ b/Source/cmExtraKateGenerator.h
@@ -25,16 +25,16 @@
   void Generate() override;
 
 private:
-  void CreateKateProjectFile(const cmLocalGenerator* lg) const;
-  void CreateDummyKateProjectFile(const cmLocalGenerator* lg) const;
-  void WriteTargets(const cmLocalGenerator* lg,
+  void CreateKateProjectFile(const cmLocalGenerator& lg) const;
+  void CreateDummyKateProjectFile(const cmLocalGenerator& lg) const;
+  void WriteTargets(const cmLocalGenerator& lg,
                     cmGeneratedFileStream& fout) const;
   void AppendTarget(cmGeneratedFileStream& fout, const std::string& target,
                     const std::string& make, const std::string& makeArgs,
                     const std::string& path,
                     const std::string& homeOutputDir) const;
 
-  std::string GenerateFilesString(const cmLocalGenerator* lg) const;
+  std::string GenerateFilesString(const cmLocalGenerator& lg) const;
   std::string GetPathBasename(const std::string& path) const;
   std::string GenerateProjectName(const std::string& name,
                                   const std::string& type,
diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx
index 495324c..413449c 100644
--- a/Source/cmExtraSublimeTextGenerator.cxx
+++ b/Source/cmExtraSublimeTextGenerator.cxx
@@ -3,6 +3,7 @@
 #include "cmExtraSublimeTextGenerator.h"
 
 #include <cstring>
+#include <memory>
 #include <set>
 #include <sstream>
 #include <utility>
@@ -182,8 +183,8 @@
   // and UTILITY targets
   for (cmLocalGenerator* lg : lgs) {
     cmMakefile* makefile = lg->GetMakefile();
-    const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
-    for (cmGeneratorTarget* target : targets) {
+    const auto& targets = lg->GetGeneratorTargets();
+    for (const auto& target : targets) {
       std::string targetName = target->GetName();
       switch (target->GetType()) {
         case cmStateEnums::GLOBAL_TARGET: {
@@ -216,11 +217,11 @@
         case cmStateEnums::SHARED_LIBRARY:
         case cmStateEnums::MODULE_LIBRARY:
         case cmStateEnums::OBJECT_LIBRARY: {
-          this->AppendTarget(fout, targetName, lg, target, make.c_str(),
+          this->AppendTarget(fout, targetName, lg, target.get(), make.c_str(),
                              makefile, compiler.c_str(), sourceFileFlags,
                              false);
           std::string fastTarget = cmStrCat(targetName, "/fast");
-          this->AppendTarget(fout, fastTarget, lg, target, make.c_str(),
+          this->AppendTarget(fout, fastTarget, lg, target.get(), make.c_str(),
                              makefile, compiler.c_str(), sourceFileFlags,
                              false);
         } break;
@@ -296,8 +297,7 @@
   fout << "\t{\n\t\t\t\"name\": \"" << lg->GetProjectName() << " - "
        << targetName << "\",\n";
   fout << "\t\t\t\"cmd\": ["
-       << this->BuildMakeCommand(make, makefileName.c_str(), targetName)
-       << "],\n";
+       << this->BuildMakeCommand(make, makefileName, targetName) << "],\n";
   fout << "\t\t\t\"working_dir\": \"${project_path}\",\n";
   fout << "\t\t\t\"file_regex\": \""
           "^(..[^:]*)(?::|\\\\()([0-9]+)(?::|\\\\))(?:([0-9]+):)?\\\\s*(.*)"
@@ -308,7 +308,8 @@
 // Create the command line for building the given target using the selected
 // make
 std::string cmExtraSublimeTextGenerator::BuildMakeCommand(
-  const std::string& make, const char* makefile, const std::string& target)
+  const std::string& make, const std::string& makefile,
+  const std::string& target)
 {
   std::string command = cmStrCat('"', make, '"');
   std::string generator = this->GlobalGenerator->GetName();
diff --git a/Source/cmExtraSublimeTextGenerator.h b/Source/cmExtraSublimeTextGenerator.h
index 7e8f2d4..078cfe7 100644
--- a/Source/cmExtraSublimeTextGenerator.h
+++ b/Source/cmExtraSublimeTextGenerator.h
@@ -44,7 +44,8 @@
   /** Returns the build command that needs to be executed to build the
    *  specified target.
    */
-  std::string BuildMakeCommand(const std::string& make, const char* makefile,
+  std::string BuildMakeCommand(const std::string& make,
+                               const std::string& makefile,
                                const std::string& target);
   /** Appends the specified target to the generated project file as a Sublime
    *  Text build system.
diff --git a/Source/cmFLTKWrapUICommand.cxx b/Source/cmFLTKWrapUICommand.cxx
index 11844e4..d88617a 100644
--- a/Source/cmFLTKWrapUICommand.cxx
+++ b/Source/cmFLTKWrapUICommand.cxx
@@ -6,15 +6,20 @@
 
 #include "cmCustomCommandLines.h"
 #include "cmExecutionStatus.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
 #include "cmMakefile.h"
+#include "cmMessageType.h"
 #include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmake.h"
 
 class cmTarget;
 
-static void FinalAction(cmMakefile& makefile, std::string const& name)
+static void FinalAction(cmMakefile& makefile, std::string const& name,
+                        const cmListFileBacktrace& lfbt)
 {
   // people should add the srcs to the target themselves, but the old command
   // didn't support that, so check and see if they added the files in and if
@@ -26,7 +31,8 @@
       ".  The problem was found while processing the source directory: ",
       makefile.GetCurrentSourceDirectory(),
       ".  This FLTK_WRAP_UI call will be ignored.");
-    cmSystemTools::Message(msg, "Warning");
+    makefile.GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_ERROR, msg,
+                                              lfbt);
   }
 }
 
@@ -116,7 +122,9 @@
   std::string const varName = target + "_FLTK_UI_SRCS";
   mf.AddDefinition(varName, sourceListValue);
 
-  mf.AddFinalAction(
-    [target](cmMakefile& makefile) { FinalAction(makefile, target); });
+  mf.AddGeneratorAction(
+    [target](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) {
+      FinalAction(*lg.GetMakefile(), target, lfbt);
+    });
   return true;
 }
diff --git a/Source/cmFileAPICMakeFiles.cxx b/Source/cmFileAPICMakeFiles.cxx
index f419997..44ba96c 100644
--- a/Source/cmFileAPICMakeFiles.cxx
+++ b/Source/cmFileAPICMakeFiles.cxx
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmFileAPICMakeFiles.h"
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -67,7 +68,7 @@
 
   cmGlobalGenerator* gg =
     this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
-  for (cmLocalGenerator const* lg : gg->GetLocalGenerators()) {
+  for (const auto& lg : gg->GetLocalGenerators()) {
     cmMakefile const* mf = lg->GetMakefile();
     for (std::string const& file : mf->GetListFiles()) {
       inputs.append(this->DumpInput(file));
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index d7993c7..955195f 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -15,9 +15,10 @@
 #include <utility>
 #include <vector>
 
+#include <cmext/algorithm>
+
 #include "cm_jsoncpp_value.h"
 
-#include "cmAlgorithms.h"
 #include "cmCryptoHash.h"
 #include "cmFileAPI.h"
 #include "cmGeneratorExpression.h"
@@ -426,7 +427,7 @@
   Json::Value configurations = Json::arrayValue;
   cmGlobalGenerator* gg =
     this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
-  auto makefiles = gg->GetMakefiles();
+  const auto& makefiles = gg->GetMakefiles();
   if (!makefiles.empty()) {
     std::vector<std::string> const& configs =
       makefiles[0]->GetGeneratorConfigs();
@@ -469,17 +470,17 @@
 {
   cmGlobalGenerator* gg =
     this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
-  std::vector<cmLocalGenerator*> const& localGens = gg->GetLocalGenerators();
+  auto const& localGens = gg->GetLocalGenerators();
 
   // Add directories in forward order to process parents before children.
   this->Directories.reserve(localGens.size());
-  for (cmLocalGenerator* lg : localGens) {
+  for (const auto& lg : localGens) {
     auto directoryIndex =
       static_cast<Json::ArrayIndex>(this->Directories.size());
     this->Directories.emplace_back();
     Directory& d = this->Directories[directoryIndex];
     d.Snapshot = lg->GetStateSnapshot().GetBuildsystemDirectory();
-    d.LocalGenerator = lg;
+    d.LocalGenerator = lg.get();
     this->DirectoryMap[d.Snapshot] = directoryIndex;
 
     d.ProjectIndex = this->AddProject(d.Snapshot);
@@ -492,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;
       }
@@ -554,8 +556,8 @@
   std::vector<cmGeneratorTarget*> targetList;
   cmGlobalGenerator* gg =
     this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
-  for (cmLocalGenerator const* lg : gg->GetLocalGenerators()) {
-    cmAppend(targetList, lg->GetGeneratorTargets());
+  for (const auto& lg : gg->GetLocalGenerators()) {
+    cm::append(targetList, lg->GetGeneratorTargets());
   }
   std::sort(targetList.begin(), targetList.end(),
             [](cmGeneratorTarget* l, cmGeneratorTarget* r) {
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index d45414f..79110ab 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -15,6 +15,7 @@
 #include <vector>
 
 #include <cm/memory>
+#include <cmext/algorithm>
 
 #include "cmsys/FStream.hxx"
 #include "cmsys/Glob.hxx"
@@ -783,7 +784,7 @@
       }
 
       std::vector<std::string>& foundFiles = g.GetFiles();
-      cmAppend(files, foundFiles);
+      cm::append(files, foundFiles);
 
       if (configureDepends) {
         std::sort(foundFiles.begin(), foundFiles.end());
@@ -1394,8 +1395,8 @@
 {
   int realsize = static_cast<int>(size * nmemb);
   const char* chPtr = static_cast<char*>(ptr);
-  cmAppend(*static_cast<cmFileCommandVectorOfChar*>(data), chPtr,
-           chPtr + realsize);
+  cm::append(*static_cast<cmFileCommandVectorOfChar*>(data), chPtr,
+             chPtr + realsize);
   return realsize;
 }
 
@@ -1408,7 +1409,7 @@
     case CURLINFO_TEXT:
     case CURLINFO_HEADER_IN:
     case CURLINFO_HEADER_OUT:
-      cmAppend(vec, chPtr, chPtr + size);
+      cm::append(vec, chPtr, chPtr + size);
       break;
     case CURLINFO_DATA_IN:
     case CURLINFO_DATA_OUT:
@@ -1418,7 +1419,7 @@
       int n = sprintf(buf, "[%" KWIML_INT_PRIu64 " bytes data]\n",
                       static_cast<KWIML_INT_uint64_t>(size));
       if (n > 0) {
-        cmAppend(vec, buf, buf + n);
+        cm::append(vec, buf, buf + n);
       }
     } break;
     default:
@@ -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.";
diff --git a/Source/cmFileLock.cxx b/Source/cmFileLock.cxx
index e90f571..6010233 100644
--- a/Source/cmFileLock.cxx
+++ b/Source/cmFileLock.cxx
@@ -3,11 +3,23 @@
 #include "cmFileLock.h"
 
 #include <cassert>
+#include <utility>
 
 #include "cmFileLockResult.h"
 
 // Common implementation
 
+cmFileLock::cmFileLock(cmFileLock&& other) noexcept
+{
+  this->File = other.File;
+#if defined(_WIN32)
+  other.File = INVALID_HANDLE_VALUE;
+#else
+  other.File = -1;
+#endif
+  this->Filename = std::move(other.Filename);
+}
+
 cmFileLock::~cmFileLock()
 {
   if (!this->Filename.empty()) {
@@ -17,6 +29,19 @@
   }
 }
 
+cmFileLock& cmFileLock::operator=(cmFileLock&& other) noexcept
+{
+  this->File = other.File;
+#if defined(_WIN32)
+  other.File = INVALID_HANDLE_VALUE;
+#else
+  other.File = -1;
+#endif
+  this->Filename = std::move(other.Filename);
+
+  return *this;
+}
+
 cmFileLockResult cmFileLock::Lock(const std::string& filename,
                                   unsigned long timeout)
 {
diff --git a/Source/cmFileLock.h b/Source/cmFileLock.h
index 2130d65..5fe068e 100644
--- a/Source/cmFileLock.h
+++ b/Source/cmFileLock.h
@@ -26,7 +26,9 @@
   ~cmFileLock();
 
   cmFileLock(cmFileLock const&) = delete;
+  cmFileLock(cmFileLock&&) noexcept;
   cmFileLock& operator=(cmFileLock const&) = delete;
+  cmFileLock& operator=(cmFileLock&&) noexcept;
 
   /**
    * @brief Lock the file.
diff --git a/Source/cmFileLockPool.cxx b/Source/cmFileLockPool.cxx
index 8db2db2..e1f6e94 100644
--- a/Source/cmFileLockPool.cxx
+++ b/Source/cmFileLockPool.cxx
@@ -3,40 +3,34 @@
 #include "cmFileLockPool.h"
 
 #include <cassert>
+#include <utility>
 
-#include "cmAlgorithms.h"
 #include "cmFileLock.h"
 #include "cmFileLockResult.h"
 
 cmFileLockPool::cmFileLockPool() = default;
 
-cmFileLockPool::~cmFileLockPool()
-{
-  cmDeleteAll(this->FunctionScopes);
-  cmDeleteAll(this->FileScopes);
-}
+cmFileLockPool::~cmFileLockPool() = default;
 
 void cmFileLockPool::PushFunctionScope()
 {
-  this->FunctionScopes.push_back(new ScopePool());
+  this->FunctionScopes.push_back(ScopePool());
 }
 
 void cmFileLockPool::PopFunctionScope()
 {
   assert(!this->FunctionScopes.empty());
-  delete this->FunctionScopes.back();
   this->FunctionScopes.pop_back();
 }
 
 void cmFileLockPool::PushFileScope()
 {
-  this->FileScopes.push_back(new ScopePool());
+  this->FileScopes.push_back(ScopePool());
 }
 
 void cmFileLockPool::PopFileScope()
 {
   assert(!this->FileScopes.empty());
-  delete this->FileScopes.back();
   this->FileScopes.pop_back();
 }
 
@@ -49,7 +43,7 @@
   if (this->FunctionScopes.empty()) {
     return cmFileLockResult::MakeNoFunction();
   }
-  return this->FunctionScopes.back()->Lock(filename, timeoutSec);
+  return this->FunctionScopes.back().Lock(filename, timeoutSec);
 }
 
 cmFileLockResult cmFileLockPool::LockFileScope(const std::string& filename,
@@ -59,7 +53,7 @@
     return cmFileLockResult::MakeAlreadyLocked();
   }
   assert(!this->FileScopes.empty());
-  return this->FileScopes.back()->Lock(filename, timeoutSec);
+  return this->FileScopes.back().Lock(filename, timeoutSec);
 }
 
 cmFileLockResult cmFileLockPool::LockProcessScope(const std::string& filename,
@@ -74,14 +68,14 @@
 cmFileLockResult cmFileLockPool::Release(const std::string& filename)
 {
   for (auto& funcScope : this->FunctionScopes) {
-    const cmFileLockResult result = funcScope->Release(filename);
+    const cmFileLockResult result = funcScope.Release(filename);
     if (!result.IsOk()) {
       return result;
     }
   }
 
   for (auto& fileScope : this->FileScopes) {
-    const cmFileLockResult result = fileScope->Release(filename);
+    const cmFileLockResult result = fileScope.Release(filename);
     if (!result.IsOk()) {
       return result;
     }
@@ -93,14 +87,14 @@
 bool cmFileLockPool::IsAlreadyLocked(const std::string& filename) const
 {
   for (auto const& funcScope : this->FunctionScopes) {
-    const bool result = funcScope->IsAlreadyLocked(filename);
+    const bool result = funcScope.IsAlreadyLocked(filename);
     if (result) {
       return true;
     }
   }
 
   for (auto const& fileScope : this->FileScopes) {
-    const bool result = fileScope->IsAlreadyLocked(filename);
+    const bool result = fileScope.IsAlreadyLocked(filename);
     if (result) {
       return true;
     }
@@ -111,21 +105,29 @@
 
 cmFileLockPool::ScopePool::ScopePool() = default;
 
-cmFileLockPool::ScopePool::~ScopePool()
+cmFileLockPool::ScopePool::~ScopePool() = default;
+
+cmFileLockPool::ScopePool::ScopePool(ScopePool&&) noexcept = default;
+
+cmFileLockPool::ScopePool& cmFileLockPool::ScopePool::operator=(
+  ScopePool&& other) noexcept
 {
-  cmDeleteAll(this->Locks);
+  if (this != &other) {
+    this->Locks = std::move(other.Locks);
+  }
+
+  return *this;
 }
 
 cmFileLockResult cmFileLockPool::ScopePool::Lock(const std::string& filename,
                                                  unsigned long timeoutSec)
 {
-  cmFileLock* lock = new cmFileLock();
-  const cmFileLockResult result = lock->Lock(filename, timeoutSec);
+  cmFileLock lock;
+  const cmFileLockResult result = lock.Lock(filename, timeoutSec);
   if (result.IsOk()) {
-    this->Locks.push_back(lock);
+    this->Locks.push_back(std::move(lock));
     return cmFileLockResult::MakeOk();
   }
-  delete lock;
   return result;
 }
 
@@ -133,8 +135,8 @@
   const std::string& filename)
 {
   for (auto& lock : this->Locks) {
-    if (lock->IsLocked(filename)) {
-      return lock->Release();
+    if (lock.IsLocked(filename)) {
+      return lock.Release();
     }
   }
   return cmFileLockResult::MakeOk();
@@ -144,7 +146,7 @@
   const std::string& filename) const
 {
   for (auto const& lock : this->Locks) {
-    if (lock->IsLocked(filename)) {
+    if (lock.IsLocked(filename)) {
       return true;
     }
   }
diff --git a/Source/cmFileLockPool.h b/Source/cmFileLockPool.h
index dae68dd..d45c82c 100644
--- a/Source/cmFileLockPool.h
+++ b/Source/cmFileLockPool.h
@@ -8,7 +8,8 @@
 #include <string>
 #include <vector>
 
-class cmFileLock;
+#include "cmFileLock.h"
+
 class cmFileLockResult;
 
 class cmFileLockPool
@@ -64,7 +65,9 @@
     ~ScopePool();
 
     ScopePool(ScopePool const&) = delete;
+    ScopePool(ScopePool&&) noexcept;
     ScopePool& operator=(ScopePool const&) = delete;
+    ScopePool& operator=(ScopePool&&) noexcept;
 
     cmFileLockResult Lock(const std::string& filename,
                           unsigned long timeoutSec);
@@ -72,17 +75,12 @@
     bool IsAlreadyLocked(const std::string& filename) const;
 
   private:
-    using List = std::vector<cmFileLock*>;
-    using It = List::iterator;
-    using CIt = List::const_iterator;
+    using List = std::vector<cmFileLock>;
 
     List Locks;
   };
 
-  using List = std::vector<ScopePool*>;
-
-  using It = List::iterator;
-  using CIt = List::const_iterator;
+  using List = std::vector<ScopePool>;
 
   List FunctionScopes;
   List FileScopes;
diff --git a/Source/cmFileMonitor.cxx b/Source/cmFileMonitor.cxx
index ac8a37e..8cfdb2d 100644
--- a/Source/cmFileMonitor.cxx
+++ b/Source/cmFileMonitor.cxx
@@ -7,9 +7,9 @@
 #include <unordered_map>
 #include <utility>
 
-#include "cmsys/SystemTools.hxx"
+#include <cm/memory>
 
-#include "cmAlgorithms.h"
+#include "cmsys/SystemTools.hxx"
 
 namespace {
 void on_directory_change(uv_fs_event_t* handle, const char* filename,
@@ -37,12 +37,12 @@
 class cmVirtualDirectoryWatcher : public cmIBaseWatcher
 {
 public:
-  ~cmVirtualDirectoryWatcher() override { cmDeleteAll(this->Children); }
+  ~cmVirtualDirectoryWatcher() override = default;
 
   cmIBaseWatcher* Find(const std::string& ps)
   {
     const auto i = this->Children.find(ps);
-    return (i == this->Children.end()) ? nullptr : i->second;
+    return (i == this->Children.end()) ? nullptr : i->second.get();
   }
 
   void Trigger(const std::string& pathSegment, int events,
@@ -96,11 +96,7 @@
     return result;
   }
 
-  void Reset()
-  {
-    cmDeleteAll(this->Children);
-    this->Children.clear();
-  }
+  void Reset() { this->Children.clear(); }
 
   void AddChildWatcher(const std::string& ps, cmIBaseWatcher* watcher)
   {
@@ -108,11 +104,12 @@
     assert(this->Children.find(ps) == this->Children.end());
     assert(watcher);
 
-    this->Children.emplace(std::make_pair(ps, watcher));
+    this->Children.emplace(ps, std::unique_ptr<cmIBaseWatcher>(watcher));
   }
 
 private:
-  std::unordered_map<std::string, cmIBaseWatcher*> Children; // owned!
+  std::unordered_map<std::string, std::unique_ptr<cmIBaseWatcher>>
+    Children; // owned!
 };
 
 // Root of all the different (on windows!) root directories:
@@ -295,14 +292,11 @@
 } // namespace
 
 cmFileMonitor::cmFileMonitor(uv_loop_t* l)
-  : Root(new cmRootWatcher(l))
+  : Root(cm::make_unique<cmRootWatcher>(l))
 {
 }
 
-cmFileMonitor::~cmFileMonitor()
-{
-  delete this->Root;
-}
+cmFileMonitor::~cmFileMonitor() = default;
 
 void cmFileMonitor::MonitorPaths(const std::vector<std::string>& paths,
                                  Callback const& cb)
@@ -316,7 +310,7 @@
     if (segmentCount < 2) { // Expect at least rootdir and filename
       continue;
     }
-    cmVirtualDirectoryWatcher* currentWatcher = this->Root;
+    cmVirtualDirectoryWatcher* currentWatcher = this->Root.get();
     for (size_t i = 0; i < segmentCount; ++i) {
       assert(currentWatcher);
 
@@ -334,11 +328,12 @@
       cmIBaseWatcher* nextWatcher = currentWatcher->Find(currentSegment);
       if (!nextWatcher) {
         if (rootSegment) { // Root part
-          assert(currentWatcher == this->Root);
-          nextWatcher = new cmRootDirectoryWatcher(this->Root, currentSegment);
+          assert(currentWatcher == this->Root.get());
+          nextWatcher =
+            new cmRootDirectoryWatcher(this->Root.get(), currentSegment);
           assert(currentWatcher->Find(currentSegment) == nextWatcher);
         } else if (fileSegment) { // File part
-          assert(currentWatcher != this->Root);
+          assert(currentWatcher != this->Root.get());
           nextWatcher = new cmFileWatcher(
             dynamic_cast<cmRealDirectoryWatcher*>(currentWatcher),
             currentSegment, cb);
diff --git a/Source/cmFileMonitor.h b/Source/cmFileMonitor.h
index 7ffc929..b510a2c 100644
--- a/Source/cmFileMonitor.h
+++ b/Source/cmFileMonitor.h
@@ -5,6 +5,7 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <functional>
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -30,5 +31,5 @@
   std::vector<std::string> WatchedDirectories() const;
 
 private:
-  cmRootWatcher* Root;
+  std::unique_ptr<cmRootWatcher> Root;
 };
diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx
index 7d74118..bec99bb 100644
--- a/Source/cmFindBase.cxx
+++ b/Source/cmFindBase.cxx
@@ -4,10 +4,11 @@
 
 #include <cstddef>
 #include <deque>
-#include <iostream>
 #include <map>
+#include <utility>
 
-#include "cmAlgorithms.h"
+#include <cmext/algorithm>
+
 #include "cmMakefile.h"
 #include "cmRange.h"
 #include "cmSearchPath.h"
@@ -116,17 +117,19 @@
       this->NoDefaultPath = true;
     } else if (this->CheckCommonArgument(args[j])) {
       doing = DoingNone;
+    } else {
       // Some common arguments were accidentally supported by CMake
       // 2.4 and 2.6.0 in the short-hand form of the command, so we
       // must support it even though it is not documented.
-    } else if (doing == DoingNames) {
-      this->Names.push_back(args[j]);
-    } else if (doing == DoingPaths) {
-      this->UserGuessArgs.push_back(args[j]);
-    } else if (doing == DoingHints) {
-      this->UserHintsArgs.push_back(args[j]);
-    } else if (doing == DoingPathSuffixes) {
-      this->AddPathSuffix(args[j]);
+      if (doing == DoingNames) {
+        this->Names.push_back(args[j]);
+      } else if (doing == DoingPaths) {
+        this->UserGuessArgs.push_back(args[j]);
+      } else if (doing == DoingHints) {
+        this->UserHintsArgs.push_back(args[j]);
+      } else if (doing == DoingPathSuffixes) {
+        this->AddPathSuffix(args[j]);
+      }
     }
   }
 
@@ -153,7 +156,7 @@
     std::vector<std::string> shortArgs = this->Names;
     this->Names.clear(); // clear out any values in Names
     this->Names.push_back(shortArgs[0]);
-    cmAppend(this->UserGuessArgs, shortArgs.begin() + 1, shortArgs.end());
+    cm::append(this->UserGuessArgs, shortArgs.begin() + 1, shortArgs.end());
   }
   this->ExpandPaths();
 
@@ -288,33 +291,6 @@
   paths.AddSuffixes(this->SearchPathSuffixes);
 }
 
-void cmFindBase::PrintFindStuff()
-{
-  std::cerr << "SearchFrameworkLast: " << this->SearchFrameworkLast << "\n";
-  std::cerr << "SearchFrameworkOnly: " << this->SearchFrameworkOnly << "\n";
-  std::cerr << "SearchFrameworkFirst: " << this->SearchFrameworkFirst << "\n";
-  std::cerr << "SearchAppBundleLast: " << this->SearchAppBundleLast << "\n";
-  std::cerr << "SearchAppBundleOnly: " << this->SearchAppBundleOnly << "\n";
-  std::cerr << "SearchAppBundleFirst: " << this->SearchAppBundleFirst << "\n";
-  std::cerr << "VariableName " << this->VariableName << "\n";
-  std::cerr << "VariableDocumentation " << this->VariableDocumentation << "\n";
-  std::cerr << "NoDefaultPath " << this->NoDefaultPath << "\n";
-  std::cerr << "NoCMakeEnvironmentPath " << this->NoCMakeEnvironmentPath
-            << "\n";
-  std::cerr << "NoCMakePath " << this->NoCMakePath << "\n";
-  std::cerr << "NoSystemEnvironmentPath " << this->NoSystemEnvironmentPath
-            << "\n";
-  std::cerr << "NoCMakeSystemPath " << this->NoCMakeSystemPath << "\n";
-  std::cerr << "EnvironmentPath " << this->EnvironmentPath << "\n";
-  std::cerr << "CMakePathName " << this->CMakePathName << "\n";
-  std::cerr << "Names  " << cmJoin(this->Names, " ") << "\n";
-  std::cerr << "\n";
-  std::cerr << "SearchPathSuffixes  ";
-  std::cerr << cmJoin(this->SearchPathSuffixes, "\n") << "\n";
-  std::cerr << "SearchPaths\n";
-  std::cerr << cmWrap("[", this->SearchPaths, "]", "\n") << "\n";
-}
-
 bool cmFindBase::CheckForVariableInCache()
 {
   if (const char* cacheValue =
@@ -343,3 +319,87 @@
   }
   return false;
 }
+
+cmFindBaseDebugState::cmFindBaseDebugState(std::string commandName,
+                                           cmFindBase const* findBase)
+  : FindCommand(findBase)
+  , CommandName(std::move(commandName))
+{
+}
+
+cmFindBaseDebugState::~cmFindBaseDebugState()
+{
+  if (this->FindCommand->DebugMode) {
+    std::string buffer =
+      cmStrCat(this->CommandName, " called with the following settings:\n");
+    buffer += cmStrCat("  VAR: ", this->FindCommand->VariableName, "\n");
+    buffer += cmStrCat(
+      "  NAMES: ", cmWrap("\"", this->FindCommand->Names, "\"", "\n         "),
+      "\n");
+    buffer += cmStrCat(
+      "  Documentation: ", this->FindCommand->VariableDocumentation, "\n");
+    buffer += "  Framework\n";
+    buffer += cmStrCat("    Only Search Frameworks: ",
+                       this->FindCommand->SearchFrameworkOnly, "\n");
+
+    buffer += cmStrCat("    Search Frameworks Last: ",
+                       this->FindCommand->SearchFrameworkLast, "\n");
+    buffer += cmStrCat("    Search Frameworks First: ",
+                       this->FindCommand->SearchFrameworkFirst, "\n");
+    buffer += "  AppBundle\n";
+    buffer += cmStrCat("    Only Search AppBundle: ",
+                       this->FindCommand->SearchAppBundleOnly, "\n");
+    buffer += cmStrCat("    Search AppBundle Last: ",
+                       this->FindCommand->SearchAppBundleLast, "\n");
+    buffer += cmStrCat("    Search AppBundle First: ",
+                       this->FindCommand->SearchAppBundleFirst, "\n");
+
+    if (this->FindCommand->NoDefaultPath) {
+      buffer += "  NO_DEFAULT_PATH Enabled\n";
+    } else {
+      buffer += cmStrCat(
+        "  CMAKE_FIND_USE_CMAKE_PATH: ", !this->FindCommand->NoCMakePath, "\n",
+        "  CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH: ",
+        !this->FindCommand->NoCMakeEnvironmentPath, "\n",
+        "  CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH: ",
+        !this->FindCommand->NoSystemEnvironmentPath, "\n",
+        "  CMAKE_FIND_USE_CMAKE_SYSTEM_PATH: ",
+        !this->FindCommand->NoCMakeSystemPath, "\n");
+    }
+
+    buffer +=
+      cmStrCat(this->CommandName, " considered the following locations:\n");
+    for (auto const& state : this->FailedSearchLocations) {
+      std::string path = cmStrCat("  ", state.path);
+      if (!state.regexName.empty()) {
+        path = cmStrCat(path, "/", state.regexName);
+      }
+      buffer += cmStrCat(path, "\n");
+    }
+
+    if (!this->FoundSearchLocation.path.empty()) {
+      buffer += cmStrCat("The item was found at\n  ",
+                         this->FoundSearchLocation.path, "\n");
+    } else {
+      buffer += "The item was not found.\n";
+    }
+
+    this->FindCommand->DebugMessage(buffer);
+  }
+}
+
+void cmFindBaseDebugState::FoundAt(std::string const& path,
+                                   std::string regexName)
+{
+  if (this->FindCommand->DebugMode) {
+    this->FoundSearchLocation = DebugLibState{ std::move(regexName), path };
+  }
+}
+
+void cmFindBaseDebugState::FailedAt(std::string const& path,
+                                    std::string regexName)
+{
+  if (this->FindCommand->DebugMode) {
+    this->FailedSearchLocations.emplace_back(std::move(regexName), path);
+  }
+}
diff --git a/Source/cmFindBase.h b/Source/cmFindBase.h
index f75db5f..fce0b11 100644
--- a/Source/cmFindBase.h
+++ b/Source/cmFindBase.h
@@ -6,6 +6,7 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "cmFindCommon.h"
@@ -31,7 +32,7 @@
   virtual bool ParseArguments(std::vector<std::string> const& args);
 
 protected:
-  void PrintFindStuff();
+  friend class cmFindBaseDebugState;
   void ExpandPaths();
 
   // see if the VariableName is already set in the cache,
@@ -63,4 +64,33 @@
   void FillUserGuessPath();
 };
 
+class cmFindBaseDebugState
+{
+public:
+  explicit cmFindBaseDebugState(std::string name, cmFindBase const* findBase);
+  ~cmFindBaseDebugState();
+
+  void FoundAt(std::string const& path, std::string regexName = std::string());
+  void FailedAt(std::string const& path,
+                std::string regexName = std::string());
+
+private:
+  struct DebugLibState
+  {
+    DebugLibState() = default;
+    DebugLibState(std::string&& n, std::string p)
+      : regexName(n)
+      , path(std::move(p))
+    {
+    }
+    std::string regexName;
+    std::string path;
+  };
+
+  cmFindBase const* FindCommand;
+  std::string CommandName;
+  std::vector<DebugLibState> FailedSearchLocations;
+  DebugLibState FoundSearchLocation;
+};
+
 #endif
diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx
index badec55..82acfed 100644
--- a/Source/cmFindCommon.cxx
+++ b/Source/cmFindCommon.cxx
@@ -7,11 +7,14 @@
 #include <cstring>
 #include <utility>
 
-#include "cmAlgorithms.h"
+#include <cmext/algorithm>
+
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
+#include "cmMessageType.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmake.h"
 
 cmFindCommon::PathGroup cmFindCommon::PathGroup::All("ALL");
 cmFindCommon::PathLabel cmFindCommon::PathLabel::PackageRoot(
@@ -52,6 +55,8 @@
   this->SearchAppBundleLast = false;
 
   this->InitializeSearchPathGroups();
+
+  this->DebugMode = false;
 }
 
 void cmFindCommon::SetError(std::string const& e)
@@ -59,6 +64,19 @@
   this->Status.SetError(e);
 }
 
+void cmFindCommon::DebugMessage(std::string const& msg) const
+{
+  if (this->Makefile) {
+    this->Makefile->IssueMessage(MessageType::LOG, msg);
+  }
+}
+
+bool cmFindCommon::ComputeIfDebugModeWanted()
+{
+  return this->Makefile->IsOn("CMAKE_FIND_DEBUG_MODE") ||
+    this->Makefile->GetCMakeInstance()->GetDebugFindOutput();
+}
+
 void cmFindCommon::InitializeSearchPathGroups()
 {
   std::vector<PathLabel>* labels;
@@ -249,7 +267,7 @@
   // If searching both rooted and unrooted paths add the original
   // paths again.
   if (this->FindRootPathMode == RootPathModeBoth) {
-    cmAppend(paths, unrootedPaths);
+    cm::append(paths, unrootedPaths);
   }
 }
 
diff --git a/Source/cmFindCommon.h b/Source/cmFindCommon.h
index 8177eac..916f3bc 100644
--- a/Source/cmFindCommon.h
+++ b/Source/cmFindCommon.h
@@ -30,8 +30,11 @@
 
   void SetError(std::string const& e);
 
+  bool DebugModeEnabled() const { return this->DebugMode; }
+
 protected:
   friend class cmSearchPath;
+  friend class cmFindBaseDebugState;
 
   /** Used to define groups of path labels */
   class PathGroup : public cmPathLabel
@@ -96,6 +99,10 @@
   /** Compute the current default search modes based on global variables.  */
   void SelectDefaultSearchModes();
 
+  /** The `InitialPass` functions of the child classes should set
+      this->DebugMode to the result of this.  */
+  bool ComputeIfDebugModeWanted();
+
   // Path arguments prior to path manipulation routines
   std::vector<std::string> UserHintsArgs;
   std::vector<std::string> UserGuessArgs;
@@ -106,6 +113,8 @@
   bool CheckCommonArgument(std::string const& arg);
   void AddPathSuffix(std::string const& arg);
 
+  void DebugMessage(std::string const& msg) const;
+  bool DebugMode;
   bool NoDefaultPath;
   bool NoPackageRootPath;
   bool NoCMakePath;
diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx
index 20221b1..d5a4bde 100644
--- a/Source/cmFindLibraryCommand.cxx
+++ b/Source/cmFindLibraryCommand.cxx
@@ -29,6 +29,7 @@
 // cmFindLibraryCommand
 bool cmFindLibraryCommand::InitialPass(std::vector<std::string> const& argsIn)
 {
+  this->DebugMode = ComputeIfDebugModeWanted();
   this->VariableDocumentation = "Path to a library.";
   this->CMakePathName = "LIBRARY";
   if (!this->ParseArguments(argsIn)) {
@@ -92,6 +93,13 @@
   original.swap(this->SearchPaths);
   for (std::string const& o : original) {
     this->AddArchitecturePath(o, 0, suffix);
+    if (this->DebugMode) {
+      std::string msg = cmStrCat(
+        "find_library(", this->VariableName, ") removed original suffix ", o,
+        " from PATH_SUFFIXES while adding architecture paths for suffix '",
+        suffix, "'");
+      this->DebugMessage(msg);
+    }
   }
 }
 
@@ -153,11 +161,23 @@
 
     if (use_dirX) {
       dirX += "/";
+      if (this->DebugMode) {
+        std::string msg = cmStrCat(
+          "find_library(", this->VariableName, ") added replacement path ",
+          dirX, " to PATH_SUFFIXES for architecture suffix '", suffix, "'");
+        this->DebugMessage(msg);
+      }
       this->SearchPaths.push_back(std::move(dirX));
     }
 
     if (use_dir) {
       this->SearchPaths.push_back(dir);
+      if (this->DebugMode) {
+        std::string msg = cmStrCat(
+          "find_library(", this->VariableName, ") added replacement path ",
+          dir, " to PATH_SUFFIXES for architecture suffix '", suffix, "'");
+        this->DebugMessage(msg);
+      }
     }
   }
 }
@@ -179,7 +199,7 @@
 
 struct cmFindLibraryHelper
 {
-  cmFindLibraryHelper(cmMakefile* mf);
+  cmFindLibraryHelper(cmMakefile* mf, cmFindBase const* findBase);
 
   // Context information.
   cmMakefile* Makefile;
@@ -198,6 +218,8 @@
   // Support for OpenBSD shared library naming: lib<name>.so.<major>.<minor>
   bool OpenBSD;
 
+  bool DebugMode;
+
   // Current names under consideration.
   struct Name
   {
@@ -227,10 +249,33 @@
   void SetName(std::string const& name);
   bool CheckDirectory(std::string const& path);
   bool CheckDirectoryForName(std::string const& path, Name& name);
+
+  cmFindBaseDebugState DebugSearches;
+
+  void DebugLibraryFailed(std::string const& name, std::string const& path)
+  {
+    if (this->DebugMode) {
+      auto regexName =
+        cmStrCat(this->PrefixRegexStr, name, this->SuffixRegexStr);
+      this->DebugSearches.FailedAt(path, regexName);
+    }
+  };
+
+  void DebugLibraryFound(std::string const& name, std::string const& path)
+  {
+    if (this->DebugMode) {
+      auto regexName =
+        cmStrCat(this->PrefixRegexStr, name, this->SuffixRegexStr);
+      this->DebugSearches.FoundAt(path, regexName);
+    }
+  };
 };
 
-cmFindLibraryHelper::cmFindLibraryHelper(cmMakefile* mf)
+cmFindLibraryHelper::cmFindLibraryHelper(cmMakefile* mf,
+                                         cmFindBase const* base)
   : Makefile(mf)
+  , DebugMode(base->DebugModeEnabled())
+  , DebugSearches("find_library", base)
 {
   this->GG = this->Makefile->GetGlobalGenerator();
 
@@ -350,7 +395,12 @@
   // library or an import library).
   if (name.TryRaw) {
     this->TestPath = cmStrCat(path, name.Raw);
-    if (cmSystemTools::FileExists(this->TestPath, true)) {
+
+    const bool exists = cmSystemTools::FileExists(this->TestPath, true);
+    if (!exists) {
+      this->DebugLibraryFailed(name.Raw, path);
+    } else {
+      this->DebugLibraryFound(name.Raw, path);
       this->BestPath = cmSystemTools::CollapseFullPath(this->TestPath);
       cmSystemTools::ConvertToUnixSlashes(this->BestPath);
       return true;
@@ -376,6 +426,8 @@
     if (name.Regex.find(testName)) {
       this->TestPath = cmStrCat(path, origName);
       if (!cmSystemTools::FileIsDirectory(this->TestPath)) {
+        this->DebugLibraryFound(name.Raw, dir);
+
         // This is a matching file.  Check if it is better than the
         // best name found so far.  Earlier prefixes are preferred,
         // followed by earlier suffixes.  For OpenBSD, shared library
@@ -402,6 +454,12 @@
     }
   }
 
+  if (this->BestPath.empty()) {
+    this->DebugLibraryFailed(name.Raw, dir);
+  } else {
+    this->DebugLibraryFound(name.Raw, this->BestPath);
+  }
+
   // Use the best candidate found in this directory, if any.
   return !this->BestPath.empty();
 }
@@ -417,7 +475,7 @@
 std::string cmFindLibraryCommand::FindNormalLibraryNamesPerDir()
 {
   // Search for all names in each directory.
-  cmFindLibraryHelper helper(this->Makefile);
+  cmFindLibraryHelper helper(this->Makefile, this);
   for (std::string const& n : this->Names) {
     helper.AddName(n);
   }
@@ -434,7 +492,7 @@
 std::string cmFindLibraryCommand::FindNormalLibraryDirsPerName()
 {
   // Search the entire path for each name.
-  cmFindLibraryHelper helper(this->Makefile);
+  cmFindLibraryHelper helper(this->Makefile, this);
   for (std::string const& n : this->Names) {
     // Switch to searching for this name.
     helper.SetName(n);
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index 2b11b62..297c72b 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -160,8 +160,8 @@
     this->RequiredCMakeVersion = CMake_VERSION_ENCODE(v[0], v[1], v[2]);
   }
 
-  // Check for debug mode.
-  this->DebugMode = this->Makefile->IsOn("CMAKE_FIND_DEBUG_MODE");
+  this->DebugMode = ComputeIfDebugModeWanted();
+  this->DebugBuffer.clear();
 
   // Lookup target architecture, if any.
   if (const char* arch =
@@ -576,6 +576,7 @@
   }
 
   this->AppendSuccessInformation();
+
   return loadedPackage;
 }
 
@@ -695,8 +696,23 @@
 bool cmFindPackageCommand::FindModule(bool& found)
 {
   std::string module = cmStrCat("Find", this->Name, ".cmake");
+
   bool system = false;
-  std::string mfile = this->Makefile->GetModulesFile(module, system);
+  std::string debugBuffer =
+    cmStrCat("find_package considered the following paths for ", this->Name,
+             ".cmake\n");
+  std::string mfile = this->Makefile->GetModulesFile(
+    module, system, this->DebugMode, debugBuffer);
+  if (this->DebugMode) {
+    if (mfile.empty()) {
+      debugBuffer = cmStrCat(debugBuffer, "The file was not found.");
+    } else {
+      debugBuffer =
+        cmStrCat(debugBuffer, "The file was found at\n  ", mfile, "\n");
+    }
+    this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+  }
+
   if (!mfile.empty()) {
     if (system) {
       auto it = this->DeprecatedFindModules.find(this->Name);
@@ -827,6 +843,11 @@
     result = false;
   }
 
+  if (this->DebugMode) {
+    this->DebugMessage(this->DebugBuffer);
+    this->DebugBuffer.clear();
+  }
+
   // package not found
   if (result && !found) {
     // warn if package required or neither quiet nor in config mode
@@ -987,6 +1008,11 @@
 
   // Look for the project's configuration file.
   bool found = false;
+  if (this->DebugMode) {
+    this->DebugBuffer = cmStrCat(this->DebugBuffer,
+                                 "find_package considered the following "
+                                 "locations for the Config module:\n");
+  }
 
   // Search for frameworks.
   if (!found && (this->SearchFrameworkFirst || this->SearchFrameworkOnly)) {
@@ -1013,6 +1039,16 @@
     found = this->FindAppBundleConfig();
   }
 
+  if (this->DebugMode) {
+    if (found) {
+      this->DebugBuffer = cmStrCat(
+        this->DebugBuffer, "The file was found at\n  ", this->FileFound, "\n");
+    } else {
+      this->DebugBuffer =
+        cmStrCat(this->DebugBuffer, "The file was not found.\n");
+    }
+  }
+
   // Store the entry in the cache so it can be set by the user.
   std::string init;
   if (found) {
@@ -1026,6 +1062,7 @@
   // We force the value since we do not get here if it was already set.
   this->Makefile->AddCacheDefinition(this->Variable, init.c_str(),
                                      help.c_str(), cmStateEnums::PATH, true);
+
   return found;
 }
 
@@ -1164,6 +1201,21 @@
   this->Makefile->FindPackageRootPathStack.pop_back();
 }
 
+inline std::size_t collectPathsForDebug(std::string& buffer,
+                                        cmSearchPath const& searchPath,
+                                        std::size_t startIndex = 0)
+{
+  const auto& paths = searchPath.GetPaths();
+  if (paths.empty()) {
+    buffer += "  none";
+    return 0;
+  }
+  for (std::size_t i = startIndex; i < paths.size(); i++) {
+    buffer += "  " + paths[i] + "\n";
+  }
+  return paths.size();
+}
+
 void cmFindPackageCommand::ComputePrefixes()
 {
   if (!this->NoDefaultPath) {
@@ -1177,7 +1229,9 @@
       this->FillPrefixesCMakeEnvironment();
     }
   }
+
   this->FillPrefixesUserHints();
+
   if (!this->NoDefaultPath) {
     if (!this->NoSystemEnvironmentPath) {
       this->FillPrefixesSystemEnvironment();
@@ -1209,29 +1263,72 @@
       paths.AddPath(path);
     }
   }
+  if (this->DebugMode) {
+    std::string debugBuffer = "<PackageName>_ROOT CMake variable "
+                              "[CMAKE_FIND_USE_PACKAGE_ROOT_PATH].\n";
+    collectPathsForDebug(debugBuffer, paths);
+    this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+  }
 }
 
 void cmFindPackageCommand::FillPrefixesCMakeEnvironment()
 {
   cmSearchPath& paths = this->LabeledPaths[PathLabel::CMakeEnvironment];
+  std::string debugBuffer;
+  std::size_t debugOffset = 0;
 
   // Check the environment variable with the same name as the cache
   // entry.
   paths.AddEnvPath(this->Variable);
+  if (this->DebugMode) {
+    debugBuffer = cmStrCat("Env variable ", this->Variable,
+                           " [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].\n");
+    debugOffset = collectPathsForDebug(debugBuffer, paths);
+  }
 
   // And now the general CMake environment variables
   paths.AddEnvPath("CMAKE_PREFIX_PATH");
+  if (this->DebugMode) {
+    debugBuffer = cmStrCat(debugBuffer,
+                           "\nCMAKE_PREFIX_PATH env variable "
+                           "[CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].\n");
+    debugOffset = collectPathsForDebug(debugBuffer, paths, debugOffset);
+  }
+
   paths.AddEnvPath("CMAKE_FRAMEWORK_PATH");
   paths.AddEnvPath("CMAKE_APPBUNDLE_PATH");
+  if (this->DebugMode) {
+    debugBuffer =
+      cmStrCat(debugBuffer,
+               "\nCMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH env "
+               "variables [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].\n");
+    collectPathsForDebug(debugBuffer, paths, debugOffset);
+    this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+  }
 }
 
 void cmFindPackageCommand::FillPrefixesCMakeVariable()
 {
   cmSearchPath& paths = this->LabeledPaths[PathLabel::CMake];
+  std::string debugBuffer;
+  std::size_t debugOffset = 0;
 
   paths.AddCMakePath("CMAKE_PREFIX_PATH");
+  if (this->DebugMode) {
+    debugBuffer = "CMAKE_PREFIX_PATH variable [CMAKE_FIND_USE_CMAKE_PATH].\n";
+    debugOffset = collectPathsForDebug(debugBuffer, paths);
+  }
+
   paths.AddCMakePath("CMAKE_FRAMEWORK_PATH");
   paths.AddCMakePath("CMAKE_APPBUNDLE_PATH");
+  if (this->DebugMode) {
+    debugBuffer =
+      cmStrCat(debugBuffer,
+               "\nCMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH variables "
+               "[CMAKE_FIND_USE_CMAKE_PATH].\n");
+    collectPathsForDebug(debugBuffer, paths, debugOffset);
+    this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+  }
 }
 
 void cmFindPackageCommand::FillPrefixesSystemEnvironment()
@@ -1251,6 +1348,12 @@
       paths.AddPath(i);
     }
   }
+  if (this->DebugMode) {
+    std::string debugBuffer = "Standard system environment variables "
+                              "[CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH].\n";
+    collectPathsForDebug(debugBuffer, paths);
+    this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+  }
 }
 
 void cmFindPackageCommand::FillPrefixesUserRegistry()
@@ -1274,6 +1377,13 @@
                                  this->LabeledPaths[PathLabel::UserRegistry]);
   }
 #endif
+  if (this->DebugMode) {
+    std::string debugBuffer =
+      "CMake User Package Registry [CMAKE_FIND_USE_PACKAGE_REGISTRY].\n";
+    collectPathsForDebug(debugBuffer,
+                         this->LabeledPaths[PathLabel::UserRegistry]);
+    this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+  }
 }
 
 void cmFindPackageCommand::FillPrefixesSystemRegistry()
@@ -1285,6 +1395,15 @@
 #if defined(_WIN32) && !defined(__CYGWIN__)
   this->LoadPackageRegistryWinSystem();
 #endif
+
+  if (this->DebugMode) {
+    std::string debugBuffer =
+      "CMake System Package Registry "
+      "[CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY].\n";
+    collectPathsForDebug(debugBuffer,
+                         this->LabeledPaths[PathLabel::SystemRegistry]);
+    this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+  }
 }
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
@@ -1457,6 +1576,13 @@
   paths.AddCMakePath("CMAKE_SYSTEM_PREFIX_PATH");
   paths.AddCMakePath("CMAKE_SYSTEM_FRAMEWORK_PATH");
   paths.AddCMakePath("CMAKE_SYSTEM_APPBUNDLE_PATH");
+
+  if (this->DebugMode) {
+    std::string debugBuffer = "CMake variables defined in the Platform file "
+                              "[CMAKE_FIND_USE_CMAKE_SYSTEM_PATH].\n";
+    collectPathsForDebug(debugBuffer, paths);
+    this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+  }
 }
 
 void cmFindPackageCommand::FillPrefixesUserGuess()
@@ -1466,6 +1592,12 @@
   for (std::string const& p : this->UserGuessArgs) {
     paths.AddUserPath(p);
   }
+  if (this->DebugMode) {
+    std::string debugBuffer =
+      "Paths specified by the find_package PATHS option.\n";
+    collectPathsForDebug(debugBuffer, paths);
+    this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+  }
 }
 
 void cmFindPackageCommand::FillPrefixesUserHints()
@@ -1475,6 +1607,12 @@
   for (std::string const& p : this->UserHintsArgs) {
     paths.AddUserPath(p);
   }
+  if (this->DebugMode) {
+    std::string debugBuffer =
+      "Paths specified by the find_package HINTS option.\n";
+    collectPathsForDebug(debugBuffer, paths);
+    this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n");
+  }
 }
 
 bool cmFindPackageCommand::SearchDirectory(std::string const& dir)
@@ -1519,7 +1657,7 @@
   for (std::string const& c : this->Configs) {
     file = cmStrCat(dir, '/', c);
     if (this->DebugMode) {
-      fprintf(stderr, "Checking file [%s]\n", file.c_str());
+      this->DebugBuffer = cmStrCat(this->DebugBuffer, "  ", file, "\n");
     }
     if (cmSystemTools::FileExists(file, true) && this->CheckVersion(file)) {
       // Allow resolving symlinks when the config file is found through a link
@@ -2032,9 +2170,6 @@
 bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in)
 {
   assert(!prefix_in.empty() && prefix_in.back() == '/');
-  if (this->DebugMode) {
-    fprintf(stderr, "Checking prefix [%s]\n", prefix_in.c_str());
-  }
 
   // Skip this if the prefix does not exist.
   if (!cmSystemTools::FileIsDirectory(prefix_in)) {
@@ -2188,9 +2323,6 @@
 bool cmFindPackageCommand::SearchFrameworkPrefix(std::string const& prefix_in)
 {
   assert(!prefix_in.empty() && prefix_in.back() == '/');
-  if (this->DebugMode) {
-    fprintf(stderr, "Checking framework prefix [%s]\n", prefix_in.c_str());
-  }
 
   // Strip the trailing slash because the path generator is about to
   // add one.
@@ -2249,9 +2381,6 @@
 bool cmFindPackageCommand::SearchAppBundlePrefix(std::string const& prefix_in)
 {
   assert(!prefix_in.empty() && prefix_in.back() == '/');
-  if (this->DebugMode) {
-    fprintf(stderr, "Checking bundle prefix [%s]\n", prefix_in.c_str());
-  }
 
   // Strip the trailing slash because the path generator is about to
   // add one.
diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h
index 85fe7b6..ae9ade7 100644
--- a/Source/cmFindPackageCommand.h
+++ b/Source/cmFindPackageCommand.h
@@ -174,7 +174,6 @@
   bool UseFindModules;
   bool NoUserRegistry;
   bool NoSystemRegistry;
-  bool DebugMode;
   bool UseLib32Paths;
   bool UseLib64Paths;
   bool UseLibx32Paths;
@@ -184,6 +183,7 @@
   std::vector<std::string> Names;
   std::vector<std::string> Configs;
   std::set<std::string> IgnoredPaths;
+  std::string DebugBuffer;
 
   /*! the selected sortOrder (None by default)*/
   SortOrderType SortOrder;
diff --git a/Source/cmFindPathCommand.cxx b/Source/cmFindPathCommand.cxx
index f5e2631..908f0c1 100644
--- a/Source/cmFindPathCommand.cxx
+++ b/Source/cmFindPathCommand.cxx
@@ -21,6 +21,7 @@
 // cmFindPathCommand
 bool cmFindPathCommand::InitialPass(std::vector<std::string> const& argsIn)
 {
+  this->DebugMode = ComputeIfDebugModeWanted();
   this->VariableDocumentation = "Path to a file.";
   this->CMakePathName = "INCLUDE";
   if (!this->ParseArguments(argsIn)) {
@@ -55,16 +56,19 @@
 
 std::string cmFindPathCommand::FindHeader()
 {
+  std::string debug_name = this->IncludeFileInPath ? "find_file" : "find_path";
+  cmFindBaseDebugState debug(debug_name, this);
   std::string header;
   if (this->SearchFrameworkFirst || this->SearchFrameworkOnly) {
-    header = this->FindFrameworkHeader();
+    header = this->FindFrameworkHeader(debug);
   }
   if (header.empty() && !this->SearchFrameworkOnly) {
-    header = this->FindNormalHeader();
+    header = this->FindNormalHeader(debug);
   }
   if (header.empty() && this->SearchFrameworkLast) {
-    header = this->FindFrameworkHeader();
+    header = this->FindFrameworkHeader(debug);
   }
+
   return header;
 }
 
@@ -116,28 +120,31 @@
   return "";
 }
 
-std::string cmFindPathCommand::FindNormalHeader()
+std::string cmFindPathCommand::FindNormalHeader(cmFindBaseDebugState& debug)
 {
   std::string tryPath;
   for (std::string const& n : this->Names) {
     for (std::string const& sp : this->SearchPaths) {
       tryPath = cmStrCat(sp, n);
       if (cmSystemTools::FileExists(tryPath)) {
+        debug.FoundAt(tryPath);
         if (this->IncludeFileInPath) {
           return tryPath;
         }
         return sp;
       }
+      debug.FailedAt(tryPath);
     }
   }
   return "";
 }
 
-std::string cmFindPathCommand::FindFrameworkHeader()
+std::string cmFindPathCommand::FindFrameworkHeader(cmFindBaseDebugState& debug)
 {
   for (std::string const& n : this->Names) {
     for (std::string const& sp : this->SearchPaths) {
       std::string fwPath = this->FindHeaderInFramework(n, sp);
+      fwPath.empty() ? debug.FailedAt(fwPath) : debug.FoundAt(fwPath);
       if (!fwPath.empty()) {
         return fwPath;
       }
diff --git a/Source/cmFindPathCommand.h b/Source/cmFindPathCommand.h
index 8d1ea8b..18bfb7d 100644
--- a/Source/cmFindPathCommand.h
+++ b/Source/cmFindPathCommand.h
@@ -32,8 +32,8 @@
   std::string FindHeaderInFramework(std::string const& file,
                                     std::string const& dir);
   std::string FindHeader();
-  std::string FindNormalHeader();
-  std::string FindFrameworkHeader();
+  std::string FindNormalHeader(cmFindBaseDebugState& debug);
+  std::string FindFrameworkHeader(cmFindBaseDebugState& debug);
 };
 
 bool cmFindPath(std::vector<std::string> const& args,
diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx
index e0a3fbf..3e49172 100644
--- a/Source/cmFindProgramCommand.cxx
+++ b/Source/cmFindProgramCommand.cxx
@@ -15,7 +15,9 @@
 
 struct cmFindProgramHelper
 {
-  cmFindProgramHelper()
+  cmFindProgramHelper(cmMakefile* makefile, cmFindBase const* base)
+    : DebugSearches("find_program", base)
+    , Makefile(makefile)
   {
 #if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
     // Consider platform-specific extensions.
@@ -41,6 +43,10 @@
   // Current full path under consideration.
   std::string TestPath;
 
+  // Debug state
+  cmFindBaseDebugState DebugSearches;
+  cmMakefile* Makefile;
+
   void AddName(std::string const& name) { this->Names.push_back(name); }
   void SetName(std::string const& name)
   {
@@ -78,8 +84,10 @@
       this->TestNameExt = cmStrCat(name, ext);
       this->TestPath =
         cmSystemTools::CollapseFullPath(this->TestNameExt, path);
-
-      if (cmSystemTools::FileExists(this->TestPath, true)) {
+      bool exists = cmSystemTools::FileExists(this->TestPath, true);
+      exists ? this->DebugSearches.FoundAt(this->TestPath)
+             : this->DebugSearches.FailedAt(this->TestPath);
+      if (exists) {
         this->BestPath = this->TestPath;
         return true;
       }
@@ -97,6 +105,7 @@
 // cmFindProgramCommand
 bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn)
 {
+  this->DebugMode = ComputeIfDebugModeWanted();
   this->VariableDocumentation = "Path to a program.";
   this->CMakePathName = "PROGRAM";
   // call cmFindBase::ParseArguments
@@ -158,7 +167,7 @@
 std::string cmFindProgramCommand::FindNormalProgramNamesPerDir()
 {
   // Search for all names in each directory.
-  cmFindProgramHelper helper;
+  cmFindProgramHelper helper(this->Makefile, this);
   for (std::string const& n : this->Names) {
     helper.AddName(n);
   }
@@ -181,7 +190,7 @@
 std::string cmFindProgramCommand::FindNormalProgramDirsPerName()
 {
   // Search the entire path for each name.
-  cmFindProgramHelper helper;
+  cmFindProgramHelper helper(this->Makefile, this);
   for (std::string const& n : this->Names) {
     // Switch to searching for this name.
     helper.SetName(n);
diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx
index 44392ba..0546186 100644
--- a/Source/cmForEachCommand.cxx
+++ b/Source/cmForEachCommand.cxx
@@ -2,8 +2,18 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmForEachCommand.h"
 
-#include <cstdio>
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+// NOTE The declaration of `std::abs` has moved to `cmath` since C++17
+// See https://en.cppreference.com/w/cpp/numeric/math/abs
+// ALERT But IWYU used to lint `#include`s do not "understand"
+// conditional compilation (i.e. `#if __cplusplus >= 201703L`)
 #include <cstdlib>
+#include <iterator>
+#include <map>
+#include <sstream>
+#include <stdexcept>
 #include <utility>
 
 #include <cm/memory>
@@ -21,12 +31,10 @@
 #include "cmSystemTools.h"
 
 namespace {
-bool HandleInMode(std::vector<std::string> const& args, cmMakefile& makefile);
-
 class cmForEachFunctionBlocker : public cmFunctionBlocker
 {
 public:
-  cmForEachFunctionBlocker(cmMakefile* mf);
+  explicit cmForEachFunctionBlocker(cmMakefile* mf);
   ~cmForEachFunctionBlocker() override;
 
   cm::string_view StartCommandName() const override { return "foreach"_s; }
@@ -38,10 +46,33 @@
   bool Replay(std::vector<cmListFileFunction> functions,
               cmExecutionStatus& inStatus) override;
 
+  void SetIterationVarsCount(const std::size_t varsCount)
+  {
+    this->IterationVarsCount = varsCount;
+  }
+  void SetZipLists() { this->ZipLists = true; }
+
   std::vector<std::string> Args;
 
 private:
+  struct InvokeResult
+  {
+    bool Restore;
+    bool Break;
+  };
+
+  bool ReplayItems(std::vector<cmListFileFunction> const& functions,
+                   cmExecutionStatus& inStatus);
+
+  bool ReplayZipLists(std::vector<cmListFileFunction> const& functions,
+                      cmExecutionStatus& inStatus);
+
+  InvokeResult invoke(std::vector<cmListFileFunction> const& functions,
+                      cmExecutionStatus& inStatus, cmMakefile& mf);
+
   cmMakefile* Makefile;
+  std::size_t IterationVarsCount = 0u;
+  bool ZipLists = false;
 };
 
 cmForEachFunctionBlocker::cmForEachFunctionBlocker(cmMakefile* mf)
@@ -60,53 +91,288 @@
 {
   std::vector<std::string> expandedArguments;
   mf.ExpandArguments(lff.Arguments, expandedArguments);
-  return expandedArguments.empty() || expandedArguments[0] == this->Args[0];
+  return expandedArguments.empty() ||
+    expandedArguments.front() == this->Args.front();
 }
 
 bool cmForEachFunctionBlocker::Replay(
   std::vector<cmListFileFunction> functions, cmExecutionStatus& inStatus)
 {
-  cmMakefile& mf = inStatus.GetMakefile();
-  // at end of for each execute recorded commands
+  return this->ZipLists ? this->ReplayZipLists(functions, inStatus)
+                        : this->ReplayItems(functions, inStatus);
+}
+
+bool cmForEachFunctionBlocker::ReplayItems(
+  std::vector<cmListFileFunction> const& functions,
+  cmExecutionStatus& inStatus)
+{
+  assert("Unexpected number of iteration variables" &&
+         this->IterationVarsCount == 1);
+
+  auto& mf = inStatus.GetMakefile();
+
+  // At end of for each execute recorded commands
   // store the old value
   std::string oldDef;
-  if (mf.GetDefinition(this->Args[0])) {
-    oldDef = mf.GetDefinition(this->Args[0]);
+  if (mf.GetDefinition(this->Args.front())) {
+    oldDef = mf.GetDefinition(this->Args.front());
   }
 
+  auto restore = false;
   for (std::string const& arg : cmMakeRange(this->Args).advance(1)) {
-    // set the variable to the loop value
-    mf.AddDefinition(this->Args[0], arg);
+    // Set the variable to the loop value
+    mf.AddDefinition(this->Args.front(), arg);
     // Invoke all the functions that were collected in the block.
-    for (cmListFileFunction const& func : functions) {
-      cmExecutionStatus status(mf);
-      mf.ExecuteCommand(func, status);
-      if (status.GetReturnInvoked()) {
-        inStatus.SetReturnInvoked();
-        // restore the variable to its prior value
-        mf.AddDefinition(this->Args[0], oldDef);
-        return true;
-      }
-      if (status.GetBreakInvoked()) {
-        // restore the variable to its prior value
-        mf.AddDefinition(this->Args[0], oldDef);
-        return true;
-      }
-      if (status.GetContinueInvoked()) {
-        break;
-      }
-      if (cmSystemTools::GetFatalErrorOccured()) {
-        return true;
-      }
+    auto r = this->invoke(functions, inStatus, mf);
+    restore = r.Restore;
+    if (r.Break) {
+      break;
     }
   }
 
-  // restore the variable to its prior value
-  mf.AddDefinition(this->Args[0], oldDef);
+  if (restore) {
+    // restore the variable to its prior value
+    mf.AddDefinition(this->Args.front(), oldDef);
+  }
   return true;
 }
+
+bool cmForEachFunctionBlocker::ReplayZipLists(
+  std::vector<cmListFileFunction> const& functions,
+  cmExecutionStatus& inStatus)
+{
+  assert("Unexpected number of iteration variables" &&
+         this->IterationVarsCount >= 1);
+
+  auto& mf = inStatus.GetMakefile();
+
+  // Expand the list of list-variables into a list of lists of strings
+  std::vector<std::vector<std::string>> values;
+  values.reserve(this->Args.size() - this->IterationVarsCount);
+  // Also track the longest list size
+  std::size_t maxItems = 0u;
+  for (auto const& var :
+       cmMakeRange(this->Args).advance(this->IterationVarsCount)) {
+    std::vector<std::string> items;
+    auto const& value = mf.GetSafeDefinition(var);
+    if (!value.empty()) {
+      cmExpandList(value, items, true);
+    }
+    maxItems = std::max(maxItems, items.size());
+    values.emplace_back(std::move(items));
+  }
+
+  // Form the list of iteration variables
+  std::vector<std::string> iterationVars;
+  if (this->IterationVarsCount > 1) {
+    // If multiple iteration variables has given,
+    // just copy them to the `iterationVars` list.
+    iterationVars.reserve(values.size());
+    std::copy(this->Args.begin(),
+              this->Args.begin() + this->IterationVarsCount,
+              std::back_inserter(iterationVars));
+  } else {
+    // In case of the only iteration variable,
+    // generate names as `var_name_N`,
+    // where `N` is the count of lists to zip
+    iterationVars.resize(values.size());
+    const auto iter_var_prefix = this->Args.front() + "_";
+    auto i = 0u;
+    std::generate(
+      iterationVars.begin(), iterationVars.end(),
+      [&]() -> std::string { return iter_var_prefix + std::to_string(i++); });
+  }
+  assert("Sanity check" && iterationVars.size() == values.size());
+
+  // Store old values for iteration variables
+  std::map<std::string, std::string> oldDefs;
+  for (auto i = 0u; i < values.size(); ++i) {
+    if (mf.GetDefinition(iterationVars[i])) {
+      oldDefs.emplace(iterationVars[i], mf.GetDefinition(iterationVars[i]));
+    }
+  }
+
+  // Form a vector of current positions in all lists (Ok, vectors) of values
+  std::vector<decltype(values)::value_type::iterator> positions;
+  positions.reserve(values.size());
+  std::transform(
+    values.begin(), values.end(), std::back_inserter(positions),
+    // Set the initial position to the beginning of every list
+    [](decltype(values)::value_type& list) { return list.begin(); });
+  assert("Sanity check" && positions.size() == values.size());
+
+  auto restore = false;
+  // Iterate over all the lists simulateneously
+  for (auto i = 0u; i < maxItems; ++i) {
+    // Declare iteration variables
+    for (auto j = 0u; j < values.size(); ++j) {
+      // Define (or not) the iteration variable if the current position
+      // still not at the end...
+      if (positions[j] != values[j].end()) {
+        mf.AddDefinition(iterationVars[j], *positions[j]);
+        ++positions[j];
+      } else {
+        mf.RemoveDefinition(iterationVars[j]);
+      }
+    }
+    // Invoke all the functions that were collected in the block.
+    auto r = this->invoke(functions, inStatus, mf);
+    restore = r.Restore;
+    if (r.Break) {
+      break;
+    }
+  }
+
+  // Restore the variables to its prior value
+  if (restore) {
+    for (auto const& p : oldDefs) {
+      mf.AddDefinition(p.first, p.second);
+    }
+  }
+  return true;
 }
 
+auto cmForEachFunctionBlocker::invoke(
+  std::vector<cmListFileFunction> const& functions,
+  cmExecutionStatus& inStatus, cmMakefile& mf) -> InvokeResult
+{
+  InvokeResult result = { true, false };
+  // Invoke all the functions that were collected in the block.
+  for (cmListFileFunction const& func : functions) {
+    cmExecutionStatus status(mf);
+    mf.ExecuteCommand(func, status);
+    if (status.GetReturnInvoked()) {
+      inStatus.SetReturnInvoked();
+      result.Break = true;
+      break;
+    }
+    if (status.GetBreakInvoked()) {
+      result.Break = true;
+      break;
+    }
+    if (status.GetContinueInvoked()) {
+      break;
+    }
+    if (cmSystemTools::GetFatalErrorOccured()) {
+      result.Restore = false;
+      result.Break = true;
+      break;
+    }
+  }
+  return result;
+}
+
+bool HandleInMode(std::vector<std::string> const& args,
+                  std::vector<std::string>::const_iterator kwInIter,
+                  cmMakefile& makefile)
+{
+  assert("A valid iterator expected" && kwInIter != args.end());
+
+  auto fb = cm::make_unique<cmForEachFunctionBlocker>(&makefile);
+
+  // Copy iteration variable names first
+  std::copy(args.begin(), kwInIter, std::back_inserter(fb->Args));
+  // Remember the count of given iteration variable names
+  const auto varsCount = fb->Args.size();
+  fb->SetIterationVarsCount(varsCount);
+
+  enum Doing
+  {
+    DoingNone,
+    DoingLists,
+    DoingItems,
+    DoingZipLists
+  };
+  Doing doing = DoingNone;
+  // Iterate over arguments past the "IN" keyword
+  for (std::string const& arg : cmMakeRange(++kwInIter, args.end())) {
+    if (arg == "LISTS") {
+      if (doing == DoingZipLists) {
+        makefile.IssueMessage(MessageType::FATAL_ERROR,
+                              "ZIP_LISTS can not be used with LISTS or ITEMS");
+        return true;
+      }
+      if (varsCount != 1u) {
+        makefile.IssueMessage(
+          MessageType::FATAL_ERROR,
+          "ITEMS or LISTS require exactly one iteration variable");
+        return true;
+      }
+      doing = DoingLists;
+
+    } else if (arg == "ITEMS") {
+      if (doing == DoingZipLists) {
+        makefile.IssueMessage(MessageType::FATAL_ERROR,
+                              "ZIP_LISTS can not be used with LISTS or ITEMS");
+        return true;
+      }
+      if (varsCount != 1u) {
+        makefile.IssueMessage(
+          MessageType::FATAL_ERROR,
+          "ITEMS or LISTS require exactly one iteration variable");
+        return true;
+      }
+      doing = DoingItems;
+
+    } else if (arg == "ZIP_LISTS") {
+      if (doing != DoingNone) {
+        makefile.IssueMessage(MessageType::FATAL_ERROR,
+                              "ZIP_LISTS can not be used with LISTS or ITEMS");
+        return true;
+      }
+      doing = DoingZipLists;
+      fb->SetZipLists();
+
+    } else if (doing == DoingLists) {
+      auto const& value = makefile.GetSafeDefinition(arg);
+      if (!value.empty()) {
+        cmExpandList(value, fb->Args, true);
+      }
+
+    } else if (doing == DoingItems || doing == DoingZipLists) {
+      fb->Args.push_back(arg);
+
+    } else {
+      makefile.IssueMessage(MessageType::FATAL_ERROR,
+                            cmStrCat("Unknown argument:\n", "  ", arg, "\n"));
+      return true;
+    }
+  }
+
+  // If `ZIP_LISTS` given and variables count more than 1,
+  // make sure the given lists count matches variables...
+  if (doing == DoingZipLists && varsCount > 1u &&
+      (2u * varsCount) != fb->Args.size()) {
+    makefile.IssueMessage(
+      MessageType::FATAL_ERROR,
+      cmStrCat("Expected ", std::to_string(varsCount),
+               " list variables, but given ",
+               std::to_string(fb->Args.size() - varsCount)));
+    return true;
+  }
+
+  makefile.AddFunctionBlocker(std::move(fb));
+
+  return true;
+}
+
+bool TryParseInteger(cmExecutionStatus& status, const std::string& str, int& i)
+{
+  try {
+    i = std::stoi(str);
+  } catch (std::invalid_argument&) {
+    std::ostringstream e;
+    e << "Invalid integer: '" << str << "'";
+    status.SetError(e.str());
+    cmSystemTools::SetFatalErrorOccured();
+    return false;
+  }
+
+  return true;
+}
+
+} // anonymous namespace
+
 bool cmForEachCommand(std::vector<std::string> const& args,
                       cmExecutionStatus& status)
 {
@@ -114,8 +380,9 @@
     status.SetError("called with incorrect number of arguments");
     return false;
   }
-  if (args.size() > 1 && args[1] == "IN") {
-    return HandleInMode(args, status.GetMakefile());
+  auto kwInIter = std::find(args.begin(), args.end(), "IN");
+  if (kwInIter != args.end()) {
+    return HandleInMode(args, kwInIter, status.GetMakefile());
   }
 
   // create a function blocker
@@ -126,16 +393,28 @@
       int stop = 0;
       int step = 0;
       if (args.size() == 3) {
-        stop = atoi(args[2].c_str());
+        if (!TryParseInteger(status, args[2], stop)) {
+          return false;
+        }
       }
       if (args.size() == 4) {
-        start = atoi(args[2].c_str());
-        stop = atoi(args[3].c_str());
+        if (!TryParseInteger(status, args[2], start)) {
+          return false;
+        }
+        if (!TryParseInteger(status, args[3], stop)) {
+          return false;
+        }
       }
       if (args.size() == 5) {
-        start = atoi(args[2].c_str());
-        stop = atoi(args[3].c_str());
-        step = atoi(args[4].c_str());
+        if (!TryParseInteger(status, args[2], start)) {
+          return false;
+        }
+        if (!TryParseInteger(status, args[3], stop)) {
+          return false;
+        }
+        if (!TryParseInteger(status, args[4], step)) {
+          return false;
+        }
       }
       if (step == 0) {
         if (start > stop) {
@@ -149,69 +428,36 @@
         status.SetError(
           cmStrCat("called with incorrect range specification: start ", start,
                    ", stop ", stop, ", step ", step));
+        cmSystemTools::SetFatalErrorOccured();
         return false;
       }
-      std::vector<std::string> range;
-      char buffer[100];
-      range.push_back(args[0]);
-      int cc;
-      for (cc = start;; cc += step) {
-        if ((step > 0 && cc > stop) || (step < 0 && cc < stop)) {
-          break;
-        }
-        sprintf(buffer, "%d", cc);
-        range.emplace_back(buffer);
-        if (cc == stop) {
-          break;
-        }
-      }
-      fb->Args = range;
+
+      // Calculate expected iterations count and reserve enough space
+      // in the `fb->Args` vector. The first item is the iteration variable
+      // name...
+      const std::size_t iter_cnt = 2u +
+        int(start < stop) * (stop - start) / std::abs(step) +
+        int(start > stop) * (start - stop) / std::abs(step);
+      fb->Args.resize(iter_cnt);
+      fb->Args.front() = args.front();
+      auto cc = start;
+      auto generator = [&cc, step]() -> std::string {
+        auto result = std::to_string(cc);
+        cc += step;
+        return result;
+      };
+      // Fill the `range` vector w/ generated string values
+      // (starting from 2nd position)
+      std::generate(++fb->Args.begin(), fb->Args.end(), generator);
     } else {
       fb->Args = args;
     }
   } else {
     fb->Args = args;
   }
+
+  fb->SetIterationVarsCount(1u);
   status.GetMakefile().AddFunctionBlocker(std::move(fb));
 
   return true;
 }
-
-namespace {
-bool HandleInMode(std::vector<std::string> const& args, cmMakefile& makefile)
-{
-  auto fb = cm::make_unique<cmForEachFunctionBlocker>(&makefile);
-  fb->Args.push_back(args[0]);
-
-  enum Doing
-  {
-    DoingNone,
-    DoingLists,
-    DoingItems
-  };
-  Doing doing = DoingNone;
-  for (unsigned int i = 2; i < args.size(); ++i) {
-    if (doing == DoingItems) {
-      fb->Args.push_back(args[i]);
-    } else if (args[i] == "LISTS") {
-      doing = DoingLists;
-    } else if (args[i] == "ITEMS") {
-      doing = DoingItems;
-    } else if (doing == DoingLists) {
-      const char* value = makefile.GetDefinition(args[i]);
-      if (value && *value) {
-        cmExpandList(value, fb->Args, true);
-      }
-    } else {
-      makefile.IssueMessage(
-        MessageType::FATAL_ERROR,
-        cmStrCat("Unknown argument:\n", "  ", args[i], "\n"));
-      return true;
-    }
-  }
-
-  makefile.AddFunctionBlocker(std::move(fb));
-
-  return true;
-}
-}
diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx
index b3ddfe0..a4c9072 100644
--- a/Source/cmFunctionCommand.cxx
+++ b/Source/cmFunctionCommand.cxx
@@ -2,15 +2,14 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmFunctionCommand.h"
 
-#include <sstream>
 #include <utility>
 
 #include <cm/memory>
 #include <cm/string_view>
+#include <cmext/algorithm>
 
 #include "cm_static_string_view.hxx"
 
-#include "cmAlgorithms.h"
 #include "cmExecutionStatus.h"
 #include "cmFunctionBlocker.h"
 #include "cmListFileCache.h"
@@ -19,8 +18,20 @@
 #include "cmRange.h"
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
 
 namespace {
+std::string const ARGC = "ARGC";
+std::string const ARGN = "ARGN";
+std::string const ARGV = "ARGV";
+std::string const CMAKE_CURRENT_FUNCTION = "CMAKE_CURRENT_FUNCTION";
+std::string const CMAKE_CURRENT_FUNCTION_LIST_FILE =
+  "CMAKE_CURRENT_FUNCTION_LIST_FILE";
+std::string const CMAKE_CURRENT_FUNCTION_LIST_DIR =
+  "CMAKE_CURRENT_FUNCTION_LIST_DIR";
+std::string const CMAKE_CURRENT_FUNCTION_LIST_LINE =
+  "CMAKE_CURRENT_FUNCTION_LIST_LINE";
+
 // define the class for function commands
 class cmFunctionHelperCommand
 {
@@ -36,8 +47,8 @@
   std::vector<cmListFileFunction> Functions;
   cmPolicies::PolicyMap Policies;
   std::string FilePath;
+  long Line;
 };
-}
 
 bool cmFunctionHelperCommand::operator()(
   std::vector<cmListFileArgument> const& args,
@@ -52,9 +63,9 @@
   // make sure the number of arguments passed is at least the number
   // required by the signature
   if (expandedArgs.size() < this->Args.size() - 1) {
-    std::string errorMsg = cmStrCat(
+    auto const errorMsg = cmStrCat(
       "Function invoked with incorrect arguments for function named: ",
-      this->Args[0]);
+      this->Args.front());
     inStatus.SetError(errorMsg);
     return false;
   }
@@ -63,30 +74,40 @@
                                             this->Policies);
 
   // set the value of argc
-  makefile.AddDefinition("ARGC", std::to_string(expandedArgs.size()));
-  makefile.MarkVariableAsUsed("ARGC");
+  makefile.AddDefinition(ARGC, std::to_string(expandedArgs.size()));
+  makefile.MarkVariableAsUsed(ARGC);
 
   // set the values for ARGV0 ARGV1 ...
-  for (unsigned int t = 0; t < expandedArgs.size(); ++t) {
-    std::ostringstream tmpStream;
-    tmpStream << "ARGV" << t;
-    makefile.AddDefinition(tmpStream.str(), expandedArgs[t]);
-    makefile.MarkVariableAsUsed(tmpStream.str());
+  for (auto t = 0u; t < expandedArgs.size(); ++t) {
+    auto const value = cmStrCat(ARGV, std::to_string(t));
+    makefile.AddDefinition(value, expandedArgs[t]);
+    makefile.MarkVariableAsUsed(value);
   }
 
   // define the formal arguments
-  for (unsigned int j = 1; j < this->Args.size(); ++j) {
+  for (auto j = 1u; j < this->Args.size(); ++j) {
     makefile.AddDefinition(this->Args[j], expandedArgs[j - 1]);
   }
 
   // define ARGV and ARGN
-  std::string argvDef = cmJoin(expandedArgs, ";");
-  auto eit = expandedArgs.begin() + (this->Args.size() - 1);
-  std::string argnDef = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";");
-  makefile.AddDefinition("ARGV", argvDef);
-  makefile.MarkVariableAsUsed("ARGV");
-  makefile.AddDefinition("ARGN", argnDef);
-  makefile.MarkVariableAsUsed("ARGN");
+  auto const argvDef = cmJoin(expandedArgs, ";");
+  auto const eit = expandedArgs.begin() + (this->Args.size() - 1);
+  auto const argnDef = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";");
+  makefile.AddDefinition(ARGV, argvDef);
+  makefile.MarkVariableAsUsed(ARGV);
+  makefile.AddDefinition(ARGN, argnDef);
+  makefile.MarkVariableAsUsed(ARGN);
+
+  makefile.AddDefinition(CMAKE_CURRENT_FUNCTION, this->Args.front());
+  makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION);
+  makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_FILE, this->FilePath);
+  makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_FILE);
+  makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_DIR,
+                         cmSystemTools::GetFilenamePath(this->FilePath));
+  makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_DIR);
+  makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_LINE,
+                         std::to_string(this->Line));
+  makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_LINE);
 
   // Invoke all the functions that were collected in the block.
   // for each function
@@ -100,7 +121,7 @@
       return false;
     }
     if (status.GetReturnInvoked()) {
-      return true;
+      break;
     }
   }
 
@@ -129,7 +150,8 @@
   std::vector<std::string> expandedArguments;
   mf.ExpandArguments(lff.Arguments, expandedArguments,
                      this->GetStartingContext().FilePath.c_str());
-  return expandedArguments.empty() || expandedArguments[0] == this->Args[0];
+  return expandedArguments.empty() ||
+    expandedArguments.front() == this->Args.front();
 }
 
 bool cmFunctionFunctionBlocker::Replay(
@@ -141,11 +163,14 @@
   f.Args = this->Args;
   f.Functions = std::move(functions);
   f.FilePath = this->GetStartingContext().FilePath;
+  f.Line = this->GetStartingContext().Line;
   mf.RecordPolicies(f.Policies);
-  mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f));
+  mf.GetState()->AddScriptedCommand(this->Args.front(), std::move(f));
   return true;
 }
 
+} // anonymous namespace
+
 bool cmFunctionCommand(std::vector<std::string> const& args,
                        cmExecutionStatus& status)
 {
@@ -155,10 +180,9 @@
   }
 
   // create a function blocker
-  {
-    auto fb = cm::make_unique<cmFunctionFunctionBlocker>();
-    cmAppend(fb->Args, args);
-    status.GetMakefile().AddFunctionBlocker(std::move(fb));
-  }
+  auto fb = cm::make_unique<cmFunctionFunctionBlocker>();
+  cm::append(fb->Args, args);
+  status.GetMakefile().AddFunctionBlocker(std::move(fb));
+
   return true;
 }
diff --git a/Source/cmGccDepfileLexerHelper.cxx b/Source/cmGccDepfileLexerHelper.cxx
new file mode 100644
index 0000000..957896f
--- /dev/null
+++ b/Source/cmGccDepfileLexerHelper.cxx
@@ -0,0 +1,126 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmGccDepfileLexerHelper.h"
+
+#include <cstdio>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "cmGccDepfileReaderTypes.h"
+
+#include "LexerParser/cmGccDepfileLexer.h"
+
+#ifdef _WIN32
+#  include "cmsys/Encoding.h"
+#endif
+
+bool cmGccDepfileLexerHelper::readFile(const char* filePath)
+{
+#ifdef _WIN32
+  wchar_t* wpath = cmsysEncoding_DupToWide(filePath);
+  FILE* file = _wfopen(wpath, L"rb");
+  free(wpath);
+#else
+  FILE* file = fopen(filePath, "r");
+#endif
+  if (!file) {
+    return false;
+  }
+  newEntry();
+  yyscan_t scanner;
+  cmGccDepfile_yylex_init(&scanner);
+  cmGccDepfile_yyset_extra(this, scanner);
+  cmGccDepfile_yyrestart(file, scanner);
+  cmGccDepfile_yylex(scanner);
+  cmGccDepfile_yylex_destroy(scanner);
+  sanitizeContent();
+  fclose(file);
+  return true;
+}
+
+void cmGccDepfileLexerHelper::newEntry()
+{
+  this->HelperState = State::Rule;
+  this->Content.emplace_back();
+  newRule();
+}
+
+void cmGccDepfileLexerHelper::newRule()
+{
+  auto& entry = this->Content.back();
+  if (entry.rules.empty() || !entry.rules.back().empty()) {
+    entry.rules.emplace_back();
+  }
+}
+
+void cmGccDepfileLexerHelper::newDependency()
+{
+  // printf("NEW DEP\n");
+  this->HelperState = State::Dependency;
+  if (this->Content.back().paths.empty() ||
+      !this->Content.back().paths.back().empty()) {
+    this->Content.back().paths.emplace_back();
+  }
+}
+
+void cmGccDepfileLexerHelper::newRuleOrDependency()
+{
+  if (this->HelperState == State::Rule) {
+    newRule();
+  } else {
+    newDependency();
+  }
+}
+
+void cmGccDepfileLexerHelper::addToCurrentPath(const char* s)
+{
+  if (this->Content.empty()) {
+    return;
+  }
+  cmGccStyleDependency* dep = &this->Content.back();
+  std::string* dst = nullptr;
+  switch (this->HelperState) {
+    case State::Rule: {
+      if (dep->rules.empty()) {
+        return;
+      }
+      dst = &dep->rules.back();
+    } break;
+    case State::Dependency: {
+      if (dep->paths.empty()) {
+        return;
+      }
+      dst = &dep->paths.back();
+    } break;
+  }
+  dst->append(s);
+}
+
+void cmGccDepfileLexerHelper::sanitizeContent()
+{
+  for (auto it = this->Content.begin(); it != this->Content.end();) {
+    // Remove empty rules
+    for (auto rit = it->rules.begin(); rit != it->rules.end();) {
+      if (rit->empty()) {
+        rit = it->rules.erase(rit);
+      } else {
+        ++rit;
+      }
+    }
+    // Remove the entry if rules are empty
+    if (it->rules.empty()) {
+      it = this->Content.erase(it);
+    } else {
+      // Remove empty paths
+      for (auto pit = it->paths.begin(); pit != it->paths.end();) {
+        if (pit->empty()) {
+          pit = it->paths.erase(pit);
+        } else {
+          ++pit;
+        }
+      }
+      ++it;
+    }
+  }
+}
diff --git a/Source/cmGccDepfileLexerHelper.h b/Source/cmGccDepfileLexerHelper.h
new file mode 100644
index 0000000..e6b2fcf
--- /dev/null
+++ b/Source/cmGccDepfileLexerHelper.h
@@ -0,0 +1,40 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmGccDepfileLexerHelper_h
+#define cmGccDepfileLexerHelper_h
+
+#include <utility>
+
+#include <cmGccDepfileReaderTypes.h>
+
+class cmGccDepfileLexerHelper
+{
+public:
+  cmGccDepfileLexerHelper() = default;
+
+  bool readFile(const char* filePath);
+  cmGccDepfileContent extractContent() && { return std::move(this->Content); }
+
+  // Functions called by the lexer
+  void newEntry();
+  void newRule();
+  void newDependency();
+  void newRuleOrDependency();
+  void addToCurrentPath(const char* s);
+
+private:
+  void sanitizeContent();
+
+  cmGccDepfileContent Content;
+
+  enum class State
+  {
+    Rule,
+    Dependency
+  };
+  State HelperState = State::Rule;
+};
+
+#define YY_EXTRA_TYPE cmGccDepfileLexerHelper*
+
+#endif
diff --git a/Source/cmGccDepfileReader.cxx b/Source/cmGccDepfileReader.cxx
new file mode 100644
index 0000000..9d70ede
--- /dev/null
+++ b/Source/cmGccDepfileReader.cxx
@@ -0,0 +1,18 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmGccDepfileReader.h"
+
+#include <type_traits>
+#include <utility>
+
+#include "cmGccDepfileLexerHelper.h"
+
+cmGccDepfileContent cmReadGccDepfile(const char* filePath)
+{
+  cmGccDepfileContent result;
+  cmGccDepfileLexerHelper helper;
+  if (helper.readFile(filePath)) {
+    result = std::move(helper).extractContent();
+  }
+  return result;
+}
diff --git a/Source/cmGccDepfileReader.h b/Source/cmGccDepfileReader.h
new file mode 100644
index 0000000..9313010
--- /dev/null
+++ b/Source/cmGccDepfileReader.h
@@ -0,0 +1,10 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmGccDepfileReader_h
+#define cmGccDepfileReader_h
+
+#include "cmGccDepfileReaderTypes.h"
+
+cmGccDepfileContent cmReadGccDepfile(const char* filePath);
+
+#endif
diff --git a/Source/cmGccDepfileReaderTypes.h b/Source/cmGccDepfileReaderTypes.h
new file mode 100644
index 0000000..8b15c73
--- /dev/null
+++ b/Source/cmGccDepfileReaderTypes.h
@@ -0,0 +1,17 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmGccDepfileReaderTypes_h
+#define cmGccDepfileReaderTypes_h
+
+#include <string>
+#include <vector>
+
+struct cmGccStyleDependency
+{
+  std::vector<std::string> rules;
+  std::vector<std::string> paths;
+};
+
+using cmGccDepfileContent = std::vector<cmGccStyleDependency>;
+
+#endif
diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx
index b7f7d1d..81d1e46 100644
--- a/Source/cmGeneratorExpression.cxx
+++ b/Source/cmGeneratorExpression.cxx
@@ -8,7 +8,6 @@
 
 #include "cmsys/RegularExpression.hxx"
 
-#include "cmAlgorithms.h"
 #include "cmGeneratorExpressionContext.h"
 #include "cmGeneratorExpressionDAGChecker.h"
 #include "cmGeneratorExpressionEvaluator.h"
@@ -22,6 +21,8 @@
 {
 }
 
+cmCompiledGeneratorExpression::~cmCompiledGeneratorExpression() = default;
+
 cmGeneratorExpression::~cmGeneratorExpression() = default;
 
 std::unique_ptr<cmCompiledGeneratorExpression> cmGeneratorExpression::Parse(
@@ -86,7 +87,7 @@
 
   this->Output.clear();
 
-  for (const cmGeneratorExpressionEvaluator* it : this->Evaluators) {
+  for (const auto& it : this->Evaluators) {
     this->Output += it->Evaluate(&context, dagChecker);
 
     this->SeenTargetProperties.insert(context.SeenTargetProperties.cbegin(),
@@ -129,11 +130,6 @@
   }
 }
 
-cmCompiledGeneratorExpression::~cmCompiledGeneratorExpression()
-{
-  cmDeleteAll(this->Evaluators);
-}
-
 std::string cmGeneratorExpression::StripEmptyListElements(
   const std::string& input)
 {
@@ -385,6 +381,20 @@
   return targetNameValidator.find(input);
 }
 
+void cmGeneratorExpression::ReplaceInstallPrefix(
+  std::string& input, const std::string& replacement)
+{
+  std::string::size_type pos = 0;
+  std::string::size_type lastPos = pos;
+
+  while ((pos = input.find("$<INSTALL_PREFIX>", lastPos)) !=
+         std::string::npos) {
+    std::string::size_type endPos = pos + sizeof("$<INSTALL_PREFIX>") - 1;
+    input.replace(pos, endPos - pos, replacement);
+    lastPos = endPos;
+  }
+}
+
 void cmCompiledGeneratorExpression::GetMaxLanguageStandard(
   const cmGeneratorTarget* tgt, std::map<std::string, std::string>& mapping)
 {
diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h
index 4bd1c9f..c4be3a1 100644
--- a/Source/cmGeneratorExpression.h
+++ b/Source/cmGeneratorExpression.h
@@ -87,6 +87,9 @@
     return input != nullptr && input[0] == '$' && input[1] == '<';
   }
 
+  static void ReplaceInstallPrefix(std::string& input,
+                                   const std::string& replacement);
+
 private:
   cmListFileBacktrace Backtrace;
 };
@@ -160,7 +163,7 @@
   friend class cmGeneratorExpression;
 
   cmListFileBacktrace Backtrace;
-  std::vector<cmGeneratorExpressionEvaluator*> Evaluators;
+  std::vector<std::unique_ptr<cmGeneratorExpressionEvaluator>> Evaluators;
   const std::string Input;
   bool NeedsEvaluation;
   bool EvaluateForBuildsystem;
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx
index e0ae170..4129a0c 100644
--- a/Source/cmGeneratorExpressionEvaluator.cxx
+++ b/Source/cmGeneratorExpressionEvaluator.cxx
@@ -2,10 +2,8 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGeneratorExpressionEvaluator.h"
 
-#include <algorithm>
 #include <sstream>
 
-#include "cmAlgorithms.h"
 #include "cmGeneratorExpressionContext.h"
 #include "cmGeneratorExpressionNode.h"
 
@@ -16,6 +14,8 @@
 {
 }
 
+GeneratorExpressionContent::~GeneratorExpressionContent() = default;
+
 std::string GeneratorExpressionContent::GetOriginalExpression() const
 {
   return std::string(this->StartContent, this->ContentLength);
@@ -25,14 +25,13 @@
   const cmGeneratorExpressionNode* node, const std::string& identifier,
   cmGeneratorExpressionContext* context,
   cmGeneratorExpressionDAGChecker* dagChecker,
-  std::vector<std::vector<cmGeneratorExpressionEvaluator*>>::const_iterator
-    pit) const
+  std::vector<cmGeneratorExpressionEvaluatorVector>::const_iterator pit) const
 {
   std::string result;
 
   const auto pend = this->ParamChildren.end();
   for (; pit != pend; ++pit) {
-    for (cmGeneratorExpressionEvaluator* pExprEval : *pit) {
+    for (auto& pExprEval : *pit) {
       if (node->RequiresLiteralInput()) {
         if (pExprEval->GetType() != cmGeneratorExpressionEvaluator::Text) {
           reportError(context, this->GetOriginalExpression(),
@@ -64,8 +63,7 @@
 {
   std::string identifier;
   {
-    for (cmGeneratorExpressionEvaluator* pExprEval :
-         this->IdentifierChildren) {
+    for (auto& pExprEval : this->IdentifierChildren) {
       identifier += pExprEval->Evaluate(context, dagChecker);
       if (context->HadError) {
         return std::string();
@@ -126,7 +124,7 @@
         return std::string();
       }
       std::string parameter;
-      for (cmGeneratorExpressionEvaluator* pExprEval : *pit) {
+      for (auto& pExprEval : *pit) {
         parameter += pExprEval->Evaluate(context, dagChecker);
         if (context->HadError) {
           return std::string();
@@ -174,10 +172,3 @@
   }
   return std::string();
 }
-
-GeneratorExpressionContent::~GeneratorExpressionContent()
-{
-  cmDeleteAll(this->IdentifierChildren);
-  std::for_each(this->ParamChildren.begin(), this->ParamChildren.end(),
-                cmDeleteAll<std::vector<cmGeneratorExpressionEvaluator*>>);
-}
diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h
index b10bb5b..10496fd 100644
--- a/Source/cmGeneratorExpressionEvaluator.h
+++ b/Source/cmGeneratorExpressionEvaluator.h
@@ -6,6 +6,7 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <cstddef>
+#include <memory>
 #include <string>
 #include <utility>
 #include <vector>
@@ -36,6 +37,9 @@
                                cmGeneratorExpressionDAGChecker*) const = 0;
 };
 
+using cmGeneratorExpressionEvaluatorVector =
+  std::vector<std::unique_ptr<cmGeneratorExpressionEvaluator>>;
+
 struct TextContent : public cmGeneratorExpressionEvaluator
 {
   TextContent(const char* start, size_t length)
@@ -68,13 +72,13 @@
 {
   GeneratorExpressionContent(const char* startContent, size_t length);
 
-  void SetIdentifier(std::vector<cmGeneratorExpressionEvaluator*> identifier)
+  void SetIdentifier(cmGeneratorExpressionEvaluatorVector&& identifier)
   {
     this->IdentifierChildren = std::move(identifier);
   }
 
   void SetParameters(
-    std::vector<std::vector<cmGeneratorExpressionEvaluator*>> parameters)
+    std::vector<cmGeneratorExpressionEvaluatorVector>&& parameters)
   {
     this->ParamChildren = std::move(parameters);
   }
@@ -102,12 +106,12 @@
     const cmGeneratorExpressionNode* node, const std::string& identifier,
     cmGeneratorExpressionContext* context,
     cmGeneratorExpressionDAGChecker* dagChecker,
-    std::vector<std::vector<cmGeneratorExpressionEvaluator*>>::const_iterator
-      pit) const;
+    std::vector<cmGeneratorExpressionEvaluatorVector>::const_iterator pit)
+    const;
 
 private:
-  std::vector<cmGeneratorExpressionEvaluator*> IdentifierChildren;
-  std::vector<std::vector<cmGeneratorExpressionEvaluator*>> ParamChildren;
+  cmGeneratorExpressionEvaluatorVector IdentifierChildren;
+  std::vector<cmGeneratorExpressionEvaluatorVector> ParamChildren;
   const char* StartContent;
   size_t ContentLength;
 };
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 66f1c71..14478c2 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -14,6 +14,7 @@
 #include <utility>
 
 #include <cm/iterator>
+#include <cm/string_view>
 
 #include "cmsys/RegularExpression.hxx"
 #include "cmsys/String.h"
@@ -37,7 +38,6 @@
 #include "cmState.h"
 #include "cmStateSnapshot.h"
 #include "cmStateTypes.h"
-#include "cmString.hxx"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
diff --git a/Source/cmGeneratorExpressionParser.cxx b/Source/cmGeneratorExpressionParser.cxx
index d6cc6ab..c2c9ef7 100644
--- a/Source/cmGeneratorExpressionParser.cxx
+++ b/Source/cmGeneratorExpressionParser.cxx
@@ -6,7 +6,10 @@
 #include <cstddef>
 #include <utility>
 
-#include "cmAlgorithms.h"
+#include <cm/memory>
+#include <cmext/algorithm>
+#include <cmext/memory>
+
 #include "cmGeneratorExpressionEvaluator.h"
 
 cmGeneratorExpressionParser::cmGeneratorExpressionParser(
@@ -17,7 +20,7 @@
 }
 
 void cmGeneratorExpressionParser::Parse(
-  std::vector<cmGeneratorExpressionEvaluator*>& result)
+  cmGeneratorExpressionEvaluatorVector& result)
 {
   it = this->Tokens.begin();
 
@@ -27,40 +30,38 @@
 }
 
 static void extendText(
-  std::vector<cmGeneratorExpressionEvaluator*>& result,
+  cmGeneratorExpressionEvaluatorVector& result,
   std::vector<cmGeneratorExpressionToken>::const_iterator it)
 {
   if (!result.empty() &&
       (*(result.end() - 1))->GetType() ==
         cmGeneratorExpressionEvaluator::Text) {
-    TextContent* textContent = static_cast<TextContent*>(*(result.end() - 1));
-    textContent->Extend(it->Length);
+    cm::static_reference_cast<TextContent>(*(result.end() - 1))
+      .Extend(it->Length);
   } else {
-    TextContent* textContent = new TextContent(it->Content, it->Length);
-    result.push_back(textContent);
+    auto textContent = cm::make_unique<TextContent>(it->Content, it->Length);
+    result.push_back(std::move(textContent));
   }
 }
 
 static void extendResult(
-  std::vector<cmGeneratorExpressionEvaluator*>& result,
-  const std::vector<cmGeneratorExpressionEvaluator*>& contents)
+  cmGeneratorExpressionParser::cmGeneratorExpressionEvaluatorVector& result,
+  cmGeneratorExpressionParser::cmGeneratorExpressionEvaluatorVector&& contents)
 {
   if (!result.empty() &&
       (*(result.end() - 1))->GetType() ==
         cmGeneratorExpressionEvaluator::Text &&
       contents.front()->GetType() == cmGeneratorExpressionEvaluator::Text) {
-    TextContent* textContent = static_cast<TextContent*>(*(result.end() - 1));
-    textContent->Extend(
-      static_cast<TextContent*>(contents.front())->GetLength());
-    delete contents.front();
-    cmAppend(result, contents.begin() + 1, contents.end());
-  } else {
-    cmAppend(result, contents);
+    cm::static_reference_cast<TextContent>(*(result.end() - 1))
+      .Extend(
+        cm::static_reference_cast<TextContent>(contents.front()).GetLength());
+    contents.erase(contents.begin());
   }
+  cm::append(result, std::move(contents));
 }
 
 void cmGeneratorExpressionParser::ParseGeneratorExpression(
-  std::vector<cmGeneratorExpressionEvaluator*>& result)
+  cmGeneratorExpressionEvaluatorVector& result)
 {
   assert(this->it != this->Tokens.end());
   unsigned int nestedLevel = this->NestingLevel;
@@ -68,7 +69,7 @@
 
   auto startToken = this->it - 1;
 
-  std::vector<cmGeneratorExpressionEvaluator*> identifier;
+  cmGeneratorExpressionEvaluatorVector identifier;
   while (this->it->TokenType != cmGeneratorExpressionToken::EndExpression &&
          this->it->TokenType != cmGeneratorExpressionToken::ColonSeparator) {
     if (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) {
@@ -87,18 +88,18 @@
 
   if (this->it != this->Tokens.end() &&
       this->it->TokenType == cmGeneratorExpressionToken::EndExpression) {
-    GeneratorExpressionContent* content = new GeneratorExpressionContent(
+    auto content = cm::make_unique<GeneratorExpressionContent>(
       startToken->Content,
       this->it->Content - startToken->Content + this->it->Length);
     assert(this->it != this->Tokens.end());
     ++this->it;
     --this->NestingLevel;
     content->SetIdentifier(std::move(identifier));
-    result.push_back(content);
+    result.push_back(std::move(content));
     return;
   }
 
-  std::vector<std::vector<cmGeneratorExpressionEvaluator*>> parameters;
+  std::vector<cmGeneratorExpressionEvaluatorVector> parameters;
   std::vector<std::vector<cmGeneratorExpressionToken>::const_iterator>
     commaTokens;
   std::vector<cmGeneratorExpressionToken>::const_iterator colonToken;
@@ -169,7 +170,7 @@
     // treat the '$<' as having been plain text, along with the
     // corresponding : and , tokens that might have been found.
     extendText(result, startToken);
-    extendResult(result, identifier);
+    extendResult(result, std::move(identifier));
     if (!parameters.empty()) {
       extendText(result, colonToken);
 
@@ -179,7 +180,7 @@
       assert(parameters.size() > commaTokens.size());
       for (; pit != pend; ++pit, ++commaIt) {
         if (!pit->empty() && !emptyParamTermination) {
-          extendResult(result, *pit);
+          extendResult(result, std::move(*pit));
         }
         if (commaIt != commaTokens.end()) {
           extendText(result, *commaIt);
@@ -193,15 +194,15 @@
 
   size_t contentLength =
     ((this->it - 1)->Content - startToken->Content) + (this->it - 1)->Length;
-  GeneratorExpressionContent* content =
-    new GeneratorExpressionContent(startToken->Content, contentLength);
+  auto content = cm::make_unique<GeneratorExpressionContent>(
+    startToken->Content, contentLength);
   content->SetIdentifier(std::move(identifier));
   content->SetParameters(std::move(parameters));
-  result.push_back(content);
+  result.push_back(std::move(content));
 }
 
 void cmGeneratorExpressionParser::ParseContent(
-  std::vector<cmGeneratorExpressionEvaluator*>& result)
+  cmGeneratorExpressionEvaluatorVector& result)
 {
   assert(this->it != this->Tokens.end());
   switch (this->it->TokenType) {
@@ -213,17 +214,16 @@
           // A comma in 'plain text' could have split text that should
           // otherwise be continuous. Extend the last text content instead of
           // creating a new one.
-          TextContent* textContent =
-            static_cast<TextContent*>(*(result.end() - 1));
-          textContent->Extend(this->it->Length);
+          cm::static_reference_cast<TextContent>(*(result.end() - 1))
+            .Extend(this->it->Length);
           assert(this->it != this->Tokens.end());
           ++this->it;
           return;
         }
       }
-      cmGeneratorExpressionEvaluator* n =
-        new TextContent(this->it->Content, this->it->Length);
-      result.push_back(n);
+      auto n =
+        cm::make_unique<TextContent>(this->it->Content, this->it->Length);
+      result.push_back(std::move(n));
       assert(this->it != this->Tokens.end());
       ++this->it;
       return;
diff --git a/Source/cmGeneratorExpressionParser.h b/Source/cmGeneratorExpressionParser.h
index e663496..1ba1654 100644
--- a/Source/cmGeneratorExpressionParser.h
+++ b/Source/cmGeneratorExpressionParser.h
@@ -5,6 +5,7 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include <memory>
 #include <vector>
 
 #include "cmGeneratorExpressionLexer.h"
@@ -15,11 +16,14 @@
 {
   cmGeneratorExpressionParser(std::vector<cmGeneratorExpressionToken> tokens);
 
-  void Parse(std::vector<cmGeneratorExpressionEvaluator*>& result);
+  using cmGeneratorExpressionEvaluatorVector =
+    std::vector<std::unique_ptr<cmGeneratorExpressionEvaluator>>;
+
+  void Parse(cmGeneratorExpressionEvaluatorVector& result);
 
 private:
-  void ParseContent(std::vector<cmGeneratorExpressionEvaluator*>&);
-  void ParseGeneratorExpression(std::vector<cmGeneratorExpressionEvaluator*>&);
+  void ParseContent(cmGeneratorExpressionEvaluatorVector&);
+  void ParseGeneratorExpression(cmGeneratorExpressionEvaluatorVector&);
 
 private:
   std::vector<cmGeneratorExpressionToken>::const_iterator it;
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 171c3ed..ba2e314 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -10,15 +10,14 @@
 #include <cstdlib>
 #include <cstring>
 #include <iterator>
-#include <memory>
+#include <queue>
 #include <sstream>
 #include <unordered_set>
 #include <utility>
 
+#include <cm/memory>
 #include <cm/string_view>
 
-#include <queue>
-
 #include "cmsys/RegularExpression.hxx"
 
 #include "cmAlgorithms.h"
@@ -26,6 +25,7 @@
 #include "cmCustomCommand.h"
 #include "cmCustomCommandGenerator.h"
 #include "cmCustomCommandLines.h"
+#include "cmFileTimes.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorExpressionContext.h"
@@ -55,11 +55,11 @@
   cmGeneratorTarget const* tgt, cmMessenger* /* messenger */,
   cmListFileBacktrace const& /* context */)
 {
-  return tgt->GetSourcesProperty();
+  return tgt->GetSourcesProperty().c_str();
 }
 
 template <>
-const char*
+const std::string&
 cmTargetPropertyComputer::ComputeLocationForBuild<cmGeneratorTarget>(
   cmGeneratorTarget const* tgt)
 {
@@ -67,7 +67,8 @@
 }
 
 template <>
-const char* cmTargetPropertyComputer::ComputeLocation<cmGeneratorTarget>(
+const std::string&
+cmTargetPropertyComputer::ComputeLocation<cmGeneratorTarget>(
   cmGeneratorTarget const* tgt, const std::string& config)
 {
   return tgt->GetLocation(config);
@@ -162,7 +163,8 @@
   cmListFileBacktrace Backtrace;
 };
 
-cmGeneratorTarget::TargetPropertyEntry* CreateTargetPropertyEntry(
+std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>
+CreateTargetPropertyEntry(
   const std::string& propertyValue,
   cmListFileBacktrace backtrace = cmListFileBacktrace(),
   bool evaluateForBuildsystem = false)
@@ -172,15 +174,18 @@
     std::unique_ptr<cmCompiledGeneratorExpression> cge =
       ge.Parse(propertyValue);
     cge->SetEvaluateForBuildsystem(evaluateForBuildsystem);
-    return new TargetPropertyEntryGenex(std::move(cge));
+    return std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>(
+      cm::make_unique<TargetPropertyEntryGenex>(std::move(cge)));
   }
 
-  return new TargetPropertyEntryString(propertyValue, std::move(backtrace));
+  return std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>(
+    cm::make_unique<TargetPropertyEntryString>(propertyValue,
+                                               std::move(backtrace)));
 }
 
 void CreatePropertyGeneratorExpressions(
   cmStringRange entries, cmBacktraceRange backtraces,
-  std::vector<cmGeneratorTarget::TargetPropertyEntry*>& items,
+  std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>>& items,
   bool evaluateForBuildsystem = false)
 {
   auto btIt = backtraces.begin();
@@ -219,13 +224,13 @@
 EvaluatedTargetPropertyEntry EvaluateTargetPropertyEntry(
   cmGeneratorTarget const* thisTarget, std::string const& config,
   std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
-  cmGeneratorTarget::TargetPropertyEntry* entry)
+  cmGeneratorTarget::TargetPropertyEntry& entry)
 {
-  EvaluatedTargetPropertyEntry ee(entry->LinkImplItem, entry->GetBacktrace());
-  cmExpandList(entry->Evaluate(thisTarget->GetLocalGenerator(), config,
-                               thisTarget, dagChecker, lang),
+  EvaluatedTargetPropertyEntry ee(entry.LinkImplItem, entry.GetBacktrace());
+  cmExpandList(entry.Evaluate(thisTarget->GetLocalGenerator(), config,
+                              thisTarget, dagChecker, lang),
                ee.Values);
-  if (entry->GetHadContextSensitiveCondition()) {
+  if (entry.GetHadContextSensitiveCondition()) {
     ee.ContextDependent = true;
   }
   return ee;
@@ -234,13 +239,14 @@
 std::vector<EvaluatedTargetPropertyEntry> EvaluateTargetPropertyEntries(
   cmGeneratorTarget const* thisTarget, std::string const& config,
   std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker,
-  std::vector<cmGeneratorTarget::TargetPropertyEntry*> const& in)
+  std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>> const&
+    in)
 {
   std::vector<EvaluatedTargetPropertyEntry> out;
   out.reserve(in.size());
-  for (cmGeneratorTarget::TargetPropertyEntry* entry : in) {
+  for (auto& entry : in) {
     out.emplace_back(EvaluateTargetPropertyEntry(thisTarget, config, lang,
-                                                 dagChecker, entry));
+                                                 dagChecker, *entry));
   }
   return out;
 }
@@ -304,29 +310,18 @@
   this->PolicyMap = t->GetPolicyMap();
 }
 
-cmGeneratorTarget::~cmGeneratorTarget()
-{
-  cmDeleteAll(this->IncludeDirectoriesEntries);
-  cmDeleteAll(this->CompileOptionsEntries);
-  cmDeleteAll(this->CompileFeaturesEntries);
-  cmDeleteAll(this->CompileDefinitionsEntries);
-  cmDeleteAll(this->LinkOptionsEntries);
-  cmDeleteAll(this->LinkDirectoriesEntries);
-  cmDeleteAll(this->PrecompileHeadersEntries);
-  cmDeleteAll(this->SourceEntries);
-  cmDeleteAll(this->LinkInformation);
-}
+cmGeneratorTarget::~cmGeneratorTarget() = default;
 
-const char* cmGeneratorTarget::GetSourcesProperty() const
+const std::string& cmGeneratorTarget::GetSourcesProperty() const
 {
   std::vector<std::string> values;
-  for (TargetPropertyEntry* se : this->SourceEntries) {
+  for (auto& se : this->SourceEntries) {
     values.push_back(se->GetInput());
   }
   static std::string value;
   value.clear();
   value = cmJoin(values, ";");
-  return value.c_str();
+  return value;
 }
 
 cmGlobalGenerator* cmGeneratorTarget::GetGlobalGenerator() const
@@ -655,6 +650,7 @@
   this->KindedSourcesMap.clear();
   this->LinkImplementationLanguageIsContextDependent = true;
   this->Objects.clear();
+  this->VisitedConfigsForObjects.clear();
 }
 
 void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before)
@@ -744,7 +740,7 @@
 {
   IMPLEMENT_VISIT(SourceKindObjectSource);
 
-  if (!this->Objects.empty()) {
+  if (this->VisitedConfigsForObjects.count(config)) {
     return;
   }
 
@@ -753,16 +749,17 @@
   }
 
   this->LocalGenerator->ComputeObjectFilenames(this->Objects, this);
+  this->VisitedConfigsForObjects.insert(config);
 }
 
 void cmGeneratorTarget::ComputeObjectMapping()
 {
-  if (!this->Objects.empty()) {
+  auto const& configs = this->Makefile->GetGeneratorConfigs();
+  std::set<std::string> configSet(configs.begin(), configs.end());
+  if (configSet == this->VisitedConfigsForObjects) {
     return;
   }
 
-  std::vector<std::string> const& configs =
-    this->Makefile->GetGeneratorConfigs();
   for (std::string const& c : configs) {
     std::vector<cmSourceFile const*> sourceFiles;
     this->GetObjectSources(sourceFiles, c);
@@ -982,13 +979,15 @@
 {
   if (!this->UtilityItemsDone) {
     this->UtilityItemsDone = true;
-    std::set<BT<std::string>> const& utilities = this->GetUtilities();
-    for (BT<std::string> const& i : utilities) {
+    std::set<BT<std::pair<std::string, bool>>> const& utilities =
+      this->GetUtilities();
+    for (BT<std::pair<std::string, bool>> const& i : utilities) {
       if (cmGeneratorTarget* gt =
-            this->LocalGenerator->FindGeneratorTargetToUse(i.Value)) {
-        this->UtilityItems.insert(cmLinkItem(gt, i.Backtrace));
+            this->LocalGenerator->FindGeneratorTargetToUse(i.Value.first)) {
+        this->UtilityItems.insert(cmLinkItem(gt, i.Value.second, i.Backtrace));
       } else {
-        this->UtilityItems.insert(cmLinkItem(i.Value, i.Backtrace));
+        this->UtilityItems.insert(
+          cmLinkItem(i.Value.first, i.Value.second, i.Backtrace));
       }
     }
   }
@@ -1001,7 +1000,8 @@
   IMPLEMENT_VISIT(SourceKindXaml);
 }
 
-const char* cmGeneratorTarget::GetLocation(const std::string& config) const
+const std::string& cmGeneratorTarget::GetLocation(
+  const std::string& config) const
 {
   static std::string location;
   if (this->IsImported()) {
@@ -1010,7 +1010,7 @@
   } else {
     location = this->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
   }
-  return location.c_str();
+  return location;
 }
 
 std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreBuildCommands()
@@ -1041,13 +1041,13 @@
   return this->Target->IsImportedGloballyVisible();
 }
 
-const char* cmGeneratorTarget::GetLocationForBuild() const
+const std::string& cmGeneratorTarget::GetLocationForBuild() const
 {
   static std::string location;
   if (this->IsImported()) {
     location = this->Target->ImportedGetFullPath(
       "", cmStateEnums::RuntimeBinaryArtifact);
-    return location.c_str();
+    return location;
   }
 
   // Now handle the deprecated build-time configuration location.
@@ -1067,7 +1067,7 @@
   }
   location += "/";
   location += this->GetFullName("", cmStateEnums::RuntimeBinaryArtifact);
-  return location.c_str();
+  return location;
 }
 
 bool cmGeneratorTarget::IsSystemIncludeDirectory(
@@ -1122,7 +1122,8 @@
 }
 
 bool cmGeneratorTarget::MaybeHaveInterfaceProperty(
-  std::string const& prop, cmGeneratorExpressionContext* context) const
+  std::string const& prop, cmGeneratorExpressionContext* context,
+  bool usage_requirements_only) const
 {
   std::string const key = prop + '@' + context->Config;
   auto i = this->MaybeInterfacePropertyExists.find(key);
@@ -1141,7 +1142,7 @@
         context->HeadTarget ? context->HeadTarget : this;
       if (cmLinkInterfaceLibraries const* iface =
             this->GetLinkInterfaceLibraries(context->Config, headTarget,
-                                            true)) {
+                                            usage_requirements_only)) {
         if (iface->HadHeadSensitiveCondition) {
           // With a different head target we may get to a library with
           // this interface property.
@@ -1151,7 +1152,8 @@
           // head target, so we can follow them.
           for (cmLinkItem const& lib : iface->Libraries) {
             if (lib.Target &&
-                lib.Target->MaybeHaveInterfaceProperty(prop, context)) {
+                lib.Target->MaybeHaveInterfaceProperty(
+                  prop, context, usage_requirements_only)) {
               maybeInterfaceProp = true;
               break;
             }
@@ -1165,12 +1167,14 @@
 
 std::string cmGeneratorTarget::EvaluateInterfaceProperty(
   std::string const& prop, cmGeneratorExpressionContext* context,
-  cmGeneratorExpressionDAGChecker* dagCheckerParent) const
+  cmGeneratorExpressionDAGChecker* dagCheckerParent,
+  bool usage_requirements_only) const
 {
   std::string result;
 
   // If the property does not appear transitively at all, we are done.
-  if (!this->MaybeHaveInterfaceProperty(prop, context)) {
+  if (!this->MaybeHaveInterfaceProperty(prop, context,
+                                        usage_requirements_only)) {
     return result;
   }
 
@@ -1202,8 +1206,8 @@
       p, context->LG, context, headTarget, &dagChecker, this);
   }
 
-  if (cmLinkInterfaceLibraries const* iface =
-        this->GetLinkInterfaceLibraries(context->Config, headTarget, true)) {
+  if (cmLinkInterfaceLibraries const* iface = this->GetLinkInterfaceLibraries(
+        context->Config, headTarget, usage_requirements_only)) {
     for (cmLinkItem const& lib : iface->Libraries) {
       // Broken code can have a target in its own link interface.
       // Don't follow such link interface entries so as not to create a
@@ -1217,8 +1221,8 @@
           context->EvaluateForBuildsystem, context->Backtrace,
           context->Language);
         std::string libResult = cmGeneratorExpression::StripEmptyListElements(
-          lib.Target->EvaluateInterfaceProperty(prop, &libContext,
-                                                &dagChecker));
+          lib.Target->EvaluateInterfaceProperty(prop, &libContext, &dagChecker,
+                                                usage_requirements_only));
         if (!libResult.empty()) {
           if (result.empty()) {
             result = std::move(libResult);
@@ -1246,7 +1250,8 @@
                          std::string const& config, std::string const& prop,
                          std::string const& lang,
                          cmGeneratorExpressionDAGChecker* dagChecker,
-                         std::vector<EvaluatedTargetPropertyEntry>& entries)
+                         std::vector<EvaluatedTargetPropertyEntry>& entries,
+                         bool usage_requirements_only = true)
 {
   if (cmLinkImplementationLibraries const* impl =
         headTarget->GetLinkImplementationLibraries(config)) {
@@ -1259,9 +1264,9 @@
         cmGeneratorExpressionContext context(
           headTarget->GetLocalGenerator(), config, false, headTarget,
           headTarget, true, lib.Backtrace, lang);
-        cmExpandList(
-          lib.Target->EvaluateInterfaceProperty(prop, &context, dagChecker),
-          ee.Values);
+        cmExpandList(lib.Target->EvaluateInterfaceProperty(
+                       prop, &context, dagChecker, usage_requirements_only),
+                     ee.Values);
         ee.ContextDependent = context.HadContextSensitiveCondition;
         entries.emplace_back(std::move(ee));
       }
@@ -1672,6 +1677,19 @@
   }
 }
 
+std::set<std::string> cmGeneratorTarget::GetAllConfigCompileLanguages() const
+{
+  std::set<std::string> languages;
+  std::vector<AllConfigSource> const& sources = this->GetAllConfigSources();
+  for (AllConfigSource const& si : sources) {
+    std::string const& lang = si.Source->GetOrDetermineLanguage();
+    if (!lang.empty()) {
+      languages.emplace(lang);
+    }
+  }
+  return languages;
+}
+
 std::string cmGeneratorTarget::GetCompilePDBName(
   const std::string& config) const
 {
@@ -2114,7 +2132,9 @@
     // If building directly for installation then the build tree install_name
     // is the same as the install tree.
     if (this->MacOSXUseInstallNameDir()) {
-      return this->GetInstallNameDirForInstallTree();
+      std::string installPrefix =
+        this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
+      return this->GetInstallNameDirForInstallTree(config, installPrefix);
     }
 
     // Use the build tree directory for the target.
@@ -2132,7 +2152,8 @@
   return "";
 }
 
-std::string cmGeneratorTarget::GetInstallNameDirForInstallTree() const
+std::string cmGeneratorTarget::GetInstallNameDirForInstallTree(
+  const std::string& config, const std::string& installPrefix) const
 {
   if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
     std::string dir;
@@ -2140,7 +2161,13 @@
 
     if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_INSTALL)) {
       if (install_name_dir && *install_name_dir) {
-        dir = cmStrCat(install_name_dir, '/');
+        dir = install_name_dir;
+        cmGeneratorExpression::ReplaceInstallPrefix(dir, installPrefix);
+        dir =
+          cmGeneratorExpression::Evaluate(dir, this->LocalGenerator, config);
+        if (!dir.empty()) {
+          dir = cmStrCat(dir, '/');
+        }
       }
     }
     if (!install_name_dir) {
@@ -2158,7 +2185,8 @@
   return this->Target->GetBacktrace();
 }
 
-const std::set<BT<std::string>>& cmGeneratorTarget::GetUtilities() const
+const std::set<BT<std::pair<std::string, bool>>>&
+cmGeneratorTarget::GetUtilities() const
 {
   return this->Target->GetUtilities();
 }
@@ -2492,11 +2520,11 @@
   info.WindowsExportAllSymbols =
     this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") &&
     this->GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS");
-#if defined(_WIN32) && !defined(CMAKE_BOOTSTRAP)
+#if !defined(CMAKE_BOOTSTRAP)
   info.DefFileGenerated =
     info.WindowsExportAllSymbols || info.Sources.size() > 1;
 #else
-  // Our __create_def helper is only available on Windows.
+  // Our __create_def helper is not available during CMake bootstrap.
   info.DefFileGenerated = false;
 #endif
   if (info.DefFileGenerated) {
@@ -2691,12 +2719,23 @@
   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) {
     // The name is a byproduct of a utility target or a PRE_BUILD, PRE_LINK, or
     // POST_BUILD command.
-    this->GeneratorTarget->Target->AddUtility(t->GetName());
+    this->GeneratorTarget->Target->AddUtility(t->GetName(), false);
   }
   if (cmSourceFile* sf = i->second.Source) {
     // For now only follow the dependency if the source file is not a
@@ -2751,14 +2790,14 @@
         depLocation = cmSystemTools::CollapseFullPath(depLocation);
         tLocation = cmSystemTools::CollapseFullPath(tLocation);
         if (depLocation == tLocation) {
-          this->GeneratorTarget->Target->AddUtility(util);
+          this->GeneratorTarget->Target->AddUtility(util, false);
           return true;
         }
       }
     } else {
       // The original name of the dependency was not a full path.  It
       // must name a target, so add the target-level dependency.
-      this->GeneratorTarget->Target->AddUtility(util);
+      this->GeneratorTarget->Target->AddUtility(util, false);
       return true;
     }
   }
@@ -2786,7 +2825,7 @@
         // this project.  Add the target-level dependency to make
         // sure the executable is up to date before this custom
         // command possibly runs.
-        this->GeneratorTarget->Target->AddUtility(command);
+        this->GeneratorTarget->Target->AddUtility(command, true);
       }
     }
 
@@ -2801,7 +2840,7 @@
   }
 
   for (cmGeneratorTarget* target : targets) {
-    this->GeneratorTarget->Target->AddUtility(target->GetName());
+    this->GeneratorTarget->Target->AddUtility(target->GetName(), true);
   }
 
   // Queue the custom command dependencies.
@@ -3064,7 +3103,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/[^/]+)?/[^/]+$");
@@ -3277,10 +3317,10 @@
           CM_FALLTHROUGH;
         }
         case cmPolicies::OLD: {
-          std::unique_ptr<TargetPropertyEntry> entry(
-            CreateTargetPropertyEntry(configProp));
+          std::unique_ptr<TargetPropertyEntry> entry =
+            CreateTargetPropertyEntry(configProp);
           entries.emplace_back(EvaluateTargetPropertyEntry(
-            this, config, language, &dagChecker, entry.get()));
+            this, config, language, &dagChecker, *entry));
         } break;
         case cmPolicies::NEW:
         case cmPolicies::REQUIRED_ALWAYS:
@@ -3373,14 +3413,22 @@
       { "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) {
       auto pchPrologue = this->Makefile->GetDefinition("CMAKE_PCH_PROLOGUE");
       auto pchEpilogue = this->Makefile->GetDefinition("CMAKE_PCH_EPILOGUE");
 
+      std::string firstHeaderOnDisk;
       {
         cmGeneratedFileStream file(
           filename_tmp, false,
@@ -3404,6 +3452,11 @@
           } else {
             file << "#include \"" << header_bt.Value << "\"\n";
           }
+
+          if (cmSystemTools::FileExists(header_bt.Value) &&
+              firstHeaderOnDisk.empty()) {
+            firstHeaderOnDisk = header_bt.Value;
+          }
         }
         if (language == "CXX") {
           file << "#endif // __cplusplus\n";
@@ -3415,6 +3468,11 @@
           file << pchEpilogue << "\n";
         }
       }
+
+      if (!firstHeaderOnDisk.empty()) {
+        cmFileTimes::Copy(firstHeaderOnDisk, filename_tmp);
+      }
+
       cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
     }
   }
@@ -3473,6 +3531,7 @@
         cmGeneratedFileStream file(filename_tmp);
         file << "/* generated by CMake */\n";
       }
+      cmFileTimes::Copy(pchHeader, filename_tmp);
       cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
     }
   }
@@ -3647,7 +3706,8 @@
                                   this->LinkOptionsEntries);
 
   AddInterfaceEntries(this, config, "INTERFACE_LINK_OPTIONS", language,
-                      &dagChecker, entries);
+                      &dagChecker, entries,
+                      this->GetPolicyStatusCMP0099() != cmPolicies::NEW);
 
   processOptions(this, entries, result, uniqueOptions, debugOptions,
                  "link options", OptionsParse::Shell);
@@ -3779,10 +3839,10 @@
   if (const char* linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) {
     std::vector<std::string> options = cmExpandedList(linkOptions);
     for (const auto& option : options) {
-      std::unique_ptr<TargetPropertyEntry> entry(
-        CreateTargetPropertyEntry(option));
-      entries.emplace_back(EvaluateTargetPropertyEntry(
-        this, config, language, &dagChecker, entry.get()));
+      std::unique_ptr<TargetPropertyEntry> entry =
+        CreateTargetPropertyEntry(option);
+      entries.emplace_back(EvaluateTargetPropertyEntry(this, config, language,
+                                                       &dagChecker, *entry));
     }
   }
   processOptions(this, entries, result, uniqueOptions, false,
@@ -3902,7 +3962,8 @@
                                   this->LinkDirectoriesEntries);
 
   AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES", language,
-                      &dagChecker, entries);
+                      &dagChecker, entries,
+                      this->GetPolicyStatusCMP0099() != cmPolicies::NEW);
 
   processLinkDirectories(this, entries, result, uniqueDirectories,
                          debugDirectories);
@@ -3933,14 +3994,15 @@
   if (const char* linkDepends = this->GetProperty("LINK_DEPENDS")) {
     std::vector<std::string> depends = cmExpandedList(linkDepends);
     for (const auto& depend : depends) {
-      std::unique_ptr<TargetPropertyEntry> entry(
-        CreateTargetPropertyEntry(depend));
-      entries.emplace_back(EvaluateTargetPropertyEntry(
-        this, config, language, &dagChecker, entry.get()));
+      std::unique_ptr<TargetPropertyEntry> entry =
+        CreateTargetPropertyEntry(depend);
+      entries.emplace_back(EvaluateTargetPropertyEntry(this, config, language,
+                                                       &dagChecker, *entry));
     }
   }
   AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS", language,
-                      &dagChecker, entries);
+                      &dagChecker, entries,
+                      this->GetPolicyStatusCMP0099() != cmPolicies::NEW);
 
   processOptions(this, entries, result, uniqueOptions, false, "link depends",
                  OptionsParse::None);
@@ -4720,9 +4782,9 @@
 }
 
 void cmGeneratorTarget::CheckPropertyCompatibility(
-  cmComputeLinkInformation* info, const std::string& config) const
+  cmComputeLinkInformation& info, const std::string& config) const
 {
-  const cmComputeLinkInformation::ItemVector& deps = info->GetItems();
+  const cmComputeLinkInformation::ItemVector& deps = info.GetItems();
 
   std::set<std::string> emittedBools;
   static const std::string strBool = "COMPATIBLE_INTERFACE_BOOL";
@@ -5067,10 +5129,11 @@
   }
 
   std::string interfaceProperty = "INTERFACE_" + p;
-  std::unique_ptr<cmGeneratorExpressionInterpreter> genexInterpreter(
-    p == "POSITION_INDEPENDENT_CODE" ? new cmGeneratorExpressionInterpreter(
-                                         tgt->GetLocalGenerator(), config, tgt)
-                                     : nullptr);
+  std::unique_ptr<cmGeneratorExpressionInterpreter> genexInterpreter;
+  if (p == "POSITION_INDEPENDENT_CODE") {
+    genexInterpreter = cm::make_unique<cmGeneratorExpressionInterpreter>(
+      tgt->GetLocalGenerator(), config, tgt);
+  }
 
   for (cmGeneratorTarget const* theTarget : deps) {
     // An error should be reported if one dependency
@@ -5217,32 +5280,41 @@
   auto i = this->LinkInformation.find(key);
   if (i == this->LinkInformation.end()) {
     // Compute information for this configuration.
-    cmComputeLinkInformation* info =
-      new cmComputeLinkInformation(this, config);
-    if (!info || !info->Compute()) {
-      delete info;
-      info = nullptr;
+    auto info = cm::make_unique<cmComputeLinkInformation>(this, config);
+    if (info && !info->Compute()) {
+      info.reset();
     }
 
     // Store the information for this configuration.
-    cmTargetLinkInformationMap::value_type entry(key, info);
-    i = this->LinkInformation.insert(entry).first;
+    i = this->LinkInformation.emplace(key, std::move(info)).first;
 
-    if (info) {
-      this->CheckPropertyCompatibility(info, config);
+    if (i->second) {
+      this->CheckPropertyCompatibility(*i->second, config);
     }
   }
-  return i->second;
+  return i->second.get();
 }
 
 void cmGeneratorTarget::GetTargetVersion(int& major, int& minor) const
 {
   int patch;
-  this->GetTargetVersion(false, major, minor, patch);
+  this->GetTargetVersion("VERSION", major, minor, patch);
 }
 
-void cmGeneratorTarget::GetTargetVersion(bool soversion, int& major,
-                                         int& minor, int& patch) const
+void cmGeneratorTarget::GetTargetVersionFallback(
+  const std::string& property, const std::string& fallback_property,
+  int& major, int& minor, int& patch) const
+{
+  if (this->GetProperty(property)) {
+    this->GetTargetVersion(property, major, minor, patch);
+  } else {
+    this->GetTargetVersion(fallback_property, major, minor, patch);
+  }
+}
+
+void cmGeneratorTarget::GetTargetVersion(const std::string& property,
+                                         int& major, int& minor,
+                                         int& patch) const
 {
   // Set the default values.
   major = 0;
@@ -5251,9 +5323,7 @@
 
   assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY);
 
-  // Look for a VERSION or SOVERSION property.
-  const char* prop = soversion ? "SOVERSION" : "VERSION";
-  if (const char* version = this->GetProperty(prop)) {
+  if (const char* version = this->GetProperty(property)) {
     // Try to parse the version number and store the results that were
     // successfully parsed.
     int parsed_major;
@@ -5383,16 +5453,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));
   }
 }
 
@@ -5401,6 +5494,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
@@ -6330,6 +6424,21 @@
   return lib;
 }
 
+bool cmGeneratorTarget::IsDeprecated() const
+{
+  const char* deprecation = this->GetProperty("DEPRECATION");
+  return deprecation && *deprecation;
+}
+
+std::string cmGeneratorTarget::GetDeprecation() const
+{
+  // find DEPRECATION property
+  if (const char* deprecation = this->GetProperty("DEPRECATION")) {
+    return deprecation;
+  }
+  return std::string();
+}
+
 void cmGeneratorTarget::GetLanguages(std::set<std::string>& languages,
                                      const std::string& config) const
 {
@@ -6379,8 +6488,7 @@
       this->GetType() != cmStateEnums::EXECUTABLE) {
     return false;
   }
-  std::set<std::string> languages;
-  this->GetLanguages(languages, "");
+  std::set<std::string> languages = this->GetAllConfigCompileLanguages();
   // Consider an explicit linker language property, but *not* the
   // computed linker language that may depend on linked targets.
   const char* linkLang = this->GetProperty("LINKER_LANGUAGE");
@@ -6462,6 +6570,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();
@@ -6470,6 +6579,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);
@@ -6482,6 +6592,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()) {
@@ -6516,7 +6630,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);
     }
 
@@ -6553,38 +6667,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;
   }
@@ -6595,10 +6687,30 @@
 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);
+    return cmLinkItem(resolved.String, false, bt);
+  }
+
+  // Check deprecation, issue message with `bt` backtrace.
+  if (resolved.Target->IsDeprecated()) {
+    std::ostringstream w;
+    /* clang-format off */
+    w <<
+      "The library that is being linked to, "  << resolved.Target->GetName() <<
+      ", is marked as being deprecated by the owner.  The message provided by "
+      "the developer is: \n" << resolved.Target->GetDeprecation() << "\n";
+    /* clang-format on */
+    this->LocalGenerator->GetCMakeInstance()->IssueMessage(
+      MessageType::AUTHOR_WARNING, w.str(), bt);
   }
 
   // Skip targets that will not really be linked.  This is probably a
@@ -6606,10 +6718,10 @@
   // within the project.
   if (resolved.Target->GetType() == cmStateEnums::EXECUTABLE &&
       !resolved.Target->IsExecutableWithExports()) {
-    return cmLinkItem(resolved.Target->GetName(), bt);
+    return cmLinkItem(resolved.Target->GetName(), false, bt);
   }
 
-  return cmLinkItem(resolved.Target, bt);
+  return cmLinkItem(resolved.Target, false, bt);
 }
 
 std::string cmGeneratorTarget::GetPDBDirectory(const std::string& config) const
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 493eafc..d81bb3d 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -7,6 +7,7 @@
 
 #include <cstddef>
 #include <map>
+#include <memory>
 #include <set>
 #include <string>
 #include <unordered_map>
@@ -45,7 +46,7 @@
 
   bool IsImported() const;
   bool IsImportedGloballyVisible() const;
-  const char* GetLocation(const std::string& config) const;
+  const std::string& GetLocation(const std::string& config) const;
 
   std::vector<cmCustomCommand> const& GetPreBuildCommands() const;
   std::vector<cmCustomCommand> const& GetPreLinkCommands() const;
@@ -64,7 +65,7 @@
   /** Get the location of the target in the build tree with a placeholder
       referencing the configuration in the native build system.  This
       location is suitable for use as the LOCATION target property.  */
-  const char* GetLocationForBuild() const;
+  const std::string& GetLocationForBuild() const;
 
   cmComputeLinkInformation* GetLinkInformation(
     const std::string& config) const;
@@ -125,7 +126,7 @@
 
   struct AllConfigSource
   {
-    cmSourceFile const* Source;
+    cmSourceFile* Source;
     cmGeneratorTarget::SourceKind Kind;
     std::vector<size_t> Configs;
   };
@@ -134,6 +135,10 @@
       per-source configurations assigned.  */
   std::vector<AllConfigSource> const& GetAllConfigSources() const;
 
+  /** Get all languages used to compile sources in any configuration.
+      This excludes the languages of objects from object libraries.  */
+  std::set<std::string> GetAllConfigCompileLanguages() const;
+
   void GetObjectSources(std::vector<cmSourceFile const*>&,
                         const std::string& config) const;
   const std::string& GetObjectName(cmSourceFile const* file);
@@ -245,6 +250,13 @@
   std::string GetAppBundleDirectory(const std::string& config,
                                     BundleDirectoryLevel level) const;
 
+  /** Return whether this target is marked as deprecated by the
+      maintainer  */
+  bool IsDeprecated() const;
+
+  /** Returns the deprecation message provided by the maintainer */
+  std::string GetDeprecation() const;
+
   /** Return whether this target is an executable Bundle, a framework
       or CFBundle on Apple.  */
   bool IsBundleOnApple() const;
@@ -274,11 +286,12 @@
 
   /** Return the install name directory for the target in the
    * install tree.  For example: "\@rpath/" or "\@loader_path/". */
-  std::string GetInstallNameDirForInstallTree() const;
+  std::string GetInstallNameDirForInstallTree(
+    const std::string& config, const std::string& installPrefix) const;
 
   cmListFileBacktrace GetBacktrace() const;
 
-  std::set<BT<std::string>> const& GetUtilities() const;
+  std::set<BT<std::pair<std::string, bool>>> const& GetUtilities() const;
 
   bool LinkLanguagePropagatesToDependents() const
   {
@@ -365,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
@@ -701,7 +719,8 @@
 
   std::string EvaluateInterfaceProperty(
     std::string const& prop, cmGeneratorExpressionContext* context,
-    cmGeneratorExpressionDAGChecker* dagCheckerParent) const;
+    cmGeneratorExpressionDAGChecker* dagCheckerParent,
+    bool usage_requirements_only = true) const;
 
   bool HaveInstallTreeRPATH(const std::string& config) const;
 
@@ -736,14 +755,22 @@
   void GetTargetVersion(int& major, int& minor) const;
 
   /** Get the target major, minor, and patch version numbers
-      interpreted from the VERSION or SOVERSION property.  Version 0
+      interpreted from the given property.  Version 0
       is returned if the property is not set or cannot be parsed.  */
-  void GetTargetVersion(bool soversion, int& major, int& minor,
+  void GetTargetVersion(std::string const& property, int& major, int& minor,
                         int& patch) const;
 
+  /** Get the target major, minor, and patch version numbers
+      interpreted from the given property and if empty use the
+      fallback property.  Version 0 is returned if the property is
+      not set or cannot be parsed.  */
+  void GetTargetVersionFallback(const std::string& property,
+                                const std::string& fallback_property,
+                                int& major, int& minor, int& patch) const;
+
   std::string GetFortranModuleDirectory(std::string const& working_dir) const;
 
-  const char* GetSourcesProperty() const;
+  const std::string& GetSourcesProperty() const;
 
 private:
   void AddSourceCommon(const std::string& src, bool before = false);
@@ -760,6 +787,7 @@
   };
   using SourceEntriesType = std::map<cmSourceFile const*, SourceEntry>;
   SourceEntriesType SourceDepends;
+  mutable std::set<std::string> VisitedConfigsForObjects;
   mutable std::map<cmSourceFile const*, std::string> Objects;
   std::set<cmSourceFile const*> ExplicitObjectName;
   mutable std::map<std::string, std::vector<std::string>> SystemIncludesCache;
@@ -816,10 +844,10 @@
   mutable std::map<std::string, CompatibleInterfaces> CompatibleInterfacesMap;
 
   using cmTargetLinkInformationMap =
-    std::map<std::string, cmComputeLinkInformation*>;
+    std::map<std::string, std::unique_ptr<cmComputeLinkInformation>>;
   mutable cmTargetLinkInformationMap LinkInformation;
 
-  void CheckPropertyCompatibility(cmComputeLinkInformation* info,
+  void CheckPropertyCompatibility(cmComputeLinkInformation& info,
                                   const std::string& config) const;
 
   struct LinkImplClosure : public std::vector<cmGeneratorTarget const*>
@@ -880,16 +908,20 @@
 
   mutable std::unordered_map<std::string, bool> MaybeInterfacePropertyExists;
   bool MaybeHaveInterfaceProperty(std::string const& prop,
-                                  cmGeneratorExpressionContext* context) const;
+                                  cmGeneratorExpressionContext* context,
+                                  bool usage_requirements_only) const;
 
-  std::vector<TargetPropertyEntry*> IncludeDirectoriesEntries;
-  std::vector<TargetPropertyEntry*> CompileOptionsEntries;
-  std::vector<TargetPropertyEntry*> CompileFeaturesEntries;
-  std::vector<TargetPropertyEntry*> CompileDefinitionsEntries;
-  std::vector<TargetPropertyEntry*> LinkOptionsEntries;
-  std::vector<TargetPropertyEntry*> LinkDirectoriesEntries;
-  std::vector<TargetPropertyEntry*> PrecompileHeadersEntries;
-  std::vector<TargetPropertyEntry*> SourceEntries;
+  using TargetPropertyEntryVector =
+    std::vector<std::unique_ptr<TargetPropertyEntry>>;
+
+  TargetPropertyEntryVector IncludeDirectoriesEntries;
+  TargetPropertyEntryVector CompileOptionsEntries;
+  TargetPropertyEntryVector CompileFeaturesEntries;
+  TargetPropertyEntryVector CompileDefinitionsEntries;
+  TargetPropertyEntryVector LinkOptionsEntries;
+  TargetPropertyEntryVector LinkDirectoriesEntries;
+  TargetPropertyEntryVector PrecompileHeadersEntries;
+  TargetPropertyEntryVector SourceEntries;
   mutable std::set<std::string> LinkImplicitNullProperties;
   mutable std::map<std::string, std::string> PchHeaders;
   mutable std::map<std::string, std::string> PchSources;
@@ -900,6 +932,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/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index 8e4352e..5e2248e 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -113,7 +113,7 @@
 
   // Tell the global generator the name of the project file
   this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME",
-                                             this->Name.c_str());
+                                             this->Name);
   this->GeneratorTarget->Target->SetProperty(
     "GENERATOR_FILE_NAME_EXT", GhsMultiGpj::GetGpjTag(this->TagType));
 
@@ -279,10 +279,10 @@
   std::string frameworkPath;
   std::string linkPath;
 
-  std::unique_ptr<cmLinkLineComputer> linkLineComputer(
+  std::unique_ptr<cmLinkLineComputer> linkLineComputer =
     this->GetGlobalGenerator()->CreateLinkLineComputer(
       this->LocalGenerator,
-      this->LocalGenerator->GetStateSnapshot().GetDirectory()));
+      this->LocalGenerator->GetStateSnapshot().GetDirectory());
 
   this->LocalGenerator->GetTargetFlags(
     linkLineComputer.get(), config, linkLibraries, flags, linkFlags,
diff --git a/Source/cmGlobVerificationManager.cxx b/Source/cmGlobVerificationManager.cxx
index 4817773..9ac5cd5 100644
--- a/Source/cmGlobVerificationManager.cxx
+++ b/Source/cmGlobVerificationManager.cxx
@@ -38,6 +38,8 @@
                    << cmVersion::GetMajorVersion() << "."
                    << cmVersion::GetMinorVersion() << "\n";
 
+  verifyScriptFile << "cmake_policy(SET CMP0009 NEW)\n";
+
   for (auto const& i : this->Cache) {
     CacheEntryKey k = std::get<0>(i);
     CacheEntryValue v = std::get<1>(i);
diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx
index 51d681d..06943e7 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.cxx
+++ b/Source/cmGlobalBorlandMakefileGenerator.cxx
@@ -2,6 +2,10 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGlobalBorlandMakefileGenerator.h"
 
+#include <utility>
+
+#include <cm/memory>
+
 #include "cmDocumentationEntry.h"
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmMakefile.h"
@@ -35,15 +39,14 @@
 }
 
 //! Create a local generator appropriate to this Global Generator
-cmLocalGenerator* cmGlobalBorlandMakefileGenerator::CreateLocalGenerator(
-  cmMakefile* mf)
+std::unique_ptr<cmLocalGenerator>
+cmGlobalBorlandMakefileGenerator::CreateLocalGenerator(cmMakefile* mf)
 {
-  cmLocalUnixMakefileGenerator3* lg =
-    new cmLocalUnixMakefileGenerator3(this, mf);
+  auto lg = cm::make_unique<cmLocalUnixMakefileGenerator3>(this, mf);
   lg->SetMakefileVariableSize(32);
   lg->SetMakeCommandEscapeTargetTwice(true);
   lg->SetBorlandMakeCurlyHack(true);
-  return lg;
+  return std::unique_ptr<cmLocalGenerator>(std::move(lg));
 }
 
 void cmGlobalBorlandMakefileGenerator::GetDocumentation(
diff --git a/Source/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h
index da04743..9af0eac 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.h
+++ b/Source/cmGlobalBorlandMakefileGenerator.h
@@ -4,6 +4,7 @@
 #define cmGlobalBorlandMakefileGenerator_h
 
 #include <iosfwd>
+#include <memory>
 
 #include "cmGlobalNMakeMakefileGenerator.h"
 
@@ -16,10 +17,10 @@
 {
 public:
   cmGlobalBorlandMakefileGenerator(cmake* cm);
-  static cmGlobalGeneratorFactory* NewFactory()
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
   {
-    return new cmGlobalGeneratorSimpleFactory<
-      cmGlobalBorlandMakefileGenerator>();
+    return std::unique_ptr<cmGlobalGeneratorFactory>(
+      new cmGlobalGeneratorSimpleFactory<cmGlobalBorlandMakefileGenerator>());
   }
 
   //! Get the name for the generator.
@@ -33,7 +34,8 @@
   static void GetDocumentation(cmDocumentationEntry& entry);
 
   //! Create a local generator appropriate to this Global Generator
-  cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
+  std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+    cmMakefile* mf) override;
 
   /**
    * Try to determine system information such as shared library
diff --git a/Source/cmGlobalCommonGenerator.cxx b/Source/cmGlobalCommonGenerator.cxx
index 9fa4467..e04eef1 100644
--- a/Source/cmGlobalCommonGenerator.cxx
+++ b/Source/cmGlobalCommonGenerator.cxx
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGlobalCommonGenerator.h"
 
+#include <memory>
 #include <utility>
 
 #include "cmGeneratorTarget.h"
@@ -24,15 +25,15 @@
 cmGlobalCommonGenerator::ComputeDirectoryTargets() const
 {
   std::map<std::string, DirectoryTarget> dirTargets;
-  for (cmLocalGenerator* lg : this->LocalGenerators) {
+  for (const auto& lg : this->LocalGenerators) {
     std::string const& currentBinaryDir(
       lg->GetStateSnapshot().GetDirectory().GetCurrentBinary());
     DirectoryTarget& dirTarget = dirTargets[currentBinaryDir];
-    dirTarget.LG = lg;
+    dirTarget.LG = lg.get();
 
     // The directory-level rule should depend on the target-level rules
     // for all targets in the directory.
-    for (auto gt : lg->GetGeneratorTargets()) {
+    for (const auto& gt : lg->GetGeneratorTargets()) {
       cmStateEnums::TargetType const type = gt->GetType();
       if (type != cmStateEnums::EXECUTABLE &&
           type != cmStateEnums::STATIC_LIBRARY &&
@@ -43,7 +44,7 @@
         continue;
       }
       DirectoryTarget::Target t;
-      t.GT = gt;
+      t.GT = gt.get();
       if (const char* exclude = gt->GetProperty("EXCLUDE_FROM_ALL")) {
         if (cmIsOn(exclude)) {
           // This target has been explicitly excluded.
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 09fb87d..6a2d4c7 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -7,9 +7,13 @@
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
+#include <functional>
 #include <initializer_list>
 #include <iterator>
 #include <sstream>
+#include <utility>
+
+#include <cm/memory>
 
 #include "cmsys/Directory.hxx"
 #include "cmsys/FStream.hxx"
@@ -31,6 +35,7 @@
 #include "cmGeneratorTarget.h"
 #include "cmInstallGenerator.h"
 #include "cmLinkLineComputer.h"
+#include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMSVC60LinkLineComputer.h"
 #include "cmMakefile.h"
@@ -121,6 +126,7 @@
 {
   Json::Value generator = Json::objectValue;
   generator["name"] = this->GetName();
+  generator["multiConfig"] = this->IsMultiConfig();
   return generator;
 }
 #endif
@@ -165,7 +171,7 @@
   return false;
 }
 
-bool cmGlobalGenerator::SetGeneratorToolset(std::string const& ts,
+bool cmGlobalGenerator::SetGeneratorToolset(std::string const& ts, bool,
                                             cmMakefile* mf)
 {
   if (ts.empty()) {
@@ -264,8 +270,8 @@
 void cmGlobalGenerator::AddBuildExportExportSet(
   cmExportBuildFileGenerator* gen)
 {
-  this->BuildExportSets[gen->GetMainExportFileName()] = gen;
   this->BuildExportExportSets[gen->GetMainExportFileName()] = gen;
+  this->AddBuildExportSet(gen);
 }
 
 bool cmGlobalGenerator::GenerateImportFile(const std::string& file)
@@ -275,13 +281,11 @@
     bool result = it->second->GenerateImportFile();
 
     if (!this->ConfigureDoneCMP0026AndCMP0024) {
-      for (cmMakefile* m : this->Makefiles) {
+      for (const auto& m : this->Makefiles) {
         m->RemoveExportBuildFileGeneratorCMP0024(it->second);
       }
     }
 
-    delete it->second;
-    it->second = nullptr;
     this->BuildExportSets.erase(it);
     return result;
   }
@@ -295,8 +299,8 @@
 bool cmGlobalGenerator::CheckTargetsForMissingSources() const
 {
   bool failed = false;
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
-    for (cmGeneratorTarget* target : localGen->GetGeneratorTargets()) {
+  for (const auto& localGen : this->LocalGenerators) {
+    for (const auto& target : localGen->GetGeneratorTargets()) {
       if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET ||
           target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY ||
           target->GetType() == cmStateEnums::TargetType::UTILITY ||
@@ -335,8 +339,8 @@
     return false;
   }
   bool failed = false;
-  for (cmLocalGenerator* generator : this->LocalGenerators) {
-    for (cmGeneratorTarget* target : generator->GetGeneratorTargets()) {
+  for (const auto& generator : this->LocalGenerators) {
+    for (const auto& target : generator->GetGeneratorTargets()) {
       if (target->GetType() == cmStateEnums::EXECUTABLE &&
           target->GetPropertyAsBool("WIN32_EXECUTABLE")) {
         std::vector<std::string> const& configs =
@@ -363,8 +367,8 @@
     return false;
   }
   bool failed = false;
-  for (cmLocalGenerator* generator : this->LocalGenerators) {
-    for (cmGeneratorTarget* target : generator->GetGeneratorTargets()) {
+  for (const auto& generator : this->LocalGenerators) {
+    for (const auto& target : generator->GetGeneratorTargets()) {
       if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET ||
           target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY ||
           target->GetType() == cmStateEnums::TargetType::UTILITY ||
@@ -650,7 +654,7 @@
 
     // Tell the generator about the toolset, if any.
     std::string toolset = mf->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET");
-    if (!this->SetGeneratorToolset(toolset, mf)) {
+    if (!this->SetGeneratorToolset(toolset, false, mf)) {
       cmSystemTools::SetFatalErrorOccured();
       return;
     }
@@ -1199,13 +1203,12 @@
 void cmGlobalGenerator::CreateLocalGenerators()
 {
   this->LocalGeneratorSearchIndex.clear();
-  cmDeleteAll(this->LocalGenerators);
   this->LocalGenerators.clear();
   this->LocalGenerators.reserve(this->Makefiles.size());
-  for (cmMakefile* m : this->Makefiles) {
-    cmLocalGenerator* lg = this->CreateLocalGenerator(m);
-    this->LocalGenerators.push_back(lg);
-    this->IndexLocalGenerator(lg);
+  for (const auto& m : this->Makefiles) {
+    auto lg = this->CreateLocalGenerator(m.get());
+    this->IndexLocalGenerator(lg.get());
+    this->LocalGenerators.push_back(std::move(lg));
   }
 }
 
@@ -1221,9 +1224,10 @@
   snapshot.GetDirectory().SetCurrentBinary(
     this->CMakeInstance->GetHomeOutputDirectory());
 
-  cmMakefile* dirMf = new cmMakefile(this, snapshot);
+  auto dirMfu = cm::make_unique<cmMakefile>(this, snapshot);
+  auto dirMf = dirMfu.get();
+  this->Makefiles.push_back(std::move(dirMfu));
   dirMf->SetRecursionDepth(this->RecursionDepth);
-  this->Makefiles.push_back(dirMf);
   this->IndexMakefile(dirMf);
 
   this->BinaryDirectories.insert(
@@ -1241,11 +1245,11 @@
     std::vector<GlobalTargetInfo> globalTargets;
     this->CreateDefaultGlobalTargets(globalTargets);
 
-    for (cmMakefile* mf : this->Makefiles) {
+    for (const auto& mf : this->Makefiles) {
       auto& targets = mf->GetTargets();
       for (GlobalTargetInfo const& globalTarget : globalTargets) {
         targets.emplace(globalTarget.Name,
-                        this->CreateGlobalTarget(globalTarget, mf));
+                        this->CreateGlobalTarget(globalTarget, mf.get()));
       }
     }
   }
@@ -1258,10 +1262,6 @@
                                           "number of local generators",
                                           cmStateEnums::INTERNAL);
 
-  // check for link libraries and include directories containing "NOTFOUND"
-  // and for infinite loops
-  this->CheckTargetProperties();
-
   if (this->CMakeInstance->GetWorkingMode() == cmake::NORMAL_MODE) {
     std::ostringstream msg;
     if (cmSystemTools::GetErrorOccuredFlag()) {
@@ -1284,6 +1284,10 @@
 void cmGlobalGenerator::CreateGenerationObjects(TargetTypes targetTypes)
 {
   this->CreateLocalGenerators();
+  // Commit side effects only if we are actually generating
+  if (this->GetConfigureDoneCMP0026()) {
+    this->CheckTargetProperties();
+  }
   this->CreateGeneratorTargets(targetTypes);
   this->ComputeBuildFileGenerators();
 }
@@ -1294,8 +1298,11 @@
 {
   this->CreateGenerationObjects(ImportedOnly);
   auto const mfit =
-    std::find(this->Makefiles.begin(), this->Makefiles.end(), mf);
-  cmLocalGenerator* lg =
+    std::find_if(this->Makefiles.begin(), this->Makefiles.end(),
+                 [mf](const std::unique_ptr<cmMakefile>& item) {
+                   return item.get() == mf;
+                 });
+  auto& lg =
     this->LocalGenerators[std::distance(this->Makefiles.begin(), mfit)];
   for (std::string const& t : targets) {
     cmGeneratorTarget* gt = lg->FindGeneratorTargetToUse(t);
@@ -1345,16 +1352,51 @@
 void cmGlobalGenerator::ComputeBuildFileGenerators()
 {
   for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
-    std::vector<cmExportBuildFileGenerator*> gens =
+    std::vector<std::unique_ptr<cmExportBuildFileGenerator>> const& gens =
       this->Makefiles[i]->GetExportBuildFileGenerators();
-    for (cmExportBuildFileGenerator* g : gens) {
-      g->Compute(this->LocalGenerators[i]);
+    for (std::unique_ptr<cmExportBuildFileGenerator> const& g : gens) {
+      g->Compute(this->LocalGenerators[i].get());
     }
   }
 }
 
+bool cmGlobalGenerator::UnsupportedVariableIsDefined(const std::string& name,
+                                                     bool supported) const
+{
+  if (!supported && this->Makefiles.front()->GetDefinition(name)) {
+    std::ostringstream e;
+    /* clang-format off */
+    e <<
+      "Generator\n"
+      "  " << this->GetName() << "\n"
+      "does not support variable\n"
+      "  " << name << "\n"
+      "but it has been specified."
+      ;
+    /* clang-format on */
+    this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    return true;
+  }
+
+  return false;
+}
+
 bool cmGlobalGenerator::Compute()
 {
+  // Make sure unsupported variables are not used.
+  if (this->UnsupportedVariableIsDefined("CMAKE_DEFAULT_BUILD_TYPE",
+                                         this->SupportsDefaultBuildType())) {
+    return false;
+  }
+  if (this->UnsupportedVariableIsDefined("CMAKE_CROSS_CONFIGS",
+                                         this->SupportsCrossConfigs())) {
+    return false;
+  }
+  if (this->UnsupportedVariableIsDefined("CMAKE_DEFAULT_CONFIGS",
+                                         this->SupportsDefaultConfigs())) {
+    return false;
+  }
+
   // Some generators track files replaced during the Generate.
   // Start with an empty vector:
   this->FilesReplacedDuringGenerate.clear();
@@ -1387,7 +1429,7 @@
   }
 
   // Add generator specific helper commands
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
+  for (const auto& localGen : this->LocalGenerators) {
     localGen->AddHelperCommands();
   }
 
@@ -1397,16 +1439,16 @@
   // on the original cmTarget instance.  It accumulates features
   // across all configurations.  Some refactoring is needed to
   // compute a per-config resulta purely during generation.
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
+  for (const auto& localGen : this->LocalGenerators) {
     if (!localGen->ComputeTargetCompileFeatures()) {
       return false;
     }
   }
 
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
+  for (const auto& localGen : this->LocalGenerators) {
     cmMakefile* mf = localGen->GetMakefile();
-    for (cmInstallGenerator* g : mf->GetInstallGenerators()) {
-      if (!g->Compute(localGen)) {
+    for (const auto& g : mf->GetInstallGenerators()) {
+      if (!g->Compute(localGen.get())) {
         return false;
       }
     }
@@ -1416,7 +1458,7 @@
 
   // Trace the dependencies, after that no custom commands should be added
   // because their dependencies might not be handled correctly
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
+  for (const auto& localGen : this->LocalGenerators) {
     localGen->TraceDependencies();
   }
 
@@ -1428,7 +1470,7 @@
   this->ForceLinkerLanguages();
 
   // Compute the manifest of main targets generated.
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
+  for (const auto& localGen : this->LocalGenerators) {
     localGen->ComputeTargetManifest();
   }
 
@@ -1445,7 +1487,7 @@
     return false;
   }
 
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
+  for (const auto& localGen : this->LocalGenerators) {
     localGen->ComputeHomeRelativeOutputPath();
   }
 
@@ -1460,6 +1502,8 @@
 
   this->ProcessEvaluationFiles();
 
+  this->CMakeInstance->UpdateProgress("Generating", 0.1f);
+
   // Generate project files
   for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
     this->SetCurrentMakefile(this->LocalGenerators[i]->GetMakefile());
@@ -1471,8 +1515,9 @@
     this->LocalGenerators[i]->GenerateTestFiles();
     this->CMakeInstance->UpdateProgress(
       "Generating",
-      (static_cast<float>(i) + 1.0f) /
-        static_cast<float>(this->LocalGenerators.size()));
+      0.1f +
+        0.9f * (static_cast<float>(i) + 1.0f) /
+          static_cast<float>(this->LocalGenerators.size()));
   }
   this->SetCurrentMakefile(nullptr);
 
@@ -1555,40 +1600,42 @@
 
 bool cmGlobalGenerator::AddAutomaticSources()
 {
-  for (cmLocalGenerator* lg : this->LocalGenerators) {
+  for (const auto& lg : this->LocalGenerators) {
     lg->CreateEvaluationFileOutputs();
-    for (cmGeneratorTarget* gt : lg->GetGeneratorTargets()) {
+    for (const auto& gt : lg->GetGeneratorTargets()) {
       if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
           gt->GetType() == cmStateEnums::UTILITY ||
           gt->GetType() == cmStateEnums::GLOBAL_TARGET) {
         continue;
       }
-      lg->AddUnityBuild(gt);
-      lg->AddPchDependencies(gt);
+      lg->AddUnityBuild(gt.get());
+      lg->AddPchDependencies(gt.get());
     }
   }
   // The above transformations may have changed the classification of sources.
   // Clear the source list and classification cache (KindedSources) of all
   // targets so that it will be recomputed correctly by the generators later
   // now that the above transformations are done for all targets.
-  for (cmLocalGenerator* lg : this->LocalGenerators) {
-    for (cmGeneratorTarget* gt : lg->GetGeneratorTargets()) {
+  for (const auto& lg : this->LocalGenerators) {
+    for (const auto& gt : lg->GetGeneratorTargets()) {
       gt->ClearSourcesCache();
     }
   }
   return true;
 }
 
-cmLinkLineComputer* cmGlobalGenerator::CreateLinkLineComputer(
+std::unique_ptr<cmLinkLineComputer> cmGlobalGenerator::CreateLinkLineComputer(
   cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const
 {
-  return new cmLinkLineComputer(outputConverter, stateDir);
+  return cm::make_unique<cmLinkLineComputer>(outputConverter, stateDir);
 }
 
-cmLinkLineComputer* cmGlobalGenerator::CreateMSVC60LinkLineComputer(
+std::unique_ptr<cmLinkLineComputer>
+cmGlobalGenerator::CreateMSVC60LinkLineComputer(
   cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const
 {
-  return new cmMSVC60LinkLineComputer(outputConverter, stateDir);
+  return std::unique_ptr<cmLinkLineComputer>(
+    cm::make_unique<cmMSVC60LinkLineComputer>(outputConverter, stateDir));
 }
 
 void cmGlobalGenerator::FinalizeTargetCompileInfo()
@@ -1597,7 +1644,7 @@
     this->CMakeInstance->GetState()->GetEnabledLanguages();
 
   // Construct per-target generator information.
-  for (cmMakefile* mf : this->Makefiles) {
+  for (const auto& mf : this->Makefiles) {
     const cmStringRange noconfig_compile_definitions =
       mf->GetCompileDefinitionsEntries();
     const cmBacktraceRange noconfig_compile_definitions_bts =
@@ -1632,7 +1679,9 @@
         for (std::string const& c : configs) {
           std::string defPropName =
             cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(c));
-          t->AppendProperty(defPropName, mf->GetProperty(defPropName));
+          if (const char* val = mf->GetProperty(defPropName)) {
+            t->AppendProperty(defPropName, val);
+          }
         }
       }
     }
@@ -1661,8 +1710,7 @@
   if (targetTypes == AllTargets) {
     for (auto& target : mf->GetTargets()) {
       cmTarget* t = &target.second;
-      cmGeneratorTarget* gt = new cmGeneratorTarget(t, lg);
-      lg->AddGeneratorTarget(gt);
+      lg->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(t, lg));
     }
   }
 
@@ -1675,31 +1723,28 @@
 {
   std::map<cmTarget*, cmGeneratorTarget*> importedMap;
   for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
-    cmMakefile* mf = this->Makefiles[i];
-    for (cmTarget* ownedImpTgt : mf->GetOwnedImportedTargets()) {
-      cmLocalGenerator* lg = this->LocalGenerators[i];
-      cmGeneratorTarget* gt = new cmGeneratorTarget(ownedImpTgt, lg);
-      lg->AddOwnedImportedGeneratorTarget(gt);
-      importedMap[ownedImpTgt] = gt;
+    auto& mf = this->Makefiles[i];
+    for (const auto& ownedImpTgt : mf->GetOwnedImportedTargets()) {
+      cmLocalGenerator* lg = this->LocalGenerators[i].get();
+      auto gt = cm::make_unique<cmGeneratorTarget>(ownedImpTgt.get(), lg);
+      importedMap[ownedImpTgt.get()] = gt.get();
+      lg->AddOwnedImportedGeneratorTarget(std::move(gt));
     }
   }
 
   // Construct per-target generator information.
   for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
-    this->CreateGeneratorTargets(targetTypes, this->Makefiles[i],
-                                 this->LocalGenerators[i], importedMap);
+    this->CreateGeneratorTargets(targetTypes, this->Makefiles[i].get(),
+                                 this->LocalGenerators[i].get(), importedMap);
   }
 }
 
 void cmGlobalGenerator::ClearGeneratorMembers()
 {
-  cmDeleteAll(this->BuildExportSets);
   this->BuildExportSets.clear();
 
-  cmDeleteAll(this->Makefiles);
   this->Makefiles.clear();
 
-  cmDeleteAll(this->LocalGenerators);
   this->LocalGenerators.clear();
 
   this->AliasTargets.clear();
@@ -1722,12 +1767,12 @@
 
 void cmGlobalGenerator::CheckTargetProperties()
 {
+  // check for link libraries and include directories containing "NOTFOUND"
+  // and for infinite loops
   std::map<std::string, std::string> notFoundMap;
-  //  std::set<std::string> notFoundMap;
-  // after it is all done do a ConfigureFinalPass
   cmState* state = this->GetCMakeInstance()->GetState();
   for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
-    this->Makefiles[i]->ConfigureFinalPass();
+    this->Makefiles[i]->Generate(*this->LocalGenerators[i]);
     for (auto const& target : this->Makefiles[i]->GetTargets()) {
       if (target.second.GetType() == cmStateEnums::INTERFACE_LIBRARY) {
         continue;
@@ -1771,11 +1816,6 @@
         }
       }
     }
-    this->CMakeInstance->UpdateProgress(
-      "Configuring",
-      0.9f +
-        0.1f * (static_cast<float>(i) + 1.0f) /
-          static_cast<float>(this->Makefiles.size()));
   }
 
   if (!notFoundMap.empty()) {
@@ -1872,6 +1912,10 @@
     output += "\n";
     return 1;
   }
+  std::string realConfig = config;
+  if (realConfig.empty()) {
+    realConfig = this->GetDefaultBuildConfig();
+  }
 
   int retVal = 0;
   cmSystemTools::SetRunCommandHideConsole(true);
@@ -1880,7 +1924,7 @@
 
   std::vector<GeneratedMakeCommand> makeCommand =
     this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, targets,
-                               config, fast, jobs, verbose, nativeOptions);
+                               realConfig, fast, jobs, verbose, nativeOptions);
 
   // Workaround to convince some commands to produce output.
   if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH &&
@@ -1892,7 +1936,7 @@
   if (clean) {
     std::vector<GeneratedMakeCommand> cleanCommand =
       this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir,
-                                 { "clean" }, config, fast, jobs, verbose);
+                                 { "clean" }, realConfig, fast, jobs, verbose);
     output += "\nRun Clean Command:";
     output += cleanCommand.front().Printable();
     output += "\n";
@@ -1999,10 +2043,10 @@
   return makeCommand;
 }
 
-void cmGlobalGenerator::AddMakefile(cmMakefile* mf)
+void cmGlobalGenerator::AddMakefile(std::unique_ptr<cmMakefile> mf)
 {
-  this->Makefiles.push_back(mf);
-  this->IndexMakefile(mf);
+  this->IndexMakefile(mf.get());
+  this->Makefiles.push_back(std::move(mf));
 
   // update progress
   // estimate how many lg there will be
@@ -2025,10 +2069,10 @@
   }
 
   int numGen = atoi(numGenC->c_str());
-  float prog = 0.9f * static_cast<float>(this->Makefiles.size()) /
-    static_cast<float>(numGen);
-  if (prog > 0.9f) {
-    prog = 0.9f;
+  float prog =
+    static_cast<float>(this->Makefiles.size()) / static_cast<float>(numGen);
+  if (prog > 1.0f) {
+    prog = 1.0f;
   }
   this->CMakeInstance->UpdateProgress("Configuring", prog);
 }
@@ -2045,9 +2089,10 @@
   this->InstallTargetEnabled = true;
 }
 
-cmLocalGenerator* cmGlobalGenerator::CreateLocalGenerator(cmMakefile* mf)
+std::unique_ptr<cmLocalGenerator> cmGlobalGenerator::CreateLocalGenerator(
+  cmMakefile* mf)
 {
-  return new cmLocalGenerator(this, mf);
+  return cm::make_unique<cmLocalGenerator>(this, mf);
 }
 
 void cmGlobalGenerator::EnableLanguagesFromGenerator(cmGlobalGenerator* gen,
@@ -2142,7 +2187,7 @@
 void cmGlobalGenerator::FillProjectMap()
 {
   this->ProjectMap.clear(); // make sure we start with a clean map
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
+  for (const auto& localGen : this->LocalGenerators) {
     // for each local generator add all projects
     cmStateSnapshot snp = localGen->GetStateSnapshot();
     std::string name;
@@ -2150,7 +2195,7 @@
       std::string snpProjName = snp.GetProjectName();
       if (name != snpProjName) {
         name = snpProjName;
-        this->ProjectMap[name].push_back(localGen);
+        this->ProjectMap[name].push_back(localGen.get());
       }
       snp = snp.GetBuildsystemDirectoryParent();
     } while (snp.IsValid());
@@ -2353,7 +2398,7 @@
 void cmGlobalGenerator::AddGlobalTarget_Package(
   std::vector<GlobalTargetInfo>& targets)
 {
-  cmMakefile* mf = this->Makefiles[0];
+  auto& mf = this->Makefiles[0];
   std::string configFile =
     cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackConfig.cmake");
   if (!cmSystemTools::FileExists(configFile)) {
@@ -2402,7 +2447,7 @@
     return;
   }
 
-  cmMakefile* mf = this->Makefiles[0];
+  auto& mf = this->Makefiles[0];
   std::string configFile =
     cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackSourceConfig.cmake");
   if (!cmSystemTools::FileExists(configFile)) {
@@ -2434,7 +2479,7 @@
 void cmGlobalGenerator::AddGlobalTarget_Test(
   std::vector<GlobalTargetInfo>& targets)
 {
-  cmMakefile* mf = this->Makefiles[0];
+  auto& mf = this->Makefiles[0];
   if (!mf->IsOn("CMAKE_TESTING_ENABLED")) {
     return;
   }
@@ -2454,6 +2499,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);
@@ -2475,6 +2527,7 @@
   }
   GlobalTargetInfo gti;
   gti.Name = editCacheTargetName;
+  gti.PerConfig = false;
   cmCustomCommandLine singleLine;
 
   // Use generator preference for the edit_cache rule if it is defined.
@@ -2509,8 +2562,10 @@
   gti.Name = rebuildCacheTargetName;
   gti.Message = "Running CMake to regenerate build system...";
   gti.UsesTerminal = true;
+  gti.PerConfig = false;
   cmCustomCommandLine singleLine;
   singleLine.push_back(cmSystemTools::GetCMakeCommand());
+  singleLine.push_back("--regenerate-during-build");
   singleLine.push_back("-S$(CMAKE_SOURCE_DIR)");
   singleLine.push_back("-B$(CMAKE_BINARY_DIR)");
   gti.CommandLines.push_back(std::move(singleLine));
@@ -2520,7 +2575,7 @@
 void cmGlobalGenerator::AddGlobalTarget_Install(
   std::vector<GlobalTargetInfo>& targets)
 {
-  cmMakefile* mf = this->Makefiles[0];
+  auto& mf = this->Makefiles[0];
   const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir();
   bool skipInstallRules = mf->IsOn("CMAKE_SKIP_INSTALL_RULES");
   if (this->InstallTargetEnabled && skipInstallRules) {
@@ -2570,7 +2625,7 @@
     singleLine.push_back(cmd);
     if (cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.') {
       std::string cfgArg = "-DBUILD_TYPE=";
-      bool useEPN = this->UseEffectivePlatformName(mf);
+      bool useEPN = this->UseEffectivePlatformName(mf.get());
       if (useEPN) {
         cfgArg += "$(CONFIGURATION)";
         singleLine.push_back(cfgArg);
@@ -2653,22 +2708,22 @@
 {
   // Package
   cmTarget target(gti.Name, cmStateEnums::GLOBAL_TARGET,
-                  cmTarget::VisibilityNormal, mf);
+                  cmTarget::VisibilityNormal, mf, gti.PerConfig);
   target.SetProperty("EXCLUDE_FROM_ALL", "TRUE");
 
   std::vector<std::string> no_outputs;
   std::vector<std::string> no_byproducts;
   std::vector<std::string> no_depends;
   // Store the custom command in the target.
-  cmCustomCommand cc(nullptr, no_outputs, no_byproducts, no_depends,
-                     gti.CommandLines, nullptr, gti.WorkingDir.c_str());
+  cmCustomCommand cc(no_outputs, no_byproducts, no_depends, gti.CommandLines,
+                     cmListFileBacktrace(), nullptr, gti.WorkingDir.c_str());
   cc.SetUsesTerminal(gti.UsesTerminal);
   target.AddPostBuildCommand(std::move(cc));
   if (!gti.Message.empty()) {
-    target.SetProperty("EchoString", gti.Message.c_str());
+    target.SetProperty("EchoString", gti.Message);
   }
   for (std::string const& d : gti.Depends) {
-    target.AddUtility(d);
+    target.AddUtility(d, false);
   }
 
   // Organize in the "predefined targets" folder:
@@ -2737,9 +2792,9 @@
 }
 
 void cmGlobalGenerator::SetExternalMakefileProjectGenerator(
-  cmExternalMakefileProjectGenerator* extraGenerator)
+  std::unique_ptr<cmExternalMakefileProjectGenerator> extraGenerator)
 {
-  this->ExtraGenerator.reset(extraGenerator);
+  this->ExtraGenerator = std::move(extraGenerator);
   if (this->ExtraGenerator) {
     this->ExtraGenerator->SetGlobalGenerator(this);
   }
@@ -2765,27 +2820,26 @@
             std::back_inserter(filenames));
 }
 
-void cmGlobalGenerator::GetTargetSets(TargetDependSet& projectTargets,
-                                      TargetDependSet& originalTargets,
-                                      cmLocalGenerator* root,
-                                      GeneratorVector const& generators)
+void cmGlobalGenerator::GetTargetSets(
+  TargetDependSet& projectTargets, TargetDependSet& originalTargets,
+  cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
 {
   // loop over all local generators
-  for (cmLocalGenerator* generator : generators) {
+  for (auto generator : generators) {
     // check to make sure generator is not excluded
     if (this->IsExcluded(root, generator)) {
       continue;
     }
     // loop over all the generator targets in the makefile
-    for (cmGeneratorTarget* target : generator->GetGeneratorTargets()) {
-      if (this->IsRootOnlyTarget(target) &&
+    for (const auto& target : generator->GetGeneratorTargets()) {
+      if (this->IsRootOnlyTarget(target.get()) &&
           target->GetLocalGenerator() != root) {
         continue;
       }
       // put the target in the set of original targets
-      originalTargets.insert(target);
+      originalTargets.insert(target.get());
       // Get the set of targets that depend on target
-      this->AddTargetDepends(target, projectTargets);
+      this->AddTargetDepends(target.get(), projectTargets);
     }
   }
 }
@@ -2961,12 +3015,12 @@
                                "/CMakeFiles/TargetDirectories.txt");
   cmGeneratedFileStream fout(fname);
 
-  for (cmLocalGenerator* lg : this->LocalGenerators) {
-    for (cmGeneratorTarget* tgt : lg->GetGeneratorTargets()) {
+  for (const auto& lg : this->LocalGenerators) {
+    for (const auto& tgt : lg->GetGeneratorTargets()) {
       if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
         continue;
       }
-      this->WriteSummary(tgt);
+      this->WriteSummary(tgt.get());
       fout << tgt->GetSupportDirectory() << "\n";
     }
   }
@@ -3108,10 +3162,20 @@
   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;
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
+  for (auto& localGen : this->LocalGenerators) {
     localGen->ProcessEvaluationFiles(generatedFiles);
   }
 }
@@ -3127,7 +3191,7 @@
   cmake::InstalledFilesMap const& installedFiles =
     this->CMakeInstance->GetInstalledFiles();
 
-  cmLocalGenerator* lg = this->LocalGenerators[0];
+  const auto& lg = this->LocalGenerators[0];
   cmMakefile* mf = lg->GetMakefile();
 
   std::vector<std::string> configs;
@@ -3146,8 +3210,8 @@
   for (auto const& i : installedFiles) {
     cmInstalledFile const& installedFile = i.second;
 
-    cmCPackPropertiesGenerator cpackPropertiesGenerator(lg, installedFile,
-                                                        configs);
+    cmCPackPropertiesGenerator cpackPropertiesGenerator(
+      lg.get(), installedFile, configs);
 
     cpackPropertiesGenerator.Generate(file, config, configs);
   }
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index f25ff7b..7dc4822 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -14,9 +14,10 @@
 #include <utility>
 #include <vector>
 
+#include <cmext/algorithm>
+
 #include "cm_codecvt.hxx"
 
-#include "cmAlgorithms.h"
 #include "cmCustomCommandLines.h"
 #include "cmDuration.h"
 #include "cmExportSet.h"
@@ -43,6 +44,7 @@
 class cmMakefile;
 class cmOutputConverter;
 class cmSourceFile;
+class cmState;
 class cmStateDirectory;
 class cmake;
 
@@ -71,7 +73,7 @@
   void Add(std::vector<std::string>::const_iterator start,
            std::vector<std::string>::const_iterator end)
   {
-    cmAppend(PrimaryCommand, start, end);
+    cm::append(PrimaryCommand, start, end);
   }
 
   std::string Printable() const { return cmJoin(PrimaryCommand, " "); }
@@ -90,11 +92,14 @@
 class cmGlobalGenerator
 {
 public:
+  using LocalGeneratorVector = std::vector<std::unique_ptr<cmLocalGenerator>>;
+
   //! Free any memory allocated with the GlobalGenerator
   cmGlobalGenerator(cmake* cm);
   virtual ~cmGlobalGenerator();
 
-  virtual cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf);
+  virtual std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+    cmMakefile* mf);
 
   //! Get the name for this generator
   virtual std::string GetName() const { return "Generic"; }
@@ -128,7 +133,14 @@
 
   /** Set the generator-specific toolset name.  Returns true if toolset
       is supported and false otherwise.  */
-  virtual bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf);
+  virtual bool SetGeneratorToolset(std::string const& ts, bool build,
+                                   cmMakefile* mf);
+
+  /** Read any other cache entries needed for cmake --build. */
+  virtual bool ReadCacheEntriesForBuild(const cmState& /*state*/)
+  {
+    return true;
+  }
 
   /**
    * Create LocalGenerators and process the CMakeLists files. This does not
@@ -157,11 +169,11 @@
    */
   virtual void Generate();
 
-  virtual cmLinkLineComputer* CreateLinkLineComputer(
+  virtual std::unique_ptr<cmLinkLineComputer> CreateLinkLineComputer(
     cmOutputConverter* outputConverter,
     cmStateDirectory const& stateDir) const;
 
-  cmLinkLineComputer* CreateMSVC60LinkLineComputer(
+  std::unique_ptr<cmLinkLineComputer> CreateMSVC60LinkLineComputer(
     cmOutputConverter* outputConverter,
     cmStateDirectory const& stateDir) const;
 
@@ -244,11 +256,11 @@
   cmake* GetCMakeInstance() const { return this->CMakeInstance; }
 
   void SetConfiguredFilesPath(cmGlobalGenerator* gen);
-  const std::vector<cmMakefile*>& GetMakefiles() const
+  const std::vector<std::unique_ptr<cmMakefile>>& GetMakefiles() const
   {
     return this->Makefiles;
   }
-  const std::vector<cmLocalGenerator*>& GetLocalGenerators() const
+  const LocalGeneratorVector& GetLocalGenerators() const
   {
     return this->LocalGenerators;
   }
@@ -263,11 +275,11 @@
     this->CurrentConfigureMakefile = mf;
   }
 
-  void AddMakefile(cmMakefile* mf);
+  void AddMakefile(std::unique_ptr<cmMakefile> mf);
 
   //! Set an generator for an "external makefile based project"
   void SetExternalMakefileProjectGenerator(
-    cmExternalMakefileProjectGenerator* extraGenerator);
+    std::unique_ptr<cmExternalMakefileProjectGenerator> extraGenerator);
 
   std::string GetExtraGeneratorName() const;
 
@@ -377,6 +389,9 @@
   // Lookup edit_cache target command preferred by this generator.
   virtual std::string GetEditCacheCommand() const { return ""; }
 
+  // Default config to use for cmake --build
+  virtual std::string GetDefaultBuildConfig() const { return "Debug"; }
+
   // Class to track a set of dependencies.
   using TargetDependSet = cmTargetDependSet;
 
@@ -410,6 +425,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.  */
@@ -431,11 +448,17 @@
       MacFolder. */
   virtual bool ShouldStripResourcePath(cmMakefile*) const;
 
+  virtual bool SupportsCustomCommandDepfile() const { return false; }
+
   std::string GetSharedLibFlagsForLanguage(std::string const& lang) const;
 
   /** Generate an <output>.rule file path for a given command output.  */
   virtual std::string GenerateRuleFile(std::string const& output) const;
 
+  virtual bool SupportsDefaultBuildType() const { return false; }
+  virtual bool SupportsCrossConfigs() const { return false; }
+  virtual bool SupportsDefaultConfigs() const { return false; }
+
   static std::string EscapeJSON(const std::string& s);
 
   void ProcessEvaluationFiles();
@@ -444,8 +467,8 @@
   {
     return this->BuildExportSets;
   }
-  void AddBuildExportSet(cmExportBuildFileGenerator*);
-  void AddBuildExportExportSet(cmExportBuildFileGenerator*);
+  void AddBuildExportSet(cmExportBuildFileGenerator* gen);
+  void AddBuildExportExportSet(cmExportBuildFileGenerator* gen);
   bool IsExportedTargetsFile(const std::string& filename) const;
   bool GenerateImportFile(const std::string& file);
   cmExportBuildFileGenerator* GetExportedTargetsFile(
@@ -475,13 +498,19 @@
 
   int RecursionDepth;
 
+  virtual void GetQtAutoGenConfigs(std::vector<std::string>& configs) const
+  {
+    configs.emplace_back("$<CONFIG>");
+  }
+
+  std::string const& GetRealPath(std::string const& dir);
+
 protected:
-  using GeneratorVector = std::vector<cmLocalGenerator*>;
   // for a project collect all its targets by following depend
   // information, and also collect all the targets
   void GetTargetSets(TargetDependSet& projectTargets,
                      TargetDependSet& originalTargets, cmLocalGenerator* root,
-                     GeneratorVector const&);
+                     std::vector<cmLocalGenerator*>& generators);
   bool IsRootOnlyTarget(cmGeneratorTarget* target) const;
   void AddTargetDepends(const cmGeneratorTarget* target,
                         TargetDependSet& projectTargets);
@@ -524,6 +553,7 @@
     std::vector<std::string> Depends;
     std::string WorkingDir;
     bool UsesTerminal = false;
+    bool PerConfig = true;
   };
 
   void CreateDefaultGlobalTargets(std::vector<GlobalTargetInfo>& targets);
@@ -539,8 +569,8 @@
   std::string FindMakeProgramFile;
   std::string ConfiguredFilesPath;
   cmake* CMakeInstance;
-  std::vector<cmMakefile*> Makefiles;
-  std::vector<cmLocalGenerator*> LocalGenerators;
+  std::vector<std::unique_ptr<cmMakefile>> Makefiles;
+  LocalGeneratorVector LocalGenerators;
   cmMakefile* CurrentConfigureMakefile;
   // map from project name to vector of local generators in that project
   std::map<std::string, std::vector<cmLocalGenerator*>> ProjectMap;
@@ -646,6 +676,9 @@
 
   virtual const char* GetBuildIgnoreErrorsFlag() const { return nullptr; }
 
+  bool UnsupportedVariableIsDefined(const std::string& name,
+                                    bool supported) const;
+
   // Cache directory content and target files to be built.
   struct DirectoryContent
   {
@@ -666,6 +699,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/cmGlobalGeneratorFactory.h b/Source/cmGlobalGeneratorFactory.h
index bb5f74c..3709365 100644
--- a/Source/cmGlobalGeneratorFactory.h
+++ b/Source/cmGlobalGeneratorFactory.h
@@ -8,6 +8,8 @@
 #include <string>
 #include <vector>
 
+#include <cm/memory>
+
 class cmGlobalGenerator;
 class cmake;
 struct cmDocumentationEntry;
@@ -23,8 +25,8 @@
   virtual ~cmGlobalGeneratorFactory() = default;
 
   /** Create a GlobalGenerator */
-  virtual cmGlobalGenerator* CreateGlobalGenerator(const std::string& n,
-                                                   cmake* cm) const = 0;
+  virtual std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+    const std::string& n, cmake* cm) const = 0;
 
   /** Get the documentation entry for this factory */
   virtual void GetDocumentation(cmDocumentationEntry& entry) const = 0;
@@ -51,13 +53,13 @@
 {
 public:
   /** Create a GlobalGenerator */
-  cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
-                                           cmake* cm) const override
+  std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+    const std::string& name, cmake* cm) const override
   {
     if (name != T::GetActualName()) {
-      return nullptr;
+      return std::unique_ptr<cmGlobalGenerator>();
     }
-    return new T(cm);
+    return std::unique_ptr<cmGlobalGenerator>(cm::make_unique<T>(cm));
   }
 
   /** Get the documentation entry for this factory */
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index 5a708ab..bb9dd37 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -8,6 +8,8 @@
 #include <ostream>
 #include <utility>
 
+#include <cm/memory>
+
 #include "cmAlgorithms.h"
 #include "cmDocumentationEntry.h"
 #include "cmGeneratedFileStream.h"
@@ -40,10 +42,11 @@
 
 cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator() = default;
 
-cmLocalGenerator* cmGlobalGhsMultiGenerator::CreateLocalGenerator(
-  cmMakefile* mf)
+std::unique_ptr<cmLocalGenerator>
+cmGlobalGhsMultiGenerator::CreateLocalGenerator(cmMakefile* mf)
 {
-  return new cmLocalGhsMultiGenerator(this, mf);
+  return std::unique_ptr<cmLocalGenerator>(
+    cm::make_unique<cmLocalGhsMultiGenerator>(this, mf));
 }
 
 void cmGlobalGhsMultiGenerator::GetDocumentation(cmDocumentationEntry& entry)
@@ -64,8 +67,11 @@
 }
 
 bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts,
-                                                    cmMakefile* mf)
+                                                    bool build, cmMakefile* mf)
 {
+  if (build) {
+    return true;
+  }
   std::string tsp; /* toolset path */
 
   this->GetToolset(mf, tsp, ts);
diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h
index ccfe073..b82e9f5 100644
--- a/Source/cmGlobalGhsMultiGenerator.h
+++ b/Source/cmGlobalGhsMultiGenerator.h
@@ -4,6 +4,7 @@
 #define cmGhsMultiGenerator_h
 
 #include <iosfwd>
+#include <memory>
 #include <set>
 #include <string>
 #include <utility>
@@ -28,13 +29,15 @@
   cmGlobalGhsMultiGenerator(cmake* cm);
   ~cmGlobalGhsMultiGenerator() override;
 
-  static cmGlobalGeneratorFactory* NewFactory()
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
   {
-    return new cmGlobalGeneratorSimpleFactory<cmGlobalGhsMultiGenerator>();
+    return std::unique_ptr<cmGlobalGeneratorFactory>(
+      new cmGlobalGeneratorSimpleFactory<cmGlobalGhsMultiGenerator>());
   }
 
   //! create the correct local generator
-  cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
+  std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+    cmMakefile* mf) override;
 
   /// @return the name of this generator.
   static std::string GetActualName() { return "Green Hills MULTI"; }
@@ -58,7 +61,8 @@
   static bool SupportsPlatform() { return true; }
 
   // Toolset / Platform Support
-  bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf) override;
+  bool SetGeneratorToolset(std::string const& ts, bool build,
+                           cmMakefile* mf) override;
   bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override;
 
   /**
diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx
index ff54288..fc3123a 100644
--- a/Source/cmGlobalJOMMakefileGenerator.cxx
+++ b/Source/cmGlobalJOMMakefileGenerator.cxx
@@ -66,7 +66,7 @@
   // Since we have full control over the invocation of JOM, let us
   // make it quiet.
   jomMakeOptions.push_back(this->MakeSilentFlag);
-  cmAppend(jomMakeOptions, makeOptions);
+  cm::append(jomMakeOptions, makeOptions);
 
   // JOM does parallel builds by default, the -j is only needed if a specific
   // number is given
diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h
index fc39ddf..9f1ec8b 100644
--- a/Source/cmGlobalJOMMakefileGenerator.h
+++ b/Source/cmGlobalJOMMakefileGenerator.h
@@ -4,6 +4,7 @@
 #define cmGlobalJOMMakefileGenerator_h
 
 #include <iosfwd>
+#include <memory>
 
 #include "cmGlobalUnixMakefileGenerator3.h"
 
@@ -16,9 +17,10 @@
 {
 public:
   cmGlobalJOMMakefileGenerator(cmake* cm);
-  static cmGlobalGeneratorFactory* NewFactory()
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
   {
-    return new cmGlobalGeneratorSimpleFactory<cmGlobalJOMMakefileGenerator>();
+    return std::unique_ptr<cmGlobalGeneratorFactory>(
+      new cmGlobalGeneratorSimpleFactory<cmGlobalJOMMakefileGenerator>());
   }
   //! Get the name for the generator.
   std::string GetName() const override
diff --git a/Source/cmGlobalMSYSMakefileGenerator.h b/Source/cmGlobalMSYSMakefileGenerator.h
index d6e4847..b2de4ff 100644
--- a/Source/cmGlobalMSYSMakefileGenerator.h
+++ b/Source/cmGlobalMSYSMakefileGenerator.h
@@ -3,6 +3,8 @@
 #ifndef cmGlobalMSYSMakefileGenerator_h
 #define cmGlobalMSYSMakefileGenerator_h
 
+#include <memory>
+
 #include "cmGlobalUnixMakefileGenerator3.h"
 
 /** \class cmGlobalMSYSMakefileGenerator
@@ -14,9 +16,10 @@
 {
 public:
   cmGlobalMSYSMakefileGenerator(cmake* cm);
-  static cmGlobalGeneratorFactory* NewFactory()
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
   {
-    return new cmGlobalGeneratorSimpleFactory<cmGlobalMSYSMakefileGenerator>();
+    return std::unique_ptr<cmGlobalGeneratorFactory>(
+      new cmGlobalGeneratorSimpleFactory<cmGlobalMSYSMakefileGenerator>());
   }
 
   //! Get the name for the generator.
diff --git a/Source/cmGlobalMinGWMakefileGenerator.h b/Source/cmGlobalMinGWMakefileGenerator.h
index 15297e3..a9f92a1 100644
--- a/Source/cmGlobalMinGWMakefileGenerator.h
+++ b/Source/cmGlobalMinGWMakefileGenerator.h
@@ -3,6 +3,8 @@
 #ifndef cmGlobalMinGWMakefileGenerator_h
 #define cmGlobalMinGWMakefileGenerator_h
 
+#include <memory>
+
 #include "cmGlobalUnixMakefileGenerator3.h"
 
 /** \class cmGlobalMinGWMakefileGenerator
@@ -14,10 +16,10 @@
 {
 public:
   cmGlobalMinGWMakefileGenerator(cmake* cm);
-  static cmGlobalGeneratorFactory* NewFactory()
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
   {
-    return new cmGlobalGeneratorSimpleFactory<
-      cmGlobalMinGWMakefileGenerator>();
+    return std::unique_ptr<cmGlobalGeneratorFactory>(
+      new cmGlobalGeneratorSimpleFactory<cmGlobalMinGWMakefileGenerator>());
   }
   //! Get the name for the generator.
   virtual std::string GetName() const
diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx
index 2273c00..c4bec23 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.cxx
+++ b/Source/cmGlobalNMakeMakefileGenerator.cxx
@@ -66,7 +66,7 @@
   // Since we have full control over the invocation of nmake, let us
   // make it quiet.
   nmakeMakeOptions.push_back(this->MakeSilentFlag);
-  cmAppend(nmakeMakeOptions, makeOptions);
+  cm::append(nmakeMakeOptions, makeOptions);
 
   return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
     makeProgram, projectName, projectDir, targetNames, config, fast,
diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h
index 4586b77..fdf6006 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.h
+++ b/Source/cmGlobalNMakeMakefileGenerator.h
@@ -4,6 +4,7 @@
 #define cmGlobalNMakeMakefileGenerator_h
 
 #include <iosfwd>
+#include <memory>
 
 #include "cmGlobalUnixMakefileGenerator3.h"
 
@@ -16,10 +17,10 @@
 {
 public:
   cmGlobalNMakeMakefileGenerator(cmake* cm);
-  static cmGlobalGeneratorFactory* NewFactory()
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
   {
-    return new cmGlobalGeneratorSimpleFactory<
-      cmGlobalNMakeMakefileGenerator>();
+    return std::unique_ptr<cmGlobalGeneratorFactory>(
+      new cmGlobalGeneratorSimpleFactory<cmGlobalNMakeMakefileGenerator>());
   }
   //! Get the name for the generator.
   std::string GetName() const override
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index da21d6c..f4d102e 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -9,6 +9,8 @@
 #include <sstream>
 
 #include <cm/memory>
+#include <cmext/algorithm>
+#include <cmext/memory>
 
 #include "cmsys/FStream.hxx"
 
@@ -23,6 +25,7 @@
 #include "cmGeneratorExpressionEvaluationFile.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmLinkLineComputer.h"
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalNinjaGenerator.h"
@@ -42,8 +45,6 @@
 #include "cmVersion.h"
 #include "cmake.h"
 
-class cmLinkLineComputer;
-
 const char* cmGlobalNinjaGenerator::NINJA_BUILD_FILE = "build.ninja";
 const char* cmGlobalNinjaGenerator::NINJA_RULES_FILE = "rules.ninja";
 const char* cmGlobalNinjaGenerator::INDENT = "  ";
@@ -83,13 +84,15 @@
   os << "# " << comment.substr(lpos) << "\n\n";
 }
 
-cmLinkLineComputer* cmGlobalNinjaGenerator::CreateLinkLineComputer(
+std::unique_ptr<cmLinkLineComputer>
+cmGlobalNinjaGenerator::CreateLinkLineComputer(
   cmOutputConverter* outputConverter,
   cmStateDirectory const& /* stateDir */) const
 {
-  return new cmNinjaLinkLineComputer(
-    outputConverter,
-    this->LocalGenerators[0]->GetStateSnapshot().GetDirectory(), this);
+  return std::unique_ptr<cmLinkLineComputer>(
+    cm::make_unique<cmNinjaLinkLineComputer>(
+      outputConverter,
+      this->LocalGenerators[0]->GetStateSnapshot().GetDirectory(), this));
 }
 
 std::string cmGlobalNinjaGenerator::EncodeRuleName(std::string const& name)
@@ -114,6 +117,11 @@
   std::string result = lit;
   cmSystemTools::ReplaceString(result, "$", "$$");
   cmSystemTools::ReplaceString(result, "\n", "$\n");
+  if (this->IsMultiConfig()) {
+    cmSystemTools::ReplaceString(result,
+                                 cmStrCat('$', this->GetCMakeCFGIntDir()),
+                                 this->GetCMakeCFGIntDir());
+  }
   return result;
 }
 
@@ -248,8 +256,8 @@
   const std::string& command, const std::string& description,
   const std::string& comment, const std::string& depfile,
   const std::string& job_pool, bool uses_terminal, bool restat,
-  const cmNinjaDeps& outputs, const cmNinjaDeps& explicitDeps,
-  const cmNinjaDeps& orderOnlyDeps)
+  const cmNinjaDeps& outputs, const std::string& config,
+  const cmNinjaDeps& explicitDeps, const cmNinjaDeps& orderOnlyDeps)
 {
   this->AddCustomCommandRule();
 
@@ -282,7 +290,11 @@
     if (!depfile.empty()) {
       vars["depfile"] = depfile;
     }
-    this->WriteBuild(*this->BuildFileStream, build);
+    if (config.empty()) {
+      this->WriteBuild(*this->GetCommonFileStream(), build);
+    } else {
+      this->WriteBuild(*this->GetImplFileStream(config), build);
+    }
   }
 
   if (this->ComputingUnknownDependencies) {
@@ -304,14 +316,15 @@
 }
 
 void cmGlobalNinjaGenerator::WriteMacOSXContentBuild(std::string input,
-                                                     std::string output)
+                                                     std::string output,
+                                                     const std::string& config)
 {
   this->AddMacOSXContentRule();
   {
     cmNinjaBuild build("COPY_OSX_CONTENT");
     build.Outputs.push_back(std::move(output));
     build.ExplicitDeps.push_back(std::move(input));
-    this->WriteBuild(*this->BuildFileStream, build);
+    this->WriteBuild(*this->GetImplFileStream(config), build);
   }
 }
 
@@ -429,9 +442,11 @@
 
 // Virtual public methods.
 
-cmLocalGenerator* cmGlobalNinjaGenerator::CreateLocalGenerator(cmMakefile* mf)
+std::unique_ptr<cmLocalGenerator> cmGlobalNinjaGenerator::CreateLocalGenerator(
+  cmMakefile* mf)
 {
-  return new cmLocalNinjaGenerator(this, mf);
+  return std::unique_ptr<cmLocalGenerator>(
+    cm::make_unique<cmLocalNinjaGenerator>(this, mf));
 }
 
 codecvt::Encoding cmGlobalNinjaGenerator::GetMakefileEncoding() const
@@ -470,14 +485,19 @@
                                            msg.str());
     return;
   }
-  if (!this->OpenBuildFileStream()) {
+  if (!this->InspectConfigTypeVariables()) {
+    return;
+  }
+  if (!this->OpenBuildFileStreams()) {
     return;
   }
   if (!this->OpenRulesFileStream()) {
     return;
   }
 
-  this->TargetDependsClosures.clear();
+  for (auto& it : this->Configs) {
+    it.second.TargetDependsClosures.clear();
+  }
 
   this->InitOutputPathPrefix();
   this->TargetAll = this->NinjaOutputPath("all");
@@ -493,19 +513,101 @@
   this->cmGlobalGenerator::Generate();
 
   this->WriteAssumedSourceDependencies();
-  this->WriteTargetAliases(*this->BuildFileStream);
-  this->WriteFolderTargets(*this->BuildFileStream);
-  this->WriteUnknownExplicitDependencies(*this->BuildFileStream);
-  this->WriteBuiltinTargets(*this->BuildFileStream);
+  this->WriteTargetAliases(*this->GetCommonFileStream());
+  this->WriteFolderTargets(*this->GetCommonFileStream());
+  this->WriteUnknownExplicitDependencies(*this->GetCommonFileStream());
+  this->WriteBuiltinTargets(*this->GetCommonFileStream());
 
   if (cmSystemTools::GetErrorOccuredFlag()) {
     this->RulesFileStream->setstate(std::ios::failbit);
-    this->BuildFileStream->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);
   }
 
   this->CloseCompileCommandsStream();
   this->CloseRulesFileStream();
-  this->CloseBuildFileStream();
+  this->CloseBuildFileStreams();
+
+#ifdef _WIN32
+  // The ninja tools will not be able to update metadata on Windows
+  // when we are re-generating inside an existing 'ninja' invocation
+  // because the outer tool has the files open for write.
+  if (!this->GetCMakeInstance()->GetRegenerateDuringBuild())
+#endif
+  {
+    this->CleanMetaData();
+  }
+}
+
+void cmGlobalNinjaGenerator::CleanMetaData()
+{
+  auto run_ninja_tool = [this](std::vector<char const*> const& args) {
+    std::vector<std::string> command;
+    command.push_back(this->NinjaCommand);
+    command.emplace_back("-C");
+    command.emplace_back(this->GetCMakeInstance()->GetHomeOutputDirectory());
+    command.emplace_back("-t");
+    for (auto const& arg : args) {
+      command.emplace_back(arg);
+    }
+    std::string error;
+    if (!cmSystemTools::RunSingleCommand(command, nullptr, &error, nullptr,
+                                         nullptr,
+                                         cmSystemTools::OUTPUT_NONE)) {
+      this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+                                             "Running\n '" +
+                                               cmJoin(command, "' '") +
+                                               "'\n"
+                                               "failed with:\n " +
+                                               error);
+      cmSystemTools::SetFatalErrorOccured();
+    }
+  };
+
+  // Can the tools below expect 'build.ninja' to be loadable?
+  bool const expectBuildManifest =
+    !this->IsMultiConfig() && this->OutputPathPrefix.empty();
+
+  // Skip some ninja tools if they need 'build.ninja' but it is missing.
+  bool const missingBuildManifest = expectBuildManifest &&
+    (this->NinjaSupportsCleanDeadTool ||
+     this->NinjaSupportsUnconditionalRecompactTool) &&
+    !cmSystemTools::FileExists("build.ninja");
+
+  // 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 && expectBuildManifest &&
+      !missingBuildManifest) {
+    run_ninja_tool({ "cleandead" });
+  }
+  // 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 && expectBuildManifest &&
+      !missingBuildManifest) {
+    run_ninja_tool({ "recompact" });
+  }
+  if (this->NinjaSupportsRestatTool && this->OutputPathPrefix.empty()) {
+    // 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);
+  }
 }
 
 bool cmGlobalNinjaGenerator::FindMakeProgram(cmMakefile* mf)
@@ -569,6 +671,16 @@
       }
     }
   }
+  this->NinjaSupportsCleanDeadTool = !cmSystemTools::VersionCompare(
+    cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+    RequiredNinjaVersionForCleanDeadTool().c_str());
+  this->NinjaSupportsUnconditionalRecompactTool =
+    !cmSystemTools::VersionCompare(
+      cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+      RequiredNinjaVersionForUnconditionalRecompactTool().c_str());
+  this->NinjaSupportsRestatTool = !cmSystemTools::VersionCompare(
+    cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+    RequiredNinjaVersionForRestatTool().c_str());
 }
 
 bool cmGlobalNinjaGenerator::CheckLanguages(
@@ -577,6 +689,17 @@
   if (cmContains(languages, "Fortran")) {
     return this->CheckFortran(mf);
   }
+  if (cmContains(languages, "Swift")) {
+    const std::string architectures =
+      mf->GetSafeDefinition("CMAKE_OSX_ARCHITECTURES");
+    if (architectures.find_first_of(';') != std::string::npos) {
+      mf->IssueMessage(MessageType::FATAL_ERROR,
+                       "multiple values for CMAKE_OSX_ARCHITECTURES not "
+                       "supported with Swift");
+      cmSystemTools::SetFatalErrorOccured();
+      return false;
+    }
+  }
   return true;
 }
 
@@ -609,6 +732,17 @@
 void cmGlobalNinjaGenerator::EnableLanguage(
   std::vector<std::string> const& langs, cmMakefile* mf, bool optional)
 {
+  if (this->IsMultiConfig()) {
+    if (!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) {
+      mf->AddCacheDefinition(
+        "CMAKE_CONFIGURATION_TYPES", "Debug;Release;RelWithDebInfo",
+        "Semicolon separated list of supported configuration types, only "
+        "supports Debug, Release, MinSizeRel, and RelWithDebInfo, anything "
+        "else will be ignored",
+        cmStateEnums::STRING);
+    }
+  }
+
   this->cmGlobalGenerator::EnableLanguage(langs, mf, optional);
   for (std::string const& l : langs) {
     if (l == "NONE") {
@@ -650,7 +784,7 @@
 cmGlobalNinjaGenerator::GenerateBuildCommand(
   const std::string& makeProgram, const std::string& /*projectName*/,
   const std::string& /*projectDir*/,
-  std::vector<std::string> const& targetNames, const std::string& /*config*/,
+  std::vector<std::string> const& targetNames, const std::string& config,
   bool /*fast*/, int jobs, bool verbose,
   std::vector<std::string> const& makeOptions)
 {
@@ -666,6 +800,8 @@
     makeCommand.Add("-j", std::to_string(jobs));
   }
 
+  this->AppendNinjaFileArgument(makeCommand, config);
+
   makeCommand.Add(makeOptions.begin(), makeOptions.end());
   for (const auto& tname : targetNames) {
     if (!tname.empty()) {
@@ -707,35 +843,21 @@
   cmGeneratorTarget* gt) const
 {
   // Compute full path to object file directory for this target.
-  std::string dir =
-    cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(), '/',
-             gt->LocalGenerator->GetTargetDirectory(gt), '/');
+  std::string dir = cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(),
+                             '/', gt->LocalGenerator->GetTargetDirectory(gt),
+                             '/', this->GetCMakeCFGIntDir(), '/');
   gt->ObjectDirectory = dir;
 }
 
 // Private methods
 
-bool cmGlobalNinjaGenerator::OpenBuildFileStream()
+bool cmGlobalNinjaGenerator::OpenBuildFileStreams()
 {
-  // Compute Ninja's build file path.
-  std::string buildFilePath =
-    cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), '/',
-             cmGlobalNinjaGenerator::NINJA_BUILD_FILE);
-
-  // Get a stream where to generate things.
-  if (!this->BuildFileStream) {
-    this->BuildFileStream = cm::make_unique<cmGeneratedFileStream>(
-      buildFilePath, false, this->GetMakefileEncoding());
-    if (!(*this->BuildFileStream)) {
-      // An error message is generated by the constructor if it cannot
-      // open the file.
-      return false;
-    }
+  if (!this->OpenFileStream(this->BuildFileStream,
+                            cmGlobalNinjaGenerator::NINJA_BUILD_FILE)) {
+    return false;
   }
 
-  // Write the do not edit header.
-  this->WriteDisclaimer(*this->BuildFileStream);
-
   // Write a comment about this file.
   *this->BuildFileStream
     << "# This file contains all the build statements describing the\n"
@@ -744,7 +866,53 @@
   return true;
 }
 
-void cmGlobalNinjaGenerator::CloseBuildFileStream()
+bool cmGlobalNinjaGenerator::OpenFileStream(
+  std::unique_ptr<cmGeneratedFileStream>& stream, const std::string& name)
+{
+  // Get a stream where to generate things.
+  if (!stream) {
+    // Compute Ninja's build file path.
+    std::string path =
+      cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), '/', name);
+    stream = cm::make_unique<cmGeneratedFileStream>(
+      path, false, this->GetMakefileEncoding());
+    if (!(*stream)) {
+      // An error message is generated by the constructor if it cannot
+      // open the file.
+      return false;
+    }
+
+    // Write the do not edit header.
+    this->WriteDisclaimer(*stream);
+  }
+
+  return true;
+}
+
+cm::optional<std::set<std::string>> cmGlobalNinjaGenerator::ListSubsetWithAll(
+  const std::set<std::string>& all, const std::set<std::string>& defaults,
+  const std::vector<std::string>& items)
+{
+  std::set<std::string> result;
+
+  for (auto const& item : items) {
+    if (item == "all") {
+      if (items.size() == 1) {
+        result = defaults;
+      } else {
+        return cm::nullopt;
+      }
+    } else if (all.count(item)) {
+      result.insert(item);
+    } else {
+      return cm::nullopt;
+    }
+  }
+
+  return cm::make_optional(result);
+}
+
+void cmGlobalNinjaGenerator::CloseBuildFileStreams()
 {
   if (this->BuildFileStream) {
     this->BuildFileStream.reset();
@@ -755,25 +923,11 @@
 
 bool cmGlobalNinjaGenerator::OpenRulesFileStream()
 {
-  // Compute Ninja's build file path.
-  std::string rulesFilePath =
-    cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), '/',
-             cmGlobalNinjaGenerator::NINJA_RULES_FILE);
-
-  // Get a stream where to generate things.
-  if (!this->RulesFileStream) {
-    this->RulesFileStream = cm::make_unique<cmGeneratedFileStream>(
-      rulesFilePath, false, this->GetMakefileEncoding());
-    if (!(*this->RulesFileStream)) {
-      // An error message is generated by the constructor if it cannot
-      // open the file.
-      return false;
-    }
+  if (!this->OpenFileStream(this->RulesFileStream,
+                            cmGlobalNinjaGenerator::NINJA_RULES_FILE)) {
+    return false;
   }
 
-  // Write the do not edit header.
-  this->WriteDisclaimer(*this->RulesFileStream);
-
   // Write comment about this file.
   /* clang-format off */
   *this->RulesFileStream
@@ -819,10 +973,10 @@
     return f->second;
   }
 
-  cmLocalNinjaGenerator* ng =
-    static_cast<cmLocalNinjaGenerator*>(this->LocalGenerators[0]);
-  std::string const& bin_dir = ng->GetState()->GetBinaryDirectory();
-  std::string convPath = ng->MaybeConvertToRelativePath(bin_dir, path);
+  const auto& ng =
+    cm::static_reference_cast<cmLocalNinjaGenerator>(this->LocalGenerators[0]);
+  std::string const& bin_dir = ng.GetState()->GetBinaryDirectory();
+  std::string convPath = ng.MaybeConvertToRelativePath(bin_dir, path);
   convPath = this->NinjaOutputPath(convPath);
 #ifdef _WIN32
   std::replace(convPath.begin(), convPath.end(), '/', '\\');
@@ -831,9 +985,10 @@
     .first->second;
 }
 
-void cmGlobalNinjaGenerator::AddAdditionalCleanFile(std::string fileName)
+void cmGlobalNinjaGenerator::AddAdditionalCleanFile(std::string fileName,
+                                                    const std::string& config)
 {
-  this->AdditionalCleanFiles.emplace(std::move(fileName));
+  this->Configs[config].AdditionalCleanFiles.emplace(std::move(fileName));
 }
 
 void cmGlobalNinjaGenerator::AddCXXCompileCommand(
@@ -901,23 +1056,22 @@
                             "Assume dependencies for generated source file.",
                             /*depfile*/ "", /*job_pool*/ "",
                             /*uses_terminal*/ false,
-                            /*restat*/ true, cmNinjaDeps(1, asd.first),
+                            /*restat*/ true, cmNinjaDeps(1, asd.first), "",
                             cmNinjaDeps(), orderOnlyDeps);
   }
 }
 
-std::string OrderDependsTargetForTarget(cmGeneratorTarget const* target)
+std::string cmGlobalNinjaGenerator::OrderDependsTargetForTarget(
+  cmGeneratorTarget const* target, const std::string& config)
 {
-  return "cmake_object_order_depends_target_" + target->GetName();
+  return "cmake_object_order_depends_target_" + target->GetName() + "_" +
+    config;
 }
 
 void cmGlobalNinjaGenerator::AppendTargetOutputs(
   cmGeneratorTarget const* target, cmNinjaDeps& outputs,
-  cmNinjaTargetDepends depends)
+  const std::string& config, cmNinjaTargetDepends depends)
 {
-  std::string configName =
-    target->Target->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
-
   // for frameworks, we want the real name, not smple name
   // frameworks always appear versioned, and the build.ninja
   // will always attempt to manage symbolic links instead
@@ -929,19 +1083,19 @@
     case cmStateEnums::STATIC_LIBRARY:
     case cmStateEnums::MODULE_LIBRARY: {
       if (depends == DependOnTargetOrdering) {
-        outputs.push_back(OrderDependsTargetForTarget(target));
+        outputs.push_back(OrderDependsTargetForTarget(target, config));
         break;
       }
     }
     // FALLTHROUGH
     case cmStateEnums::EXECUTABLE: {
       outputs.push_back(this->ConvertToNinjaPath(target->GetFullPath(
-        configName, cmStateEnums::RuntimeBinaryArtifact, realname)));
+        config, cmStateEnums::RuntimeBinaryArtifact, realname)));
       break;
     }
     case cmStateEnums::OBJECT_LIBRARY: {
       if (depends == DependOnTargetOrdering) {
-        outputs.push_back(OrderDependsTargetForTarget(target));
+        outputs.push_back(OrderDependsTargetForTarget(target, config));
         break;
       }
     }
@@ -951,7 +1105,11 @@
       std::string path =
         target->GetLocalGenerator()->GetCurrentBinaryDirectory() +
         std::string("/") + target->GetName();
-      outputs.push_back(this->ConvertToNinjaPath(path));
+      std::string output = this->ConvertToNinjaPath(path);
+      if (target->Target->IsPerConfig()) {
+        output = this->BuildAlias(output, config);
+      }
+      outputs.push_back(output);
       break;
     }
 
@@ -962,15 +1120,17 @@
 
 void cmGlobalNinjaGenerator::AppendTargetDepends(
   cmGeneratorTarget const* target, cmNinjaDeps& outputs,
+  const std::string& config, const std::string& fileConfig,
   cmNinjaTargetDepends depends)
 {
   if (target->GetType() == cmStateEnums::GLOBAL_TARGET) {
     // These depend only on other CMake-provided targets, e.g. "all".
-    for (BT<std::string> const& util : target->GetUtilities()) {
+    for (BT<std::pair<std::string, bool>> const& util :
+         target->GetUtilities()) {
       std::string d =
         target->GetLocalGenerator()->GetCurrentBinaryDirectory() + "/" +
-        util.Value;
-      outputs.push_back(this->ConvertToNinjaPath(d));
+        util.Value.first;
+      outputs.push_back(this->BuildAlias(this->ConvertToNinjaPath(d), config));
     }
   } else {
     cmNinjaDeps outs;
@@ -979,29 +1139,36 @@
       if (targetDep->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
         continue;
       }
-      this->AppendTargetOutputs(targetDep, outs, depends);
+      if (targetDep.IsCross()) {
+        this->AppendTargetOutputs(targetDep, outs, fileConfig, depends);
+      } else {
+        this->AppendTargetOutputs(targetDep, outs, config, depends);
+      }
     }
     std::sort(outs.begin(), outs.end());
-    cmAppend(outputs, outs);
+    cm::append(outputs, outs);
   }
 }
 
 void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
-  cmGeneratorTarget const* target, cmNinjaDeps& outputs)
+  cmGeneratorTarget const* target, cmNinjaDeps& outputs,
+  const std::string& config)
 {
   cmNinjaOuts outs;
-  this->AppendTargetDependsClosure(target, outs, true);
-  cmAppend(outputs, outs);
+  this->AppendTargetDependsClosure(target, outs, config, true);
+  cm::append(outputs, outs);
 }
 
 void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
-  cmGeneratorTarget const* target, cmNinjaOuts& outputs, bool omit_self)
+  cmGeneratorTarget const* target, cmNinjaOuts& outputs,
+  const std::string& config, bool omit_self)
 {
 
   // try to locate the target in the cache
-  auto find = this->TargetDependsClosures.lower_bound(target);
+  auto find = this->Configs[config].TargetDependsClosures.lower_bound(target);
 
-  if (find == this->TargetDependsClosures.end() || find->first != target) {
+  if (find == this->Configs[config].TargetDependsClosures.end() ||
+      find->first != target) {
     // We now calculate the closure outputs by inspecting the dependent
     // targets recursively.
     // For that we have to distinguish between a local result set that is only
@@ -1011,15 +1178,16 @@
     cmNinjaOuts this_outs; // this will be the new cache entry
 
     for (auto const& dep_target : this->GetTargetDirectDepends(target)) {
-      if (dep_target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+      if (dep_target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+          (this->EnableCrossConfigBuild() && !dep_target.IsCross())) {
         continue;
       }
 
       // Collect the dependent targets for _this_ target
-      this->AppendTargetDependsClosure(dep_target, this_outs, false);
+      this->AppendTargetDependsClosure(dep_target, this_outs, config, false);
     }
-    find = this->TargetDependsClosures.emplace_hint(find, target,
-                                                    std::move(this_outs));
+    find = this->Configs[config].TargetDependsClosures.emplace_hint(
+      find, target, std::move(this_outs));
   }
 
   // now fill the outputs of the final result from the newly generated cache
@@ -1029,29 +1197,56 @@
   // finally generate the outputs of the target itself, if applicable
   cmNinjaDeps outs;
   if (!omit_self) {
-    this->AppendTargetOutputs(target, outs);
+    this->AppendTargetOutputs(target, outs, config);
   }
   outputs.insert(outs.begin(), outs.end());
 }
 
 void cmGlobalNinjaGenerator::AddTargetAlias(const std::string& alias,
-                                            cmGeneratorTarget* target)
+                                            cmGeneratorTarget* target,
+                                            const std::string& config)
 {
-  std::string buildAlias = this->NinjaOutputPath(alias);
+  std::string outputPath = this->NinjaOutputPath(alias);
+  std::string buildAlias = this->BuildAlias(outputPath, config);
   cmNinjaDeps outputs;
-  this->AppendTargetOutputs(target, outputs);
-  // Mark the target's outputs as ambiguous to ensure that no other target uses
-  // the output as an alias.
+  this->AppendTargetOutputs(target, outputs, config);
+  // Mark the target's outputs as ambiguous to ensure that no other target
+  // uses the output as an alias.
   for (std::string const& output : outputs) {
-    TargetAliases[output] = nullptr;
+    this->TargetAliases[output].GeneratorTarget = nullptr;
+    this->DefaultTargetAliases[output].GeneratorTarget = nullptr;
+    for (const std::string& config2 :
+         this->Makefiles.front()->GetGeneratorConfigs()) {
+      this->Configs[config2].TargetAliases[output].GeneratorTarget = nullptr;
+    }
   }
 
   // Insert the alias into the map.  If the alias was already present in the
   // map and referred to another target, mark it as ambiguous.
-  std::pair<TargetAliasMap::iterator, bool> newAlias =
-    TargetAliases.insert(std::make_pair(buildAlias, target));
-  if (newAlias.second && newAlias.first->second != target) {
-    newAlias.first->second = nullptr;
+  TargetAlias ta;
+  ta.GeneratorTarget = target;
+  ta.Config = config;
+
+  auto newAliasGlobal =
+    this->TargetAliases.insert(std::make_pair(buildAlias, ta));
+  if (newAliasGlobal.second &&
+      newAliasGlobal.first->second.GeneratorTarget != target) {
+    newAliasGlobal.first->second.GeneratorTarget = nullptr;
+  }
+
+  auto newAliasConfig =
+    this->Configs[config].TargetAliases.insert(std::make_pair(outputPath, ta));
+  if (newAliasConfig.second &&
+      newAliasConfig.first->second.GeneratorTarget != target) {
+    newAliasConfig.first->second.GeneratorTarget = nullptr;
+  }
+  if (this->DefaultConfigs.count(config)) {
+    auto newAliasDefaultGlobal =
+      this->DefaultTargetAliases.insert(std::make_pair(outputPath, ta));
+    if (newAliasDefaultGlobal.second &&
+        newAliasDefaultGlobal.first->second.GeneratorTarget != target) {
+      newAliasDefaultGlobal.first->second.GeneratorTarget = nullptr;
+    }
   }
 }
 
@@ -1061,10 +1256,10 @@
   os << "# Target aliases.\n\n";
 
   cmNinjaBuild build("phony");
-  build.Outputs.emplace_back("");
-  for (auto const& ta : TargetAliases) {
+  build.Outputs.emplace_back();
+  for (auto const& ta : this->TargetAliases) {
     // Don't write ambiguous aliases.
-    if (!ta.second) {
+    if (!ta.second.GeneratorTarget) {
       continue;
     }
 
@@ -1074,13 +1269,69 @@
       continue;
     }
 
-    // Outputs
-    build.Outputs[0] = ta.first;
-    // Explicit depdendencies
+    build.Outputs.front() = ta.first;
     build.ExplicitDeps.clear();
-    this->AppendTargetOutputs(ta.second, build.ExplicitDeps);
-    // Write
-    this->WriteBuild(os, build);
+    if (ta.second.Config == "all") {
+      for (auto const& config : this->CrossConfigs) {
+        this->AppendTargetOutputs(ta.second.GeneratorTarget,
+                                  build.ExplicitDeps, config);
+      }
+    } else {
+      this->AppendTargetOutputs(ta.second.GeneratorTarget, build.ExplicitDeps,
+                                ta.second.Config);
+    }
+    this->WriteBuild(this->EnableCrossConfigBuild() &&
+                         (ta.second.Config == "all" ||
+                          this->CrossConfigs.count(ta.second.Config))
+                       ? os
+                       : *this->GetImplFileStream(ta.second.Config),
+                     build);
+  }
+
+  if (this->IsMultiConfig()) {
+    for (auto const& config : this->Makefiles.front()->GetGeneratorConfigs()) {
+      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();
+        this->AppendTargetOutputs(ta.second.GeneratorTarget,
+                                  build.ExplicitDeps, config);
+        this->WriteBuild(*this->GetConfigFileStream(config), build);
+      }
+    }
+
+    if (!this->DefaultConfigs.empty()) {
+      for (auto const& ta : this->DefaultTargetAliases) {
+        // 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();
+        for (auto const& config : this->DefaultConfigs) {
+          this->AppendTargetOutputs(ta.second.GeneratorTarget,
+                                    build.ExplicitDeps, config);
+        }
+        this->WriteBuild(*this->GetDefaultFileStream(), build);
+      }
+    }
   }
 }
 
@@ -1097,24 +1348,73 @@
     cmGlobalNinjaGenerator::WriteDivider(os);
     std::string const& currentBinaryDir = it.first;
     DirectoryTarget const& dt = it.second;
+    std::vector<std::string> configs;
+    dt.LG->GetMakefile()->GetConfigurations(configs, true);
+    if (configs.empty()) {
+      configs.emplace_back();
+    }
 
     // Setup target
+    cmNinjaDeps configDeps;
     build.Comment = "Folder: " + currentBinaryDir;
-    build.Outputs.emplace_back(
-      this->ConvertToNinjaPath(currentBinaryDir + "/all"));
-    for (DirectoryTarget::Target const& t : dt.Targets) {
-      if (!t.ExcludeFromAll) {
-        this->AppendTargetOutputs(t.GT, build.ExplicitDeps);
+    build.Outputs.emplace_back();
+    for (auto const& config : configs) {
+      build.ExplicitDeps.clear();
+      build.Outputs.front() = this->BuildAlias(
+        this->ConvertToNinjaPath(currentBinaryDir + "/all"), config);
+      configDeps.emplace_back(build.Outputs.front());
+      for (DirectoryTarget::Target const& t : dt.Targets) {
+        if (!t.ExcludeFromAll) {
+          this->AppendTargetOutputs(t.GT, build.ExplicitDeps, config);
+        }
+      }
+      for (DirectoryTarget::Dir const& d : dt.Children) {
+        if (!d.ExcludeFromAll) {
+          build.ExplicitDeps.emplace_back(this->BuildAlias(
+            this->ConvertToNinjaPath(d.Path + "/all"), config));
+        }
+      }
+      // Write target
+      this->WriteBuild(this->EnableCrossConfigBuild() &&
+                           this->CrossConfigs.count(config)
+                         ? os
+                         : *this->GetImplFileStream(config),
+                       build);
+    }
+
+    // Add shortcut target
+    if (this->IsMultiConfig()) {
+      for (auto const& config : configs) {
+        build.ExplicitDeps = { this->BuildAlias(
+          this->ConvertToNinjaPath(currentBinaryDir + "/all"), config) };
+        build.Outputs.front() =
+          this->ConvertToNinjaPath(currentBinaryDir + "/all");
+        this->WriteBuild(*this->GetConfigFileStream(config), build);
+      }
+
+      if (!this->DefaultFileConfig.empty()) {
+        build.ExplicitDeps.clear();
+        for (auto const& config : this->DefaultConfigs) {
+          build.ExplicitDeps.push_back(this->BuildAlias(
+            this->ConvertToNinjaPath(currentBinaryDir + "/all"), config));
+        }
+        build.Outputs.front() =
+          this->ConvertToNinjaPath(currentBinaryDir + "/all");
+        this->WriteBuild(*this->GetDefaultFileStream(), build);
       }
     }
-    for (DirectoryTarget::Dir const& d : dt.Children) {
-      if (!d.ExcludeFromAll) {
-        build.ExplicitDeps.emplace_back(
-          this->ConvertToNinjaPath(d.Path + "/all"));
+
+    // Add target for all configs
+    if (this->EnableCrossConfigBuild()) {
+      build.ExplicitDeps.clear();
+      for (auto const& config : this->CrossConfigs) {
+        build.ExplicitDeps.push_back(this->BuildAlias(
+          this->ConvertToNinjaPath(currentBinaryDir + "/all"), config));
       }
+      build.Outputs.front() = this->BuildAlias(
+        this->ConvertToNinjaPath(currentBinaryDir + "/all"), "all");
+      this->WriteBuild(os, build);
     }
-    // Write target
-    this->WriteBuild(os, build);
   }
 }
 
@@ -1148,7 +1448,7 @@
   // get the list of files that cmake itself has generated as a
   // product of configuration.
 
-  for (cmLocalGenerator* lg : this->LocalGenerators) {
+  for (const auto& lg : this->LocalGenerators) {
     // get the vector of files created by this makefile and convert them
     // to ninja paths, which are all relative in respect to the build directory
     for (std::string const& file : lg->GetMakefile()->GetOutputFiles()) {
@@ -1161,8 +1461,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()) {
@@ -1247,10 +1546,17 @@
   cmGlobalNinjaGenerator::WriteDivider(os);
   os << "# Built-in targets\n\n";
 
-  this->WriteTargetDefault(os);
   this->WriteTargetRebuildManifest(os);
   this->WriteTargetClean(os);
   this->WriteTargetHelp(os);
+
+  for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) {
+    this->WriteTargetDefault(*this->GetConfigFileStream(config));
+  }
+
+  if (!this->DefaultFileConfig.empty()) {
+    this->WriteTargetDefault(*this->GetDefaultFileStream());
+  }
 }
 
 void cmGlobalNinjaGenerator::WriteTargetDefault(std::ostream& os)
@@ -1268,12 +1574,12 @@
   if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
     return;
   }
-  cmLocalGenerator* lg = this->LocalGenerators[0];
+  const auto& lg = this->LocalGenerators[0];
 
   {
     cmNinjaRule rule("RERUN_CMAKE");
     rule.Command =
-      cmStrCat(CMakeCmd(), " -S",
+      cmStrCat(CMakeCmd(), " --regenerate-during-build -S",
                lg->ConvertToOutputFormat(lg->GetSourceDirectory(),
                                          cmOutputConverter::SHELL),
                " -B",
@@ -1287,9 +1593,9 @@
 
   cmNinjaBuild reBuild("RERUN_CMAKE");
   reBuild.Comment = "Re-run CMake if any of its inputs changed.";
-  reBuild.Outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE));
+  this->AddRebuildManifestOutputs(reBuild.Outputs);
 
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
+  for (const auto& localGen : this->LocalGenerators) {
     for (std::string const& fi : localGen->GetMakefile()->GetListFiles()) {
       reBuild.ImplicitDeps.push_back(this->ConvertToNinjaPath(fi));
     }
@@ -1376,14 +1682,14 @@
 
 std::string cmGlobalNinjaGenerator::CMakeCmd() const
 {
-  cmLocalGenerator* lgen = this->LocalGenerators.at(0);
+  const auto& lgen = this->LocalGenerators.at(0);
   return lgen->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(),
                                      cmOutputConverter::SHELL);
 }
 
 std::string cmGlobalNinjaGenerator::NinjaCmd() const
 {
-  cmLocalGenerator* lgen = this->LocalGenerators[0];
+  const auto& lgen = this->LocalGenerators[0];
   if (lgen != nullptr) {
     return lgen->ConvertToOutputFormat(this->NinjaCommand,
                                        cmOutputConverter::SHELL);
@@ -1413,13 +1719,27 @@
 
 bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os)
 {
-  cmLocalGenerator* lgr = this->LocalGenerators.at(0);
+  const auto& lgr = this->LocalGenerators.at(0);
   std::string cleanScriptRel = "CMakeFiles/clean_additional.cmake";
   std::string cleanScriptAbs =
     cmStrCat(lgr->GetBinaryDirectory(), '/', cleanScriptRel);
+  std::vector<std::string> configs;
+  this->Makefiles[0]->GetConfigurations(configs, true);
+  if (configs.empty()) {
+    configs.emplace_back();
+  }
 
   // Check if there are additional files to clean
-  if (this->AdditionalCleanFiles.empty()) {
+  bool empty = true;
+  for (auto const& config : configs) {
+    auto const it = this->Configs.find(config);
+    if (it != this->Configs.end() &&
+        !it->second.AdditionalCleanFiles.empty()) {
+      empty = false;
+      break;
+    }
+  }
+  if (empty) {
     // Remove cmake clean script file if it exists
     cmSystemTools::RemoveFile(cleanScriptAbs);
     return false;
@@ -1431,14 +1751,23 @@
     if (!fout) {
       return false;
     }
-    fout << "# Additional clean files\n\n";
-    fout << "file(REMOVE_RECURSE\n";
-    for (std::string const& acf : this->AdditionalCleanFiles) {
-      fout << "  "
-           << cmOutputConverter::EscapeForCMake(ConvertToNinjaPath(acf))
-           << '\n';
+    fout << "# Additional clean files\ncmake_minimum_required(VERSION 3.16)\n";
+    for (auto const& config : configs) {
+      auto const it = this->Configs.find(config);
+      if (it != this->Configs.end() &&
+          !it->second.AdditionalCleanFiles.empty()) {
+        fout << "\nif(\"${CONFIG}\" STREQUAL \"\" OR \"${CONFIG}\" STREQUAL \""
+             << config << "\")\n";
+        fout << "  file(REMOVE_RECURSE\n";
+        for (std::string const& acf : it->second.AdditionalCleanFiles) {
+          fout << "  "
+               << cmOutputConverter::EscapeForCMake(ConvertToNinjaPath(acf))
+               << '\n';
+        }
+        fout << "  )\n";
+        fout << "endif()\n";
+      }
     }
-    fout << ")\n";
   }
   // Register clean script file
   lgr->GetMakefile()->AddCMakeOutputFile(cleanScriptAbs);
@@ -1447,7 +1776,7 @@
   {
     cmNinjaRule rule("CLEAN_ADDITIONAL");
     rule.Command = cmStrCat(
-      CMakeCmd(), " -P ",
+      CMakeCmd(), " -DCONFIG=$CONFIG -P ",
       lgr->ConvertToOutputFormat(this->NinjaOutputPath(cleanScriptRel),
                                  cmOutputConverter::SHELL));
     rule.Description = "Cleaning additional files...";
@@ -1459,9 +1788,19 @@
   {
     cmNinjaBuild build("CLEAN_ADDITIONAL");
     build.Comment = "Clean additional files.";
-    build.Outputs.push_back(
-      this->NinjaOutputPath(this->GetAdditionalCleanTargetName()));
-    WriteBuild(os, build);
+    build.Outputs.emplace_back();
+    for (auto const& config : configs) {
+      build.Outputs.front() = this->BuildAlias(
+        this->NinjaOutputPath(this->GetAdditionalCleanTargetName()), config);
+      build.Variables["CONFIG"] = config;
+      WriteBuild(os, build);
+    }
+    if (this->IsMultiConfig()) {
+      build.Outputs.front() =
+        this->NinjaOutputPath(this->GetAdditionalCleanTargetName());
+      build.Variables["CONFIG"] = "";
+      WriteBuild(os, build);
+    }
   }
   // Return success
   return true;
@@ -1476,22 +1815,113 @@
   // Write rule
   {
     cmNinjaRule rule("CLEAN");
-    rule.Command = NinjaCmd() + " -t clean";
+    rule.Command = NinjaCmd() + " $FILE_ARG -t clean $TARGETS";
     rule.Description = "Cleaning all built files...";
     rule.Comment = "Rule for cleaning all built files.";
     WriteRule(*this->RulesFileStream, rule);
   }
 
+  auto const configs = this->Makefiles.front()->GetGeneratorConfigs();
+
   // Write build
   {
     cmNinjaBuild build("CLEAN");
     build.Comment = "Clean all the built files.";
-    build.Outputs.push_back(this->NinjaOutputPath(this->GetCleanTargetName()));
-    if (additionalFiles) {
-      build.ExplicitDeps.push_back(
-        this->NinjaOutputPath(this->GetAdditionalCleanTargetName()));
+    build.Outputs.emplace_back();
+
+    for (auto const& config : configs) {
+      build.Outputs.front() = this->BuildAlias(
+        this->NinjaOutputPath(this->GetCleanTargetName()), config);
+      if (this->IsMultiConfig()) {
+        build.Variables["TARGETS"] =
+          cmStrCat(this->BuildAlias(GetByproductsForCleanTargetName(), config),
+                   " ", GetByproductsForCleanTargetName());
+      }
+      build.ExplicitDeps.clear();
+      if (additionalFiles) {
+        build.ExplicitDeps.push_back(this->BuildAlias(
+          this->NinjaOutputPath(this->GetAdditionalCleanTargetName()),
+          config));
+      }
+      for (auto const& fileConfig : configs) {
+        if (fileConfig != config && !this->EnableCrossConfigBuild()) {
+          continue;
+        }
+        if (this->IsMultiConfig()) {
+          build.Variables["FILE_ARG"] = cmStrCat(
+            "-f ",
+            cmGlobalNinjaMultiGenerator::GetNinjaImplFilename(fileConfig));
+        }
+        this->WriteBuild(*this->GetImplFileStream(fileConfig), build);
+      }
     }
+
+    if (this->EnableCrossConfigBuild()) {
+      build.Outputs.front() = this->BuildAlias(
+        this->NinjaOutputPath(this->GetCleanTargetName()), "all");
+      build.ExplicitDeps.clear();
+
+      if (additionalFiles) {
+        for (auto const& config : this->CrossConfigs) {
+          build.ExplicitDeps.push_back(this->BuildAlias(
+            this->NinjaOutputPath(this->GetAdditionalCleanTargetName()),
+            config));
+        }
+      }
+
+      std::vector<std::string> byproducts;
+      for (auto const& config : this->CrossConfigs) {
+        byproducts.push_back(
+          this->BuildAlias(GetByproductsForCleanTargetName(), config));
+      }
+      build.Variables["TARGETS"] = cmJoin(byproducts, " ");
+
+      for (auto const& fileConfig : configs) {
+        build.Variables["FILE_ARG"] = cmStrCat(
+          "-f ",
+          cmGlobalNinjaMultiGenerator::GetNinjaImplFilename(fileConfig));
+        this->WriteBuild(*this->GetImplFileStream(fileConfig), build);
+      }
+    }
+  }
+
+  if (this->IsMultiConfig()) {
+    cmNinjaBuild build("phony");
+    build.Outputs.emplace_back(
+      this->NinjaOutputPath(this->GetCleanTargetName()));
+    build.ExplicitDeps.emplace_back();
+
+    for (auto const& config : configs) {
+      build.ExplicitDeps.front() = this->BuildAlias(
+        this->NinjaOutputPath(this->GetCleanTargetName()), config);
+      this->WriteBuild(*this->GetConfigFileStream(config), build);
+    }
+
+    if (!this->DefaultConfigs.empty()) {
+      build.ExplicitDeps.clear();
+      for (auto const& config : this->DefaultConfigs) {
+        build.ExplicitDeps.push_back(this->BuildAlias(
+          this->NinjaOutputPath(this->GetCleanTargetName()), config));
+      }
+      this->WriteBuild(*this->GetDefaultFileStream(), build);
+    }
+  }
+
+  // Write byproducts
+  if (this->IsMultiConfig()) {
+    cmNinjaBuild build("phony");
+    build.Comment = "Clean byproducts.";
+    build.Outputs.emplace_back(
+      this->ConvertToNinjaPath(GetByproductsForCleanTargetName()));
+    build.ExplicitDeps = this->ByproductsForCleanTarget;
     WriteBuild(os, build);
+
+    for (auto const& config : configs) {
+      build.Outputs.front() = this->BuildAlias(
+        this->ConvertToNinjaPath(GetByproductsForCleanTargetName()), config);
+      build.ExplicitDeps = this->Configs[config].ByproductsForCleanTarget;
+      WriteBuild(os, build);
+    }
   }
 }
 
@@ -1809,11 +2239,9 @@
     snapshot.GetDirectory().SetRelativePathTopSource(dir_top_src.c_str());
     snapshot.GetDirectory().SetRelativePathTopBinary(dir_top_bld.c_str());
     auto mfd = cm::make_unique<cmMakefile>(this, snapshot);
-    std::unique_ptr<cmLocalNinjaGenerator> lgd(
-      static_cast<cmLocalNinjaGenerator*>(
-        this->CreateLocalGenerator(mfd.get())));
-    this->Makefiles.push_back(mfd.release());
-    this->LocalGenerators.push_back(lgd.release());
+    auto lgd = this->CreateLocalGenerator(mfd.get());
+    this->Makefiles.push_back(std::move(mfd));
+    this->LocalGenerators.push_back(std::move(lgd));
   }
 
   std::vector<cmDyndepObjectInfo> objects;
@@ -1920,6 +2348,11 @@
   return true;
 }
 
+bool cmGlobalNinjaGenerator::EnableCrossConfigBuild() const
+{
+  return !this->CrossConfigs.empty();
+}
+
 int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
                              std::vector<std::string>::const_iterator argEnd)
 {
@@ -1990,13 +2423,266 @@
   cmake cm(cmake::RoleInternal, cmState::Unknown);
   cm.SetHomeDirectory(dir_top_src);
   cm.SetHomeOutputDirectory(dir_top_bld);
-  std::unique_ptr<cmGlobalNinjaGenerator> ggd(
-    static_cast<cmGlobalNinjaGenerator*>(cm.CreateGlobalGenerator("Ninja")));
+  auto ggd = cm.CreateGlobalGenerator("Ninja");
   if (!ggd ||
-      !ggd->WriteDyndepFile(dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld,
-                            arg_dd, arg_ddis, module_dir, linked_target_dirs,
-                            arg_lang)) {
+      !cm::static_reference_cast<cmGlobalNinjaGenerator>(ggd).WriteDyndepFile(
+        dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld, arg_dd, arg_ddis,
+        module_dir, linked_target_dirs, arg_lang)) {
     return 1;
   }
   return 0;
 }
+
+void cmGlobalNinjaGenerator::AppendDirectoryForConfig(
+  const std::string& prefix, const std::string& config,
+  const std::string& suffix, std::string& dir)
+{
+  if (!config.empty() && this->IsMultiConfig()) {
+    dir += prefix;
+    dir += config;
+    dir += suffix;
+  }
+}
+
+std::set<std::string> cmGlobalNinjaGenerator::GetCrossConfigs(
+  const std::string& fileConfig) const
+{
+  auto result = this->CrossConfigs;
+  result.insert(fileConfig);
+  return result;
+}
+
+const char* cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE =
+  "CMakeFiles/common.ninja";
+const char* cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION = ".ninja";
+
+cmGlobalNinjaMultiGenerator::cmGlobalNinjaMultiGenerator(cmake* cm)
+  : cmGlobalNinjaGenerator(cm)
+{
+  cm->GetState()->SetIsGeneratorMultiConfig(true);
+  cm->GetState()->SetNinjaMulti(true);
+}
+
+void cmGlobalNinjaMultiGenerator::GetDocumentation(cmDocumentationEntry& entry)
+{
+  entry.Name = cmGlobalNinjaMultiGenerator::GetActualName();
+  entry.Brief = "Generates build-<Config>.ninja files.";
+}
+
+std::string cmGlobalNinjaMultiGenerator::ExpandCFGIntDir(
+  const std::string& str, const std::string& config) const
+{
+  std::string result = str;
+  cmSystemTools::ReplaceString(result, this->GetCMakeCFGIntDir(), config);
+  return result;
+}
+
+bool cmGlobalNinjaMultiGenerator::OpenBuildFileStreams()
+{
+  if (!this->OpenFileStream(this->CommonFileStream,
+                            cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE)) {
+    return false;
+  }
+
+  if (!this->DefaultFileConfig.empty()) {
+    if (!this->OpenFileStream(this->DefaultFileStream, NINJA_BUILD_FILE)) {
+      return false;
+    }
+    *this->DefaultFileStream
+      << "# Build using rules for '" << this->DefaultFileConfig << "'.\n\n"
+      << "include " << GetNinjaImplFilename(this->DefaultFileConfig) << "\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],
+                              GetNinjaConfigFilename(config))) {
+      return false;
+    }
+
+    // Write a comment about this file.
+    *this->ConfigFileStreams[config]
+      << "# This file contains aliases specific to the \"" << config
+      << "\"\n# configuration.\n\n"
+      << "include " << GetNinjaImplFilename(config) << "\n\n";
+  }
+
+  return true;
+}
+
+void cmGlobalNinjaMultiGenerator::CloseBuildFileStreams()
+{
+  if (this->CommonFileStream) {
+    this->CommonFileStream.reset();
+  } else {
+    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 {
+      cmSystemTools::Error(
+        cmStrCat("Config file stream for \"", config, "\" was not open."));
+    }
+  }
+}
+
+void cmGlobalNinjaMultiGenerator::AppendNinjaFileArgument(
+  GeneratedMakeCommand& command, const std::string& config) const
+{
+  if (!config.empty()) {
+    command.Add("-f");
+    command.Add(GetNinjaConfigFilename(config));
+  }
+}
+
+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,
+                  cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION);
+}
+
+void cmGlobalNinjaMultiGenerator::AddRebuildManifestOutputs(
+  cmNinjaDeps& outputs) const
+{
+  for (auto const& config : this->Makefiles.front()->GetGeneratorConfigs()) {
+    outputs.push_back(this->NinjaOutputPath(GetNinjaImplFilename(config)));
+    outputs.push_back(this->NinjaOutputPath(GetNinjaConfigFilename(config)));
+  }
+  if (!this->DefaultFileConfig.empty()) {
+    outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE));
+  }
+}
+
+void cmGlobalNinjaMultiGenerator::GetQtAutoGenConfigs(
+  std::vector<std::string>& configs) const
+{
+  auto const oldSize = configs.size();
+  this->Makefiles.front()->GetConfigurations(configs);
+  if (configs.size() == oldSize) {
+    configs.emplace_back();
+  }
+}
+
+bool cmGlobalNinjaMultiGenerator::InspectConfigTypeVariables()
+{
+  this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_DEFAULT_BUILD_TYPE");
+  this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_CROSS_CONFIGS");
+  this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_DEFAULT_CONFIGS");
+  return this->ReadCacheEntriesForBuild(*this->Makefiles.front()->GetState());
+}
+
+std::string cmGlobalNinjaMultiGenerator::GetDefaultBuildConfig() const
+{
+  return "";
+}
+
+bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild(
+  const cmState& state)
+{
+  std::vector<std::string> configsVec;
+  cmExpandList(state.GetSafeCacheEntryValue("CMAKE_CONFIGURATION_TYPES"),
+               configsVec);
+  if (configsVec.empty()) {
+    configsVec.emplace_back();
+  }
+  std::set<std::string> configs(configsVec.cbegin(), configsVec.cend());
+
+  this->DefaultFileConfig =
+    state.GetSafeCacheEntryValue("CMAKE_DEFAULT_BUILD_TYPE");
+  if (this->DefaultFileConfig.empty()) {
+    this->DefaultFileConfig = configsVec.front();
+  }
+  if (!configs.count(this->DefaultFileConfig)) {
+    std::ostringstream msg;
+    msg << "The configuration specified by "
+        << "CMAKE_DEFAULT_BUILD_TYPE (" << this->DefaultFileConfig
+        << ") is not present in CMAKE_CONFIGURATION_TYPES";
+    this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+                                           msg.str());
+    return false;
+  }
+
+  std::vector<std::string> crossConfigsVec;
+  cmExpandList(state.GetSafeCacheEntryValue("CMAKE_CROSS_CONFIGS"),
+               crossConfigsVec);
+  auto crossConfigs = ListSubsetWithAll(configs, configs, crossConfigsVec);
+  if (!crossConfigs) {
+    std::ostringstream msg;
+    msg << "CMAKE_CROSS_CONFIGS is not a subset of "
+        << "CMAKE_CONFIGURATION_TYPES";
+    this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+                                           msg.str());
+    return false;
+  }
+  this->CrossConfigs = *crossConfigs;
+
+  auto defaultConfigsString =
+    state.GetSafeCacheEntryValue("CMAKE_DEFAULT_CONFIGS");
+  if (defaultConfigsString.empty()) {
+    defaultConfigsString = this->DefaultFileConfig;
+  }
+  if (!defaultConfigsString.empty() &&
+      defaultConfigsString != this->DefaultFileConfig &&
+      (this->DefaultFileConfig.empty() || this->CrossConfigs.empty())) {
+    std::ostringstream msg;
+    msg << "CMAKE_DEFAULT_CONFIGS cannot be used without "
+        << "CMAKE_DEFAULT_BUILD_TYPE or CMAKE_CROSS_CONFIGS";
+    this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+                                           msg.str());
+    return false;
+  }
+
+  std::vector<std::string> defaultConfigsVec;
+  cmExpandList(defaultConfigsString, defaultConfigsVec);
+  if (!this->DefaultFileConfig.empty()) {
+    auto defaultConfigs =
+      ListSubsetWithAll(this->GetCrossConfigs(this->DefaultFileConfig),
+                        this->CrossConfigs, defaultConfigsVec);
+    if (!defaultConfigs) {
+      std::ostringstream msg;
+      msg << "CMAKE_DEFAULT_CONFIGS is not a subset of CMAKE_CROSS_CONFIGS";
+      this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+                                             msg.str());
+      return false;
+    }
+    this->DefaultConfigs = *defaultConfigs;
+  }
+
+  return true;
+}
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 244e9fd..5668dd1 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -15,6 +15,8 @@
 #include <utility>
 #include <vector>
 
+#include <cm/optional>
+
 #include "cm_codecvt.hxx"
 
 #include "cmGeneratedFileStream.h"
@@ -22,6 +24,7 @@
 #include "cmGlobalGeneratorFactory.h"
 #include "cmNinjaTypes.h"
 #include "cmPolicies.h"
+#include "cmStringAlgorithms.h"
 
 class cmCustomCommand;
 class cmGeneratorTarget;
@@ -29,6 +32,7 @@
 class cmLocalGenerator;
 class cmMakefile;
 class cmOutputConverter;
+class cmState;
 class cmStateDirectory;
 class cmake;
 struct cmDocumentationEntry;
@@ -73,10 +77,10 @@
   static void WriteDivider(std::ostream& os);
 
   static std::string EncodeRuleName(std::string const& name);
-  static std::string EncodeLiteral(const std::string& lit);
+  std::string EncodeLiteral(const std::string& lit);
   std::string EncodePath(const std::string& path);
 
-  cmLinkLineComputer* CreateLinkLineComputer(
+  std::unique_ptr<cmLinkLineComputer> CreateLinkLineComputer(
     cmOutputConverter* outputConverter,
     cmStateDirectory const& stateDir) const override;
 
@@ -111,11 +115,12 @@
     const std::string& command, const std::string& description,
     const std::string& comment, const std::string& depfile,
     const std::string& pool, bool uses_terminal, bool restat,
-    const cmNinjaDeps& outputs,
+    const cmNinjaDeps& outputs, const std::string& config,
     const cmNinjaDeps& explicitDeps = cmNinjaDeps(),
     const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps());
 
-  void WriteMacOSXContentBuild(std::string input, std::string output);
+  void WriteMacOSXContentBuild(std::string input, std::string output,
+                               const std::string& config);
 
   /**
    * Write a rule statement to @a os.
@@ -151,12 +156,14 @@
 public:
   cmGlobalNinjaGenerator(cmake* cm);
 
-  static cmGlobalGeneratorFactory* NewFactory()
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
   {
-    return new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaGenerator>();
+    return std::unique_ptr<cmGlobalGeneratorFactory>(
+      new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaGenerator>());
   }
 
-  cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
+  std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+    cmMakefile* mf) override;
 
   std::string GetName() const override
   {
@@ -204,7 +211,26 @@
   }
   const char* GetCleanTargetName() const override { return "clean"; }
 
-  cmGeneratedFileStream* GetBuildFileStream() const
+  bool SupportsCustomCommandDepfile() const override { return true; }
+
+  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();
   }
@@ -231,12 +257,17 @@
   MapToNinjaPathImpl MapToNinjaPath() { return { this }; }
 
   // -- Additional clean files
-  void AddAdditionalCleanFile(std::string fileName);
+  void AddAdditionalCleanFile(std::string fileName, const std::string& config);
   const char* GetAdditionalCleanTargetName() const
   {
     return "CMakeFiles/clean.additional";
   }
 
+  static const char* GetByproductsForCleanTargetName()
+  {
+    return "CMakeFiles/cmake_byproducts_for_clean_target";
+  }
+
   void AddCXXCompileCommand(const std::string& commandLine,
                             const std::string& sourceFile);
 
@@ -260,9 +291,9 @@
 
   /// Called when we have seen the given custom command.  Returns true
   /// if we has seen it before.
-  bool SeenCustomCommand(cmCustomCommand const* cc)
+  bool SeenCustomCommand(cmCustomCommand const* cc, const std::string& config)
   {
-    return !this->CustomCommands.insert(cc).second;
+    return !this->Configs[config].CustomCommands.insert(cc).second;
   }
 
   /// Called when we have seen the given custom command output.
@@ -284,25 +315,43 @@
     ASD.insert(deps.begin(), deps.end());
   }
 
+  static std::string OrderDependsTargetForTarget(
+    cmGeneratorTarget const* target, const std::string& config);
+
   void AppendTargetOutputs(
     cmGeneratorTarget const* target, cmNinjaDeps& outputs,
+    const std::string& config,
     cmNinjaTargetDepends depends = DependOnTargetArtifact);
   void AppendTargetDepends(
     cmGeneratorTarget const* target, cmNinjaDeps& outputs,
+    const std::string& config, const std::string& fileConfig,
     cmNinjaTargetDepends depends = DependOnTargetArtifact);
   void AppendTargetDependsClosure(cmGeneratorTarget const* target,
-                                  cmNinjaDeps& outputs);
+                                  cmNinjaDeps& outputs,
+                                  const std::string& config);
   void AppendTargetDependsClosure(cmGeneratorTarget const* target,
-                                  cmNinjaOuts& outputs, bool omit_self);
+                                  cmNinjaOuts& outputs,
+                                  const std::string& config, bool omit_self);
 
-  const std::vector<cmLocalGenerator*>& GetLocalGenerators() const
+  void AppendDirectoryForConfig(const std::string& prefix,
+                                const std::string& config,
+                                const std::string& suffix,
+                                std::string& dir) override;
+
+  virtual void AppendNinjaFileArgument(GeneratedMakeCommand& /*command*/,
+                                       const std::string& /*config*/) const
   {
-    return LocalGenerators;
+  }
+
+  virtual void AddRebuildManifestOutputs(cmNinjaDeps& outputs) const
+  {
+    outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE));
   }
 
   int GetRuleCmdLength(const std::string& name) { return RuleCmdLength[name]; }
 
-  void AddTargetAlias(const std::string& alias, cmGeneratorTarget* target);
+  void AddTargetAlias(const std::string& alias, cmGeneratorTarget* target,
+                      const std::string& config);
 
   void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override;
 
@@ -316,6 +365,12 @@
     return "1.9";
   }
   static std::string RequiredNinjaVersionForDyndeps() { return "1.10"; }
+  static std::string RequiredNinjaVersionForRestatTool() { return "1.10"; }
+  static std::string RequiredNinjaVersionForUnconditionalRecompactTool()
+  {
+    return "1.10";
+  }
+  static std::string RequiredNinjaVersionForCleanDeadTool() { return "1.10"; }
   bool SupportsConsolePool() const;
   bool SupportsImplicitOuts() const;
   bool SupportsManifestRestat() const;
@@ -335,11 +390,52 @@
                        std::vector<std::string> const& linked_target_dirs,
                        std::string const& arg_lang);
 
+  virtual std::string BuildAlias(const std::string& alias,
+                                 const std::string& /*config*/) const
+  {
+    return alias;
+  }
+
+  virtual std::string ConfigDirectory(const std::string& /*config*/) const
+  {
+    return "";
+  }
+
+  cmNinjaDeps& GetByproductsForCleanTarget()
+  {
+    return this->ByproductsForCleanTarget;
+  }
+
+  cmNinjaDeps& GetByproductsForCleanTarget(const std::string& config)
+  {
+    return this->Configs[config].ByproductsForCleanTarget;
+  }
+
+  bool EnableCrossConfigBuild() const;
+
+  std::set<std::string> GetCrossConfigs(const std::string& config) const;
+
 protected:
   void Generate() override;
 
   bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const override { return true; }
 
+  virtual bool OpenBuildFileStreams();
+  virtual void CloseBuildFileStreams();
+
+  bool OpenFileStream(std::unique_ptr<cmGeneratedFileStream>& stream,
+                      const std::string& name);
+
+  static cm::optional<std::set<std::string>> ListSubsetWithAll(
+    const std::set<std::string>& all, const std::set<std::string>& defaults,
+    const std::vector<std::string>& items);
+
+  virtual bool InspectConfigTypeVariables() { return true; }
+
+  std::set<std::string> CrossConfigs;
+  std::set<std::string> DefaultConfigs;
+  std::string DefaultFileConfig;
+
 private:
   std::string GetEditCacheCommand() const override;
   bool FindMakeProgram(cmMakefile* mf) override;
@@ -348,13 +444,11 @@
                       cmMakefile* mf) const override;
   bool CheckFortran(cmMakefile* mf) const;
 
-  bool OpenBuildFileStream();
-  void CloseBuildFileStream();
-
   void CloseCompileCommandsStream();
 
   bool OpenRulesFileStream();
   void CloseRulesFileStream();
+  void CleanMetaData();
 
   /// Write the common disclaimer text at the top of each build file.
   void WriteDisclaimer(std::ostream& os);
@@ -395,9 +489,6 @@
 
   bool UsingGCCOnWindows = false;
 
-  /// The set of custom commands we have seen.
-  std::set<cmCustomCommand const*> CustomCommands;
-
   /// The set of custom command outputs we have seen.
   std::set<std::string> CustomCommandOutputs;
 
@@ -416,10 +507,14 @@
   /// The mapping from source file to assumed dependencies.
   std::map<std::string, std::set<std::string>> AssumedSourceDependencies;
 
-  using TargetAliasMap = std::map<std::string, cmGeneratorTarget*>;
+  struct TargetAlias
+  {
+    cmGeneratorTarget* GeneratorTarget;
+    std::string Config;
+  };
+  using TargetAliasMap = std::map<std::string, TargetAlias>;
   TargetAliasMap TargetAliases;
-
-  std::map<cmGeneratorTarget const*, cmNinjaOuts> TargetDependsClosures;
+  TargetAliasMap DefaultTargetAliases;
 
   /// the local cache for calls to ConvertToNinjaPath
   mutable std::unordered_map<std::string, std::string> ConvertToNinjaPathCache;
@@ -431,6 +526,9 @@
   bool NinjaSupportsManifestRestat = false;
   bool NinjaSupportsMultilineDepfile = false;
   bool NinjaSupportsDyndeps = false;
+  bool NinjaSupportsRestatTool = false;
+  bool NinjaSupportsUnconditionalRecompactTool = false;
+  bool NinjaSupportsCleanDeadTool = false;
 
 private:
   void InitOutputPathPrefix();
@@ -438,7 +536,125 @@
   std::string OutputPathPrefix;
   std::string TargetAll;
   std::string CMakeCacheFile;
-  std::set<std::string> AdditionalCleanFiles;
+
+  struct ByConfig
+  {
+    std::set<std::string> AdditionalCleanFiles;
+
+    /// The set of custom commands we have seen.
+    std::set<cmCustomCommand const*> CustomCommands;
+
+    std::map<cmGeneratorTarget const*, cmNinjaOuts> TargetDependsClosures;
+
+    TargetAliasMap TargetAliases;
+
+    cmNinjaDeps ByproductsForCleanTarget;
+  };
+  std::map<std::string, ByConfig> Configs;
+
+  cmNinjaDeps ByproductsForCleanTarget;
+};
+
+class cmGlobalNinjaMultiGenerator : public cmGlobalNinjaGenerator
+{
+public:
+  /// The default name of Ninja's common file. Typically: common.ninja.
+  static const char* NINJA_COMMON_FILE;
+  /// The default file extension to use for per-config Ninja files.
+  static const char* NINJA_FILE_EXTENSION;
+
+  cmGlobalNinjaMultiGenerator(cmake* cm);
+  bool IsMultiConfig() const override { return true; }
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
+  {
+    return std::unique_ptr<cmGlobalGeneratorFactory>(
+      new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaMultiGenerator>());
+  }
+
+  static void GetDocumentation(cmDocumentationEntry& entry);
+
+  std::string GetName() const override
+  {
+    return cmGlobalNinjaMultiGenerator::GetActualName();
+  }
+
+  static std::string GetActualName() { return "Ninja Multi-Config"; }
+
+  std::string BuildAlias(const std::string& alias,
+                         const std::string& config) const override
+  {
+    if (config.empty()) {
+      return alias;
+    }
+    return cmStrCat(alias, ":", config);
+  }
+
+  std::string ConfigDirectory(const std::string& config) const override
+  {
+    if (!config.empty()) {
+      return cmStrCat('/', config);
+    }
+    return "";
+  }
+
+  const char* GetCMakeCFGIntDir() const override { return "${CONFIGURATION}"; }
+
+  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();
+  }
+
+  void AppendNinjaFileArgument(GeneratedMakeCommand& command,
+                               const std::string& config) const override;
+
+  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 InspectConfigTypeVariables() override;
+
+  std::string GetDefaultBuildConfig() const override;
+
+  bool ReadCacheEntriesForBuild(const cmState& state) override;
+
+  bool SupportsDefaultBuildType() const override { return true; }
+  bool SupportsCrossConfigs() const override { return true; }
+  bool SupportsDefaultConfigs() const override { return true; }
+
+protected:
+  bool OpenBuildFileStreams() override;
+  void CloseBuildFileStreams() override;
+
+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 4c2d69f..90c9ef0 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -8,8 +8,9 @@
 #include <utility>
 
 #include <cm/memory>
+#include <cmext/algorithm>
+#include <cmext/memory>
 
-#include "cmAlgorithms.h"
 #include "cmDocumentationEntry.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
@@ -61,10 +62,11 @@
 }
 
 //! Create a local generator appropriate to this Global Generator
-cmLocalGenerator* cmGlobalUnixMakefileGenerator3::CreateLocalGenerator(
-  cmMakefile* mf)
+std::unique_ptr<cmLocalGenerator>
+cmGlobalUnixMakefileGenerator3::CreateLocalGenerator(cmMakefile* mf)
 {
-  return new cmLocalUnixMakefileGenerator3(this, mf);
+  return std::unique_ptr<cmLocalGenerator>(
+    cm::make_unique<cmLocalUnixMakefileGenerator3>(this, mf));
 }
 
 void cmGlobalUnixMakefileGenerator3::GetDocumentation(
@@ -144,11 +146,11 @@
   for (auto& pmi : this->ProgressMap) {
     pmi.second.WriteProgressVariables(total, current);
   }
-  for (cmLocalGenerator* lg : this->LocalGenerators) {
+  for (const auto& lg : this->LocalGenerators) {
     std::string markFileName =
       cmStrCat(lg->GetCurrentBinaryDirectory(), "/CMakeFiles/progress.marks");
     cmGeneratedFileStream markFile(markFileName);
-    markFile << this->CountProgressMarksInAll(lg) << "\n";
+    markFile << this->CountProgressMarksInAll(*lg) << "\n";
   }
 
   // write the main makefile
@@ -203,11 +205,11 @@
   }
 
   // get a local generator for some useful methods
-  cmLocalUnixMakefileGenerator3* lg =
-    static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[0]);
+  auto& lg = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(
+    this->LocalGenerators[0]);
 
   // Write the do not edit header.
-  lg->WriteDisclaimer(makefileStream);
+  lg.WriteDisclaimer(makefileStream);
 
   // Write the main entry point target.  This must be the VERY first
   // target so that make with no arguments will run it.
@@ -217,10 +219,10 @@
   depends.emplace_back("all");
 
   // Write the rule.
-  lg->WriteMakeRule(makefileStream,
-                    "Default target executed when no arguments are "
-                    "given to make.",
-                    "default_target", depends, no_commands, true);
+  lg.WriteMakeRule(makefileStream,
+                   "Default target executed when no arguments are "
+                   "given to make.",
+                   "default_target", depends, no_commands, true);
 
   depends.clear();
 
@@ -231,7 +233,7 @@
   }
 
   // Write out the "special" stuff
-  lg->WriteSpecialTargetsTop(makefileStream);
+  lg.WriteSpecialTargetsTop(makefileStream);
 
   // Write the directory level rules.
   for (auto const& it : this->ComputeDirectoryTargets()) {
@@ -239,13 +241,14 @@
   }
 
   // Write the target convenience rules
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
+  for (const auto& localGen : this->LocalGenerators) {
     this->WriteConvenienceRules2(
-      makefileStream, static_cast<cmLocalUnixMakefileGenerator3*>(localGen));
+      makefileStream,
+      cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(localGen));
   }
 
   // Write special bottom targets
-  lg->WriteSpecialTargetsBottom(makefileStream);
+  lg.WriteSpecialTargetsBottom(makefileStream);
 }
 
 void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
@@ -268,12 +271,14 @@
   std::string makefileName =
     cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), "/Makefile");
 
-  // get a local generator for some useful methods
-  cmLocalUnixMakefileGenerator3* lg =
-    static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[0]);
+  {
+    // get a local generator for some useful methods
+    auto& lg = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(
+      this->LocalGenerators[0]);
 
-  // Write the do not edit header.
-  lg->WriteDisclaimer(cmakefileStream);
+    // Write the do not edit header.
+    lg.WriteDisclaimer(cmakefileStream);
+  }
 
   // Save the generator name
   cmakefileStream << "# The generator used is:\n"
@@ -282,9 +287,9 @@
 
   // for each cmMakefile get its list of dependencies
   std::vector<std::string> lfiles;
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
+  for (const auto& localGen : this->LocalGenerators) {
     // Get the list of files contributing to this generation step.
-    cmAppend(lfiles, localGen->GetMakefile()->GetListFiles());
+    cm::append(lfiles, localGen->GetMakefile()->GetListFiles());
   }
 
   cmake* cm = this->GetCMakeInstance();
@@ -300,59 +305,61 @@
   lfiles.erase(new_end, lfiles.end());
 #endif
 
-  // reset lg to the first makefile
-  lg = static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[0]);
-
-  std::string currentBinDir = lg->GetCurrentBinaryDirectory();
-  // Save the list to the cmake file.
-  cmakefileStream
-    << "# The top level Makefile was generated from the following files:\n"
-    << "set(CMAKE_MAKEFILE_DEPENDS\n"
-    << "  \"CMakeCache.txt\"\n";
-  for (std::string const& f : lfiles) {
-    cmakefileStream << "  \""
-                    << lg->MaybeConvertToRelativePath(currentBinDir, f)
-                    << "\"\n";
-  }
-  cmakefileStream << "  )\n\n";
-
-  // Build the path to the cache check file.
-  std::string check =
-    cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(),
-             "/CMakeFiles/cmake.check_cache");
-
-  // Set the corresponding makefile in the cmake file.
-  cmakefileStream << "# The corresponding makefile is:\n"
-                  << "set(CMAKE_MAKEFILE_OUTPUTS\n"
-                  << "  \""
-                  << lg->MaybeConvertToRelativePath(currentBinDir,
-                                                    makefileName)
-                  << "\"\n"
-                  << "  \""
-                  << lg->MaybeConvertToRelativePath(currentBinDir, check)
-                  << "\"\n";
-  cmakefileStream << "  )\n\n";
-
-  const std::string binDir = lg->GetBinaryDirectory();
-
-  // CMake must rerun if a byproduct is missing.
   {
-    cmakefileStream << "# Byproducts of CMake generate step:\n"
-                    << "set(CMAKE_MAKEFILE_PRODUCTS\n";
-    for (std::string const& outfile : lg->GetMakefile()->GetOutputFiles()) {
+    // reset lg to the first makefile
+    const auto& lg = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(
+      this->LocalGenerators[0]);
+
+    const std::string& currentBinDir = lg.GetCurrentBinaryDirectory();
+    // Save the list to the cmake file.
+    cmakefileStream
+      << "# The top level Makefile was generated from the following files:\n"
+      << "set(CMAKE_MAKEFILE_DEPENDS\n"
+      << "  \"CMakeCache.txt\"\n";
+    for (std::string const& f : lfiles) {
       cmakefileStream << "  \""
-                      << lg->MaybeConvertToRelativePath(binDir, outfile)
+                      << lg.MaybeConvertToRelativePath(currentBinDir, f)
                       << "\"\n";
     }
+    cmakefileStream << "  )\n\n";
+
+    // Build the path to the cache check file.
+    std::string check =
+      cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(),
+               "/CMakeFiles/cmake.check_cache");
+
+    // Set the corresponding makefile in the cmake file.
+    cmakefileStream << "# The corresponding makefile is:\n"
+                    << "set(CMAKE_MAKEFILE_OUTPUTS\n"
+                    << "  \""
+                    << lg.MaybeConvertToRelativePath(currentBinDir,
+                                                     makefileName)
+                    << "\"\n"
+                    << "  \""
+                    << lg.MaybeConvertToRelativePath(currentBinDir, check)
+                    << "\"\n";
+    cmakefileStream << "  )\n\n";
+
+    const std::string& binDir = lg.GetBinaryDirectory();
+
+    // CMake must rerun if a byproduct is missing.
+    {
+      cmakefileStream << "# Byproducts of CMake generate step:\n"
+                      << "set(CMAKE_MAKEFILE_PRODUCTS\n";
+      for (std::string const& outfile : lg.GetMakefile()->GetOutputFiles()) {
+        cmakefileStream << "  \""
+                        << lg.MaybeConvertToRelativePath(binDir, outfile)
+                        << "\"\n";
+      }
+    }
 
     // add in all the directory information files
     std::string tmpStr;
-    for (cmLocalGenerator* localGen : this->LocalGenerators) {
-      lg = static_cast<cmLocalUnixMakefileGenerator3*>(localGen);
-      tmpStr = cmStrCat(lg->GetCurrentBinaryDirectory(),
+    for (const auto& localGen : this->LocalGenerators) {
+      tmpStr = cmStrCat(localGen->GetCurrentBinaryDirectory(),
                         "/CMakeFiles/CMakeDirectoryInformation.cmake");
       cmakefileStream << "  \""
-                      << lg->MaybeConvertToRelativePath(binDir, tmpStr)
+                      << localGen->MaybeConvertToRelativePath(binDir, tmpStr)
                       << "\"\n";
     }
     cmakefileStream << "  )\n\n";
@@ -364,26 +371,24 @@
 
 void cmGlobalUnixMakefileGenerator3::WriteMainCMakefileLanguageRules(
   cmGeneratedFileStream& cmakefileStream,
-  std::vector<cmLocalGenerator*>& lGenerators)
+  std::vector<std::unique_ptr<cmLocalGenerator>>& lGenerators)
 {
-  cmLocalUnixMakefileGenerator3* lg;
-
   // now list all the target info files
   cmakefileStream << "# Dependency information for all targets:\n";
   cmakefileStream << "set(CMAKE_DEPEND_INFO_FILES\n";
-  for (cmLocalGenerator* lGenerator : lGenerators) {
-    lg = static_cast<cmLocalUnixMakefileGenerator3*>(lGenerator);
+  for (const auto& lGenerator : lGenerators) {
+    const auto& lg =
+      cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(lGenerator);
     // for all of out targets
-    for (cmGeneratorTarget* tgt : lg->GetGeneratorTargets()) {
+    for (const auto& tgt : lg.GetGeneratorTargets()) {
       if ((tgt->GetType() == cmStateEnums::EXECUTABLE) ||
           (tgt->GetType() == cmStateEnums::STATIC_LIBRARY) ||
           (tgt->GetType() == cmStateEnums::SHARED_LIBRARY) ||
           (tgt->GetType() == cmStateEnums::MODULE_LIBRARY) ||
           (tgt->GetType() == cmStateEnums::OBJECT_LIBRARY) ||
           (tgt->GetType() == cmStateEnums::UTILITY)) {
-        cmGeneratorTarget* gt = tgt;
-        std::string tname =
-          cmStrCat(lg->GetRelativeTargetDirectory(gt), "/DependInfo.cmake");
+        std::string tname = cmStrCat(lg.GetRelativeTargetDirectory(tgt.get()),
+                                     "/DependInfo.cmake");
         cmSystemTools::ConvertToUnixSlashes(tname);
         cmakefileStream << "  \"" << tname << "\"\n";
       }
@@ -487,7 +492,7 @@
   std::unique_ptr<cmMakefile> mfu;
   cmMakefile* mf;
   if (!this->Makefiles.empty()) {
-    mf = this->Makefiles[0];
+    mf = this->Makefiles[0].get();
   } else {
     cmStateSnapshot snapshot = this->CMakeInstance->GetCurrentSnapshot();
     snapshot.GetDirectory().SetCurrentSource(
@@ -545,11 +550,11 @@
   }
 
   // write the target convenience rules
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
-    cmLocalUnixMakefileGenerator3* lg =
-      static_cast<cmLocalUnixMakefileGenerator3*>(localGen);
+  for (const auto& localGen : this->LocalGenerators) {
+    auto& lg =
+      cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(localGen);
     // for each target Generate the rule files for each target.
-    for (cmGeneratorTarget* gtarget : lg->GetGeneratorTargets()) {
+    for (const auto& gtarget : lg.GetGeneratorTargets()) {
       // Don't emit the same rule twice (e.g. two targets with the same
       // simple name)
       int type = gtarget->GetType();
@@ -564,23 +569,23 @@
            (type == cmStateEnums::OBJECT_LIBRARY) ||
            (type == cmStateEnums::UTILITY))) {
         // Add a rule to build the target by name.
-        lg->WriteDivider(ruleFileStream);
+        lg.WriteDivider(ruleFileStream);
         ruleFileStream << "# Target rules for targets named " << name
                        << "\n\n";
 
         // Write the rule.
         commands.clear();
         std::string tmp = "CMakeFiles/Makefile2";
-        commands.push_back(lg->GetRecursiveMakeCall(tmp, name));
+        commands.push_back(lg.GetRecursiveMakeCall(tmp, name));
         depends.clear();
         if (regenerate) {
           depends.emplace_back("cmake_check_build_system");
         }
-        lg->WriteMakeRule(ruleFileStream, "Build rule for target.", name,
-                          depends, commands, true);
+        lg.WriteMakeRule(ruleFileStream, "Build rule for target.", name,
+                         depends, commands, true);
 
         // Add a fast rule to build the target
-        std::string localName = lg->GetRelativeTargetDirectory(gtarget);
+        std::string localName = lg.GetRelativeTargetDirectory(gtarget.get());
         std::string makefileName;
         makefileName = cmStrCat(localName, "/build.make");
         depends.clear();
@@ -588,23 +593,23 @@
         std::string makeTargetName = cmStrCat(localName, "/build");
         localName = cmStrCat(name, "/fast");
         commands.push_back(
-          lg->GetRecursiveMakeCall(makefileName, makeTargetName));
-        lg->WriteMakeRule(ruleFileStream, "fast build rule for target.",
-                          localName, depends, commands, true);
+          lg.GetRecursiveMakeCall(makefileName, makeTargetName));
+        lg.WriteMakeRule(ruleFileStream, "fast build rule for target.",
+                         localName, depends, commands, true);
 
         // Add a local name for the rule to relink the target before
         // installation.
-        if (gtarget->NeedRelinkBeforeInstall(lg->GetConfigName())) {
-          makeTargetName =
-            cmStrCat(lg->GetRelativeTargetDirectory(gtarget), "/preinstall");
+        if (gtarget->NeedRelinkBeforeInstall(lg.GetConfigName())) {
+          makeTargetName = cmStrCat(
+            lg.GetRelativeTargetDirectory(gtarget.get()), "/preinstall");
           localName = cmStrCat(name, "/preinstall");
           depends.clear();
           commands.clear();
           commands.push_back(
-            lg->GetRecursiveMakeCall(makefileName, makeTargetName));
-          lg->WriteMakeRule(ruleFileStream,
-                            "Manual pre-install relink rule for target.",
-                            localName, depends, commands, true);
+            lg.GetRecursiveMakeCall(makefileName, makeTargetName));
+          lg.WriteMakeRule(ruleFileStream,
+                           "Manual pre-install relink rule for target.",
+                           localName, depends, commands, true);
         }
       }
     }
@@ -612,7 +617,7 @@
 }
 
 void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
-  std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg)
+  std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3& lg)
 {
   std::vector<std::string> depends;
   std::vector<std::string> commands;
@@ -625,7 +630,7 @@
   }
 
   // for each target Generate the rule files for each target.
-  for (cmGeneratorTarget* gtarget : lg->GetGeneratorTargets()) {
+  for (const auto& gtarget : lg.GetGeneratorTargets()) {
     int type = gtarget->GetType();
     std::string name = gtarget->GetName();
     if (!name.empty() &&
@@ -637,31 +642,31 @@
          (type == cmStateEnums::UTILITY))) {
       std::string makefileName;
       // Add a rule to build the target by name.
-      localName = lg->GetRelativeTargetDirectory(gtarget);
+      localName = lg.GetRelativeTargetDirectory(gtarget.get());
       makefileName = cmStrCat(localName, "/build.make");
 
-      lg->WriteDivider(ruleFileStream);
+      lg.WriteDivider(ruleFileStream);
       ruleFileStream << "# Target rules for target " << localName << "\n\n";
 
       commands.clear();
       makeTargetName = cmStrCat(localName, "/depend");
       commands.push_back(
-        lg->GetRecursiveMakeCall(makefileName, makeTargetName));
+        lg.GetRecursiveMakeCall(makefileName, makeTargetName));
 
       makeTargetName = cmStrCat(localName, "/build");
       commands.push_back(
-        lg->GetRecursiveMakeCall(makefileName, makeTargetName));
+        lg.GetRecursiveMakeCall(makefileName, makeTargetName));
 
       // Write the rule.
       localName += "/all";
       depends.clear();
 
       cmLocalUnixMakefileGenerator3::EchoProgress progress;
-      progress.Dir = cmStrCat(lg->GetBinaryDirectory(), "/CMakeFiles");
+      progress.Dir = cmStrCat(lg.GetBinaryDirectory(), "/CMakeFiles");
       {
         std::ostringstream progressArg;
         const char* sep = "";
-        for (unsigned long progFile : this->ProgressMap[gtarget].Marks) {
+        for (unsigned long progFile : this->ProgressMap[gtarget.get()].Marks) {
           progressArg << sep << progFile;
           sep = ",";
         }
@@ -676,13 +681,13 @@
       }
 
       if (targetMessages) {
-        lg->AppendEcho(commands, "Built target " + name,
-                       cmLocalUnixMakefileGenerator3::EchoNormal, &progress);
+        lg.AppendEcho(commands, "Built target " + name,
+                      cmLocalUnixMakefileGenerator3::EchoNormal, &progress);
       }
 
-      this->AppendGlobalTargetDepends(depends, gtarget);
-      lg->WriteMakeRule(ruleFileStream, "All Build rule for target.",
-                        localName, depends, commands, true);
+      this->AppendGlobalTargetDepends(depends, gtarget.get());
+      lg.WriteMakeRule(ruleFileStream, "All Build rule for target.", localName,
+                       depends, commands, true);
 
       // Write the rule.
       commands.clear();
@@ -692,20 +697,21 @@
         std::ostringstream progCmd;
         progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
         // # in target
-        progCmd << lg->ConvertToOutputFormat(
+        progCmd << lg.ConvertToOutputFormat(
           cmSystemTools::CollapseFullPath(progress.Dir),
           cmOutputConverter::SHELL);
         //
         std::set<cmGeneratorTarget const*> emitted;
-        progCmd << " " << this->CountProgressMarksInTarget(gtarget, emitted);
+        progCmd << " "
+                << this->CountProgressMarksInTarget(gtarget.get(), emitted);
         commands.push_back(progCmd.str());
       }
       std::string tmp = "CMakeFiles/Makefile2";
-      commands.push_back(lg->GetRecursiveMakeCall(tmp, localName));
+      commands.push_back(lg.GetRecursiveMakeCall(tmp, localName));
       {
         std::ostringstream progCmd;
         progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
-        progCmd << lg->ConvertToOutputFormat(
+        progCmd << lg.ConvertToOutputFormat(
           cmSystemTools::CollapseFullPath(progress.Dir),
           cmOutputConverter::SHELL);
         progCmd << " 0";
@@ -715,39 +721,39 @@
       if (regenerate) {
         depends.emplace_back("cmake_check_build_system");
       }
-      localName = cmStrCat(lg->GetRelativeTargetDirectory(gtarget), "/rule");
-      lg->WriteMakeRule(ruleFileStream,
-                        "Build rule for subdir invocation for target.",
-                        localName, depends, commands, true);
+      localName =
+        cmStrCat(lg.GetRelativeTargetDirectory(gtarget.get()), "/rule");
+      lg.WriteMakeRule(ruleFileStream,
+                       "Build rule for subdir invocation for target.",
+                       localName, depends, commands, true);
 
       // Add a target with the canonical name (no prefix, suffix or path).
       commands.clear();
       depends.clear();
       depends.push_back(localName);
-      lg->WriteMakeRule(ruleFileStream, "Convenience name for target.", name,
-                        depends, commands, true);
+      lg.WriteMakeRule(ruleFileStream, "Convenience name for target.", name,
+                       depends, commands, true);
 
       // Add rules to prepare the target for installation.
-      if (gtarget->NeedRelinkBeforeInstall(lg->GetConfigName())) {
-        localName =
-          cmStrCat(lg->GetRelativeTargetDirectory(gtarget), "/preinstall");
+      if (gtarget->NeedRelinkBeforeInstall(lg.GetConfigName())) {
+        localName = cmStrCat(lg.GetRelativeTargetDirectory(gtarget.get()),
+                             "/preinstall");
         depends.clear();
         commands.clear();
-        commands.push_back(lg->GetRecursiveMakeCall(makefileName, localName));
-        lg->WriteMakeRule(ruleFileStream,
-                          "Pre-install relink rule for target.", localName,
-                          depends, commands, true);
+        commands.push_back(lg.GetRecursiveMakeCall(makefileName, localName));
+        lg.WriteMakeRule(ruleFileStream, "Pre-install relink rule for target.",
+                         localName, depends, commands, true);
       }
 
       // add the clean rule
-      localName = lg->GetRelativeTargetDirectory(gtarget);
+      localName = lg.GetRelativeTargetDirectory(gtarget.get());
       makeTargetName = cmStrCat(localName, "/clean");
       depends.clear();
       commands.clear();
       commands.push_back(
-        lg->GetRecursiveMakeCall(makefileName, makeTargetName));
-      lg->WriteMakeRule(ruleFileStream, "clean rule for target.",
-                        makeTargetName, depends, commands, true);
+        lg.GetRecursiveMakeCall(makefileName, makeTargetName));
+      lg.WriteMakeRule(ruleFileStream, "clean rule for target.",
+                       makeTargetName, depends, commands, true);
       commands.clear();
     }
   }
@@ -759,8 +765,8 @@
 {
   this->DirectoryTargetsMap.clear();
   // Loop over all targets in all local generators.
-  for (cmLocalGenerator* lg : this->LocalGenerators) {
-    for (cmGeneratorTarget* gt : lg->GetGeneratorTargets()) {
+  for (const auto& lg : this->LocalGenerators) {
+    for (const auto& gt : lg->GetGeneratorTargets()) {
       cmLocalGenerator* tlg = gt->GetLocalGenerator();
 
       if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
@@ -778,12 +784,13 @@
         // This local generator includes the target.
         std::set<cmGeneratorTarget const*>& targetSet =
           this->DirectoryTargetsMap[csnp];
-        targetSet.insert(gt);
+        targetSet.insert(gt.get());
 
         // Add dependencies of the included target.  An excluded
         // target may still be included if it is a dependency of a
         // non-excluded target.
-        for (cmTargetDepend const& tgtdep : this->GetTargetDirectDepends(gt)) {
+        for (cmTargetDepend const& tgtdep :
+             this->GetTargetDirectDepends(gt.get())) {
           targetSet.insert(tgtdep);
         }
       }
@@ -808,12 +815,12 @@
 }
 
 size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInAll(
-  cmLocalGenerator* lg)
+  const cmLocalGenerator& lg)
 {
   size_t count = 0;
   std::set<cmGeneratorTarget const*> emitted;
   for (cmGeneratorTarget const* target :
-       this->DirectoryTargetsMap[lg->GetStateSnapshot()]) {
+       this->DirectoryTargetsMap[lg.GetStateSnapshot()]) {
     count += this->CountProgressMarksInTarget(target, emitted);
   }
   return count;
@@ -885,33 +892,48 @@
 
   // 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 (cmLocalGenerator* localGen : this->LocalGenerators) {
-    cmLocalUnixMakefileGenerator3* lg2 =
-      static_cast<cmLocalUnixMakefileGenerator3*>(localGen);
+  for (const auto& localGen : this->LocalGenerators) {
+    const auto& lg2 =
+      cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(localGen);
     // for the passed in makefile or if this is the top Makefile wripte out
     // the targets
-    if (lg2 == lg || lg->IsRootMakefile()) {
+    if (&lg2 == lg || lg->IsRootMakefile()) {
       // for each target Generate the rule files for each target.
-      for (cmGeneratorTarget* target : lg2->GetGeneratorTargets()) {
+      for (const auto& target : lg2.GetGeneratorTargets()) {
         cmStateEnums::TargetType type = target->GetType();
         if ((type == cmStateEnums::EXECUTABLE) ||
             (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/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
index 79db30e..340a7ef 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.h
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -8,6 +8,7 @@
 #include <cstddef>
 #include <iosfwd>
 #include <map>
+#include <memory>
 #include <set>
 #include <string>
 #include <vector>
@@ -61,10 +62,10 @@
 {
 public:
   cmGlobalUnixMakefileGenerator3(cmake* cm);
-  static cmGlobalGeneratorFactory* NewFactory()
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
   {
-    return new cmGlobalGeneratorSimpleFactory<
-      cmGlobalUnixMakefileGenerator3>();
+    return std::unique_ptr<cmGlobalGeneratorFactory>(
+      new cmGlobalGeneratorSimpleFactory<cmGlobalUnixMakefileGenerator3>());
   }
 
   //! Get the name for the generator.
@@ -89,7 +90,8 @@
   /** Get the documentation entry for this generator.  */
   static void GetDocumentation(cmDocumentationEntry& entry);
 
-  cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
+  std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+    cmMakefile* mf) override;
 
   /**
    * Try to determine system information such as shared library
@@ -107,8 +109,9 @@
    */
   void Generate() override;
 
-  void WriteMainCMakefileLanguageRules(cmGeneratedFileStream& cmakefileStream,
-                                       std::vector<cmLocalGenerator*>&);
+  void WriteMainCMakefileLanguageRules(
+    cmGeneratedFileStream& cmakefileStream,
+    std::vector<std::unique_ptr<cmLocalGenerator>>&);
 
   // write out the help rule listing the valid targets
   void WriteHelpRule(std::ostream& ruleFileStream,
@@ -161,7 +164,7 @@
   void WriteMainCMakefile();
 
   void WriteConvenienceRules2(std::ostream& ruleFileStream,
-                              cmLocalUnixMakefileGenerator3*);
+                              cmLocalUnixMakefileGenerator3&);
 
   void WriteDirectoryRule2(std::ostream& ruleFileStream,
                            DirectoryTarget const& dt, const char* pass,
@@ -227,7 +230,7 @@
   size_t CountProgressMarksInTarget(
     cmGeneratorTarget const* target,
     std::set<cmGeneratorTarget const*>& emitted);
-  size_t CountProgressMarksInAll(cmLocalGenerator* lg);
+  size_t CountProgressMarksInAll(const cmLocalGenerator& lg);
 
   cmGeneratedFileStream* CommandDatabase;
 
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index f6472ab..ccb6c50 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -4,6 +4,8 @@
 
 #include <algorithm>
 
+#include <cm/memory>
+
 #include "cmsys/FStream.hxx"
 #include "cmsys/Glob.hxx"
 #include "cmsys/RegularExpression.hxx"
@@ -26,6 +28,16 @@
 static const char vs10generatorName[] = "Visual Studio 10 2010";
 static std::map<std::string, std::vector<cmIDEFlagTable>> loadedFlagJsonFiles;
 
+static void ConvertToWindowsSlashes(std::string& s)
+{
+  // first convert all of the slashes
+  for (auto& ch : s) {
+    if (ch == '/') {
+      ch = '\\';
+    }
+  }
+}
+
 // Map generator name without year to name with year.
 static const char* cmVS10GenName(const std::string& name, std::string& genName)
 {
@@ -45,27 +57,30 @@
   : public cmGlobalGeneratorFactory
 {
 public:
-  cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
-                                           cmake* cm) const override
+  std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+    const std::string& name, cmake* cm) const override
   {
     std::string genName;
     const char* p = cmVS10GenName(name, genName);
     if (!p) {
-      return 0;
+      return std::unique_ptr<cmGlobalGenerator>();
     }
     if (!*p) {
-      return new cmGlobalVisualStudio10Generator(cm, genName, "");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudio10Generator(cm, genName, ""));
     }
     if (*p++ != ' ') {
-      return 0;
+      return std::unique_ptr<cmGlobalGenerator>();
     }
     if (strcmp(p, "Win64") == 0) {
-      return new cmGlobalVisualStudio10Generator(cm, genName, "x64");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudio10Generator(cm, genName, "x64"));
     }
     if (strcmp(p, "IA64") == 0) {
-      return new cmGlobalVisualStudio10Generator(cm, genName, "Itanium");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudio10Generator(cm, genName, "Itanium"));
     }
-    return 0;
+    return std::unique_ptr<cmGlobalGenerator>();
   }
 
   void GetDocumentation(cmDocumentationEntry& entry) const override
@@ -105,9 +120,10 @@
   std::string GetDefaultPlatformName() const override { return "Win32"; }
 };
 
-cmGlobalGeneratorFactory* cmGlobalVisualStudio10Generator::NewFactory()
+std::unique_ptr<cmGlobalGeneratorFactory>
+cmGlobalVisualStudio10Generator::NewFactory()
 {
-  return new Factory;
+  return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
 }
 
 cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator(
@@ -193,7 +209,7 @@
 }
 
 bool cmGlobalVisualStudio10Generator::SetGeneratorToolset(
-  std::string const& ts, cmMakefile* mf)
+  std::string const& ts, bool build, cmMakefile* mf)
 {
   if (this->SystemIsWindowsCE && ts.empty() &&
       this->DefaultPlatformToolset.empty()) {
@@ -208,7 +224,11 @@
     return false;
   }
 
-  if (!this->FindVCTargetsPath(mf)) {
+  if (build) {
+    return true;
+  }
+
+  if (this->CustomVCTargetsPath.empty() && !this->FindVCTargetsPath(mf)) {
     return false;
   }
 
@@ -355,6 +375,11 @@
   if (const char* cudaDir = this->GetPlatformToolsetCudaCustomDir()) {
     mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR", cudaDir);
   }
+  if (const char* vcTargetsDir = this->GetCustomVCTargetsPath()) {
+    mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_VCTARGETS_CUSTOM_DIR",
+                      vcTargetsDir);
+  }
+
   return true;
 }
 
@@ -448,6 +473,11 @@
     this->GeneratorToolsetVersion = value;
     return true;
   }
+  if (key == "VCTargetsPath") {
+    this->CustomVCTargetsPath = value;
+    ConvertToWindowsSlashes(this->CustomVCTargetsPath);
+    return true;
+  }
   return false;
 }
 
@@ -556,10 +586,11 @@
 }
 
 //! Create a local generator appropriate to this Global Generator
-cmLocalGenerator* cmGlobalVisualStudio10Generator::CreateLocalGenerator(
-  cmMakefile* mf)
+std::unique_ptr<cmLocalGenerator>
+cmGlobalVisualStudio10Generator::CreateLocalGenerator(cmMakefile* mf)
 {
-  return new cmLocalVisualStudio10Generator(this, mf);
+  return std::unique_ptr<cmLocalGenerator>(
+    cm::make_unique<cmLocalVisualStudio10Generator>(this, mf));
 }
 
 void cmGlobalVisualStudio10Generator::Generate()
@@ -590,7 +621,7 @@
       "To avoid this problem CMake must use a full path for this file "
       "which then triggers the VS 10 property dialog bug.";
     /* clang-format on */
-    lg->IssueMessage(MessageType::WARNING, e.str().c_str());
+    lg->IssueMessage(MessageType::WARNING, e.str());
   }
 }
 
@@ -609,6 +640,14 @@
   cmGlobalVisualStudio8Generator::EnableLanguage(lang, mf, optional);
 }
 
+const char* cmGlobalVisualStudio10Generator::GetCustomVCTargetsPath() const
+{
+  if (this->CustomVCTargetsPath.empty()) {
+    return nullptr;
+  }
+  return this->CustomVCTargetsPath.c_str();
+}
+
 const char* cmGlobalVisualStudio10Generator::GetPlatformToolset() const
 {
   std::string const& toolset = this->GetPlatformToolsetString();
@@ -803,7 +842,7 @@
   // Prepare the work directory.
   if (!cmSystemTools::MakeDirectory(wd)) {
     std::string e = "Failed to make directory:\n  " + wd;
-    mf->IssueMessage(MessageType::FATAL_ERROR, e.c_str());
+    mf->IssueMessage(MessageType::FATAL_ERROR, e);
     cmSystemTools::SetFatalErrorOccured();
     return false;
   }
@@ -924,7 +963,7 @@
     if (ret != 0) {
       e << "Exit code: " << ret << "\n";
     }
-    mf->IssueMessage(MessageType::FATAL_ERROR, e.str().c_str());
+    mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
     cmSystemTools::SetFatalErrorOccured();
     return false;
   }
@@ -1098,8 +1137,7 @@
   // Hide them away under the CMakeFiles directory.
   std::string ruleDir = cmStrCat(
     this->GetCMakeInstance()->GetHomeOutputDirectory(), "/CMakeFiles/",
-    cmSystemTools::ComputeStringMD5(
-      cmSystemTools::GetFilenamePath(output).c_str()));
+    cmSystemTools::ComputeStringMD5(cmSystemTools::GetFilenamePath(output)));
   std::string ruleFile =
     cmStrCat(ruleDir, '/', cmSystemTools::GetFilenameName(output), ".rule");
   return ruleFile;
@@ -1293,7 +1331,7 @@
     e << "JSON flag table \"" << filename <<
       "\" could not be loaded.\n";
     /* clang-format on */
-    mf->IssueMessage(MessageType::FATAL_ERROR, e.str().c_str());
+    mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
   }
   return ret;
 }
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index 56f1193..f659ff3 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -3,6 +3,8 @@
 #ifndef cmGlobalVisualStudio10Generator_h
 #define cmGlobalVisualStudio10Generator_h
 
+#include <memory>
+
 #include "cmGlobalVisualStudio8Generator.h"
 #include "cmVisualStudio10ToolsetOptions.h"
 
@@ -14,13 +16,14 @@
 class cmGlobalVisualStudio10Generator : public cmGlobalVisualStudio8Generator
 {
 public:
-  static cmGlobalGeneratorFactory* NewFactory();
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory();
 
   bool MatchesGeneratorName(const std::string& name) const override;
 
   bool SetSystemName(std::string const& s, cmMakefile* mf) override;
   bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override;
-  bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf) override;
+  bool SetGeneratorToolset(std::string const& ts, bool build,
+                           cmMakefile* mf) override;
 
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
     const std::string& makeProgram, const std::string& projectName,
@@ -30,7 +33,8 @@
       std::vector<std::string>()) override;
 
   //! create the correct local generator
-  cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
+  std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+    cmMakefile* mf) override;
 
   /**
    * Try to determine system information such as shared library
@@ -45,6 +49,9 @@
   bool IsNsightTegra() const;
   std::string GetNsightTegraVersion() const;
 
+  /** The vctargets path for the target platform.  */
+  const char* GetCustomVCTargetsPath() const;
+
   /** The toolset name for the target platform.  */
   const char* GetPlatformToolset() const;
   std::string const& GetPlatformToolsetString() const;
@@ -157,6 +164,7 @@
   std::string GeneratorToolset;
   std::string GeneratorToolsetVersion;
   std::string GeneratorToolsetHostArchitecture;
+  std::string GeneratorToolsetCustomVCTargetsDir;
   std::string GeneratorToolsetCuda;
   std::string GeneratorToolsetCudaCustomDir;
   std::string DefaultPlatformToolset;
@@ -209,6 +217,7 @@
 
   bool ParseGeneratorToolset(std::string const& ts, cmMakefile* mf);
 
+  std::string CustomVCTargetsPath;
   std::string VCTargetsPath;
   bool FindVCTargetsPath(cmMakefile* mf);
 
diff --git a/Source/cmGlobalVisualStudio11Generator.cxx b/Source/cmGlobalVisualStudio11Generator.cxx
index 4b74ef1..a385375 100644
--- a/Source/cmGlobalVisualStudio11Generator.cxx
+++ b/Source/cmGlobalVisualStudio11Generator.cxx
@@ -2,6 +2,8 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGlobalVisualStudio11Generator.h"
 
+#include <utility>
+
 #include "cmAlgorithms.h"
 #include "cmDocumentationEntry.h"
 #include "cmLocalVisualStudio10Generator.h"
@@ -28,38 +30,41 @@
   : public cmGlobalGeneratorFactory
 {
 public:
-  cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
-                                           cmake* cm) const override
+  std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+    const std::string& name, cmake* cm) const override
   {
     std::string genName;
     const char* p = cmVS11GenName(name, genName);
     if (!p) {
-      return 0;
+      return std::unique_ptr<cmGlobalGenerator>();
     }
     if (!*p) {
-      return new cmGlobalVisualStudio11Generator(cm, genName, "");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudio11Generator(cm, genName, ""));
     }
     if (*p++ != ' ') {
-      return 0;
+      return std::unique_ptr<cmGlobalGenerator>();
     }
     if (strcmp(p, "Win64") == 0) {
-      return new cmGlobalVisualStudio11Generator(cm, genName, "x64");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudio11Generator(cm, genName, "x64"));
     }
     if (strcmp(p, "ARM") == 0) {
-      return new cmGlobalVisualStudio11Generator(cm, genName, "ARM");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudio11Generator(cm, genName, "ARM"));
     }
 
     std::set<std::string> installedSDKs =
       cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs();
 
     if (installedSDKs.find(p) == installedSDKs.end()) {
-      return 0;
+      return std::unique_ptr<cmGlobalGenerator>();
     }
 
-    cmGlobalVisualStudio11Generator* ret =
-      new cmGlobalVisualStudio11Generator(cm, name, p);
+    auto ret = std::unique_ptr<cmGlobalVisualStudio11Generator>(
+      new cmGlobalVisualStudio11Generator(cm, name, p));
     ret->WindowsCEVersion = "8.00";
-    return ret;
+    return std::unique_ptr<cmGlobalGenerator>(std::move(ret));
   }
 
   void GetDocumentation(cmDocumentationEntry& entry) const override
@@ -113,9 +118,10 @@
   std::string GetDefaultPlatformName() const override { return "Win32"; }
 };
 
-cmGlobalGeneratorFactory* cmGlobalVisualStudio11Generator::NewFactory()
+std::unique_ptr<cmGlobalGeneratorFactory>
+cmGlobalVisualStudio11Generator::NewFactory()
 {
-  return new Factory;
+  return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
 }
 
 cmGlobalVisualStudio11Generator::cmGlobalVisualStudio11Generator(
diff --git a/Source/cmGlobalVisualStudio11Generator.h b/Source/cmGlobalVisualStudio11Generator.h
index f8cce18..5f1ff73 100644
--- a/Source/cmGlobalVisualStudio11Generator.h
+++ b/Source/cmGlobalVisualStudio11Generator.h
@@ -6,6 +6,7 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <iosfwd>
+#include <memory>
 #include <set>
 #include <string>
 
@@ -20,7 +21,7 @@
 class cmGlobalVisualStudio11Generator : public cmGlobalVisualStudio10Generator
 {
 public:
-  static cmGlobalGeneratorFactory* NewFactory();
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory();
 
   bool MatchesGeneratorName(const std::string& name) const override;
 
diff --git a/Source/cmGlobalVisualStudio12Generator.cxx b/Source/cmGlobalVisualStudio12Generator.cxx
index d9702c9..5a27994 100644
--- a/Source/cmGlobalVisualStudio12Generator.cxx
+++ b/Source/cmGlobalVisualStudio12Generator.cxx
@@ -28,27 +28,30 @@
   : public cmGlobalGeneratorFactory
 {
 public:
-  cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
-                                           cmake* cm) const override
+  std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+    const std::string& name, cmake* cm) const override
   {
     std::string genName;
     const char* p = cmVS12GenName(name, genName);
     if (!p) {
-      return 0;
+      return std::unique_ptr<cmGlobalGenerator>();
     }
     if (!*p) {
-      return new cmGlobalVisualStudio12Generator(cm, genName, "");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudio12Generator(cm, genName, ""));
     }
     if (*p++ != ' ') {
-      return 0;
+      return std::unique_ptr<cmGlobalGenerator>();
     }
     if (strcmp(p, "Win64") == 0) {
-      return new cmGlobalVisualStudio12Generator(cm, genName, "x64");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudio12Generator(cm, genName, "x64"));
     }
     if (strcmp(p, "ARM") == 0) {
-      return new cmGlobalVisualStudio12Generator(cm, genName, "ARM");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudio12Generator(cm, genName, "ARM"));
     }
-    return 0;
+    return std::unique_ptr<cmGlobalGenerator>();
   }
 
   void GetDocumentation(cmDocumentationEntry& entry) const override
@@ -88,9 +91,10 @@
   std::string GetDefaultPlatformName() const override { return "Win32"; }
 };
 
-cmGlobalGeneratorFactory* cmGlobalVisualStudio12Generator::NewFactory()
+std::unique_ptr<cmGlobalGeneratorFactory>
+cmGlobalVisualStudio12Generator::NewFactory()
 {
-  return new Factory;
+  return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
 }
 
 cmGlobalVisualStudio12Generator::cmGlobalVisualStudio12Generator(
diff --git a/Source/cmGlobalVisualStudio12Generator.h b/Source/cmGlobalVisualStudio12Generator.h
index 53b7091..bdd40ff 100644
--- a/Source/cmGlobalVisualStudio12Generator.h
+++ b/Source/cmGlobalVisualStudio12Generator.h
@@ -6,6 +6,7 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <iosfwd>
+#include <memory>
 #include <string>
 
 #include "cmGlobalVisualStudio11Generator.h"
@@ -18,7 +19,7 @@
 class cmGlobalVisualStudio12Generator : public cmGlobalVisualStudio11Generator
 {
 public:
-  static cmGlobalGeneratorFactory* NewFactory();
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory();
 
   bool MatchesGeneratorName(const std::string& name) const override;
 
diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx
index cd48474..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"
@@ -28,27 +29,30 @@
   : public cmGlobalGeneratorFactory
 {
 public:
-  cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
-                                           cmake* cm) const override
+  std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+    const std::string& name, cmake* cm) const override
   {
     std::string genName;
     const char* p = cmVS14GenName(name, genName);
     if (!p) {
-      return 0;
+      return std::unique_ptr<cmGlobalGenerator>();
     }
     if (!*p) {
-      return new cmGlobalVisualStudio14Generator(cm, genName, "");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudio14Generator(cm, genName, ""));
     }
     if (*p++ != ' ') {
-      return 0;
+      return std::unique_ptr<cmGlobalGenerator>();
     }
     if (strcmp(p, "Win64") == 0) {
-      return new cmGlobalVisualStudio14Generator(cm, genName, "x64");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudio14Generator(cm, genName, "x64"));
     }
     if (strcmp(p, "ARM") == 0) {
-      return new cmGlobalVisualStudio14Generator(cm, genName, "ARM");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudio14Generator(cm, genName, "ARM"));
     }
-    return 0;
+    return std::unique_ptr<cmGlobalGenerator>();
   }
 
   void GetDocumentation(cmDocumentationEntry& entry) const override
@@ -88,9 +92,10 @@
   std::string GetDefaultPlatformName() const override { return "Win32"; }
 };
 
-cmGlobalGeneratorFactory* cmGlobalVisualStudio14Generator::NewFactory()
+std::unique_ptr<cmGlobalGeneratorFactory>
+cmGlobalVisualStudio14Generator::NewFactory()
 {
-  return new Factory;
+  return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
 }
 
 cmGlobalVisualStudio14Generator::cmGlobalVisualStudio14Generator(
@@ -299,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) {
@@ -309,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/cmGlobalVisualStudio14Generator.h b/Source/cmGlobalVisualStudio14Generator.h
index 6e12d3e..ccc2917 100644
--- a/Source/cmGlobalVisualStudio14Generator.h
+++ b/Source/cmGlobalVisualStudio14Generator.h
@@ -6,6 +6,7 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <iosfwd>
+#include <memory>
 #include <string>
 
 #include "cmGlobalVisualStudio12Generator.h"
@@ -18,7 +19,7 @@
 class cmGlobalVisualStudio14Generator : public cmGlobalVisualStudio12Generator
 {
 public:
-  static cmGlobalGeneratorFactory* NewFactory();
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory();
 
   bool MatchesGeneratorName(const std::string& name) const override;
 
diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx
index e8e9ece..d0aec61 100644
--- a/Source/cmGlobalVisualStudio71Generator.cxx
+++ b/Source/cmGlobalVisualStudio71Generator.cxx
@@ -87,7 +87,7 @@
 // the libraries it uses are also done here
 void cmGlobalVisualStudio71Generator::WriteProject(std::ostream& fout,
                                                    const std::string& dspname,
-                                                   const char* dir,
+                                                   const std::string& dir,
                                                    cmGeneratorTarget const* t)
 {
   // check to see if this is a fortran build
@@ -109,7 +109,7 @@
 
   std::string guid = this->GetGUID(dspname);
   fout << project << dspname << "\", \"" << this->ConvertToSolutionPath(dir)
-       << (dir[0] ? "\\" : "") << dspname << ext << "\", \"{" << guid
+       << (!dir.empty() ? "\\" : "") << dspname << ext << "\", \"{" << guid
        << "}\"\n";
   fout << "\tProjectSection(ProjectDependencies) = postProject\n";
   this->WriteProjectDepends(fout, dspname, dir, t);
@@ -138,7 +138,7 @@
 // Note, that dependencies from executables to
 // the libraries it uses are also done here
 void cmGlobalVisualStudio71Generator::WriteProjectDepends(
-  std::ostream& fout, const std::string&, const char*,
+  std::ostream& fout, const std::string&, const std::string&,
   cmGeneratorTarget const* target)
 {
   VSDependSet const& depends = this->VSTargetDepends[target];
@@ -156,8 +156,9 @@
 // Write a dsp file into the SLN file, Note, that dependencies from
 // executables to the libraries it uses are also done here
 void cmGlobalVisualStudio71Generator::WriteExternalProject(
-  std::ostream& fout, const std::string& name, const char* location,
-  const char* typeGuid, const std::set<BT<std::string>>& depends)
+  std::ostream& fout, const std::string& name, const std::string& location,
+  const char* typeGuid,
+  const std::set<BT<std::pair<std::string, bool>>>& depends)
 {
   fout << "Project(\"{"
        << (typeGuid ? typeGuid : this->ExternalProjectType(location))
@@ -169,8 +170,8 @@
   // project instead of in the global section
   if (!depends.empty()) {
     fout << "\tProjectSection(ProjectDependencies) = postProject\n";
-    for (BT<std::string> const& it : depends) {
-      std::string const& dep = it.Value;
+    for (BT<std::pair<std::string, bool>> const& it : depends) {
+      std::string const& dep = it.Value.first;
       if (!dep.empty()) {
         fout << "\t\t{" << this->GetGUID(dep) << "} = {" << this->GetGUID(dep)
              << "}\n";
diff --git a/Source/cmGlobalVisualStudio71Generator.h b/Source/cmGlobalVisualStudio71Generator.h
index 85755af..7eadaf3 100644
--- a/Source/cmGlobalVisualStudio71Generator.h
+++ b/Source/cmGlobalVisualStudio71Generator.h
@@ -22,18 +22,20 @@
   virtual void WriteSolutionConfigurations(
     std::ostream& fout, std::vector<std::string> const& configs);
   void WriteProject(std::ostream& fout, const std::string& name,
-                    const char* path, const cmGeneratorTarget* t) override;
+                    const std::string& path,
+                    const cmGeneratorTarget* t) override;
   void WriteProjectDepends(std::ostream& fout, const std::string& name,
-                           const char* path,
+                           const std::string& path,
                            cmGeneratorTarget const* t) override;
   void WriteProjectConfigurations(
     std::ostream& fout, const std::string& name,
     cmGeneratorTarget const& target, std::vector<std::string> const& configs,
     const std::set<std::string>& configsPartOfDefaultBuild,
     const std::string& platformMapping = "") override;
-  void WriteExternalProject(std::ostream& fout, const std::string& name,
-                            const char* path, const char* typeGuid,
-                            const std::set<BT<std::string>>& depends) override;
+  void WriteExternalProject(
+    std::ostream& fout, const std::string& name, const std::string& path,
+    const char* typeGuid,
+    const std::set<BT<std::pair<std::string, bool>>>& depends) override;
 
   // Folders are not supported by VS 7.1.
   bool UseFolderProperty() const override { return false; }
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index 40b214c..9799124 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -2,8 +2,10 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGlobalVisualStudio7Generator.h"
 
+#include <utility>
 #include <vector>
 
+#include <cm/memory>
 #include <cm/string_view>
 
 #include <windows.h>
@@ -184,7 +186,7 @@
 }
 
 const char* cmGlobalVisualStudio7Generator::ExternalProjectType(
-  const char* location)
+  const std::string& location)
 {
   std::string extension = cmSystemTools::GetFilenameLastExtension(location);
   if (extension == ".vbproj") {
@@ -263,12 +265,11 @@
 }
 
 //! Create a local generator appropriate to this Global Generator
-cmLocalGenerator* cmGlobalVisualStudio7Generator::CreateLocalGenerator(
-  cmMakefile* mf)
+std::unique_ptr<cmLocalGenerator>
+cmGlobalVisualStudio7Generator::CreateLocalGenerator(cmMakefile* mf)
 {
-  cmLocalVisualStudio7Generator* lg =
-    new cmLocalVisualStudio7Generator(this, mf);
-  return lg;
+  auto lg = cm::make_unique<cmLocalVisualStudio7Generator>(this, mf);
+  return std::unique_ptr<cmLocalGenerator>(std::move(lg));
 }
 
 #if !defined(CMAKE_BOOTSTRAP)
@@ -300,7 +301,7 @@
   if (!cmSystemTools::GetErrorOccuredFlag() &&
       !this->LocalGenerators.empty()) {
     this->CallVisualStudioMacro(MacroReload,
-                                GetSLNFile(this->LocalGenerators[0]));
+                                GetSLNFile(this->LocalGenerators[0].get()));
   }
 }
 
@@ -345,8 +346,8 @@
     if (expath) {
       std::set<std::string> allConfigurations(configs.begin(), configs.end());
       const char* mapping = target->GetProperty("VS_PLATFORM_MAPPING");
-      this->WriteProjectConfigurations(fout, target->GetName().c_str(),
-                                       *target, configs, allConfigurations,
+      this->WriteProjectConfigurations(fout, target->GetName(), *target,
+                                       configs, allConfigurations,
                                        mapping ? mapping : "");
     } else {
       const std::set<std::string>& configsPartOfDefaultBuild =
@@ -379,7 +380,7 @@
       std::string project = target->GetName();
       std::string location = expath;
 
-      this->WriteExternalProject(fout, project.c_str(), location.c_str(),
+      this->WriteExternalProject(fout, project, location,
                                  target->GetProperty("VS_PROJECT_TYPE"),
                                  target->GetUtilities());
       written = true;
@@ -388,11 +389,11 @@
       if (vcprojName) {
         cmLocalGenerator* lg = target->GetLocalGenerator();
         std::string dir = lg->GetCurrentBinaryDirectory();
-        dir = root->MaybeConvertToRelativePath(rootBinaryDir, dir.c_str());
+        dir = root->MaybeConvertToRelativePath(rootBinaryDir, dir);
         if (dir == ".") {
           dir.clear(); // msbuild cannot handle ".\" prefix
         }
-        this->WriteProject(fout, vcprojName, dir.c_str(), target);
+        this->WriteProject(fout, vcprojName, dir, target);
         written = true;
       }
     }
@@ -482,7 +483,7 @@
 }
 
 std::string cmGlobalVisualStudio7Generator::ConvertToSolutionPath(
-  const char* path)
+  const std::string& path)
 {
   // Convert to backslashes.  Do not use ConvertToOutputPath because
   // we will add quoting ourselves, and we know these projects always
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
index 7a9fcef..6cc1cf8 100644
--- a/Source/cmGlobalVisualStudio7Generator.h
+++ b/Source/cmGlobalVisualStudio7Generator.h
@@ -3,6 +3,8 @@
 #ifndef cmGlobalVisualStudio7Generator_h
 #define cmGlobalVisualStudio7Generator_h
 
+#include <memory>
+
 #include "cmGlobalGeneratorFactory.h"
 #include "cmGlobalVisualStudioGenerator.h"
 
@@ -20,7 +22,8 @@
   ~cmGlobalVisualStudio7Generator();
 
   //! Create a local generator appropriate to this Global Generator
-  cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
+  std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+    cmMakefile* mf) override;
 
 #if !defined(CMAKE_BOOTSTRAP)
   Json::Value GetJson() const override;
@@ -107,16 +110,17 @@
   std::string const& GetDevEnvCommand();
   virtual std::string FindDevEnvCommand();
 
-  static const char* ExternalProjectType(const char* location);
+  static const char* ExternalProjectType(const std::string& location);
 
   virtual void OutputSLNFile(cmLocalGenerator* root,
                              std::vector<cmLocalGenerator*>& generators);
   virtual void WriteSLNFile(std::ostream& fout, cmLocalGenerator* root,
                             std::vector<cmLocalGenerator*>& generators) = 0;
   virtual void WriteProject(std::ostream& fout, const std::string& name,
-                            const char* path, const cmGeneratorTarget* t) = 0;
+                            const std::string& path,
+                            const cmGeneratorTarget* t) = 0;
   virtual void WriteProjectDepends(std::ostream& fout, const std::string& name,
-                                   const char* path,
+                                   const std::string& path,
                                    cmGeneratorTarget const* t) = 0;
   virtual void WriteProjectConfigurations(
     std::ostream& fout, const std::string& name,
@@ -138,10 +142,11 @@
     OrderedTargetDependSet const& projectTargets);
 
   virtual void WriteExternalProject(
-    std::ostream& fout, const std::string& name, const char* path,
-    const char* typeGuid, const std::set<BT<std::string>>& dependencies) = 0;
+    std::ostream& fout, const std::string& name, const std::string& path,
+    const char* typeGuid,
+    const std::set<BT<std::pair<std::string, bool>>>& dependencies) = 0;
 
-  std::string ConvertToSolutionPath(const char* path);
+  std::string ConvertToSolutionPath(const std::string& path);
 
   std::set<std::string> IsPartOfDefaultBuild(
     std::vector<std::string> const& configs,
diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx
index 8e6125b..1c62fbd 100644
--- a/Source/cmGlobalVisualStudio8Generator.cxx
+++ b/Source/cmGlobalVisualStudio8Generator.cxx
@@ -2,6 +2,9 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGlobalVisualStudio8Generator.h"
 
+#include <cm/memory>
+#include <cmext/memory>
+
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
 #include "cmDocumentationEntry.h"
@@ -96,21 +99,22 @@
     return false;
   }
 
-  std::vector<cmLocalGenerator*> const& generators = this->LocalGenerators;
-  cmLocalVisualStudio7Generator* lg =
-    static_cast<cmLocalVisualStudio7Generator*>(generators[0]);
-  cmMakefile* mf = lg->GetMakefile();
+  std::vector<std::unique_ptr<cmLocalGenerator>> const& generators =
+    this->LocalGenerators;
+  auto& lg =
+    cm::static_reference_cast<cmLocalVisualStudio7Generator>(generators[0]);
 
   const char* no_working_directory = nullptr;
   std::vector<std::string> no_byproducts;
   std::vector<std::string> no_depends;
   cmCustomCommandLines no_commands;
-  cmTarget* tgt = mf->AddUtilityCommand(
-    CMAKE_CHECK_BUILD_SYSTEM_TARGET, cmCommandOrigin::Generator, false,
-    no_working_directory, no_byproducts, no_depends, no_commands);
+  cmTarget* tgt = lg.AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false,
+                                       no_working_directory, no_byproducts,
+                                       no_depends, no_commands);
 
-  cmGeneratorTarget* gt = new cmGeneratorTarget(tgt, lg);
-  lg->AddGeneratorTarget(gt);
+  auto ptr = cm::make_unique<cmGeneratorTarget>(tgt, &lg);
+  auto gt = ptr.get();
+  lg.AddGeneratorTarget(std::move(ptr));
 
   // Organize in the "predefined targets" folder:
   //
@@ -128,7 +132,7 @@
                stampList);
     std::string stampFile;
     cmGeneratedFileStream fout(stampListFile.c_str());
-    for (cmLocalGenerator const* gi : generators) {
+    for (const auto& gi : generators) {
       stampFile = cmStrCat(gi->GetMakefile()->GetCurrentBinaryDirectory(),
                            "/CMakeFiles/generate.stamp");
       fout << stampFile << "\n";
@@ -141,8 +145,8 @@
     // Collect the input files used to generate all targets in this
     // project.
     std::vector<std::string> listFiles;
-    for (cmLocalGenerator* gen : generators) {
-      cmAppend(listFiles, gen->GetMakefile()->GetListFiles());
+    for (const auto& gen : generators) {
+      cm::append(listFiles, gen->GetMakefile()->GetListFiles());
     }
 
     // Add a custom prebuild target to run the VerifyGlobs script.
@@ -153,7 +157,7 @@
       std::vector<std::string> byproducts;
       byproducts.push_back(cm->GetGlobVerifyStamp());
 
-      mf->AddCustomCommandToTarget(
+      lg.AddCustomCommandToTarget(
         CMAKE_CHECK_BUILD_SYSTEM_TARGET, byproducts, no_depends,
         verifyCommandLines, cmCustomCommandType::PRE_BUILD,
         "Checking File Globs", no_working_directory, false);
@@ -171,10 +175,10 @@
     listFiles.erase(new_end, listFiles.end());
 
     // Create a rule to re-run CMake.
-    std::string argS = cmStrCat("-S", lg->GetSourceDirectory());
-    std::string argB = cmStrCat("-B", lg->GetBinaryDirectory());
+    std::string argS = cmStrCat("-S", lg.GetSourceDirectory());
+    std::string argB = cmStrCat("-B", lg.GetBinaryDirectory());
     std::string const sln =
-      lg->GetBinaryDirectory() + "/" + lg->GetProjectName() + ".sln";
+      lg.GetBinaryDirectory() + "/" + lg.GetProjectName() + ".sln";
     cmCustomCommandLines commandLines = cmMakeSingleCommandLine(
       { cmSystemTools::GetCMakeCommand(), argS, argB, "--check-stamp-list",
         stampList, "--vs-solution-file", sln });
@@ -185,7 +189,7 @@
     // (this could be avoided with per-target source files)
     std::string no_main_dependency;
     cmImplicitDependsList no_implicit_depends;
-    if (cmSourceFile* file = mf->AddCustomCommandToOutput(
+    if (cmSourceFile* file = lg.AddCustomCommandToOutput(
           stamps, no_byproducts, listFiles, no_main_dependency,
           no_implicit_depends, commandLines, "Checking Build System",
           no_working_directory, true, false)) {
@@ -203,12 +207,11 @@
   cmGlobalVisualStudio7Generator::AddExtraIDETargets();
   if (this->AddCheckTarget()) {
     for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
-      const std::vector<cmGeneratorTarget*>& tgts =
-        this->LocalGenerators[i]->GetGeneratorTargets();
+      const auto& tgts = this->LocalGenerators[i]->GetGeneratorTargets();
       // All targets depend on the build-system check target.
-      for (cmGeneratorTarget const* ti : tgts) {
+      for (const auto& ti : tgts) {
         if (ti->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
-          ti->Target->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET);
+          ti->Target->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false);
         }
       }
     }
@@ -304,7 +307,7 @@
 }
 
 void cmGlobalVisualStudio8Generator::WriteProjectDepends(
-  std::ostream& fout, const std::string&, const char*,
+  std::ostream& fout, const std::string&, const std::string&,
   cmGeneratorTarget const* gt)
 {
   TargetDependSet const& unordered = this->GetTargetDirectDepends(gt);
@@ -322,9 +325,10 @@
   cmGeneratorTarget* target)
 {
   // Look for utility dependencies that magically link.
-  for (BT<std::string> const& ui : target->GetUtilities()) {
+  for (BT<std::pair<std::string, bool>> const& ui : target->GetUtilities()) {
     if (cmGeneratorTarget* depTarget =
-          target->GetLocalGenerator()->FindGeneratorTargetToUse(ui.Value)) {
+          target->GetLocalGenerator()->FindGeneratorTargetToUse(
+            ui.Value.first)) {
       if (depTarget->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
           depTarget->GetProperty("EXTERNAL_MSPROJECT")) {
         // This utility dependency names an external .vcproj target.
diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h
index 352bc3c..8f8e33b 100644
--- a/Source/cmGlobalVisualStudio8Generator.h
+++ b/Source/cmGlobalVisualStudio8Generator.h
@@ -74,7 +74,7 @@
     const std::string& platformMapping = "") override;
   bool ComputeTargetDepends() override;
   void WriteProjectDepends(std::ostream& fout, const std::string& name,
-                           const char* path,
+                           const std::string& path,
                            const cmGeneratorTarget* t) override;
 
   bool UseFolderProperty() const override;
diff --git a/Source/cmGlobalVisualStudio9Generator.cxx b/Source/cmGlobalVisualStudio9Generator.cxx
index 6e61d26..9f73c15 100644
--- a/Source/cmGlobalVisualStudio9Generator.cxx
+++ b/Source/cmGlobalVisualStudio9Generator.cxx
@@ -2,6 +2,8 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGlobalVisualStudio9Generator.h"
 
+#include <utility>
+
 #include "cmDocumentationEntry.h"
 #include "cmLocalVisualStudio7Generator.h"
 #include "cmMakefile.h"
@@ -13,43 +15,46 @@
 class cmGlobalVisualStudio9Generator::Factory : public cmGlobalGeneratorFactory
 {
 public:
-  cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
-                                           cmake* cm) const override
+  std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+    const std::string& name, cmake* cm) const override
   {
     if (strncmp(name.c_str(), vs9generatorName,
                 sizeof(vs9generatorName) - 1) != 0) {
-      return 0;
+      return std::unique_ptr<cmGlobalGenerator>();
     }
 
     const char* p = name.c_str() + sizeof(vs9generatorName) - 1;
     if (p[0] == '\0') {
-      return new cmGlobalVisualStudio9Generator(cm, name, "");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudio9Generator(cm, name, ""));
     }
 
     if (p[0] != ' ') {
-      return 0;
+      return std::unique_ptr<cmGlobalGenerator>();
     }
 
     ++p;
 
     if (!strcmp(p, "IA64")) {
-      return new cmGlobalVisualStudio9Generator(cm, name, "Itanium");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudio9Generator(cm, name, "Itanium"));
     }
 
     if (!strcmp(p, "Win64")) {
-      return new cmGlobalVisualStudio9Generator(cm, name, "x64");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudio9Generator(cm, name, "x64"));
     }
 
     cmVisualStudioWCEPlatformParser parser(p);
     parser.ParseVersion("9.0");
     if (!parser.Found()) {
-      return 0;
+      return std::unique_ptr<cmGlobalGenerator>();
     }
 
-    cmGlobalVisualStudio9Generator* ret =
-      new cmGlobalVisualStudio9Generator(cm, name, p);
+    auto ret = std::unique_ptr<cmGlobalVisualStudio9Generator>(
+      new cmGlobalVisualStudio9Generator(cm, name, p));
     ret->WindowsCEVersion = parser.GetOSVersion();
-    return ret;
+    return std::unique_ptr<cmGlobalGenerator>(std::move(ret));
   }
 
   void GetDocumentation(cmDocumentationEntry& entry) const override
@@ -103,9 +108,10 @@
   std::string GetDefaultPlatformName() const override { return "Win32"; }
 };
 
-cmGlobalGeneratorFactory* cmGlobalVisualStudio9Generator::NewFactory()
+std::unique_ptr<cmGlobalGeneratorFactory>
+cmGlobalVisualStudio9Generator::NewFactory()
 {
-  return new Factory;
+  return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
 }
 
 cmGlobalVisualStudio9Generator::cmGlobalVisualStudio9Generator(
diff --git a/Source/cmGlobalVisualStudio9Generator.h b/Source/cmGlobalVisualStudio9Generator.h
index 7bebfd6..53318a6 100644
--- a/Source/cmGlobalVisualStudio9Generator.h
+++ b/Source/cmGlobalVisualStudio9Generator.h
@@ -3,6 +3,8 @@
 #ifndef cmGlobalVisualStudio9Generator_h
 #define cmGlobalVisualStudio9Generator_h
 
+#include <memory>
+
 #include "cmGlobalVisualStudio8Generator.h"
 
 /** \class cmGlobalVisualStudio9Generator
@@ -13,7 +15,7 @@
 class cmGlobalVisualStudio9Generator : public cmGlobalVisualStudio8Generator
 {
 public:
-  static cmGlobalGeneratorFactory* NewFactory();
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory();
 
   /**
    * Where does this version of Visual Studio look for macros for the
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index ed0cba7..1ec1559 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -7,6 +7,7 @@
 #include <iostream>
 
 #include <cm/iterator>
+#include <cm/memory>
 
 #include <windows.h>
 
@@ -196,12 +197,12 @@
     if (!gen.empty()) {
       // Use no actual command lines so that the target itself is not
       // considered always out of date.
-      cmTarget* allBuild = gen[0]->GetMakefile()->AddUtilityCommand(
-        "ALL_BUILD", cmCommandOrigin::Generator, true, no_working_dir,
-        no_byproducts, no_depends, no_commands, false, "Build all projects");
+      cmTarget* allBuild = gen[0]->AddUtilityCommand(
+        "ALL_BUILD", true, no_working_dir, no_byproducts, no_depends,
+        no_commands, false, "Build all projects");
 
-      cmGeneratorTarget* gt = new cmGeneratorTarget(allBuild, gen[0]);
-      gen[0]->AddGeneratorTarget(gt);
+      gen[0]->AddGeneratorTarget(
+        cm::make_unique<cmGeneratorTarget>(allBuild, gen[0]));
 
       //
       // Organize in the "predefined targets" folder:
@@ -212,13 +213,13 @@
 
       // Now make all targets depend on the ALL_BUILD target
       for (cmLocalGenerator const* i : gen) {
-        for (cmGeneratorTarget* tgt : i->GetGeneratorTargets()) {
+        for (const auto& tgt : i->GetGeneratorTargets()) {
           if (tgt->GetType() == cmStateEnums::GLOBAL_TARGET ||
               tgt->IsImported()) {
             continue;
           }
-          if (!this->IsExcluded(gen[0], tgt)) {
-            allBuild->AddUtility(tgt->GetName());
+          if (!this->IsExcluded(gen[0], tgt.get())) {
+            allBuild->AddUtility(tgt->GetName(), false);
           }
         }
       }
@@ -307,7 +308,7 @@
   if (!dir.empty()) {
     std::string macrosFile = dir + "/CMakeMacros/" CMAKE_VSMACROS_FILENAME;
     std::string nextSubkeyName;
-    if (cmSystemTools::FileExists(macrosFile.c_str()) &&
+    if (cmSystemTools::FileExists(macrosFile) &&
         IsVisualStudioMacrosFileRegistered(
           macrosFile, this->GetUserMacrosRegKeyBase(), nextSubkeyName)) {
       if (m == MacroReload) {
@@ -389,8 +390,8 @@
   }
   for (auto const& it : this->ProjectMap) {
     for (const cmLocalGenerator* i : it.second) {
-      for (cmGeneratorTarget* ti : i->GetGeneratorTargets()) {
-        this->ComputeVSTargetDepends(ti);
+      for (const auto& ti : i->GetGeneratorTargets()) {
+        this->ComputeVSTargetDepends(ti.get());
       }
     }
   }
@@ -592,7 +593,7 @@
         std::string filepath;
         std::string filepathname;
         std::string filepathpath;
-        if (cmSystemTools::FileExists(fullname.c_str())) {
+        if (cmSystemTools::FileExists(fullname)) {
           filename = cmSystemTools::GetFilenameName(fullname);
           filepath = cmSystemTools::GetFilenamePath(fullname);
           filepathname = cmSystemTools::GetFilenameName(filepath);
@@ -799,19 +800,9 @@
 bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly(
   cmGeneratorTarget const* gt)
 {
-  // check to see if this is a fortran build
-  {
-    // Issue diagnostic if the source files depend on the config.
-    std::vector<cmSourceFile*> sources;
-    if (!gt->GetConfigCommonSourceFiles(sources)) {
-      return false;
-    }
-  }
-
   // If there's only one source language, Fortran has to be used
   // in order for the sources to compile.
-  std::set<std::string> languages;
-  gt->GetLanguages(languages, "");
+  std::set<std::string> languages = gt->GetAllConfigCompileLanguages();
   // Consider an explicit linker language property, but *not* the
   // computed linker language that may depend on linked targets.
   // This allows the project to control the language choice in
@@ -926,7 +917,7 @@
       std::string objFile = it;
       // replace $(ConfigurationName) in the object names
       cmSystemTools::ReplaceString(objFile, this->GetCMakeCFGIntDir(),
-                                   configName.c_str());
+                                   configName);
       if (cmHasLiteralSuffix(objFile, ".obj")) {
         fout << objFile << "\n";
       }
@@ -939,9 +930,10 @@
 
   cmCustomCommandLines commandLines = cmMakeSingleCommandLine(
     { cmakeCommand, "-E", "__create_def", mdi->DefFile, objs_file });
-  cmCustomCommand command(gt->Target->GetMakefile(), outputs, empty, empty,
-                          commandLines, "Auto build dll exports", ".");
-  commands.push_back(command);
+  cmCustomCommand command(outputs, empty, empty, commandLines,
+                          gt->Target->GetMakefile()->GetBacktrace(),
+                          "Auto build dll exports", ".");
+  commands.push_back(std::move(command));
 }
 
 static bool OpenSolution(std::string sln)
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/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
index a371633..13ae32a 100644
--- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
@@ -121,30 +121,33 @@
   : public cmGlobalGeneratorFactory
 {
 public:
-  cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
-                                           cmake* cm) const override
+  std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+    const std::string& name, cmake* cm) const override
   {
     std::string genName;
     const char* p = cmVS15GenName(name, genName);
     if (!p) {
-      return 0;
+      return std::unique_ptr<cmGlobalGenerator>();
     }
     if (!*p) {
-      return new cmGlobalVisualStudioVersionedGenerator(
-        cmGlobalVisualStudioGenerator::VS15, cm, genName, "");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudioVersionedGenerator(
+          cmGlobalVisualStudioGenerator::VS15, cm, genName, ""));
     }
     if (*p++ != ' ') {
-      return 0;
+      return std::unique_ptr<cmGlobalGenerator>();
     }
     if (strcmp(p, "Win64") == 0) {
-      return new cmGlobalVisualStudioVersionedGenerator(
-        cmGlobalVisualStudioGenerator::VS15, cm, genName, "x64");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudioVersionedGenerator(
+          cmGlobalVisualStudioGenerator::VS15, cm, genName, "x64"));
     }
     if (strcmp(p, "ARM") == 0) {
-      return new cmGlobalVisualStudioVersionedGenerator(
-        cmGlobalVisualStudioGenerator::VS15, cm, genName, "ARM");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudioVersionedGenerator(
+          cmGlobalVisualStudioGenerator::VS15, cm, genName, "ARM"));
     }
-    return 0;
+    return std::unique_ptr<cmGlobalGenerator>();
   }
 
   void GetDocumentation(cmDocumentationEntry& entry) const override
@@ -185,10 +188,10 @@
   std::string GetDefaultPlatformName() const override { return "Win32"; }
 };
 
-cmGlobalGeneratorFactory*
+std::unique_ptr<cmGlobalGeneratorFactory>
 cmGlobalVisualStudioVersionedGenerator::NewFactory15()
 {
-  return new Factory15;
+  return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory15);
 }
 
 static const char vs16generatorName[] = "Visual Studio 16 2019";
@@ -212,19 +215,20 @@
   : public cmGlobalGeneratorFactory
 {
 public:
-  cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
-                                           cmake* cm) const override
+  std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+    const std::string& name, cmake* cm) const override
   {
     std::string genName;
     const char* p = cmVS16GenName(name, genName);
     if (!p) {
-      return 0;
+      return std::unique_ptr<cmGlobalGenerator>();
     }
     if (!*p) {
-      return new cmGlobalVisualStudioVersionedGenerator(
-        cmGlobalVisualStudioGenerator::VS16, cm, genName, "");
+      return std::unique_ptr<cmGlobalGenerator>(
+        new cmGlobalVisualStudioVersionedGenerator(
+          cmGlobalVisualStudioGenerator::VS16, cm, genName, ""));
     }
-    return 0;
+    return std::unique_ptr<cmGlobalGenerator>();
   }
 
   void GetDocumentation(cmDocumentationEntry& entry) const override
@@ -265,10 +269,10 @@
   }
 };
 
-cmGlobalGeneratorFactory*
+std::unique_ptr<cmGlobalGeneratorFactory>
 cmGlobalVisualStudioVersionedGenerator::NewFactory16()
 {
-  return new Factory16;
+  return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory16);
 }
 
 cmGlobalVisualStudioVersionedGenerator::cmGlobalVisualStudioVersionedGenerator(
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.h b/Source/cmGlobalVisualStudioVersionedGenerator.h
index 466816b..abb6095 100644
--- a/Source/cmGlobalVisualStudioVersionedGenerator.h
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.h
@@ -6,6 +6,7 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <iosfwd>
+#include <memory>
 #include <string>
 
 #include "cmGlobalVisualStudio14Generator.h"
@@ -19,8 +20,8 @@
   : public cmGlobalVisualStudio14Generator
 {
 public:
-  static cmGlobalGeneratorFactory* NewFactory15();
-  static cmGlobalGeneratorFactory* NewFactory16();
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory15();
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory16();
 
   bool MatchesGeneratorName(const std::string& name) const override;
 
diff --git a/Source/cmGlobalWatcomWMakeGenerator.h b/Source/cmGlobalWatcomWMakeGenerator.h
index 64ace13..c0daf8a 100644
--- a/Source/cmGlobalWatcomWMakeGenerator.h
+++ b/Source/cmGlobalWatcomWMakeGenerator.h
@@ -6,6 +6,7 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <iosfwd>
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -25,9 +26,10 @@
 {
 public:
   cmGlobalWatcomWMakeGenerator(cmake* cm);
-  static cmGlobalGeneratorFactory* NewFactory()
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
   {
-    return new cmGlobalGeneratorSimpleFactory<cmGlobalWatcomWMakeGenerator>();
+    return std::unique_ptr<cmGlobalGeneratorFactory>(
+      new cmGlobalGeneratorSimpleFactory<cmGlobalWatcomWMakeGenerator>());
   }
   //! Get the name for the generator.
   std::string GetName() const override
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index aee475b..e0005a4 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGlobalXCodeGenerator.h"
 
+#include <algorithm>
 #include <cassert>
 #include <cstdio>
 #include <cstring>
@@ -9,6 +10,7 @@
 #include <sstream>
 
 #include <cm/memory>
+#include <cmext/algorithm>
 
 #include "cmsys/RegularExpression.hxx"
 
@@ -129,8 +131,8 @@
 class cmGlobalXCodeGenerator::Factory : public cmGlobalGeneratorFactory
 {
 public:
-  cmGlobalGenerator* CreateGlobalGenerator(const std::string& name,
-                                           cmake* cm) const override;
+  std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+    const std::string& name, cmake* cm) const override;
 
   void GetDocumentation(cmDocumentationEntry& entry) const override
   {
@@ -179,16 +181,17 @@
   cm->GetState()->SetIsGeneratorMultiConfig(true);
 }
 
-cmGlobalGeneratorFactory* cmGlobalXCodeGenerator::NewFactory()
+std::unique_ptr<cmGlobalGeneratorFactory> cmGlobalXCodeGenerator::NewFactory()
 {
-  return new Factory;
+  return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
 }
 
-cmGlobalGenerator* cmGlobalXCodeGenerator::Factory::CreateGlobalGenerator(
-  const std::string& name, cmake* cm) const
+std::unique_ptr<cmGlobalGenerator>
+cmGlobalXCodeGenerator::Factory::CreateGlobalGenerator(const std::string& name,
+                                                       cmake* cm) const
 {
   if (name != GetActualName()) {
-    return nullptr;
+    return std::unique_ptr<cmGlobalGenerator>();
   }
 #if !defined(CMAKE_BOOTSTRAP)
   cmXcodeVersionParser parser;
@@ -224,16 +227,17 @@
   if (version_number < 50) {
     cm->IssueMessage(MessageType::FATAL_ERROR,
                      "Xcode " + version_string + " not supported.");
-    return nullptr;
+    return std::unique_ptr<cmGlobalGenerator>();
   }
 
-  auto gg = cm::make_unique<cmGlobalXCodeGenerator>(cm, version_string,
-                                                    version_number);
-  return gg.release();
+  return std::unique_ptr<cmGlobalGenerator>(
+    cm::make_unique<cmGlobalXCodeGenerator>(cm, version_string,
+                                            version_number));
 #else
   std::cerr << "CMake should be built with cmake to use Xcode, "
                "default to Xcode 1.5\n";
-  return new cmGlobalXCodeGenerator(cm);
+  return std::unique_ptr<cmGlobalGenerator>(
+    cm::make_unique<cmGlobalXCodeGenerator>(cm));
 #endif
 }
 
@@ -267,7 +271,7 @@
 }
 
 bool cmGlobalXCodeGenerator::SetGeneratorToolset(std::string const& ts,
-                                                 cmMakefile* mf)
+                                                 bool build, cmMakefile* mf)
 {
   if (ts.find_first_of(",=") != std::string::npos) {
     std::ostringstream e;
@@ -283,6 +287,9 @@
     return false;
   }
   this->GeneratorToolset = ts;
+  if (build) {
+    return true;
+  }
   if (!this->GeneratorToolset.empty()) {
     mf->AddDefinition("CMAKE_XCODE_PLATFORM_TOOLSET", this->GeneratorToolset);
   }
@@ -388,9 +395,11 @@
 }
 
 //! Create a local generator appropriate to this Global Generator
-cmLocalGenerator* cmGlobalXCodeGenerator::CreateLocalGenerator(cmMakefile* mf)
+std::unique_ptr<cmLocalGenerator> cmGlobalXCodeGenerator::CreateLocalGenerator(
+  cmMakefile* mf)
 {
-  return new cmLocalXCodeGenerator(this, mf);
+  return std::unique_ptr<cmLocalGenerator>(
+    cm::make_unique<cmLocalXCodeGenerator>(this, mf));
 }
 
 void cmGlobalXCodeGenerator::AddExtraIDETargets()
@@ -409,10 +418,10 @@
 {
   size_t index = 0;
   auto const& lgens = this->GetLocalGenerators();
-  for (cmLocalGenerator* lgen : lgens) {
-    auto const& targets = lgen->GetGeneratorTargets();
-    for (cmGeneratorTarget const* gt : targets) {
-      this->ComputeTargetOrder(gt, index);
+  for (auto const& lgen : lgens) {
+    const auto& targets = lgen->GetGeneratorTargets();
+    for (const auto& gt : targets) {
+      this->ComputeTargetOrder(gt.get(), index);
     }
   }
   assert(index == this->TargetOrderIndex.size());
@@ -496,20 +505,16 @@
 void cmGlobalXCodeGenerator::AddExtraTargets(
   cmLocalGenerator* root, std::vector<cmLocalGenerator*>& gens)
 {
-  cmMakefile* mf = root->GetMakefile();
-
   const char* no_working_directory = nullptr;
   std::vector<std::string> no_byproducts;
   std::vector<std::string> no_depends;
 
   // Add ALL_BUILD
-  cmTarget* allbuild = mf->AddUtilityCommand(
-    "ALL_BUILD", cmCommandOrigin::Generator, true, no_working_directory,
-    no_byproducts, no_depends,
+  cmTarget* allbuild = root->AddUtilityCommand(
+    "ALL_BUILD", true, no_working_directory, no_byproducts, no_depends,
     cmMakeSingleCommandLine({ "echo", "Build all projects" }));
 
-  cmGeneratorTarget* allBuildGt = new cmGeneratorTarget(allbuild, root);
-  root->AddGeneratorTarget(allBuildGt);
+  root->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(allbuild, root));
 
   // Add XCODE depend helper
   std::string dir = root->GetCurrentBinaryDirectory();
@@ -520,52 +525,53 @@
   // Add ZERO_CHECK
   bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION");
   bool generateTopLevelProjectOnly =
-    mf->IsOn("CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY");
+    root->GetMakefile()->IsOn("CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY");
   bool isTopLevel =
     !root->GetStateSnapshot().GetBuildsystemDirectoryParent().IsValid();
-  if (regenerate && (isTopLevel || !generateTopLevelProjectOnly)) {
+  bool isGenerateProject = isTopLevel || !generateTopLevelProjectOnly;
+  if (regenerate && isGenerateProject) {
     this->CreateReRunCMakeFile(root, gens);
     std::string file =
       this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile);
     cmSystemTools::ReplaceString(file, "\\ ", " ");
-    cmTarget* check = mf->AddUtilityCommand(
-      CMAKE_CHECK_BUILD_SYSTEM_TARGET, cmCommandOrigin::Generator, true,
-      no_working_directory, no_byproducts, no_depends,
-      cmMakeSingleCommandLine({ "make", "-f", file }));
+    cmTarget* check =
+      root->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, true,
+                              no_working_directory, no_byproducts, no_depends,
+                              cmMakeSingleCommandLine({ "make", "-f", file }));
 
-    cmGeneratorTarget* checkGt = new cmGeneratorTarget(check, root);
-    root->AddGeneratorTarget(checkGt);
+    root->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(check, root));
   }
 
   // now make the allbuild depend on all the non-utility targets
   // in the project
   for (auto& gen : gens) {
-    for (auto target : gen->GetGeneratorTargets()) {
+    for (const auto& target : gen->GetGeneratorTargets()) {
       if (target->GetType() == cmStateEnums::GLOBAL_TARGET) {
         continue;
       }
 
       if (regenerate &&
           (target->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET)) {
-        target->Target->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET);
+        target->Target->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false);
       }
 
       // make all exe, shared libs and modules
       // run the depend check makefile as a post build rule
       // this will make sure that when the next target is built
       // things are up-to-date
-      if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+      if (isGenerateProject &&
+          target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
         commandLines.front().back() = // fill placeholder
           this->PostBuildMakeTarget(target->GetName(), "$(CONFIGURATION)");
-        gen->GetMakefile()->AddCustomCommandToTarget(
+        gen->AddCustomCommandToTarget(
           target->GetName(), no_byproducts, no_depends, commandLines,
           cmCustomCommandType::POST_BUILD, "Depend check for xcode",
           dir.c_str(), true, false, "", "", false,
           cmObjectLibraryCommands::Accept);
       }
 
-      if (!this->IsExcluded(gens[0], target)) {
-        allbuild->AddUtility(target->GetName());
+      if (!this->IsExcluded(gens[0], target.get())) {
+        allbuild->AddUtility(target->GetName(), false);
       }
     }
   }
@@ -576,7 +582,7 @@
 {
   std::vector<std::string> lfiles;
   for (auto gen : gens) {
-    cmAppend(lfiles, gen->GetMakefile()->GetListFiles());
+    cm::append(lfiles, gen->GetMakefile()->GetListFiles());
   }
 
   // sort the array
@@ -1093,8 +1099,8 @@
   cmLocalGenerator* gen, std::vector<cmXCodeObject*>& targets)
 {
   this->SetCurrentLocalGenerator(gen);
-  std::vector<cmGeneratorTarget*> gts =
-    this->CurrentLocalGenerator->GetGeneratorTargets();
+  std::vector<cmGeneratorTarget*> gts;
+  cm::append(gts, this->CurrentLocalGenerator->GetGeneratorTargets());
   std::sort(gts.begin(), gts.end(),
             [this](cmGeneratorTarget const* l, cmGeneratorTarget const* r) {
               return this->TargetOrderIndex[l] < this->TargetOrderIndex[r];
@@ -1364,11 +1370,11 @@
 
 void cmGlobalXCodeGenerator::ForceLinkerLanguages()
 {
-  for (auto localGenerator : this->LocalGenerators) {
+  for (const auto& localGenerator : this->LocalGenerators) {
     // All targets depend on the build-system check target.
-    for (auto tgt : localGenerator->GetGeneratorTargets()) {
+    for (const auto& tgt : localGenerator->GetGeneratorTargets()) {
       // This makes sure all targets link using the proper language.
-      this->ForceLinkerLanguage(tgt);
+      this->ForceLinkerLanguage(tgt.get());
     }
   }
 }
@@ -1460,12 +1466,12 @@
       { cmSystemTools::GetCMakeCommand(), "-E", "cmake_symlink_library",
         str_file, str_so_file, str_link_file });
 
-    cmCustomCommand command(this->CurrentMakefile, std::vector<std::string>(),
-                            std::vector<std::string>(),
-                            std::vector<std::string>(), cmd,
-                            "Creating symlinks", "");
+    cmCustomCommand command(
+      std::vector<std::string>(), std::vector<std::string>(),
+      std::vector<std::string>(), cmd, this->CurrentMakefile->GetBacktrace(),
+      "Creating symlinks", "");
 
-    postbuild.push_back(command);
+    postbuild.push_back(std::move(command));
   }
 
   std::vector<cmSourceFile*> classes;
@@ -2353,9 +2359,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);
 
@@ -2365,8 +2368,9 @@
     int minor;
     int patch;
 
-    // VERSION -> current_version
-    gtgt->GetTargetVersion(false, major, minor, patch);
+    // MACHO_CURRENT_VERSION or VERSION -> current_version
+    gtgt->GetTargetVersionFallback("MACHO_CURRENT_VERSION", "VERSION", major,
+                                   minor, patch);
     std::ostringstream v;
 
     // Xcode always wants at least 1.0.0 or nothing
@@ -2376,8 +2380,9 @@
     buildSettings->AddAttribute("DYLIB_CURRENT_VERSION",
                                 this->CreateString(v.str()));
 
-    // SOVERSION -> compatibility_version
-    gtgt->GetTargetVersion(true, major, minor, patch);
+    // MACHO_COMPATIBILITY_VERSION or SOVERSION -> compatibility_version
+    gtgt->GetTargetVersionFallback("MACHO_COMPATIBILITY_VERSION", "SOVERSION",
+                                   major, minor, patch);
     std::ostringstream vso;
 
     // Xcode always wants at least 1.0.0 or nothing
@@ -2834,7 +2839,7 @@
   for (auto& generator : generators) {
     cmMakefile* mf = generator->GetMakefile();
     std::vector<cmSourceGroup> sourceGroups = mf->GetSourceGroups();
-    for (auto gtgt : generator->GetGeneratorTargets()) {
+    for (const auto& gtgt : generator->GetGeneratorTargets()) {
       // Same skipping logic here as in CreateXCodeTargets so that we do not
       // end up with (empty anyhow) ZERO_CHECK, install, or test source
       // groups:
@@ -2849,11 +2854,12 @@
         continue;
       }
 
-      auto addSourceToGroup = [this, mf, gtgt,
+      auto addSourceToGroup = [this, mf, &gtgt,
                                &sourceGroups](std::string const& source) {
         cmSourceGroup* sourceGroup = mf->FindSourceGroup(source, sourceGroups);
-        cmXCodeObject* pbxgroup = this->CreateOrGetPBXGroup(gtgt, sourceGroup);
-        std::string key = GetGroupMapKeyFromPath(gtgt, source);
+        cmXCodeObject* pbxgroup =
+          this->CreateOrGetPBXGroup(gtgt.get(), sourceGroup);
+        std::string key = GetGroupMapKeyFromPath(gtgt.get(), source);
         this->GroupMap[key] = pbxgroup;
       };
 
@@ -2879,7 +2885,7 @@
 
       // Add the Info.plist we are about to generate for an App Bundle.
       if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) {
-        std::string plist = this->ComputeInfoPListLocation(gtgt);
+        std::string plist = this->ComputeInfoPListLocation(gtgt.get());
         cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource(
           plist, true, cmSourceFileLocationKind::Known);
         addSourceToGroup(sf->ResolveFullPath());
@@ -3415,7 +3421,7 @@
           (root->GetMakefile()->GetCMakeInstance()->GetIsInTryCompile() ||
            obj->GetTarget()->GetPropertyAsBool("XCODE_GENERATE_SCHEME"))) {
         const std::string& targetName = obj->GetTarget()->GetName();
-        cmXCodeScheme schm(obj, testables[targetName],
+        cmXCodeScheme schm(root, obj, testables[targetName],
                            this->CurrentConfigurationTypes,
                            this->XcodeVersion);
         schm.WriteXCodeSharedScheme(xcProjDir,
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index af905d0..df68f80 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -7,6 +7,7 @@
 
 #include <iosfwd>
 #include <map>
+#include <memory>
 #include <set>
 #include <string>
 #include <vector>
@@ -34,7 +35,7 @@
 public:
   cmGlobalXCodeGenerator(cmake* cm, std::string const& version_string,
                          unsigned int version_number);
-  static cmGlobalGeneratorFactory* NewFactory();
+  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory();
 
   //! Get the name for the generator.
   std::string GetName() const override
@@ -47,7 +48,8 @@
   static void GetDocumentation(cmDocumentationEntry& entry);
 
   //! Create a local generator appropriate to this Global Generator
-  cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
+  std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+    cmMakefile* mf) override;
 
   /**
    * Try to determine system information such as shared library
@@ -103,7 +105,8 @@
 
   bool ShouldStripResourcePath(cmMakefile*) const override;
 
-  bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf) override;
+  bool SetGeneratorToolset(std::string const& ts, bool build,
+                           cmMakefile* mf) override;
   void AppendFlag(std::string& flags, std::string const& flag) const;
 
 protected:
diff --git a/Source/cmGraphAdjacencyList.h b/Source/cmGraphAdjacencyList.h
index 5ed6af4..4e1f128 100644
--- a/Source/cmGraphAdjacencyList.h
+++ b/Source/cmGraphAdjacencyList.h
@@ -18,9 +18,10 @@
 class cmGraphEdge
 {
 public:
-  cmGraphEdge(int n, bool s, cmListFileBacktrace bt)
+  cmGraphEdge(int n, bool s, bool c, cmListFileBacktrace bt)
     : Dest(n)
     , Strong(s)
+    , Cross(c)
     , Backtrace(std::move(bt))
   {
   }
@@ -28,11 +29,14 @@
 
   bool IsStrong() const { return this->Strong; }
 
+  bool IsCross() const { return this->Cross; }
+
   cmListFileBacktrace const& GetBacktrace() const { return this->Backtrace; }
 
 private:
   int Dest;
   bool Strong;
+  bool Cross;
   cmListFileBacktrace Backtrace;
 };
 struct cmGraphEdgeList : public std::vector<cmGraphEdge>
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
index e0d545d..1b77678 100644
--- a/Source/cmGraphVizWriter.cxx
+++ b/Source/cmGraphVizWriter.cxx
@@ -2,176 +2,192 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGraphVizWriter.h"
 
-#include <cstddef>
+#include <cctype>
 #include <iostream>
 #include <memory>
-#include <sstream>
+#include <set>
 #include <utility>
 
+#include <cm/memory>
+
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmLinkItem.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmState.h"
 #include "cmStateSnapshot.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
-#include "cmTarget.h"
 #include "cmake.h"
 
 namespace {
-enum LinkLibraryScopeType
-{
-  LLT_SCOPE_PUBLIC,
-  LLT_SCOPE_PRIVATE,
-  LLT_SCOPE_INTERFACE
-};
 
-const char* const GRAPHVIZ_PRIVATE_EDEGE_STYLE = "dashed";
-const char* const GRAPHVIZ_INTERFACE_EDEGE_STYLE = "dotted";
+char const* const GRAPHVIZ_EDGE_STYLE_PUBLIC = "solid";
+char const* const GRAPHVIZ_EDGE_STYLE_INTERFACE = "dashed";
+char const* const GRAPHVIZ_EDGE_STYLE_PRIVATE = "dotted";
 
-std::string getLinkLibraryStyle(const LinkLibraryScopeType& type)
-{
-  std::string style;
-  switch (type) {
-    case LLT_SCOPE_PRIVATE:
-      style = "[style = " + std::string(GRAPHVIZ_PRIVATE_EDEGE_STYLE) + "]";
-      break;
-    case LLT_SCOPE_INTERFACE:
-      style = "[style = " + std::string(GRAPHVIZ_INTERFACE_EDEGE_STYLE) + "]";
-      break;
-    default:
-      break;
-  }
-  return style;
-}
+char const* const GRAPHVIZ_NODE_SHAPE_EXECUTABLE = "egg"; // egg-xecutable
 
-const char* getShapeForTarget(const cmGeneratorTarget* target)
+// Normal libraries.
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC = "octagon";
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED = "doubleoctagon";
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE = "tripleoctagon";
+
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE = "pentagon";
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT = "hexagon";
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN = "septagon";
+
+char const* const GRAPHVIZ_NODE_SHAPE_UTILITY = "box";
+
+const char* getShapeForTarget(const cmLinkItem& item)
 {
-  if (!target) {
-    return "ellipse";
+  if (item.Target == nullptr) {
+    return GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN;
   }
 
-  switch (target->GetType()) {
+  switch (item.Target->GetType()) {
     case cmStateEnums::EXECUTABLE:
-      return "house";
+      return GRAPHVIZ_NODE_SHAPE_EXECUTABLE;
     case cmStateEnums::STATIC_LIBRARY:
-      return "diamond";
+      return GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC;
     case cmStateEnums::SHARED_LIBRARY:
-      return "polygon";
+      return GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED;
     case cmStateEnums::MODULE_LIBRARY:
-      return "octagon";
+      return GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE;
+    case cmStateEnums::OBJECT_LIBRARY:
+      return GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT;
+    case cmStateEnums::UTILITY:
+      return GRAPHVIZ_NODE_SHAPE_UTILITY;
+    case cmStateEnums::INTERFACE_LIBRARY:
+      return GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE;
+    case cmStateEnums::UNKNOWN_LIBRARY:
     default:
-      break;
+      return GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN;
   }
-
-  return "box";
-}
-
-std::map<std::string, LinkLibraryScopeType> getScopedLinkLibrariesFromTarget(
-  cmTarget* Target, const cmGlobalGenerator* globalGenerator)
-{
-  char sep = ';';
-  std::map<std::string, LinkLibraryScopeType> tokens;
-  size_t start = 0;
-  size_t end = 0;
-
-  const char* pInterfaceLinkLibraries =
-    Target->GetProperty("INTERFACE_LINK_LIBRARIES");
-  const char* pLinkLibraries = Target->GetProperty("LINK_LIBRARIES");
-
-  if (!pInterfaceLinkLibraries && !pLinkLibraries) {
-    return tokens; // target is not linked against any other libraries
-  }
-
-  // make sure we don't touch a null-ptr
-  auto interfaceLinkLibraries =
-    std::string(pInterfaceLinkLibraries ? pInterfaceLinkLibraries : "");
-  auto linkLibraries = std::string(pLinkLibraries ? pLinkLibraries : "");
-
-  // first extract interfaceLinkLibraries
-  while (start < interfaceLinkLibraries.length()) {
-
-    if ((end = interfaceLinkLibraries.find(sep, start)) == std::string::npos) {
-      end = interfaceLinkLibraries.length();
-    }
-
-    std::string element = interfaceLinkLibraries.substr(start, end - start);
-    if (globalGenerator->IsAlias(element)) {
-      const auto tgt = globalGenerator->FindTarget(element);
-      if (tgt) {
-        element = tgt->GetName();
-      }
-    }
-
-    if (std::string::npos == element.find("$<LINK_ONLY:", 0)) {
-      // we assume first, that this library is an interface library.
-      // if we find it again in the linklibraries property, we promote it to an
-      // public library.
-      tokens[element] = LLT_SCOPE_INTERFACE;
-    } else {
-      // this is an private linked static library.
-      // we take care of this case in the second iterator.
-    }
-    start = end + 1;
-  }
-
-  // second extract linkLibraries
-  start = 0;
-  while (start < linkLibraries.length()) {
-
-    if ((end = linkLibraries.find(sep, start)) == std::string::npos) {
-      end = linkLibraries.length();
-    }
-
-    std::string element = linkLibraries.substr(start, end - start);
-    if (globalGenerator->IsAlias(element)) {
-      const auto tgt = globalGenerator->FindTarget(element);
-      if (tgt) {
-        element = tgt->GetName();
-      }
-    }
-
-    if (tokens.find(element) == tokens.end()) {
-      // this library is not found in interfaceLinkLibraries but in
-      // linkLibraries.
-      // this results in a private linked library.
-      tokens[element] = LLT_SCOPE_PRIVATE;
-    } else if (LLT_SCOPE_INTERFACE == tokens[element]) {
-      // this library is found in interfaceLinkLibraries and linkLibraries.
-      // this results in a public linked library.
-      tokens[element] = LLT_SCOPE_PUBLIC;
-    } else {
-      // private and public linked libraries should not be changed anymore.
-    }
-
-    start = end + 1;
-  }
-
-  return tokens;
 }
 }
 
-cmGraphVizWriter::cmGraphVizWriter(const cmGlobalGenerator* globalGenerator)
-  : GraphType("digraph")
-  , GraphName("GG")
+cmGraphVizWriter::cmGraphVizWriter(std::string const& fileName,
+                                   const cmGlobalGenerator* globalGenerator)
+  : FileName(fileName)
+  , GlobalFileStream(fileName)
+  , GraphName(globalGenerator->GetSafeGlobalSetting("CMAKE_PROJECT_NAME"))
   , GraphHeader("node [\n  fontsize = \"12\"\n];")
   , GraphNodePrefix("node")
   , GlobalGenerator(globalGenerator)
-  , LocalGenerators(globalGenerator->GetLocalGenerators())
+  , NextNodeId(0)
   , GenerateForExecutables(true)
   , GenerateForStaticLibs(true)
   , GenerateForSharedLibs(true)
   , GenerateForModuleLibs(true)
-  , GenerateForInterface(true)
+  , GenerateForInterfaceLibs(true)
+  , GenerateForObjectLibs(true)
+  , GenerateForUnknownLibs(true)
+  , GenerateForCustomTargets(false)
   , GenerateForExternals(true)
   , GeneratePerTarget(true)
   , GenerateDependers(true)
-  , HaveTargetsAndLibs(false)
 {
 }
 
+cmGraphVizWriter::~cmGraphVizWriter()
+{
+  this->WriteFooter(this->GlobalFileStream);
+
+  for (auto& fileStream : this->PerTargetFileStreams) {
+    this->WriteFooter(*fileStream.second);
+  }
+
+  for (auto& fileStream : this->TargetDependersFileStreams) {
+    this->WriteFooter(*fileStream.second);
+  }
+}
+
+void cmGraphVizWriter::VisitGraph(std::string const&)
+{
+  this->WriteHeader(GlobalFileStream, this->GraphName);
+  this->WriteLegend(GlobalFileStream);
+}
+
+void cmGraphVizWriter::OnItem(cmLinkItem const& item)
+{
+  if (this->ItemExcluded(item)) {
+    return;
+  }
+
+  NodeNames[item.AsStr()] = cmStrCat(GraphNodePrefix, NextNodeId);
+  ++NextNodeId;
+
+  this->WriteNode(this->GlobalFileStream, item);
+
+  if (this->GeneratePerTarget) {
+    this->CreateTargetFile(this->PerTargetFileStreams, item);
+  }
+
+  if (this->GenerateDependers) {
+    this->CreateTargetFile(this->TargetDependersFileStreams, item,
+                           ".dependers");
+  }
+}
+
+void cmGraphVizWriter::CreateTargetFile(FileStreamMap& fileStreamMap,
+                                        cmLinkItem const& item,
+                                        std::string const& fileNameSuffix)
+{
+  auto const pathSafeItemName = PathSafeString(item.AsStr());
+  auto const perTargetFileName =
+    cmStrCat(this->FileName, '.', pathSafeItemName, fileNameSuffix);
+  auto perTargetFileStream =
+    cm::make_unique<cmGeneratedFileStream>(perTargetFileName);
+
+  this->WriteHeader(*perTargetFileStream, item.AsStr());
+  this->WriteNode(*perTargetFileStream, item);
+
+  fileStreamMap.emplace(item.AsStr(), std::move(perTargetFileStream));
+}
+
+void cmGraphVizWriter::OnDirectLink(cmLinkItem const& depender,
+                                    cmLinkItem const& dependee,
+                                    DependencyType dt)
+{
+  this->VisitLink(depender, dependee, true, GetEdgeStyle(dt));
+}
+
+void cmGraphVizWriter::OnIndirectLink(cmLinkItem const& depender,
+                                      cmLinkItem const& dependee)
+{
+  this->VisitLink(depender, dependee, false);
+}
+
+void cmGraphVizWriter::VisitLink(cmLinkItem const& depender,
+                                 cmLinkItem const& dependee, bool isDirectLink,
+                                 std::string const& scopeType)
+{
+  if (this->ItemExcluded(depender) || this->ItemExcluded(dependee)) {
+    return;
+  }
+
+  if (!isDirectLink) {
+    return;
+  }
+
+  this->WriteConnection(this->GlobalFileStream, depender, dependee, scopeType);
+
+  if (this->GeneratePerTarget) {
+    auto fileStream = PerTargetFileStreams[depender.AsStr()].get();
+    this->WriteNode(*fileStream, dependee);
+    this->WriteConnection(*fileStream, depender, dependee, scopeType);
+  }
+
+  if (this->GenerateDependers) {
+    auto fileStream = TargetDependersFileStreams[dependee.AsStr()].get();
+    this->WriteNode(*fileStream, depender);
+    this->WriteConnection(*fileStream, depender, dependee, scopeType);
+  }
+}
+
 void cmGraphVizWriter::ReadSettings(
   const std::string& settingsFileName,
   const std::string& fallbackSettingsFileName)
@@ -208,7 +224,6 @@
     }                                                                         \
   } while (false)
 
-  __set_if_set(this->GraphType, "GRAPHVIZ_GRAPH_TYPE");
   __set_if_set(this->GraphName, "GRAPHVIZ_GRAPH_NAME");
   __set_if_set(this->GraphHeader, "GRAPHVIZ_GRAPH_HEADER");
   __set_if_set(this->GraphNodePrefix, "GRAPHVIZ_NODE_PREFIX");
@@ -225,7 +240,10 @@
   __set_bool_if_set(this->GenerateForStaticLibs, "GRAPHVIZ_STATIC_LIBS");
   __set_bool_if_set(this->GenerateForSharedLibs, "GRAPHVIZ_SHARED_LIBS");
   __set_bool_if_set(this->GenerateForModuleLibs, "GRAPHVIZ_MODULE_LIBS");
-  __set_bool_if_set(this->GenerateForInterface, "GRAPHVIZ_INTERFACE");
+  __set_bool_if_set(this->GenerateForInterfaceLibs, "GRAPHVIZ_INTERFACE_LIBS");
+  __set_bool_if_set(this->GenerateForObjectLibs, "GRAPHVIZ_OBJECT_LIBS");
+  __set_bool_if_set(this->GenerateForUnknownLibs, "GRAPHVIZ_UNKNOWN_LIBS");
+  __set_bool_if_set(this->GenerateForCustomTargets, "GRAPHVIZ_CUSTOM_TARGETS");
   __set_bool_if_set(this->GenerateForExternals, "GRAPHVIZ_EXTERNAL_LIBS");
   __set_bool_if_set(this->GeneratePerTarget, "GRAPHVIZ_GENERATE_PER_TARGET");
   __set_bool_if_set(this->GenerateDependers, "GRAPHVIZ_GENERATE_DEPENDERS");
@@ -248,329 +266,170 @@
   }
 }
 
-// Iterate over all targets and write for each one a graph which shows
-// which other targets depend on it.
-void cmGraphVizWriter::WriteTargetDependersFiles(const std::string& fileName)
+void cmGraphVizWriter::Write()
 {
-  if (!this->GenerateDependers) {
-    return;
-  }
+  auto gg = this->GlobalGenerator;
 
-  this->CollectTargetsAndLibs();
+  this->VisitGraph(gg->GetName());
 
-  for (auto const& ptr : this->TargetPtrs) {
-    if (ptr.second == nullptr) {
-      continue;
-    }
+  // We want to traverse in a determined order, such that the output is always
+  // the same for a given project (this makes tests reproducible, etc.)
+  std::set<cmGeneratorTarget const*, cmGeneratorTarget::StrictTargetComparison>
+    sortedGeneratorTargets;
 
-    if (!this->GenerateForTargetType(ptr.second->GetType())) {
-      continue;
-    }
-
-    std::string currentFilename =
-      cmStrCat(fileName, '.', ptr.first, ".dependers");
-
-    cmGeneratedFileStream str(currentFilename);
-    if (!str) {
-      return;
-    }
-
-    std::set<std::string> insertedConnections;
-    std::set<std::string> insertedNodes;
-
-    std::cout << "Writing " << currentFilename << "..." << std::endl;
-    this->WriteHeader(str);
-
-    this->WriteDependerConnections(ptr.first, insertedNodes,
-                                   insertedConnections, str);
-
-    this->WriteFooter(str);
-  }
-}
-
-// Iterate over all targets and write for each one a graph which shows
-// on which targets it depends.
-void cmGraphVizWriter::WritePerTargetFiles(const std::string& fileName)
-{
-  if (!this->GeneratePerTarget) {
-    return;
-  }
-
-  this->CollectTargetsAndLibs();
-
-  for (auto const& ptr : this->TargetPtrs) {
-    if (ptr.second == nullptr) {
-      continue;
-    }
-
-    if (!this->GenerateForTargetType(ptr.second->GetType())) {
-      continue;
-    }
-
-    std::set<std::string> insertedConnections;
-    std::set<std::string> insertedNodes;
-
-    std::string currentFilename = cmStrCat(fileName, '.', ptr.first);
-    cmGeneratedFileStream str(currentFilename);
-    if (!str) {
-      return;
-    }
-
-    std::cout << "Writing " << currentFilename << "..." << std::endl;
-    this->WriteHeader(str);
-
-    this->WriteConnections(ptr.first, insertedNodes, insertedConnections, str);
-    this->WriteFooter(str);
-  }
-}
-
-void cmGraphVizWriter::WriteGlobalFile(const std::string& fileName)
-{
-  this->CollectTargetsAndLibs();
-
-  cmGeneratedFileStream str(fileName);
-  if (!str) {
-    return;
-  }
-  this->WriteHeader(str);
-
-  std::cout << "Writing " << fileName << "..." << std::endl;
-
-  std::set<std::string> insertedConnections;
-  std::set<std::string> insertedNodes;
-
-  for (auto const& ptr : this->TargetPtrs) {
-    if (ptr.second == nullptr) {
-      continue;
-    }
-
-    if (!this->GenerateForTargetType(ptr.second->GetType())) {
-      continue;
-    }
-
-    this->WriteConnections(ptr.first, insertedNodes, insertedConnections, str);
-  }
-  this->WriteFooter(str);
-}
-
-void cmGraphVizWriter::WriteHeader(cmGeneratedFileStream& str) const
-{
-  str << this->GraphType << " \"" << this->GraphName << "\" {" << std::endl;
-  str << this->GraphHeader << std::endl;
-}
-
-void cmGraphVizWriter::WriteFooter(cmGeneratedFileStream& str) const
-{
-  str << "}" << std::endl;
-}
-
-void cmGraphVizWriter::WriteConnections(
-  const std::string& targetName, std::set<std::string>& insertedNodes,
-  std::set<std::string>& insertedConnections, cmGeneratedFileStream& str) const
-{
-  auto targetPtrIt = this->TargetPtrs.find(targetName);
-
-  if (targetPtrIt == this->TargetPtrs.end()) // not found at all
-  {
-    return;
-  }
-
-  this->WriteNode(targetName, targetPtrIt->second, insertedNodes, str);
-
-  if (targetPtrIt->second == nullptr) // it's an external library
-  {
-    return;
-  }
-
-  std::string myNodeName = this->TargetNamesNodes.find(targetName)->second;
-  std::map<std::string, LinkLibraryScopeType> ll =
-    getScopedLinkLibrariesFromTarget(targetPtrIt->second->Target,
-                                     GlobalGenerator);
-
-  for (auto const& llit : ll) {
-    const std::string& libName = llit.first;
-    auto libNameIt = this->TargetNamesNodes.find(libName);
-
-    // can happen e.g. if GRAPHVIZ_TARGET_IGNORE_REGEX is used
-    if (libNameIt == this->TargetNamesNodes.end()) {
-      continue;
-    }
-
-    std::string connectionName = cmStrCat(myNodeName, '-', libNameIt->second);
-    if (insertedConnections.find(connectionName) ==
-        insertedConnections.end()) {
-      insertedConnections.insert(connectionName);
-      this->WriteNode(libName, this->TargetPtrs.find(libName)->second,
-                      insertedNodes, str);
-
-      str << "    \"" << myNodeName << "\" -> \"" << libNameIt->second << "\"";
-
-      str << getLinkLibraryStyle(llit.second);
-
-      str << " // " << targetName << " -> " << libName << std::endl;
-      this->WriteConnections(libName, insertedNodes, insertedConnections, str);
-    }
-  }
-}
-
-void cmGraphVizWriter::WriteDependerConnections(
-  const std::string& targetName, std::set<std::string>& insertedNodes,
-  std::set<std::string>& insertedConnections, cmGeneratedFileStream& str) const
-{
-  auto targetPtrIt = this->TargetPtrs.find(targetName);
-
-  if (targetPtrIt == this->TargetPtrs.end()) // not found at all
-  {
-    return;
-  }
-
-  this->WriteNode(targetName, targetPtrIt->second, insertedNodes, str);
-
-  if (targetPtrIt->second == nullptr) // it's an external library
-  {
-    return;
-  }
-
-  std::string myNodeName = this->TargetNamesNodes.find(targetName)->second;
-
-  // now search who links against me
-  for (auto const& tptr : this->TargetPtrs) {
-    if (tptr.second == nullptr) {
-      continue;
-    }
-
-    if (!this->GenerateForTargetType(tptr.second->GetType())) {
-      continue;
-    }
-
-    // Now we have a target, check whether it links against targetName.
-    // If so, draw a connection, and then continue with dependers on that one.
-    std::map<std::string, LinkLibraryScopeType> ll =
-      getScopedLinkLibrariesFromTarget(tptr.second->Target, GlobalGenerator);
-
-    for (auto const& llit : ll) {
-      if (llit.first == targetName) {
-        // So this target links against targetName.
-        auto dependerNodeNameIt = this->TargetNamesNodes.find(tptr.first);
-
-        if (dependerNodeNameIt != this->TargetNamesNodes.end()) {
-          std::string connectionName =
-            cmStrCat(dependerNodeNameIt->second, '-', myNodeName);
-
-          if (insertedConnections.find(connectionName) ==
-              insertedConnections.end()) {
-            insertedConnections.insert(connectionName);
-            this->WriteNode(tptr.first, tptr.second, insertedNodes, str);
-
-            str << "    \"" << dependerNodeNameIt->second << "\" -> \""
-                << myNodeName << "\"";
-            str << " // " << targetName << " -> " << tptr.first << std::endl;
-            str << getLinkLibraryStyle(llit.second);
-            this->WriteDependerConnections(tptr.first, insertedNodes,
-                                           insertedConnections, str);
-          }
-        }
-        break;
+  for (const auto& lg : gg->GetLocalGenerators()) {
+    for (const auto& gt : lg->GetGeneratorTargets()) {
+      // Reserved targets have inconsistent names across platforms (e.g. 'all'
+      // vs. 'ALL_BUILD'), which can disrupt the traversal ordering.
+      // We don't need or want them anyway.
+      if (!cmGlobalGenerator::IsReservedTarget(gt->GetName())) {
+        sortedGeneratorTargets.insert(gt.get());
       }
     }
   }
-}
 
-void cmGraphVizWriter::WriteNode(const std::string& targetName,
-                                 const cmGeneratorTarget* target,
-                                 std::set<std::string>& insertedNodes,
-                                 cmGeneratedFileStream& str) const
-{
-  if (insertedNodes.find(targetName) == insertedNodes.end()) {
-    insertedNodes.insert(targetName);
-    auto nameIt = this->TargetNamesNodes.find(targetName);
-
-    str << "    \"" << nameIt->second << "\" [ label=\"" << targetName
-        << "\" shape=\"" << getShapeForTarget(target) << "\"];" << std::endl;
+  for (auto const gt : sortedGeneratorTargets) {
+    auto item = cmLinkItem(gt, false, gt->GetBacktrace());
+    this->VisitItem(item);
   }
 }
 
-void cmGraphVizWriter::CollectTargetsAndLibs()
+void cmGraphVizWriter::WriteHeader(cmGeneratedFileStream& fs,
+                                   const std::string& name)
 {
-  if (!this->HaveTargetsAndLibs) {
-    this->HaveTargetsAndLibs = true;
-    int cnt = this->CollectAllTargets();
-    if (this->GenerateForExternals) {
-      this->CollectAllExternalLibs(cnt);
-    }
-  }
+  auto const escapedGraphName = EscapeForDotFile(name);
+  fs << "digraph \"" << escapedGraphName << "\" {" << std::endl;
+  fs << this->GraphHeader << std::endl;
 }
 
-int cmGraphVizWriter::CollectAllTargets()
+void cmGraphVizWriter::WriteFooter(cmGeneratedFileStream& fs)
 {
-  int cnt = 0;
-  // First pass get the list of all cmake targets
-  for (cmLocalGenerator* lg : this->LocalGenerators) {
-    const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
-    for (cmGeneratorTarget* target : targets) {
-      const std::string& realTargetName = target->GetName();
-      if (this->IgnoreThisTarget(realTargetName)) {
-        // Skip ignored targets
-        continue;
-      }
-      // std::cout << "Found target: " << tit->first << std::endl;
-      std::ostringstream ostr;
-      ostr << this->GraphNodePrefix << cnt++;
-      this->TargetNamesNodes[realTargetName] = ostr.str();
-      this->TargetPtrs[realTargetName] = target;
+  fs << "}" << std::endl;
+}
+
+void cmGraphVizWriter::WriteLegend(cmGeneratedFileStream& fs)
+{
+  // Note that the subgraph name must start with "cluster", as done here, to
+  // make Graphviz layout engines do the right thing and keep the nodes
+  // together.
+  fs << "subgraph clusterLegend {" << std::endl;
+  fs << "  label = \"Legend\";" << std::endl;
+  // Set the color of the box surrounding the legend.
+  fs << "  color = black;" << std::endl;
+  // We use invisible edges just to enforce the layout.
+  fs << "  edge [ style = invis ];" << std::endl;
+
+  // Nodes.
+  fs << "  legendNode0 [ label = \"Executable\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_EXECUTABLE << " ];" << std::endl;
+
+  fs << "  legendNode1 [ label = \"Static Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC << " ];" << std::endl;
+  fs << "  legendNode2 [ label = \"Shared Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED << " ];" << std::endl;
+  fs << "  legendNode3 [ label = \"Module Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE << " ];" << std::endl;
+
+  fs << "  legendNode4 [ label = \"Interface Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE << " ];" << std::endl;
+  fs << "  legendNode5 [ label = \"Object Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT << " ];" << std::endl;
+  fs << "  legendNode6 [ label = \"Unknown Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN << " ];" << std::endl;
+
+  fs << "  legendNode7 [ label = \"Custom Target\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_UTILITY << " ];" << std::endl;
+
+  // Edges.
+  // Some of those are dummy (invisible) edges to enforce a layout.
+  fs << "  legendNode0 -> legendNode1 [ style = " << GRAPHVIZ_EDGE_STYLE_PUBLIC
+     << " ];" << std::endl;
+  fs << "  legendNode0 -> legendNode2 [ style = " << GRAPHVIZ_EDGE_STYLE_PUBLIC
+     << " ];" << std::endl;
+  fs << "  legendNode0 -> legendNode3;" << std::endl;
+
+  fs << "  legendNode1 -> legendNode4 [ label = \"Interface\", style = "
+     << GRAPHVIZ_EDGE_STYLE_INTERFACE << " ];" << std::endl;
+  fs << "  legendNode2 -> legendNode5 [ label = \"Private\", style = "
+     << GRAPHVIZ_EDGE_STYLE_PRIVATE << " ];" << std::endl;
+  fs << "  legendNode3 -> legendNode6 [ style = " << GRAPHVIZ_EDGE_STYLE_PUBLIC
+     << " ];" << std::endl;
+
+  fs << "  legendNode0 -> legendNode7;" << std::endl;
+
+  fs << "}" << std::endl;
+}
+
+void cmGraphVizWriter::WriteNode(cmGeneratedFileStream& fs,
+                                 cmLinkItem const& item)
+{
+  auto const& itemName = item.AsStr();
+  auto const& nodeName = this->NodeNames[itemName];
+
+  auto const itemNameWithAliases = ItemNameWithAliases(itemName);
+  auto const escapedLabel = EscapeForDotFile(itemNameWithAliases);
+
+  fs << "    \"" << nodeName << "\" [ label = \"" << escapedLabel
+     << "\", shape = " << getShapeForTarget(item) << " ];" << std::endl;
+}
+
+void cmGraphVizWriter::WriteConnection(cmGeneratedFileStream& fs,
+                                       cmLinkItem const& depender,
+                                       cmLinkItem const& dependee,
+                                       std::string const& edgeStyle)
+{
+  auto const& dependerName = depender.AsStr();
+  auto const& dependeeName = dependee.AsStr();
+
+  fs << "    \"" << this->NodeNames[dependerName] << "\" -> \""
+     << this->NodeNames[dependeeName] << "\" ";
+
+  fs << edgeStyle;
+
+  fs << " // " << dependerName << " -> " << dependeeName << std::endl;
+}
+
+bool cmGraphVizWriter::ItemExcluded(cmLinkItem const& item)
+{
+  auto const itemName = item.AsStr();
+
+  if (this->ItemNameFilteredOut(itemName)) {
+    return true;
+  }
+
+  if (item.Target == nullptr) {
+    return !this->GenerateForExternals;
+  }
+
+  if (item.Target->GetType() == cmStateEnums::UTILITY) {
+    if ((itemName.find("Nightly") == 0) ||
+        (itemName.find("Continuous") == 0) ||
+        (itemName.find("Experimental") == 0)) {
+      return true;
     }
   }
 
-  return cnt;
-}
-
-int cmGraphVizWriter::CollectAllExternalLibs(int cnt)
-{
-  // Ok, now find all the stuff we link to that is not in cmake
-  for (cmLocalGenerator* lg : this->LocalGenerators) {
-    const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
-    for (cmGeneratorTarget* target : targets) {
-      const std::string& realTargetName = target->GetName();
-      if (this->IgnoreThisTarget(realTargetName)) {
-        // Skip ignored targets
-        continue;
-      }
-      const cmTarget::LinkLibraryVectorType* ll =
-        &(target->Target->GetOriginalLinkLibraries());
-      for (auto const& llit : *ll) {
-        std::string libName = llit.first;
-        if (this->IgnoreThisTarget(libName)) {
-          // Skip ignored targets
-          continue;
-        }
-
-        if (GlobalGenerator->IsAlias(libName)) {
-          const auto tgt = GlobalGenerator->FindTarget(libName);
-          if (tgt) {
-            libName = tgt->GetName();
-          }
-        }
-
-        auto tarIt = this->TargetPtrs.find(libName);
-        if (tarIt == this->TargetPtrs.end()) {
-          std::ostringstream ostr;
-          ostr << this->GraphNodePrefix << cnt++;
-          this->TargetNamesNodes[libName] = ostr.str();
-          this->TargetPtrs[libName] = nullptr;
-          // str << "    \"" << ostr << "\" [ label=\"" << libName
-          // <<  "\" shape=\"ellipse\"];" << std::endl;
-        }
-      }
-    }
+  if (item.Target->IsImported() && !this->GenerateForExternals) {
+    return true;
   }
-  return cnt;
+
+  return !this->TargetTypeEnabled(item.Target->GetType());
 }
 
-bool cmGraphVizWriter::IgnoreThisTarget(const std::string& name)
+bool cmGraphVizWriter::ItemNameFilteredOut(std::string const& itemName)
 {
+  if (itemName == ">") {
+    // FIXME: why do we even receive such a target here?
+    return true;
+  }
+
+  if (cmGlobalGenerator::IsReservedTarget(itemName)) {
+    return true;
+  }
+
   for (cmsys::RegularExpression& regEx : this->TargetsToIgnoreRegex) {
     if (regEx.is_valid()) {
-      if (regEx.find(name)) {
+      if (regEx.find(itemName)) {
         return true;
       }
     }
@@ -579,7 +438,7 @@
   return false;
 }
 
-bool cmGraphVizWriter::GenerateForTargetType(
+bool cmGraphVizWriter::TargetTypeEnabled(
   cmStateEnums::TargetType targetType) const
 {
   switch (targetType) {
@@ -592,9 +451,73 @@
     case cmStateEnums::MODULE_LIBRARY:
       return this->GenerateForModuleLibs;
     case cmStateEnums::INTERFACE_LIBRARY:
-      return this->GenerateForInterface;
+      return this->GenerateForInterfaceLibs;
+    case cmStateEnums::OBJECT_LIBRARY:
+      return this->GenerateForObjectLibs;
+    case cmStateEnums::UNKNOWN_LIBRARY:
+      return this->GenerateForUnknownLibs;
+    case cmStateEnums::UTILITY:
+      return this->GenerateForCustomTargets;
+    case cmStateEnums::GLOBAL_TARGET:
+      // Built-in targets like edit_cache, etc.
+      // We don't need/want those in the dot file.
+      return false;
     default:
       break;
   }
   return false;
 }
+
+std::string cmGraphVizWriter::ItemNameWithAliases(
+  std::string const& itemName) const
+{
+  auto nameWithAliases = itemName;
+
+  for (auto const& lg : this->GlobalGenerator->GetLocalGenerators()) {
+    for (auto const& aliasTargets : lg->GetMakefile()->GetAliasTargets()) {
+      if (aliasTargets.second == itemName) {
+        nameWithAliases += "\\n(" + aliasTargets.first + ")";
+      }
+    }
+  }
+
+  return nameWithAliases;
+}
+
+std::string cmGraphVizWriter::GetEdgeStyle(DependencyType dt)
+{
+  std::string style;
+  switch (dt) {
+    case DependencyType::LinkPrivate:
+      style = "[ style = " + std::string(GRAPHVIZ_EDGE_STYLE_PRIVATE) + " ]";
+      break;
+    case DependencyType::LinkInterface:
+      style = "[ style = " + std::string(GRAPHVIZ_EDGE_STYLE_INTERFACE) + " ]";
+      break;
+    default:
+      break;
+  }
+  return style;
+}
+
+std::string cmGraphVizWriter::EscapeForDotFile(std::string const& str)
+{
+  return cmSystemTools::EscapeChars(str.data(), "\"");
+}
+
+std::string cmGraphVizWriter::PathSafeString(std::string const& str)
+{
+  std::string pathSafeStr;
+
+  // We'll only keep alphanumerical characters, plus the following ones that
+  // are common, and safe on all platforms:
+  auto const extra_chars = std::set<char>{ '.', '-', '_' };
+
+  for (char c : str) {
+    if (std::isalnum(c) || extra_chars.find(c) != extra_chars.cend()) {
+      pathSafeStr += c;
+    }
+  }
+
+  return pathSafeStr;
+}
diff --git a/Source/cmGraphVizWriter.h b/Source/cmGraphVizWriter.h
index 9c3051f..578660d 100644
--- a/Source/cmGraphVizWriter.h
+++ b/Source/cmGraphVizWriter.h
@@ -6,87 +6,106 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <map>
-#include <set>
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "cmsys/RegularExpression.hxx"
 
+#include "cmGeneratedFileStream.h"
+#include "cmLinkItemGraphVisitor.h"
 #include "cmStateTypes.h"
 
-class cmGeneratedFileStream;
-class cmGeneratorTarget;
-class cmLocalGenerator;
+class cmLinkItem;
 class cmGlobalGenerator;
 
 /** This class implements writing files for graphviz (dot) for graphs
  * representing the dependencies between the targets in the project. */
-class cmGraphVizWriter
+class cmGraphVizWriter : public cmLinkItemGraphVisitor
 {
 public:
-  cmGraphVizWriter(const cmGlobalGenerator* globalGenerator);
+  cmGraphVizWriter(std::string const& fileName,
+                   const cmGlobalGenerator* globalGenerator);
+  ~cmGraphVizWriter() override;
+
+  void VisitGraph(std::string const& name) override;
+
+  void OnItem(cmLinkItem const& item) override;
+
+  void OnDirectLink(cmLinkItem const& depender, cmLinkItem const& dependee,
+                    DependencyType dt) override;
+
+  void OnIndirectLink(cmLinkItem const& depender,
+                      cmLinkItem const& dependee) override;
 
   void ReadSettings(const std::string& settingsFileName,
                     const std::string& fallbackSettingsFileName);
 
-  void WritePerTargetFiles(const std::string& fileName);
-  void WriteTargetDependersFiles(const std::string& fileName);
+  void Write();
 
-  void WriteGlobalFile(const std::string& fileName);
+private:
+  using FileStreamMap =
+    std::map<std::string, std::unique_ptr<cmGeneratedFileStream>>;
 
-protected:
-  void CollectTargetsAndLibs();
+  void VisitLink(cmLinkItem const& depender, cmLinkItem const& dependee,
+                 bool isDirectLink, std::string const& scopeType = "");
 
-  int CollectAllTargets();
+  void WriteHeader(cmGeneratedFileStream& fs, std::string const& name);
 
-  int CollectAllExternalLibs(int cnt);
+  void WriteFooter(cmGeneratedFileStream& fs);
 
-  void WriteHeader(cmGeneratedFileStream& str) const;
+  void WriteLegend(cmGeneratedFileStream& fs);
 
-  void WriteConnections(const std::string& targetName,
-                        std::set<std::string>& insertedNodes,
-                        std::set<std::string>& insertedConnections,
-                        cmGeneratedFileStream& str) const;
+  void WriteNode(cmGeneratedFileStream& fs, cmLinkItem const& item);
 
-  void WriteDependerConnections(const std::string& targetName,
-                                std::set<std::string>& insertedNodes,
-                                std::set<std::string>& insertedConnections,
-                                cmGeneratedFileStream& str) const;
+  void CreateTargetFile(FileStreamMap& fileStreamMap, cmLinkItem const& target,
+                        std::string const& fileNameSuffix = "");
 
-  void WriteNode(const std::string& targetName,
-                 const cmGeneratorTarget* target,
-                 std::set<std::string>& insertedNodes,
-                 cmGeneratedFileStream& str) const;
+  void WriteConnection(cmGeneratedFileStream& fs,
+                       cmLinkItem const& dependerTargetName,
+                       cmLinkItem const& dependeeTargetName,
+                       std::string const& edgeStyle);
 
-  void WriteFooter(cmGeneratedFileStream& str) const;
+  bool ItemExcluded(cmLinkItem const& item);
+  bool ItemNameFilteredOut(std::string const& itemName);
+  bool TargetTypeEnabled(cmStateEnums::TargetType targetType) const;
 
-  bool IgnoreThisTarget(const std::string& name);
+  std::string ItemNameWithAliases(std::string const& itemName) const;
 
-  bool GenerateForTargetType(cmStateEnums::TargetType targetType) const;
+  static std::string GetEdgeStyle(DependencyType dt);
 
-  std::string GraphType;
+  static std::string EscapeForDotFile(std::string const& str);
+
+  static std::string PathSafeString(std::string const& str);
+
+  std::string FileName;
+  cmGeneratedFileStream GlobalFileStream;
+  FileStreamMap PerTargetFileStreams;
+  FileStreamMap TargetDependersFileStreams;
+
   std::string GraphName;
   std::string GraphHeader;
   std::string GraphNodePrefix;
 
   std::vector<cmsys::RegularExpression> TargetsToIgnoreRegex;
 
-  const cmGlobalGenerator* GlobalGenerator;
-  const std::vector<cmLocalGenerator*>& LocalGenerators;
+  cmGlobalGenerator const* GlobalGenerator;
 
-  std::map<std::string, const cmGeneratorTarget*> TargetPtrs;
-  // maps from the actual target names to node names in dot:
-  std::map<std::string, std::string> TargetNamesNodes;
+  int NextNodeId;
+  // maps from the actual item names to node names in dot:
+  std::map<std::string, std::string> NodeNames;
 
   bool GenerateForExecutables;
   bool GenerateForStaticLibs;
   bool GenerateForSharedLibs;
   bool GenerateForModuleLibs;
-  bool GenerateForInterface;
+  bool GenerateForInterfaceLibs;
+  bool GenerateForObjectLibs;
+  bool GenerateForUnknownLibs;
+  bool GenerateForCustomTargets;
   bool GenerateForExternals;
   bool GeneratePerTarget;
   bool GenerateDependers;
-  bool HaveTargetsAndLibs;
 };
 
 #endif
diff --git a/Source/cmIDEOptions.cxx b/Source/cmIDEOptions.cxx
index 71326d2..b53319f 100644
--- a/Source/cmIDEOptions.cxx
+++ b/Source/cmIDEOptions.cxx
@@ -4,6 +4,8 @@
 
 #include <iterator>
 
+#include <cmext/algorithm>
+
 #include <string.h>
 
 #include "cmsys/String.h"
@@ -173,7 +175,7 @@
 }
 void cmIDEOptions::AddDefines(const std::vector<std::string>& defines)
 {
-  cmAppend(this->Defines, defines);
+  cm::append(this->Defines, defines);
 }
 
 std::vector<std::string> const& cmIDEOptions::GetDefines() const
@@ -195,7 +197,7 @@
 }
 void cmIDEOptions::AddIncludes(const std::vector<std::string>& includes)
 {
-  cmAppend(this->Includes, includes);
+  cm::append(this->Includes, includes);
 }
 
 std::vector<std::string> const& cmIDEOptions::GetIncludes() const
diff --git a/Source/cmIncludeDirectoryCommand.cxx b/Source/cmIncludeDirectoryCommand.cxx
index 170aea1..b408f72 100644
--- a/Source/cmIncludeDirectoryCommand.cxx
+++ b/Source/cmIncludeDirectoryCommand.cxx
@@ -6,7 +6,8 @@
 #include <set>
 #include <utility>
 
-#include "cmAlgorithms.h"
+#include <cmext/algorithm>
+
 #include "cmExecutionStatus.h"
 #include "cmGeneratorExpression.h"
 #include "cmMakefile.h"
@@ -58,9 +59,9 @@
     GetIncludes(mf, *i, includes);
 
     if (before) {
-      cmAppend(beforeIncludes, includes);
+      cm::append(beforeIncludes, includes);
     } else {
-      cmAppend(afterIncludes, includes);
+      cm::append(afterIncludes, includes);
     }
     if (system) {
       systemIncludes.insert(includes.begin(), includes.end());
diff --git a/Source/cmIncludeExternalMSProjectCommand.cxx b/Source/cmIncludeExternalMSProjectCommand.cxx
index fa1e8bc..5b532ce 100644
--- a/Source/cmIncludeExternalMSProjectCommand.cxx
+++ b/Source/cmIncludeExternalMSProjectCommand.cxx
@@ -77,28 +77,27 @@
 
     if (!customGuid.empty()) {
       std::string guidVariable = utility_name + "_GUID_CMAKE";
-      mf.GetCMakeInstance()->AddCacheEntry(guidVariable.c_str(),
-                                           customGuid.c_str(), "Stored GUID",
+      mf.GetCMakeInstance()->AddCacheEntry(guidVariable, customGuid.c_str(),
+                                           "Stored GUID",
                                            cmStateEnums::INTERNAL);
     }
 
     // Create a target instance for this utility.
-    cmTarget* target =
-      mf.AddNewTarget(cmStateEnums::UTILITY, utility_name.c_str());
+    cmTarget* target = mf.AddNewTarget(cmStateEnums::UTILITY, utility_name);
     if (mf.GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
       target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
     }
 
-    target->SetProperty("GENERATOR_FILE_NAME", utility_name.c_str());
-    target->SetProperty("EXTERNAL_MSPROJECT", path.c_str());
+    target->SetProperty("GENERATOR_FILE_NAME", utility_name);
+    target->SetProperty("EXTERNAL_MSPROJECT", path);
 
     if (!customType.empty())
-      target->SetProperty("VS_PROJECT_TYPE", customType.c_str());
+      target->SetProperty("VS_PROJECT_TYPE", customType);
     if (!platformMapping.empty())
-      target->SetProperty("VS_PLATFORM_MAPPING", platformMapping.c_str());
+      target->SetProperty("VS_PLATFORM_MAPPING", platformMapping);
 
     for (std::string const& d : depends) {
-      target->AddUtility(d.c_str());
+      target->AddUtility(d, false);
     }
   }
 #endif
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index e511196..d669ed7 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;
 
     // Avoid selecting default destinations for PUBLIC_HEADER and
     // PRIVATE_HEADER if any artifacts are specified.
@@ -491,7 +492,7 @@
               target, runtimeArgs, false, helper.Makefile->GetBacktrace());
             artifactsSpecified = true;
           }
-          if ((archiveGenerator == nullptr) && (runtimeGenerator == nullptr)) {
+          if (!archiveGenerator && !runtimeGenerator) {
             archiveGenerator = CreateInstallTargetGenerator(
               target, archiveArgs, true, helper.Makefile->GetBacktrace(),
               helper.GetArchiveDestination(nullptr));
@@ -744,43 +745,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(), ";");
 
@@ -788,6 +764,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
@@ -975,7 +974,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;
@@ -1134,7 +1133,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) {
@@ -1220,7 +1219,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 "
@@ -1232,10 +1231,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.
@@ -1323,12 +1322,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
@@ -1437,12 +1435,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 d623943..3c59f01 100644
--- a/Source/cmInstallFilesCommand.cxx
+++ b/Source/cmInstallFilesCommand.cxx
@@ -2,16 +2,21 @@
    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"
 #include "cmInstallFilesGenerator.h"
 #include "cmInstallGenerator.h"
+#include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
+class cmListFileBacktrace;
+
 static std::string FindInstallSource(cmMakefile& makefile, const char* name);
 static void CreateInstallGenerator(cmMakefile& makefile,
                                    std::string const& dest,
@@ -43,9 +48,10 @@
     CreateInstallGenerator(mf, dest, files);
   } else {
     std::vector<std::string> finalArgs(args.begin() + 1, args.end());
-    mf.AddFinalAction([dest, finalArgs](cmMakefile& makefile) {
-      FinalAction(makefile, dest, finalArgs);
-    });
+    mf.AddGeneratorAction(
+      [dest, finalArgs](cmLocalGenerator& lg, const cmListFileBacktrace&) {
+        FinalAction(*lg.GetMakefile(), dest, finalArgs);
+      });
   }
 
   mf.GetGlobalGenerator()->AddInstallComponent(
@@ -109,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 6bb4409..be07fd4 100644
--- a/Source/cmInstallProgramsCommand.cxx
+++ b/Source/cmInstallProgramsCommand.cxx
@@ -2,15 +2,20 @@
    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"
 #include "cmInstallFilesGenerator.h"
 #include "cmInstallGenerator.h"
+#include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
+class cmListFileBacktrace;
+
 static void FinalAction(cmMakefile& makefile, std::string const& dest,
                         std::vector<std::string> const& args);
 static std::string FindInstallSource(cmMakefile& makefile, const char* name);
@@ -33,9 +38,10 @@
 
   std::string const& dest = args[0];
   std::vector<std::string> const finalArgs(args.begin() + 1, args.end());
-  mf.AddFinalAction([dest, finalArgs](cmMakefile& makefile) {
-    FinalAction(makefile, dest, finalArgs);
-  });
+  mf.AddGeneratorAction(
+    [dest, finalArgs](cmLocalGenerator& lg, const cmListFileBacktrace&) {
+      FinalAction(*lg.GetMakefile(), dest, finalArgs);
+    });
   return true;
 }
 
@@ -83,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 aa92fa7..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))
@@ -554,7 +554,8 @@
       // components of the install_name field then we need to create a
       // mapping to be applied after installation.
       std::string for_build = tgt->GetInstallNameDirForBuildTree(config);
-      std::string for_install = tgt->GetInstallNameDirForInstallTree();
+      std::string for_install = tgt->GetInstallNameDirForInstallTree(
+        config, "${CMAKE_INSTALL_PREFIX}");
       if (for_build != for_install) {
         // The directory portions differ.  Append the filename to
         // create the mapping.
@@ -577,7 +578,8 @@
   if (this->Target->GetType() == cmStateEnums::SHARED_LIBRARY) {
     std::string for_build =
       this->Target->GetInstallNameDirForBuildTree(config);
-    std::string for_install = this->Target->GetInstallNameDirForInstallTree();
+    std::string for_install = this->Target->GetInstallNameDirForInstallTree(
+      config, "${CMAKE_INSTALL_PREFIX}");
 
     if (this->Target->IsFrameworkOnApple() && for_install.empty()) {
       // Frameworks seem to have an id corresponding to their own full
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/cmInstalledFile.cxx b/Source/cmInstalledFile.cxx
index eabe590..a65ae03 100644
--- a/Source/cmInstalledFile.cxx
+++ b/Source/cmInstalledFile.cxx
@@ -4,7 +4,6 @@
 
 #include <utility>
 
-#include "cmAlgorithms.h"
 #include "cmGeneratorExpression.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
@@ -12,17 +11,11 @@
 
 cmInstalledFile::cmInstalledFile() = default;
 
-cmInstalledFile::~cmInstalledFile()
-{
-  delete NameExpression;
-}
+cmInstalledFile::~cmInstalledFile() = default;
 
 cmInstalledFile::Property::Property() = default;
 
-cmInstalledFile::Property::~Property()
-{
-  cmDeleteAll(this->ValueExpressions);
-}
+cmInstalledFile::Property::~Property() = default;
 
 void cmInstalledFile::SetName(cmMakefile* mf, const std::string& name)
 {
@@ -30,7 +23,7 @@
   cmGeneratorExpression ge(backtrace);
 
   this->Name = name;
-  this->NameExpression = ge.Parse(name).release();
+  this->NameExpression = ge.Parse(name);
 }
 
 std::string const& cmInstalledFile::GetName() const
@@ -63,7 +56,7 @@
   cmGeneratorExpression ge(backtrace);
 
   Property& property = this->Properties[prop];
-  property.ValueExpressions.push_back(ge.Parse(value).release());
+  property.ValueExpressions.push_back(ge.Parse(value));
 }
 
 bool cmInstalledFile::HasProperty(const std::string& prop) const
@@ -84,7 +77,7 @@
   std::string output;
   std::string separator;
 
-  for (auto ve : property.ValueExpressions) {
+  for (const auto& ve : property.ValueExpressions) {
     output += separator;
     output += ve->GetInput();
     separator = ";";
diff --git a/Source/cmInstalledFile.h b/Source/cmInstalledFile.h
index ee809ee..698151e 100644
--- a/Source/cmInstalledFile.h
+++ b/Source/cmInstalledFile.h
@@ -24,7 +24,7 @@
   using CompiledGeneratorExpressionPtrType =
     std::unique_ptr<cmCompiledGeneratorExpression>;
 
-  using ExpressionVectorType = std::vector<cmCompiledGeneratorExpression*>;
+  using ExpressionVectorType = std::vector<CompiledGeneratorExpressionPtrType>;
 
   struct Property
   {
@@ -73,7 +73,7 @@
 
 private:
   std::string Name;
-  cmCompiledGeneratorExpression* NameExpression = nullptr;
+  CompiledGeneratorExpressionPtrType NameExpression;
   PropertyMapType Properties;
 };
 
diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx
index b23ab43..dd36386 100644
--- a/Source/cmJsonObjects.cxx
+++ b/Source/cmJsonObjects.cxx
@@ -8,13 +8,15 @@
 #include <functional>
 #include <limits>
 #include <map>
+#include <memory>
 #include <set>
 #include <string>
 #include <unordered_map>
 #include <utility>
 #include <vector>
 
-#include "cmAlgorithms.h"
+#include <cmext/algorithm>
+
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
@@ -43,7 +45,7 @@
 std::vector<std::string> getConfigurations(const cmake* cm)
 {
   std::vector<std::string> configurations;
-  auto makefiles = cm->GetGlobalGenerator()->GetMakefiles();
+  const auto& makefiles = cm->GetGlobalGenerator()->GetMakefiles();
   if (makefiles.empty()) {
     return configurations;
   }
@@ -82,8 +84,8 @@
                       std::vector<std::string>* tmpFiles)
 {
   const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot() + '/';
-  std::vector<cmMakefile*> const& makefiles = gg->GetMakefiles();
-  for (cmMakefile const* mf : makefiles) {
+  auto const& makefiles = gg->GetMakefiles();
+  for (const auto& mf : makefiles) {
     for (std::string const& lf : mf->GetListFiles()) {
 
       const std::string startOfFile = lf.substr(0, cmakeRootDir.size());
@@ -485,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);
@@ -601,7 +603,7 @@
 
   std::vector<cmGeneratorTarget*> targetList;
   for (auto const& lgIt : generators) {
-    cmAppend(targetList, lgIt->GetGeneratorTargets());
+    cm::append(targetList, lgIt->GetGeneratorTargets());
   }
   std::sort(targetList.begin(), targetList.end());
 
@@ -641,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/cmLinkItem.cxx b/Source/cmLinkItem.cxx
index 91eb183..4e50d70 100644
--- a/Source/cmLinkItem.cxx
+++ b/Source/cmLinkItem.cxx
@@ -8,14 +8,17 @@
 
 cmLinkItem::cmLinkItem() = default;
 
-cmLinkItem::cmLinkItem(std::string n, cmListFileBacktrace bt)
+cmLinkItem::cmLinkItem(std::string n, bool c, cmListFileBacktrace bt)
   : String(std::move(n))
+  , Cross(c)
   , Backtrace(std::move(bt))
 {
 }
 
-cmLinkItem::cmLinkItem(cmGeneratorTarget const* t, cmListFileBacktrace bt)
+cmLinkItem::cmLinkItem(cmGeneratorTarget const* t, bool c,
+                       cmListFileBacktrace bt)
   : Target(t)
+  , Cross(c)
   , Backtrace(std::move(bt))
 {
 }
@@ -39,12 +42,16 @@
     return false;
   }
   // Order among strings.
-  return l.String < r.String;
+  if (l.String < r.String) {
+    return true;
+  }
+  // Order among cross-config.
+  return l.Cross < r.Cross;
 }
 
 bool operator==(cmLinkItem const& l, cmLinkItem const& r)
 {
-  return l.Target == r.Target && l.String == r.String;
+  return l.Target == r.Target && l.String == r.String && l.Cross == r.Cross;
 }
 
 std::ostream& operator<<(std::ostream& os, cmLinkItem const& item)
diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h
index 2d9378b..0ea25c0 100644
--- a/Source/cmLinkItem.h
+++ b/Source/cmLinkItem.h
@@ -24,10 +24,11 @@
 
 public:
   cmLinkItem();
-  cmLinkItem(std::string s, cmListFileBacktrace bt);
-  cmLinkItem(cmGeneratorTarget const* t, cmListFileBacktrace bt);
+  cmLinkItem(std::string s, bool c, cmListFileBacktrace bt);
+  cmLinkItem(cmGeneratorTarget const* t, bool c, cmListFileBacktrace bt);
   std::string const& AsStr() const;
   cmGeneratorTarget const* Target = nullptr;
+  bool Cross = false;
   cmListFileBacktrace Backtrace;
   friend bool operator<(cmLinkItem const& l, cmLinkItem const& r);
   friend bool operator==(cmLinkItem const& l, cmLinkItem const& r);
diff --git a/Source/cmLinkItemGraphVisitor.cxx b/Source/cmLinkItemGraphVisitor.cxx
new file mode 100644
index 0000000..acc23c8
--- /dev/null
+++ b/Source/cmLinkItemGraphVisitor.cxx
@@ -0,0 +1,142 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmLinkItemGraphVisitor.h"
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "cmGeneratorTarget.h"
+#include "cmLinkItem.h"
+#include "cmMakefile.h"
+
+void cmLinkItemGraphVisitor::VisitItem(cmLinkItem const& item)
+{
+  if (this->ItemVisited(item)) {
+    return;
+  }
+
+  this->OnItem(item);
+
+  this->VisitLinks(item, item);
+}
+
+void cmLinkItemGraphVisitor::VisitLinks(cmLinkItem const& item,
+                                        cmLinkItem const& rootItem)
+{
+  if (this->LinkVisited(item, rootItem)) {
+    return;
+  }
+
+  if (item.Target == nullptr) {
+    return;
+  }
+
+  for (auto const& config : item.Target->Makefile->GetGeneratorConfigs()) {
+    this->VisitLinks(item, rootItem, config);
+  }
+}
+
+void cmLinkItemGraphVisitor::VisitLinks(cmLinkItem const& item,
+                                        cmLinkItem const& rootItem,
+                                        std::string const& config)
+{
+  auto const& target = *item.Target;
+
+  DependencyMap dependencies;
+  cmLinkItemGraphVisitor::GetDependencies(target, config, dependencies);
+
+  for (auto const& d : dependencies) {
+    auto const& dependency = d.second;
+    auto const& dependencyType = dependency.first;
+    auto const& dependee = dependency.second;
+    this->VisitItem(dependee);
+
+    if (this->LinkVisited(item, dependee)) {
+      continue;
+    }
+
+    this->OnDirectLink(item, dependee, dependencyType);
+
+    if (rootItem.AsStr() != item.AsStr()) {
+      this->OnIndirectLink(rootItem, dependee);
+    }
+
+    // Visit all the direct and indirect links.
+    this->VisitLinks(dependee, dependee);
+    this->VisitLinks(dependee, item);
+    this->VisitLinks(dependee, rootItem);
+  }
+}
+
+bool cmLinkItemGraphVisitor::ItemVisited(cmLinkItem const& item)
+{
+  auto& collection = this->VisitedItems;
+
+  bool const visited = collection.find(item.AsStr()) != collection.cend();
+
+  if (!visited) {
+    collection.insert(item.AsStr());
+  }
+
+  return visited;
+}
+
+bool cmLinkItemGraphVisitor::LinkVisited(cmLinkItem const& depender,
+                                         cmLinkItem const& dependee)
+{
+  auto const link = std::make_pair<>(depender.AsStr(), dependee.AsStr());
+
+  bool const linkVisited =
+    this->VisitedLinks.find(link) != this->VisitedLinks.cend();
+
+  if (!linkVisited) {
+    this->VisitedLinks.insert(link);
+  }
+
+  return linkVisited;
+}
+
+void cmLinkItemGraphVisitor::GetDependencies(cmGeneratorTarget const& target,
+                                             std::string const& config,
+                                             DependencyMap& dependencies)
+{
+  auto implementationLibraries = target.GetLinkImplementationLibraries(config);
+  if (implementationLibraries != nullptr) {
+    for (auto const& lib : implementationLibraries->Libraries) {
+      auto const& name = lib.AsStr();
+      dependencies[name] = Dependency(DependencyType::LinkPrivate, lib);
+    }
+  }
+
+  auto interfaceLibraries =
+    target.GetLinkInterfaceLibraries(config, &target, true);
+  if (interfaceLibraries != nullptr) {
+    for (auto const& lib : interfaceLibraries->Libraries) {
+      auto const& name = lib.AsStr();
+      if (dependencies.find(name) != dependencies.cend()) {
+        dependencies[name] = Dependency(DependencyType::LinkPublic, lib);
+      } else {
+        dependencies[name] = Dependency(DependencyType::LinkInterface, lib);
+      }
+    }
+  }
+
+  std::vector<cmGeneratorTarget*> objectLibraries;
+  target.GetObjectLibrariesCMP0026(objectLibraries);
+  for (auto const& lib : objectLibraries) {
+    auto const& name = lib->GetName();
+    if (dependencies.find(name) == dependencies.cend()) {
+      auto objectItem = cmLinkItem(lib, false, lib->GetBacktrace());
+      dependencies[name] = Dependency(DependencyType::Object, objectItem);
+    }
+  }
+
+  auto const& utilityItems = target.GetUtilityItems();
+  for (auto const& item : utilityItems) {
+    auto const& name = item.AsStr();
+    if (dependencies.find(name) == dependencies.cend()) {
+      dependencies[name] = Dependency(DependencyType::Utility, item);
+    }
+  }
+}
diff --git a/Source/cmLinkItemGraphVisitor.h b/Source/cmLinkItemGraphVisitor.h
new file mode 100644
index 0000000..21dc659
--- /dev/null
+++ b/Source/cmLinkItemGraphVisitor.h
@@ -0,0 +1,75 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmLinkItemGraphVisitor_h
+#define cmLinkItemGraphVisitor_h
+
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+
+#include "cmLinkItem.h"
+
+class cmGeneratorTarget;
+
+/** \class cmLinkItemGraphVisitor
+ * \brief Visits a graph of linked items.
+ *
+ * Allows to visit items and dependency links (direct and indirect) between
+ * those items.
+ * This abstract class takes care of the graph traversal, making sure that:
+ *   - it terminates even in the presence of cycles;
+ *   - it visits every object once (and only once);
+ *   - it visits the objects in the same order every time.
+ *
+ * Children classes only have to implement OnItem() etc. to handle whatever
+ * logic they care about.
+ */
+class cmLinkItemGraphVisitor
+{
+public:
+  virtual ~cmLinkItemGraphVisitor() = default;
+
+  virtual void VisitGraph(std::string const& name) = 0;
+
+  void VisitItem(cmLinkItem const& item);
+
+protected:
+  enum class DependencyType
+  {
+    LinkInterface,
+    LinkPublic,
+    LinkPrivate,
+    Object,
+    Utility
+  };
+
+  virtual void OnItem(cmLinkItem const& item) = 0;
+
+  virtual void OnDirectLink(cmLinkItem const& depender,
+                            cmLinkItem const& dependee, DependencyType dt) = 0;
+
+  virtual void OnIndirectLink(cmLinkItem const& depender,
+                              cmLinkItem const& dependee) = 0;
+
+private:
+  std::set<std::string> VisitedItems;
+
+  std::set<std::pair<std::string, std::string>> VisitedLinks;
+
+  void VisitLinks(cmLinkItem const& item, cmLinkItem const& rootItem);
+  void VisitLinks(cmLinkItem const& item, cmLinkItem const& rootItem,
+                  std::string const& config);
+
+  using Dependency = std::pair<DependencyType, cmLinkItem>;
+  using DependencyMap = std::map<std::string, Dependency>;
+
+  bool ItemVisited(cmLinkItem const& item);
+  bool LinkVisited(cmLinkItem const& depender, cmLinkItem const& dependee);
+
+  static void GetDependencies(cmGeneratorTarget const& target,
+                              std::string const& config,
+                              DependencyMap& dependencies);
+};
+
+#endif
diff --git a/Source/cmLinkLibrariesCommand.cxx b/Source/cmLinkLibrariesCommand.cxx
index cb63ceb..2b8f836 100644
--- a/Source/cmLinkLibrariesCommand.cxx
+++ b/Source/cmLinkLibrariesCommand.cxx
@@ -32,7 +32,7 @@
       }
       mf.AppendProperty("LINK_LIBRARIES", "optimized");
     }
-    mf.AppendProperty("LINK_LIBRARIES", i->c_str());
+    mf.AppendProperty("LINK_LIBRARIES", *i);
   }
 
   return true;
diff --git a/Source/cmLinkLineComputer.cxx b/Source/cmLinkLineComputer.cxx
index 3d516f8..480c005 100644
--- a/Source/cmLinkLineComputer.cxx
+++ b/Source/cmLinkLineComputer.cxx
@@ -22,6 +22,7 @@
   , OutputConverter(outputConverter)
   , ForResponse(false)
   , UseWatcomQuote(false)
+  , UseNinjaMulti(false)
   , Relink(false)
 {
 }
@@ -33,6 +34,11 @@
   this->UseWatcomQuote = useWatcomQuote;
 }
 
+void cmLinkLineComputer::SetUseNinjaMulti(bool useNinjaMulti)
+{
+  this->UseNinjaMulti = useNinjaMulti;
+}
+
 void cmLinkLineComputer::SetForResponse(bool forResponse)
 {
   this->ForResponse = forResponse;
@@ -92,10 +98,14 @@
 
 std::string cmLinkLineComputer::ConvertToOutputFormat(std::string const& input)
 {
-  cmOutputConverter::OutputFormat shellFormat = (this->ForResponse)
-    ? cmOutputConverter::RESPONSE
-    : ((this->UseWatcomQuote) ? cmOutputConverter::WATCOMQUOTE
-                              : cmOutputConverter::SHELL);
+  cmOutputConverter::OutputFormat shellFormat = cmOutputConverter::SHELL;
+  if (this->ForResponse) {
+    shellFormat = cmOutputConverter::RESPONSE;
+  } else if (this->UseWatcomQuote) {
+    shellFormat = cmOutputConverter::WATCOMQUOTE;
+  } else if (this->UseNinjaMulti) {
+    shellFormat = cmOutputConverter::NINJAMULTI;
+  }
 
   return this->OutputConverter->ConvertToOutputFormat(input, shellFormat);
 }
@@ -103,10 +113,14 @@
 std::string cmLinkLineComputer::ConvertToOutputForExisting(
   std::string const& input)
 {
-  cmOutputConverter::OutputFormat shellFormat = (this->ForResponse)
-    ? cmOutputConverter::RESPONSE
-    : ((this->UseWatcomQuote) ? cmOutputConverter::WATCOMQUOTE
-                              : cmOutputConverter::SHELL);
+  cmOutputConverter::OutputFormat shellFormat = cmOutputConverter::SHELL;
+  if (this->ForResponse) {
+    shellFormat = cmOutputConverter::RESPONSE;
+  } else if (this->UseWatcomQuote) {
+    shellFormat = cmOutputConverter::WATCOMQUOTE;
+  } else if (this->UseNinjaMulti) {
+    shellFormat = cmOutputConverter::NINJAMULTI;
+  }
 
   return this->OutputConverter->ConvertToOutputForExisting(input, shellFormat);
 }
@@ -142,9 +156,11 @@
           type = cmStateEnums::ImportLibraryArtifact;
         }
 
-        linkPathNoBT += cmStrCat(
-          " ", libPathFlag, item.Target->GetDirectory(cli.GetConfig(), type),
-          libPathTerminator, " ");
+        linkPathNoBT +=
+          cmStrCat(" ", libPathFlag,
+                   this->ConvertToOutputForExisting(
+                     item.Target->GetDirectory(cli.GetConfig(), type)),
+                   libPathTerminator, " ");
       }
     }
 
diff --git a/Source/cmLinkLineComputer.h b/Source/cmLinkLineComputer.h
index f426976..df42468 100644
--- a/Source/cmLinkLineComputer.h
+++ b/Source/cmLinkLineComputer.h
@@ -28,6 +28,7 @@
   cmLinkLineComputer& operator=(cmLinkLineComputer const&) = delete;
 
   void SetUseWatcomQuote(bool useWatcomQuote);
+  void SetUseNinjaMulti(bool useNinjaMulti);
   void SetForResponse(bool forResponse);
   void SetRelink(bool relink);
 
@@ -69,6 +70,7 @@
 
   bool ForResponse;
   bool UseWatcomQuote;
+  bool UseNinjaMulti;
   bool Relink;
 };
 
diff --git a/Source/cmLoadCacheCommand.cxx b/Source/cmLoadCacheCommand.cxx
index 1184bcb..d49e711 100644
--- a/Source/cmLoadCacheCommand.cxx
+++ b/Source/cmLoadCacheCommand.cxx
@@ -24,12 +24,20 @@
 {
   if (args.empty()) {
     status.SetError("called with wrong number of arguments.");
+    return false;
   }
 
   if (args.size() >= 2 && args[1] == "READ_WITH_PREFIX") {
     return ReadWithPrefix(args, status);
   }
 
+  if (status.GetMakefile().GetCMakeInstance()->GetWorkingMode() ==
+      cmake::SCRIPT_MODE) {
+    status.SetError(
+      "Only load_cache(READ_WITH_PREFIX) may be used in script mode");
+    return false;
+  }
+
   // Cache entries to be excluded from the import list.
   // If this set is empty, all cache entries are brought in
   // and they can not be overridden.
diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx
index 23ace64..92258e2 100644
--- a/Source/cmLoadCommandCommand.cxx
+++ b/Source/cmLoadCommandCommand.cxx
@@ -14,6 +14,7 @@
 #include "cmCommand.h"
 #include "cmDynamicLoader.h"
 #include "cmExecutionStatus.h"
+#include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
@@ -25,6 +26,8 @@
 #  include <malloc.h> /* for malloc/free on QNX */
 #endif
 
+class cmListFileBacktrace;
+
 namespace {
 
 const char* LastName = nullptr;
@@ -158,8 +161,10 @@
   if (result) {
     if (this->Impl->FinalPass) {
       auto impl = this->Impl;
-      this->Makefile->AddFinalAction(
-        [impl](cmMakefile& makefile) { impl->DoFinalPass(&makefile); });
+      this->Makefile->AddGeneratorAction(
+        [impl](cmLocalGenerator& lg, const cmListFileBacktrace&) {
+          impl->DoFinalPass(lg.GetMakefile());
+        });
     }
     return true;
   }
diff --git a/Source/cmLocalCommonGenerator.cxx b/Source/cmLocalCommonGenerator.cxx
index f86955d..025ef7e 100644
--- a/Source/cmLocalCommonGenerator.cxx
+++ b/Source/cmLocalCommonGenerator.cxx
@@ -17,13 +17,9 @@
   : cmLocalGenerator(gg, mf)
   , WorkingDirectory(std::move(wd))
 {
-  // Store the configuration name that will be generated.
-  if (const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE")) {
-    // Use the build type given by the user.
-    this->ConfigName = config;
-  } else {
-    // No configuration type given.
-    this->ConfigName.clear();
+  this->Makefile->GetConfigurations(this->ConfigNames);
+  if (this->ConfigNames.empty()) {
+    this->ConfigNames.emplace_back();
   }
 }
 
diff --git a/Source/cmLocalCommonGenerator.h b/Source/cmLocalCommonGenerator.h
index eaef6ab..378ca63 100644
--- a/Source/cmLocalCommonGenerator.h
+++ b/Source/cmLocalCommonGenerator.h
@@ -7,6 +7,7 @@
 
 #include <map>
 #include <string>
+#include <vector>
 
 #include "cmLocalGenerator.h"
 
@@ -25,7 +26,10 @@
                          std::string wd);
   ~cmLocalCommonGenerator() override;
 
-  std::string const& GetConfigName() const { return this->ConfigName; }
+  std::vector<std::string> const& GetConfigNames() const
+  {
+    return this->ConfigNames;
+  }
 
   std::string GetWorkingDirectory() const { return this->WorkingDirectory; }
 
@@ -39,7 +43,7 @@
 protected:
   std::string WorkingDirectory;
 
-  std::string ConfigName;
+  std::vector<std::string> ConfigNames;
 
   friend class cmCommonTargetGenerator;
 };
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index af92e1b..00ad62e 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -2,6 +2,22 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmLocalGenerator.h"
 
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <initializer_list>
+#include <iterator>
+#include <sstream>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/algorithm>
+
 #include "cmsys/RegularExpression.hxx"
 
 #include "cmAlgorithms.h"
@@ -40,20 +56,6 @@
 #  include "cmCryptoHash.h"
 #endif
 
-#include <algorithm>
-#include <cassert>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <initializer_list>
-#include <iterator>
-#include <sstream>
-#include <unordered_set>
-#include <utility>
-#include <vector>
-
-#include <cm/string_view>
-
 #if defined(__HAIKU__)
 #  include <FindDirectory.h>
 #  include <StorageDefs.h>
@@ -181,11 +183,7 @@
                                        this->LinkerSysroot);
 }
 
-cmLocalGenerator::~cmLocalGenerator()
-{
-  cmDeleteAll(this->GeneratorTargets);
-  cmDeleteAll(this->OwnedImportedGeneratorTargets);
-}
+cmLocalGenerator::~cmLocalGenerator() = default;
 
 void cmLocalGenerator::IssueMessage(MessageType t,
                                     std::string const& text) const
@@ -263,8 +261,8 @@
 void cmLocalGenerator::TraceDependencies()
 {
   // Generate the rule files for each target.
-  const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
-  for (cmGeneratorTarget* target : targets) {
+  const auto& targets = this->GetGeneratorTargets();
+  for (const auto& target : targets) {
     if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
       continue;
     }
@@ -317,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);
   }
@@ -365,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);
   }
 }
@@ -375,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;
@@ -395,7 +388,7 @@
       return;
     }
 
-    cmAppend(generatedFiles, files);
+    cm::append(generatedFiles, files);
     std::inplace_merge(generatedFiles.begin(),
                        generatedFiles.end() - files.size(),
                        generatedFiles.end());
@@ -559,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);
     }
   }
@@ -635,11 +627,14 @@
   }
 }
 
-void cmLocalGenerator::AddGeneratorTarget(cmGeneratorTarget* gt)
+void cmLocalGenerator::AddGeneratorTarget(
+  std::unique_ptr<cmGeneratorTarget> gt)
 {
-  this->GeneratorTargets.push_back(gt);
-  this->GeneratorTargetSearchIndex.emplace(gt->GetName(), gt);
-  this->GlobalGenerator->IndexGeneratorTarget(gt);
+  cmGeneratorTarget* gt_ptr = gt.get();
+
+  this->GeneratorTargets.push_back(std::move(gt));
+  this->GeneratorTargetSearchIndex.emplace(gt_ptr->GetName(), gt_ptr);
+  this->GlobalGenerator->IndexGeneratorTarget(gt_ptr);
 }
 
 void cmLocalGenerator::AddImportedGeneratorTarget(cmGeneratorTarget* gt)
@@ -648,9 +643,10 @@
   this->GlobalGenerator->IndexGeneratorTarget(gt);
 }
 
-void cmLocalGenerator::AddOwnedImportedGeneratorTarget(cmGeneratorTarget* gt)
+void cmLocalGenerator::AddOwnedImportedGeneratorTarget(
+  std::unique_ptr<cmGeneratorTarget> gt)
 {
-  this->OwnedImportedGeneratorTargets.push_back(gt);
+  this->OwnedImportedGeneratorTargets.push_back(std::move(gt));
 }
 
 cmGeneratorTarget* cmLocalGenerator::FindLocalNonAliasGeneratorTarget(
@@ -673,8 +669,8 @@
   }
 
   // Add our targets to the manifest for each configuration.
-  const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
-  for (cmGeneratorTarget* target : targets) {
+  const auto& targets = this->GetGeneratorTargets();
+  for (const auto& target : targets) {
     if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
       continue;
     }
@@ -695,17 +691,18 @@
 
   using LanguagePair = std::pair<std::string, std::string>;
   std::vector<LanguagePair> pairedLanguages{ { "OBJC", "C" },
-                                             { "OBJCXX", "CXX" } };
-  std::set<LanguagePair> objcEnabledLanguages;
+                                             { "OBJCXX", "CXX" },
+                                             { "CUDA", "CXX" } };
+  std::set<LanguagePair> inferredEnabledLanguages;
   for (auto const& lang : pairedLanguages) {
     if (this->Makefile->GetState()->GetLanguageEnabled(lang.first)) {
-      objcEnabledLanguages.insert(lang);
+      inferredEnabledLanguages.insert(lang);
     }
   }
 
   // Process compile features of all targets.
-  const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
-  for (cmGeneratorTarget* target : targets) {
+  const auto& targets = this->GetGeneratorTargets();
+  for (const auto& target : targets) {
     for (std::string const& c : configNames) {
       if (!target->ComputeCompileFeatures(c)) {
         return false;
@@ -738,12 +735,17 @@
             target->GetProperty(cmStrCat(lang.second, property)));
         }
       };
-      for (auto const& lang : objcEnabledLanguages) {
+      for (auto const& lang : pairedLanguages) {
         if (copyStandardToObjLang(lang)) {
           copyPropertyToObjLang(lang, "_STANDARD_REQUIRED");
           copyPropertyToObjLang(lang, "_EXTENSIONS");
         }
       }
+      if (const char* standard = target->GetProperty("CUDA_STANDARD")) {
+        if (std::string{ standard } == "98") {
+          target->Target->SetProperty("CUDA_STANDARD", "03");
+        }
+      }
     }
   }
 
@@ -988,6 +990,91 @@
   }
 }
 
+cmTarget* cmLocalGenerator::AddCustomCommandToTarget(
+  const std::string& target, const std::vector<std::string>& byproducts,
+  const std::vector<std::string>& depends,
+  const cmCustomCommandLines& commandLines, cmCustomCommandType type,
+  const char* comment, const char* workingDir, bool escapeOldStyle,
+  bool uses_terminal, const std::string& depfile, const std::string& job_pool,
+  bool command_expand_lists, cmObjectLibraryCommands objLibCommands)
+{
+  cmTarget* t = this->Makefile->GetCustomCommandTarget(
+    target, objLibCommands, this->DirectoryBacktrace);
+  if (!t) {
+    return nullptr;
+  }
+
+  detail::AddCustomCommandToTarget(
+    *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, t, byproducts,
+    depends, commandLines, type, comment, workingDir, escapeOldStyle,
+    uses_terminal, depfile, job_pool, command_expand_lists);
+
+  return t;
+}
+
+cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput(
+  const std::string& output, const std::vector<std::string>& depends,
+  const std::string& main_dependency, const cmCustomCommandLines& commandLines,
+  const char* comment, const char* workingDir, bool replace,
+  bool escapeOldStyle, bool uses_terminal, bool command_expand_lists,
+  const std::string& depfile, const std::string& job_pool)
+{
+  std::vector<std::string> no_byproducts;
+  cmImplicitDependsList no_implicit_depends;
+  return this->AddCustomCommandToOutput(
+    { output }, no_byproducts, depends, main_dependency, no_implicit_depends,
+    commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal,
+    command_expand_lists, depfile, job_pool);
+}
+
+cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput(
+  const std::vector<std::string>& outputs,
+  const std::vector<std::string>& byproducts,
+  const std::vector<std::string>& depends, const std::string& main_dependency,
+  const cmImplicitDependsList& implicit_depends,
+  const cmCustomCommandLines& commandLines, const char* comment,
+  const char* workingDir, bool replace, bool escapeOldStyle,
+  bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+  const std::string& job_pool)
+{
+  // Make sure there is at least one output.
+  if (outputs.empty()) {
+    cmSystemTools::Error("Attempt to add a custom rule with no output!");
+    return nullptr;
+  }
+
+  return detail::AddCustomCommandToOutput(
+    *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, outputs,
+    byproducts, depends, main_dependency, implicit_depends, commandLines,
+    comment, workingDir, replace, escapeOldStyle, uses_terminal,
+    command_expand_lists, depfile, job_pool);
+}
+
+cmTarget* cmLocalGenerator::AddUtilityCommand(
+  const std::string& utilityName, bool excludeFromAll, const char* workingDir,
+  const std::vector<std::string>& byproducts,
+  const std::vector<std::string>& depends,
+  const cmCustomCommandLines& commandLines, bool escapeOldStyle,
+  const char* comment, bool uses_terminal, bool command_expand_lists,
+  const std::string& job_pool)
+{
+  cmTarget* target =
+    this->Makefile->AddNewUtilityTarget(utilityName, excludeFromAll);
+  target->SetIsGeneratorProvided(true);
+
+  if (commandLines.empty() && depends.empty()) {
+    return target;
+  }
+
+  detail::AddUtilityCommand(
+    *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, target,
+    this->Makefile->GetUtilityOutput(target), workingDir, byproducts, depends,
+    commandLines, escapeOldStyle, comment, uses_terminal, command_expand_lists,
+    job_pool);
+
+  return target;
+}
+
 std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit(
   cmGeneratorTarget const* target, std::string const& lang,
   std::string const& config, bool stripImplicitDirs,
@@ -1084,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);
       }
     }
@@ -1095,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
@@ -1685,23 +1772,10 @@
                                             const std::string& lang,
                                             const std::string& config)
 {
-  // Only add macOS specific flags on Darwin platforms (macOS and iOS):
+  // Only add Apple specific flags on Apple platforms
   if (this->Makefile->IsOn("APPLE") && this->EmitUniversalBinaryFlags) {
     std::vector<std::string> archs;
     target->GetAppleArchs(config, archs);
-    const char* sysroot = this->Makefile->GetDefinition("CMAKE_OSX_SYSROOT");
-    if (sysroot && sysroot[0] == '/' && !sysroot[1]) {
-      sysroot = nullptr;
-    }
-    std::string sysrootFlagVar =
-      std::string("CMAKE_") + lang + "_SYSROOT_FLAG";
-    const char* sysrootFlag = this->Makefile->GetDefinition(sysrootFlagVar);
-    const char* deploymentTarget =
-      this->Makefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET");
-    std::string deploymentTargetFlagVar =
-      std::string("CMAKE_") + lang + "_OSX_DEPLOYMENT_TARGET_FLAG";
-    const char* deploymentTargetFlag =
-      this->Makefile->GetDefinition(deploymentTargetFlagVar);
     if (!archs.empty() && !lang.empty() &&
         (lang[0] == 'C' || lang[0] == 'F' || lang[0] == 'O')) {
       for (std::string const& arch : archs) {
@@ -1710,13 +1784,44 @@
       }
     }
 
-    if (sysrootFlag && *sysrootFlag && sysroot && *sysroot) {
-      flags += " ";
-      flags += sysrootFlag;
-      flags += " ";
-      flags += this->ConvertToOutputFormat(sysroot, SHELL);
+    const char* sysroot = this->Makefile->GetDefinition("CMAKE_OSX_SYSROOT");
+    if (sysroot && sysroot[0] == '/' && !sysroot[1]) {
+      sysroot = nullptr;
+    }
+    std::string sysrootFlagVar =
+      std::string("CMAKE_") + lang + "_SYSROOT_FLAG";
+    const char* sysrootFlag = this->Makefile->GetDefinition(sysrootFlagVar);
+    if (sysrootFlag && *sysrootFlag) {
+      std::vector<std::string> arch_sysroots;
+      if (const char* arch_sysroots_str =
+            this->Makefile->GetDefinition("CMAKE_APPLE_ARCH_SYSROOTS")) {
+        cmExpandList(std::string(arch_sysroots_str), arch_sysroots, true);
+      }
+      if (!arch_sysroots.empty()) {
+        assert(arch_sysroots.size() == archs.size());
+        for (size_t i = 0; i < archs.size(); ++i) {
+          if (arch_sysroots[i].empty()) {
+            continue;
+          }
+          flags += " -Xarch_" + archs[i] + " ";
+          // Combine sysroot flag and path to work with -Xarch
+          std::string arch_sysroot = sysrootFlag + arch_sysroots[i];
+          flags += this->ConvertToOutputFormat(arch_sysroot, SHELL);
+        }
+      } else if (sysroot && *sysroot) {
+        flags += " ";
+        flags += sysrootFlag;
+        flags += " ";
+        flags += this->ConvertToOutputFormat(sysroot, SHELL);
+      }
     }
 
+    const char* deploymentTarget =
+      this->Makefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET");
+    std::string deploymentTargetFlagVar =
+      std::string("CMAKE_") + lang + "_OSX_DEPLOYMENT_TARGET_FLAG";
+    const char* deploymentTargetFlag =
+      this->Makefile->GetDefinition(deploymentTargetFlagVar);
     if (deploymentTargetFlag && *deploymentTargetFlag && deploymentTarget &&
         *deploymentTarget) {
       flags += " ";
@@ -1864,7 +1969,8 @@
       case cmStateEnums::SHARED_LIBRARY:
       case cmStateEnums::MODULE_LIBRARY:
       case cmStateEnums::UNKNOWN_LIBRARY:
-        dep = target->GetLocation(config);
+        dep = target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact,
+                                  /*realname=*/true);
         return true;
       case cmStateEnums::OBJECT_LIBRARY:
         // An object library has no single file on which to depend.
@@ -1898,8 +2004,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;
 }
 
@@ -2004,17 +2118,22 @@
     langStdMap["OBJC"].emplace_back("99");
     langStdMap["OBJC"].emplace_back("90");
 
+    langStdMap["CUDA"].emplace_back("20");
+    langStdMap["CUDA"].emplace_back("17");
     langStdMap["CUDA"].emplace_back("14");
     langStdMap["CUDA"].emplace_back("11");
-    langStdMap["CUDA"].emplace_back("98");
+    langStdMap["CUDA"].emplace_back("03");
   }
 
   std::string standard(standardProp);
-
+  if (lang == "CUDA" && standard == "98") {
+    standard = "03";
+  }
   std::vector<std::string>& stds = langStdMap[lang];
 
   auto stdIt = std::find(stds.begin(), stds.end(), standard);
   if (stdIt == stds.end()) {
+
     std::string e =
       lang + "_STANDARD is set to invalid value '" + standard + "'";
     this->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
@@ -2296,174 +2415,175 @@
 void cmLocalGenerator::AppendFlagEscape(std::string& flags,
                                         const std::string& rawFlag) const
 {
-  this->AppendFlags(flags, this->EscapeForShell(rawFlag));
+  this->AppendFlags(
+    flags,
+    this->EscapeForShell(rawFlag, false, false, false, this->IsNinjaMulti()));
 }
 
 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);
   }
 
-  // FIXME: Refactor collection of sources to not evaluate object libraries.
-  std::vector<cmSourceFile*> sources;
-  target->GetSourceFiles(sources, config);
+  for (std::string const& config : configsList) {
+    // FIXME: Refactor collection of sources to not evaluate object libraries.
+    std::vector<cmSourceFile*> sources;
+    target->GetSourceFiles(sources, 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;
-    }
-
-    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);
+          target->AddSource(pchSource, true);
+        }
 
-          if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) {
+        const std::string pchFile = target->GetPchFile(config, lang);
 
-            const std::string pdb_prefix =
-              this->GetGlobalGenerator()->IsMultiConfig()
-              ? cmStrCat(this->GlobalGenerator->GetCMakeCFGIntDir(), "/")
-              : "";
+        // 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);
 
-            const std::string target_compile_pdb_dir = cmStrCat(
-              target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/",
-              target->GetName(), ".dir/");
+            if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) {
 
-            const std::string copy_script =
-              cmStrCat(target_compile_pdb_dir, "copy_idb_pdb.cmake");
-            cmGeneratedFileStream file(copy_script);
+              const std::string pdb_prefix =
+                this->GetGlobalGenerator()->IsMultiConfig()
+                ? cmStrCat(this->GlobalGenerator->GetCMakeCFGIntDir(), "/")
+                : "";
 
-            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(
+              const std::string target_compile_pdb_dir = cmStrCat(
                 target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/",
-                target->GetName(), ".dir/${PDB_PREFIX}");
+                target->GetName(), ".dir/");
 
-              const std::string to_file =
-                cmStrCat(to_dir, pchReuseFrom, extension);
+              const std::string copy_script =
+                cmStrCat(target_compile_pdb_dir, "copy_idb_pdb.cmake");
+              cmGeneratedFileStream file(copy_script);
 
-              std::string dest_file = to_file;
+              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 prefix = target->GetSafeProperty("PREFIX");
-              if (!prefix.empty()) {
-                dest_file = cmStrCat(to_dir, prefix, pchReuseFrom, extension);
-              }
+                const std::string to_dir = cmStrCat(
+                  target->GetLocalGenerator()->GetCurrentBinaryDirectory(),
+                  "/", target->GetName(), ".dir/${PDB_PREFIX}");
 
-              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
+                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";
               }
-              file << "endif()\n";
-            }
 
-            cmCustomCommandLines commandLines;
-            cmCustomCommandLine currentLine;
-            currentLine.push_back(cmSystemTools::GetCMakeCommand());
-            currentLine.push_back(cmStrCat("-DPDB_PREFIX=", pdb_prefix));
-            currentLine.push_back("-P");
-            currentLine.push_back(copy_script);
-            commandLines.push_back(std::move(currentLine));
+              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;
+              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"));
+              std::vector<std::string> outputs;
+              outputs.push_back(cmStrCat(target_compile_pdb_dir, pdb_prefix,
+                                         pchReuseFrom, ".pdb"));
 
-            if (this->GetGlobalGenerator()->IsMultiConfig()) {
-              this->Makefile->AddCustomCommandToTarget(
-                target->GetName(), outputs, no_deps, commandLines,
-                cmCustomCommandType::PRE_BUILD, no_message, no_current_dir);
-            } else {
-              cmImplicitDependsList no_implicit_depends;
-              cmSourceFile* copy_rule =
-                this->Makefile->AddCustomCommandToOutput(
+              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());
+                if (copy_rule) {
+                  target->AddSource(copy_rule->ResolveFullPath());
+                }
               }
+
+              target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
+                                          target_compile_pdb_dir);
             }
 
-            target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
-                                        target_compile_pdb_dir.c_str());
+            std::string pchSourceObj =
+              reuseTarget->GetPchFileObject(config, lang);
+
+            // Link to the pch object file
+            target->Target->AppendProperty(
+              "LINK_FLAGS",
+              cmStrCat(" ", this->ConvertToOutputFormat(pchSourceObj, SHELL)),
+              true);
           }
-
-          std::string pchSourceObj =
-            reuseTarget->GetPchFileObject(config, lang);
-
-          // Link to the pch object file
-          target->Target->AppendProperty(
-            "LINK_FLAGS",
-            cmStrCat(" ", this->ConvertToOutputFormat(pchSourceObj, SHELL))
-              .c_str(),
-            true);
+        } else {
+          pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str());
         }
-      } 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);
+        // 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);
+      }
     }
   }
 }
@@ -2513,8 +2633,7 @@
       batchSize = filtered_sources.size();
     }
 
-    for (size_t itemsLeft = filtered_sources.size(), chunk = batchSize,
-                batch = 0;
+    for (size_t itemsLeft = filtered_sources.size(), chunk, batch = 0;
          itemsLeft > 0; itemsLeft -= chunk, ++batch) {
 
       chunk = std::min(itemsLeft, batchSize);
@@ -2626,11 +2745,11 @@
 }
 
 void cmLocalGenerator::AppendCompileOptions(std::string& options,
-                                            const char* options_list,
+                                            std::string const& options_list,
                                             const char* regex) const
 {
   // Short-circuit if there are no options.
-  if (!options_list) {
+  if (options_list.empty()) {
     return;
   }
 
@@ -2684,11 +2803,11 @@
 }
 
 void cmLocalGenerator::AppendIncludeDirectories(
-  std::vector<std::string>& includes, const char* includes_list,
+  std::vector<std::string>& includes, const std::string& includes_list,
   const cmSourceFile& sourceFile) const
 {
   // Short-circuit if there are no includes.
-  if (!includes_list) {
+  if (includes_list.empty()) {
     return;
   }
 
@@ -2882,7 +3001,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,
@@ -2898,15 +3017,15 @@
 {
   // Convert the old-style install specification from each target to
   // an install generator and run it.
-  const std::vector<cmGeneratorTarget*>& tgts = this->GetGeneratorTargets();
-  for (cmGeneratorTarget* l : tgts) {
+  const auto& tgts = this->GetGeneratorTargets();
+  for (const auto& l : tgts) {
     if (l->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
       continue;
     }
 
     // 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);
     }
 
@@ -2927,8 +3046,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: {
@@ -2936,19 +3055,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;
@@ -2959,7 +3078,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);
     }
   }
@@ -3115,6 +3234,11 @@
   return this->GetState()->UseNMake();
 }
 
+bool cmLocalGenerator::IsNinjaMulti() const
+{
+  return this->GetState()->UseNinjaMulti();
+}
+
 std::string cmLocalGenerator::GetObjectFileNameWithoutTarget(
   const cmSourceFile& source, std::string const& dir_max,
   bool* hasSourceExtension, char const* customOutputExtension)
@@ -3443,3 +3567,245 @@
   cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_BUNDLE_VERSION");
   mf->ConfigureFile(inFile, fname, false, false, false);
 }
+
+namespace {
+void CreateGeneratedSource(cmLocalGenerator& lg, const std::string& output,
+                           cmCommandOrigin origin,
+                           const cmListFileBacktrace& lfbt)
+{
+  if (cmGeneratorExpression::Find(output) == std::string::npos) {
+    // Outputs without generator expressions from the project are already
+    // created and marked as generated.  Do not mark them again, because
+    // other commands might have overwritten the property.
+    if (origin == cmCommandOrigin::Generator) {
+      lg.GetMakefile()->GetOrCreateGeneratedSource(output);
+    }
+  } else {
+    lg.GetCMakeInstance()->IssueMessage(
+      MessageType::FATAL_ERROR,
+      "Generator expressions in custom command outputs are not implemented!",
+      lfbt);
+  }
+}
+
+void CreateGeneratedSources(cmLocalGenerator& lg,
+                            const std::vector<std::string>& outputs,
+                            cmCommandOrigin origin,
+                            const cmListFileBacktrace& lfbt)
+{
+  for (std::string const& o : outputs) {
+    CreateGeneratedSource(lg, o, origin, lfbt);
+  }
+}
+
+cmSourceFile* AddCustomCommand(
+  cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+  const std::vector<std::string>& outputs,
+  const std::vector<std::string>& byproducts,
+  const std::vector<std::string>& depends, const std::string& main_dependency,
+  const cmImplicitDependsList& implicit_depends,
+  const cmCustomCommandLines& commandLines, const char* comment,
+  const char* workingDir, bool replace, bool escapeOldStyle,
+  bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+  const std::string& job_pool)
+{
+  cmMakefile* mf = lg.GetMakefile();
+
+  // Choose a source file on which to store the custom command.
+  cmSourceFile* file = nullptr;
+  if (!commandLines.empty() && !main_dependency.empty()) {
+    // The main dependency was specified.  Use it unless a different
+    // custom command already used it.
+    file = mf->GetSource(main_dependency);
+    if (file && file->GetCustomCommand() && !replace) {
+      // The main dependency already has a custom command.
+      if (commandLines == file->GetCustomCommand()->GetCommandLines()) {
+        // The existing custom command is identical.  Silently ignore
+        // the duplicate.
+        return file;
+      }
+      // The existing custom command is different.  We need to
+      // generate a rule file for this new command.
+      file = nullptr;
+    } else if (!file) {
+      file = mf->CreateSource(main_dependency);
+    }
+  }
+
+  // Generate a rule file if the main dependency is not available.
+  if (!file) {
+    cmGlobalGenerator* gg = lg.GetGlobalGenerator();
+
+    // Construct a rule file associated with the first output produced.
+    std::string outName = gg->GenerateRuleFile(outputs[0]);
+
+    // Check if the rule file already exists.
+    file = mf->GetSource(outName, cmSourceFileLocationKind::Known);
+    if (file && file->GetCustomCommand() && !replace) {
+      // The rule file already exists.
+      if (commandLines != file->GetCustomCommand()->GetCommandLines()) {
+        lg.GetCMakeInstance()->IssueMessage(
+          MessageType::FATAL_ERROR,
+          cmStrCat("Attempt to add a custom rule to output\n  ", outName,
+                   "\nwhich already has a custom rule."),
+          lfbt);
+      }
+      return file;
+    }
+
+    // Create a cmSourceFile for the rule file.
+    if (!file) {
+      file = mf->CreateSource(outName, true, cmSourceFileLocationKind::Known);
+    }
+    file->SetProperty("__CMAKE_RULE", "1");
+  }
+
+  // Attach the custom command to the file.
+  if (file) {
+    // Construct a complete list of dependencies.
+    std::vector<std::string> depends2(depends);
+    if (!main_dependency.empty()) {
+      depends2.push_back(main_dependency);
+    }
+
+    std::unique_ptr<cmCustomCommand> cc = cm::make_unique<cmCustomCommand>(
+      outputs, byproducts, depends2, commandLines, lfbt, comment, workingDir);
+    cc->SetEscapeOldStyle(escapeOldStyle);
+    cc->SetEscapeAllowMakeVars(true);
+    cc->SetImplicitDepends(implicit_depends);
+    cc->SetUsesTerminal(uses_terminal);
+    cc->SetCommandExpandLists(command_expand_lists);
+    cc->SetDepfile(depfile);
+    cc->SetJobPool(job_pool);
+    file->SetCustomCommand(std::move(cc));
+
+    mf->AddSourceOutputs(file, outputs, byproducts);
+  }
+  return file;
+}
+}
+
+namespace detail {
+void AddCustomCommandToTarget(cmLocalGenerator& lg,
+                              const cmListFileBacktrace& lfbt,
+                              cmCommandOrigin origin, cmTarget* target,
+                              const std::vector<std::string>& byproducts,
+                              const std::vector<std::string>& depends,
+                              const cmCustomCommandLines& commandLines,
+                              cmCustomCommandType type, const char* comment,
+                              const char* workingDir, bool escapeOldStyle,
+                              bool uses_terminal, const std::string& depfile,
+                              const std::string& job_pool,
+                              bool command_expand_lists)
+{
+  cmMakefile* mf = lg.GetMakefile();
+
+  // Always create the byproduct sources and mark them generated.
+  CreateGeneratedSources(lg, byproducts, origin, lfbt);
+
+  // Add the command to the appropriate build step for the target.
+  std::vector<std::string> no_output;
+  cmCustomCommand cc(no_output, byproducts, depends, commandLines, lfbt,
+                     comment, workingDir);
+  cc.SetEscapeOldStyle(escapeOldStyle);
+  cc.SetEscapeAllowMakeVars(true);
+  cc.SetUsesTerminal(uses_terminal);
+  cc.SetCommandExpandLists(command_expand_lists);
+  cc.SetDepfile(depfile);
+  cc.SetJobPool(job_pool);
+  switch (type) {
+    case cmCustomCommandType::PRE_BUILD:
+      target->AddPreBuildCommand(std::move(cc));
+      break;
+    case cmCustomCommandType::PRE_LINK:
+      target->AddPreLinkCommand(std::move(cc));
+      break;
+    case cmCustomCommandType::POST_BUILD:
+      target->AddPostBuildCommand(std::move(cc));
+      break;
+  }
+
+  mf->AddTargetByproducts(target, byproducts);
+}
+
+cmSourceFile* AddCustomCommandToOutput(
+  cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+  cmCommandOrigin origin, const std::vector<std::string>& outputs,
+  const std::vector<std::string>& byproducts,
+  const std::vector<std::string>& depends, const std::string& main_dependency,
+  const cmImplicitDependsList& implicit_depends,
+  const cmCustomCommandLines& commandLines, const char* comment,
+  const char* workingDir, bool replace, bool escapeOldStyle,
+  bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+  const std::string& job_pool)
+{
+  // Always create the output sources and mark them generated.
+  CreateGeneratedSources(lg, outputs, origin, lfbt);
+  CreateGeneratedSources(lg, byproducts, origin, lfbt);
+
+  return AddCustomCommand(
+    lg, lfbt, outputs, byproducts, depends, main_dependency, implicit_depends,
+    commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal,
+    command_expand_lists, depfile, job_pool);
+}
+
+void AppendCustomCommandToOutput(cmLocalGenerator& lg,
+                                 const cmListFileBacktrace& lfbt,
+                                 const std::string& output,
+                                 const std::vector<std::string>& depends,
+                                 const cmImplicitDependsList& implicit_depends,
+                                 const cmCustomCommandLines& commandLines)
+{
+  // Lookup an existing command.
+  if (cmSourceFile* sf = lg.GetMakefile()->GetSourceFileWithOutput(output)) {
+    if (cmCustomCommand* cc = sf->GetCustomCommand()) {
+      cc->AppendCommands(commandLines);
+      cc->AppendDepends(depends);
+      cc->AppendImplicitDepends(implicit_depends);
+      return;
+    }
+  }
+
+  // No existing command found.
+  lg.GetCMakeInstance()->IssueMessage(
+    MessageType::FATAL_ERROR,
+    cmStrCat("Attempt to append to output\n  ", output,
+             "\nwhich is not already a custom command output."),
+    lfbt);
+}
+
+void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+                       cmCommandOrigin origin, cmTarget* target,
+                       const cmUtilityOutput& force, const char* workingDir,
+                       const std::vector<std::string>& byproducts,
+                       const std::vector<std::string>& depends,
+                       const cmCustomCommandLines& commandLines,
+                       bool escapeOldStyle, const char* comment,
+                       bool uses_terminal, bool command_expand_lists,
+                       const std::string& job_pool)
+{
+  // Always create the byproduct sources and mark them generated.
+  CreateGeneratedSource(lg, force.Name, origin, lfbt);
+  CreateGeneratedSources(lg, byproducts, origin, lfbt);
+
+  // Use an empty comment to avoid generation of default comment.
+  if (!comment) {
+    comment = "";
+  }
+
+  std::string no_main_dependency;
+  cmImplicitDependsList no_implicit_depends;
+  cmSourceFile* rule = AddCustomCommand(
+    lg, lfbt, { force.Name }, byproducts, depends, no_main_dependency,
+    no_implicit_depends, commandLines, comment, workingDir, /*replace=*/false,
+    escapeOldStyle, uses_terminal, command_expand_lists, /*depfile=*/"",
+    job_pool);
+  if (rule) {
+    lg.GetMakefile()->AddTargetByproducts(target, byproducts);
+  }
+
+  if (!force.NameCMP0049.empty()) {
+    target->AddSource(force.NameCMP0049);
+  }
+}
+}
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 12359db..88194b7 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -7,6 +7,7 @@
 
 #include <iosfwd>
 #include <map>
+#include <memory>
 #include <set>
 #include <string>
 #include <unordered_map>
@@ -14,6 +15,7 @@
 
 #include "cm_kwiml.h"
 
+#include "cmCustomCommandTypes.h"
 #include "cmListFileCache.h"
 #include "cmMessageType.h"
 #include "cmOutputConverter.h"
@@ -22,13 +24,16 @@
 
 class cmComputeLinkInformation;
 class cmCustomCommandGenerator;
+class cmCustomCommandLines;
 class cmGeneratorTarget;
 class cmGlobalGenerator;
+class cmImplicitDependsList;
 class cmLinkLineComputer;
 class cmMakefile;
 class cmRulePlaceholderExpander;
 class cmSourceFile;
 class cmState;
+class cmTarget;
 class cmake;
 
 /** \class cmLocalGenerator
@@ -143,14 +148,16 @@
                               bool forResponseFile = false,
                               const std::string& config = "");
 
-  const std::vector<cmGeneratorTarget*>& GetGeneratorTargets() const
+  using GeneratorTargetVector =
+    std::vector<std::unique_ptr<cmGeneratorTarget>>;
+  const GeneratorTargetVector& GetGeneratorTargets() const
   {
     return this->GeneratorTargets;
   }
 
-  void AddGeneratorTarget(cmGeneratorTarget* gt);
+  void AddGeneratorTarget(std::unique_ptr<cmGeneratorTarget> gt);
   void AddImportedGeneratorTarget(cmGeneratorTarget* gt);
-  void AddOwnedImportedGeneratorTarget(cmGeneratorTarget* gt);
+  void AddOwnedImportedGeneratorTarget(std::unique_ptr<cmGeneratorTarget> gt);
 
   cmGeneratorTarget* FindLocalNonAliasGeneratorTarget(
     const std::string& name) const;
@@ -160,15 +167,8 @@
    * Process a list of include directories
    */
   void AppendIncludeDirectories(std::vector<std::string>& includes,
-                                const char* includes_list,
-                                const cmSourceFile& sourceFile) const;
-  void AppendIncludeDirectories(std::vector<std::string>& includes,
                                 std::string const& includes_list,
-                                const cmSourceFile& sourceFile) const
-  {
-    this->AppendIncludeDirectories(includes, includes_list.c_str(),
-                                   sourceFile);
-  }
+                                const cmSourceFile& sourceFile) const;
   void AppendIncludeDirectories(std::vector<std::string>& includes,
                                 const std::vector<std::string>& includes_vec,
                                 const cmSourceFile& sourceFile) const;
@@ -188,14 +188,9 @@
    * Encode a list of compile options for the compiler
    * command line.
    */
-  void AppendCompileOptions(std::string& options, const char* options_list,
-                            const char* regex = nullptr) const;
   void AppendCompileOptions(std::string& options,
                             std::string const& options_list,
-                            const char* regex = nullptr) const
-  {
-    this->AppendCompileOptions(options, options_list.c_str(), regex);
-  }
+                            const char* regex = nullptr) const;
   void AppendCompileOptions(std::string& options,
                             const std::vector<std::string>& options_vec,
                             const char* regex = nullptr) const;
@@ -292,6 +287,51 @@
                          cmGeneratorTarget* target, const std::string& lang,
                          const std::string& config);
 
+  /**
+   * Add a custom PRE_BUILD, PRE_LINK, or POST_BUILD command to a target.
+   */
+  cmTarget* AddCustomCommandToTarget(
+    const std::string& target, const std::vector<std::string>& byproducts,
+    const std::vector<std::string>& depends,
+    const cmCustomCommandLines& commandLines, cmCustomCommandType type,
+    const char* comment, const char* workingDir, bool escapeOldStyle = true,
+    bool uses_terminal = false, const std::string& depfile = "",
+    const std::string& job_pool = "", bool command_expand_lists = false,
+    cmObjectLibraryCommands objLibCommands = cmObjectLibraryCommands::Reject);
+
+  /**
+   * Add a custom command to a source file.
+   */
+  cmSourceFile* AddCustomCommandToOutput(
+    const std::string& output, const std::vector<std::string>& depends,
+    const std::string& main_dependency,
+    const cmCustomCommandLines& commandLines, const char* comment,
+    const char* workingDir, bool replace = false, bool escapeOldStyle = true,
+    bool uses_terminal = false, bool command_expand_lists = false,
+    const std::string& depfile = "", const std::string& job_pool = "");
+  cmSourceFile* AddCustomCommandToOutput(
+    const std::vector<std::string>& outputs,
+    const std::vector<std::string>& byproducts,
+    const std::vector<std::string>& depends,
+    const std::string& main_dependency,
+    const cmImplicitDependsList& implicit_depends,
+    const cmCustomCommandLines& commandLines, const char* comment,
+    const char* workingDir, bool replace = false, bool escapeOldStyle = true,
+    bool uses_terminal = false, bool command_expand_lists = false,
+    const std::string& depfile = "", const std::string& job_pool = "");
+
+  /**
+   * Add a utility to the build.  A utility target is a command that is run
+   * every time the target is built.
+   */
+  cmTarget* AddUtilityCommand(
+    const std::string& utilityName, bool excludeFromAll,
+    const char* workingDir, const std::vector<std::string>& byproducts,
+    const std::vector<std::string>& depends,
+    const cmCustomCommandLines& commandLines, bool escapeOldStyle = true,
+    const char* comment = nullptr, bool uses_terminal = false,
+    bool command_expand_lists = false, const std::string& job_pool = "");
+
   std::string GetProjectName() const;
 
   /** Compute the language used to compile the given source file.  */
@@ -414,6 +454,7 @@
   bool IsWatcomWMake() const;
   bool IsMinGWMake() const;
   bool IsNMake() const;
+  bool IsNinjaMulti() const;
 
   void IssueMessage(MessageType t, std::string const& text) const;
 
@@ -461,11 +502,11 @@
   using GeneratorTargetMap =
     std::unordered_map<std::string, cmGeneratorTarget*>;
   GeneratorTargetMap GeneratorTargetSearchIndex;
-  std::vector<cmGeneratorTarget*> GeneratorTargets;
+  GeneratorTargetVector GeneratorTargets;
 
   std::set<cmGeneratorTarget const*> WarnCMP0063;
   GeneratorTargetMap ImportedGeneratorTargets;
-  std::vector<cmGeneratorTarget*> OwnedImportedGeneratorTargets;
+  GeneratorTargetVector OwnedImportedGeneratorTargets;
   std::map<std::string, std::string> AliasTargets;
 
   std::map<std::string, std::string> Compilers;
@@ -494,4 +535,46 @@
                                      std::string::size_type max_total_len);
 #endif
 
+namespace detail {
+void AddCustomCommandToTarget(cmLocalGenerator& lg,
+                              const cmListFileBacktrace& lfbt,
+                              cmCommandOrigin origin, cmTarget* target,
+                              const std::vector<std::string>& byproducts,
+                              const std::vector<std::string>& depends,
+                              const cmCustomCommandLines& commandLines,
+                              cmCustomCommandType type, const char* comment,
+                              const char* workingDir, bool escapeOldStyle,
+                              bool uses_terminal, const std::string& depfile,
+                              const std::string& job_pool,
+                              bool command_expand_lists);
+
+cmSourceFile* AddCustomCommandToOutput(
+  cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+  cmCommandOrigin origin, const std::vector<std::string>& outputs,
+  const std::vector<std::string>& byproducts,
+  const std::vector<std::string>& depends, const std::string& main_dependency,
+  const cmImplicitDependsList& implicit_depends,
+  const cmCustomCommandLines& commandLines, const char* comment,
+  const char* workingDir, bool replace, bool escapeOldStyle,
+  bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+  const std::string& job_pool);
+
+void AppendCustomCommandToOutput(cmLocalGenerator& lg,
+                                 const cmListFileBacktrace& lfbt,
+                                 const std::string& output,
+                                 const std::vector<std::string>& depends,
+                                 const cmImplicitDependsList& implicit_depends,
+                                 const cmCustomCommandLines& commandLines);
+
+void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+                       cmCommandOrigin origin, cmTarget* target,
+                       const cmUtilityOutput& force, const char* workingDir,
+                       const std::vector<std::string>& byproducts,
+                       const std::vector<std::string>& depends,
+                       const cmCustomCommandLines& commandLines,
+                       bool escapeOldStyle, const char* comment,
+                       bool uses_terminal, bool command_expand_lists,
+                       const std::string& job_pool);
+}
+
 #endif
diff --git a/Source/cmLocalGhsMultiGenerator.cxx b/Source/cmLocalGhsMultiGenerator.cxx
index 4b10798..098fa5a 100644
--- a/Source/cmLocalGhsMultiGenerator.cxx
+++ b/Source/cmLocalGhsMultiGenerator.cxx
@@ -5,6 +5,8 @@
 #include <algorithm>
 #include <utility>
 
+#include <cmext/algorithm>
+
 #include "cmGeneratorTarget.h"
 #include "cmGhsMultiTargetGenerator.h"
 #include "cmGlobalGenerator.h"
@@ -50,10 +52,11 @@
 
 void cmLocalGhsMultiGenerator::Generate()
 {
-  std::vector<cmGeneratorTarget*> remaining = this->GetGeneratorTargets();
+  std::vector<cmGeneratorTarget*> remaining;
+  cm::append(remaining, this->GetGeneratorTargets());
   for (auto& t : remaining) {
     if (t) {
-      GenerateTargetsDepthFirst(t, remaining);
+      this->GenerateTargetsDepthFirst(t, remaining);
     }
   }
 }
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index 134bbe1..be1dd0d 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -29,6 +29,7 @@
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmTarget.h"
 #include "cmake.h"
 
 cmLocalNinjaGenerator::cmLocalNinjaGenerator(cmGlobalGenerator* gg,
@@ -61,7 +62,12 @@
     this->HomeRelativeOutputPath.clear();
   }
 
-  this->WriteProcessedMakefile(this->GetBuildFileStream());
+  if (this->GetGlobalGenerator()->IsMultiConfig()) {
+    for (auto const& config : this->GetConfigNames()) {
+      this->WriteProcessedMakefile(this->GetImplFileStream(config));
+    }
+  }
+  this->WriteProcessedMakefile(this->GetCommonFileStream());
 #ifdef NINJA_GEN_VERBOSE_FILES
   this->WriteProcessedMakefile(this->GetRulesFileStream());
 #endif
@@ -82,18 +88,26 @@
     }
   }
 
-  for (cmGeneratorTarget* target : this->GetGeneratorTargets()) {
+  for (const auto& target : this->GetGeneratorTargets()) {
     if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
       continue;
     }
-    auto tg = cmNinjaTargetGenerator::New(target);
+    auto tg = cmNinjaTargetGenerator::New(target.get());
     if (tg) {
-      tg->Generate();
+      if (target->Target->IsPerConfig()) {
+        for (auto const& config : this->GetConfigNames()) {
+          tg->Generate(config);
+        }
+      } else {
+        tg->Generate("");
+      }
     }
   }
 
-  this->WriteCustomCommandBuildStatements();
-  this->AdditionalCleanFiles();
+  for (auto const& config : this->GetConfigNames()) {
+    this->WriteCustomCommandBuildStatements(config);
+    this->AdditionalCleanFiles(config);
+  }
 }
 
 // TODO: Picked up from cmLocalUnixMakefileGenerator3.  Refactor it.
@@ -140,9 +154,15 @@
 
 // Private methods.
 
-cmGeneratedFileStream& cmLocalNinjaGenerator::GetBuildFileStream() const
+cmGeneratedFileStream& cmLocalNinjaGenerator::GetImplFileStream(
+  const std::string& config) const
 {
-  return *this->GetGlobalNinjaGenerator()->GetBuildFileStream();
+  return *this->GetGlobalNinjaGenerator()->GetImplFileStream(config);
+}
+
+cmGeneratedFileStream& cmLocalNinjaGenerator::GetCommonFileStream() const
+{
+  return *this->GetGlobalNinjaGenerator()->GetCommonFileStream();
 }
 
 cmGeneratedFileStream& cmLocalNinjaGenerator::GetRulesFileStream() const
@@ -162,10 +182,22 @@
 
 void cmLocalNinjaGenerator::WriteBuildFileTop()
 {
-  // For the build file.
-  this->WriteProjectHeader(this->GetBuildFileStream());
-  this->WriteNinjaRequiredVersion(this->GetBuildFileStream());
-  this->WriteNinjaFilesInclusion(this->GetBuildFileStream());
+  this->WriteProjectHeader(this->GetCommonFileStream());
+
+  if (this->GetGlobalGenerator()->IsMultiConfig()) {
+    for (auto const& config : this->GetConfigNames()) {
+      auto& stream = this->GetImplFileStream(config);
+      this->WriteProjectHeader(stream);
+      this->WriteNinjaRequiredVersion(stream);
+      this->WriteNinjaConfigurationVariable(stream, config);
+      this->WriteNinjaFilesInclusionConfig(stream);
+    }
+  } else {
+    this->WriteNinjaRequiredVersion(this->GetCommonFileStream());
+    this->WriteNinjaConfigurationVariable(this->GetCommonFileStream(),
+                                          this->GetConfigNames().front());
+  }
+  this->WriteNinjaFilesInclusionCommon(this->GetCommonFileStream());
 
   // For the rule file.
   this->WriteProjectHeader(this->GetRulesFileStream());
@@ -175,7 +207,8 @@
 {
   cmGlobalNinjaGenerator::WriteDivider(os);
   os << "# Project: " << this->GetProjectName() << std::endl
-     << "# Configuration: " << this->ConfigName << std::endl;
+     << "# Configurations: " << cmJoin(this->GetConfigNames(), ", ")
+     << std::endl;
   cmGlobalNinjaGenerator::WriteDivider(os);
 }
 
@@ -206,6 +239,14 @@
      << std::endl;
 }
 
+void cmLocalNinjaGenerator::WriteNinjaConfigurationVariable(
+  std::ostream& os, const std::string& config)
+{
+  cmGlobalNinjaGenerator::WriteVariable(
+    os, "CONFIGURATION", config,
+    "Set configuration variable for custom commands.");
+}
+
 void cmLocalNinjaGenerator::WritePools(std::ostream& os)
 {
   cmGlobalNinjaGenerator::WriteDivider(os);
@@ -235,7 +276,21 @@
   }
 }
 
-void cmLocalNinjaGenerator::WriteNinjaFilesInclusion(std::ostream& os)
+void cmLocalNinjaGenerator::WriteNinjaFilesInclusionConfig(std::ostream& os)
+{
+  cmGlobalNinjaGenerator::WriteDivider(os);
+  os << "# Include auxiliary files.\n"
+     << "\n";
+  cmGlobalNinjaGenerator* ng = this->GetGlobalNinjaGenerator();
+  std::string const ninjaCommonFile =
+    ng->NinjaOutputPath(cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE);
+  std::string const commonFilePath = ng->EncodePath(ninjaCommonFile);
+  cmGlobalNinjaGenerator::WriteInclude(os, commonFilePath,
+                                       "Include common file.");
+  os << "\n";
+}
+
+void cmLocalNinjaGenerator::WriteNinjaFilesInclusionCommon(std::ostream& os)
 {
   cmGlobalNinjaGenerator::WriteDivider(os);
   os << "# Include auxiliary files.\n"
@@ -263,25 +318,30 @@
 }
 
 void cmLocalNinjaGenerator::AppendTargetOutputs(cmGeneratorTarget* target,
-                                                cmNinjaDeps& outputs)
+                                                cmNinjaDeps& outputs,
+                                                const std::string& config)
 {
-  this->GetGlobalNinjaGenerator()->AppendTargetOutputs(target, outputs);
+  this->GetGlobalNinjaGenerator()->AppendTargetOutputs(target, outputs,
+                                                       config);
 }
 
 void cmLocalNinjaGenerator::AppendTargetDepends(cmGeneratorTarget* target,
                                                 cmNinjaDeps& outputs,
+                                                const std::string& config,
+                                                const std::string& fileConfig,
                                                 cmNinjaTargetDepends depends)
 {
-  this->GetGlobalNinjaGenerator()->AppendTargetDepends(target, outputs,
-                                                       depends);
+  this->GetGlobalNinjaGenerator()->AppendTargetDepends(target, outputs, config,
+                                                       fileConfig, depends);
 }
 
 void cmLocalNinjaGenerator::AppendCustomCommandDeps(
-  cmCustomCommandGenerator const& ccg, cmNinjaDeps& ninjaDeps)
+  cmCustomCommandGenerator const& ccg, cmNinjaDeps& ninjaDeps,
+  const std::string& config)
 {
   for (std::string const& i : ccg.GetDepends()) {
     std::string dep;
-    if (this->GetRealDependency(i, this->GetConfigName(), dep)) {
+    if (this->GetRealDependency(i, config, dep)) {
       ninjaDeps.push_back(
         this->GetGlobalNinjaGenerator()->ConvertToNinjaPath(dep));
     }
@@ -416,6 +476,8 @@
 void cmLocalNinjaGenerator::AppendCustomCommandLines(
   cmCustomCommandGenerator const& ccg, std::vector<std::string>& cmdLines)
 {
+  auto* gg = this->GetGlobalNinjaGenerator();
+
   if (ccg.GetNumberOfCommands() > 0) {
     std::string wd = ccg.GetWorkingDirectory();
     if (wd.empty()) {
@@ -437,8 +499,10 @@
 
   for (unsigned i = 0; i != ccg.GetNumberOfCommands(); ++i) {
     cmdLines.push_back(launcher +
-                       this->ConvertToOutputFormat(ccg.GetCommand(i),
-                                                   cmOutputConverter::SHELL));
+                       this->ConvertToOutputFormat(
+                         ccg.GetCommand(i),
+                         gg->IsMultiConfig() ? cmOutputConverter::NINJAMULTI
+                                             : cmOutputConverter::SHELL));
 
     std::string& cmd = cmdLines.back();
     ccg.AppendArguments(i, cmd);
@@ -446,14 +510,15 @@
 }
 
 void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
-  cmCustomCommand const* cc, const cmNinjaDeps& orderOnlyDeps)
+  cmCustomCommand const* cc, const cmNinjaDeps& orderOnlyDeps,
+  const std::string& config)
 {
   cmGlobalNinjaGenerator* gg = this->GetGlobalNinjaGenerator();
-  if (gg->SeenCustomCommand(cc)) {
+  if (gg->SeenCustomCommand(cc, config)) {
     return;
   }
 
-  cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), this);
+  cmCustomCommandGenerator ccg(*cc, config, this);
 
   const std::vector<std::string>& outputs = ccg.GetOutputs();
   const std::vector<std::string>& byproducts = ccg.GetByproducts();
@@ -484,7 +549,7 @@
   }
 
   cmNinjaDeps ninjaDeps;
-  this->AppendCustomCommandDeps(ccg, ninjaDeps);
+  this->AppendCustomCommandDeps(ccg, ninjaDeps, config);
 
   std::vector<std::string> cmdLines;
   this->AppendCustomCommandLines(ccg, cmdLines);
@@ -495,7 +560,7 @@
     build.Outputs = std::move(ninjaOutputs);
     build.ExplicitDeps = std::move(ninjaDeps);
     build.OrderOnlyDeps = orderOnlyDeps;
-    gg->WriteBuild(this->GetBuildFileStream(), build);
+    gg->WriteBuild(this->GetImplFileStream(config), build);
   } else {
     std::string customStep = cmSystemTools::GetFilenameName(ninjaOutputs[0]);
     // Hash full path to make unique.
@@ -507,8 +572,8 @@
       this->BuildCommandLine(cmdLines, customStep),
       this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0],
       cc->GetDepfile(), cc->GetJobPool(), cc->GetUsesTerminal(),
-      /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, ninjaDeps,
-      orderOnlyDeps);
+      /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, config,
+      ninjaDeps, orderOnlyDeps);
   }
 }
 
@@ -524,7 +589,8 @@
   ins.first->second.insert(target);
 }
 
-void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements()
+void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements(
+  const std::string& config)
 {
   for (cmCustomCommand const* customCommand : this->CustomCommands) {
     auto i = this->CustomCommandTargets.find(customCommand);
@@ -542,15 +608,16 @@
     auto j = i->second.begin();
     assert(j != i->second.end());
     std::vector<std::string> ccTargetDeps;
-    this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(*j,
-                                                                ccTargetDeps);
+    this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(
+      *j, ccTargetDeps, config);
     std::sort(ccTargetDeps.begin(), ccTargetDeps.end());
     ++j;
 
     for (; j != i->second.end(); ++j) {
       std::vector<std::string> jDeps;
       std::vector<std::string> depsIntersection;
-      this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(*j, jDeps);
+      this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(*j, jDeps,
+                                                                  config);
       std::sort(jDeps.begin(), jDeps.end());
       std::set_intersection(ccTargetDeps.begin(), ccTargetDeps.end(),
                             jDeps.begin(), jDeps.end(),
@@ -558,7 +625,7 @@
       ccTargetDeps = depsIntersection;
     }
 
-    this->WriteCustomCommandBuildStatement(i->first, ccTargetDeps);
+    this->WriteCustomCommandBuildStatement(i->first, ccTargetDeps, config);
   }
 }
 
@@ -599,15 +666,13 @@
   return launcher;
 }
 
-void cmLocalNinjaGenerator::AdditionalCleanFiles()
+void cmLocalNinjaGenerator::AdditionalCleanFiles(const std::string& config)
 {
   if (const char* prop_value =
         this->Makefile->GetProperty("ADDITIONAL_CLEAN_FILES")) {
     std::vector<std::string> cleanFiles;
     {
-      cmExpandList(cmGeneratorExpression::Evaluate(
-                     prop_value, this,
-                     this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")),
+      cmExpandList(cmGeneratorExpression::Evaluate(prop_value, this, config),
                    cleanFiles);
     }
     std::string const& binaryDir = this->GetCurrentBinaryDirectory();
@@ -615,7 +680,7 @@
     for (std::string const& cleanFile : cleanFiles) {
       // Support relative paths
       gg->AddAdditionalCleanFile(
-        cmSystemTools::CollapseFullPath(cleanFile, binaryDir));
+        cmSystemTools::CollapseFullPath(cleanFile, binaryDir), config);
     }
   }
 }
diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h
index f64534c..ef160e7 100644
--- a/Source/cmLocalNinjaGenerator.h
+++ b/Source/cmLocalNinjaGenerator.h
@@ -64,9 +64,11 @@
     std::string const& customStep = std::string(),
     cmGeneratorTarget const* target = nullptr) const;
 
-  void AppendTargetOutputs(cmGeneratorTarget* target, cmNinjaDeps& outputs);
+  void AppendTargetOutputs(cmGeneratorTarget* target, cmNinjaDeps& outputs,
+                           const std::string& config);
   void AppendTargetDepends(
-    cmGeneratorTarget* target, cmNinjaDeps& outputs,
+    cmGeneratorTarget* target, cmNinjaDeps& outputs, const std::string& config,
+    const std::string& fileConfig,
     cmNinjaTargetDepends depends = DependOnTargetArtifact);
 
   void AddCustomCommandTarget(cmCustomCommand const* cc,
@@ -74,7 +76,8 @@
   void AppendCustomCommandLines(cmCustomCommandGenerator const& ccg,
                                 std::vector<std::string>& cmdLines);
   void AppendCustomCommandDeps(cmCustomCommandGenerator const& ccg,
-                               cmNinjaDeps& ninjaDeps);
+                               cmNinjaDeps& ninjaDeps,
+                               const std::string& config);
 
 protected:
   std::string ConvertToIncludeReference(
@@ -83,20 +86,25 @@
     bool forceFullPaths = false) override;
 
 private:
-  cmGeneratedFileStream& GetBuildFileStream() const;
+  cmGeneratedFileStream& GetImplFileStream(const std::string& config) const;
+  cmGeneratedFileStream& GetCommonFileStream() const;
   cmGeneratedFileStream& GetRulesFileStream() const;
 
   void WriteBuildFileTop();
   void WriteProjectHeader(std::ostream& os);
   void WriteNinjaRequiredVersion(std::ostream& os);
-  void WriteNinjaFilesInclusion(std::ostream& os);
+  void WriteNinjaConfigurationVariable(std::ostream& os,
+                                       const std::string& config);
+  void WriteNinjaFilesInclusionConfig(std::ostream& os);
+  void WriteNinjaFilesInclusionCommon(std::ostream& os);
   void WriteProcessedMakefile(std::ostream& os);
   void WritePools(std::ostream& os);
 
   void WriteCustomCommandBuildStatement(cmCustomCommand const* cc,
-                                        const cmNinjaDeps& orderOnlyDeps);
+                                        const cmNinjaDeps& orderOnlyDeps,
+                                        const std::string& config);
 
-  void WriteCustomCommandBuildStatements();
+  void WriteCustomCommandBuildStatements(const std::string& config);
 
   std::string MakeCustomLauncher(cmCustomCommandGenerator const& ccg);
 
@@ -104,7 +112,7 @@
                                  std::string const& customStep,
                                  cmGeneratorTarget const* target) const;
 
-  void AdditionalCleanFiles();
+  void AdditionalCleanFiles(const std::string& config);
 
   std::string HomeRelativeOutputPath;
 
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 4a70248..63c6680 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -3,16 +3,18 @@
 #include "cmLocalUnixMakefileGenerator3.h"
 
 #include <algorithm>
+#include <cassert>
 #include <cstdio>
 #include <sstream>
 #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"
@@ -106,6 +108,13 @@
 
 cmLocalUnixMakefileGenerator3::~cmLocalUnixMakefileGenerator3() = default;
 
+std::string cmLocalUnixMakefileGenerator3::GetConfigName() const
+{
+  auto const& configNames = this->GetConfigNames();
+  assert(configNames.size() == 1);
+  return configNames.front();
+}
+
 void cmLocalUnixMakefileGenerator3::Generate()
 {
   // Record whether some options are enabled to avoid checking many
@@ -121,12 +130,12 @@
   // Generate the rule files for each target.
   cmGlobalUnixMakefileGenerator3* gg =
     static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
-  for (cmGeneratorTarget* target : this->GetGeneratorTargets()) {
+  for (const auto& target : this->GetGeneratorTargets()) {
     if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
       continue;
     }
     std::unique_ptr<cmMakefileTargetGenerator> tg(
-      cmMakefileTargetGenerator::New(target));
+      cmMakefileTargetGenerator::New(target.get()));
     if (tg) {
       tg->WriteRuleFiles();
       gg->RecordTargetProgress(tg.get());
@@ -157,15 +166,15 @@
 void cmLocalUnixMakefileGenerator3::GetLocalObjectFiles(
   std::map<std::string, LocalObjectInfo>& localObjectFiles)
 {
-  for (cmGeneratorTarget* gt : this->GetGeneratorTargets()) {
+  for (const auto& gt : this->GetGeneratorTargets()) {
     if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
       continue;
     }
     std::vector<cmSourceFile const*> objectSources;
-    gt->GetObjectSources(objectSources, this->ConfigName);
+    gt->GetObjectSources(objectSources, this->GetConfigName());
     // Compute full path to object file directory for this target.
     std::string dir = cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(),
-                               '/', this->GetTargetDirectory(gt), '/');
+                               '/', this->GetTargetDirectory(gt.get()), '/');
     // Compute the name of each object file.
     for (cmSourceFile const* sf : objectSources) {
       bool hasSourceExtension = true;
@@ -176,7 +185,7 @@
       }
       LocalObjectInfo& info = localObjectFiles[objectName];
       info.HasSourceExtension = hasSourceExtension;
-      info.emplace_back(gt, sf->GetLanguage());
+      info.emplace_back(gt.get(), sf->GetLanguage());
     }
   }
 }
@@ -352,7 +361,7 @@
   // for each target we just provide a rule to cd up to the top and do a make
   // on the target
   std::string localName;
-  for (cmGeneratorTarget* target : this->GetGeneratorTargets()) {
+  for (const auto& target : this->GetGeneratorTargets()) {
     if ((target->GetType() == cmStateEnums::EXECUTABLE) ||
         (target->GetType() == cmStateEnums::STATIC_LIBRARY) ||
         (target->GetType() == cmStateEnums::SHARED_LIBRARY) ||
@@ -362,7 +371,8 @@
       emitted.insert(target->GetName());
 
       // for subdirs add a rule to build this specific target by name.
-      localName = cmStrCat(this->GetRelativeTargetDirectory(target), "/rule");
+      localName =
+        cmStrCat(this->GetRelativeTargetDirectory(target.get()), "/rule");
       commands.clear();
       depends.clear();
 
@@ -383,11 +393,11 @@
       }
 
       // Add a fast rule to build the target
-      std::string makefileName =
-        cmStrCat(this->GetRelativeTargetDirectory(target), "/build.make");
+      std::string makefileName = cmStrCat(
+        this->GetRelativeTargetDirectory(target.get()), "/build.make");
       // make sure the makefile name is suitable for a makefile
       std::string makeTargetName =
-        cmStrCat(this->GetRelativeTargetDirectory(target), "/build");
+        cmStrCat(this->GetRelativeTargetDirectory(target.get()), "/build");
       localName = cmStrCat(target->GetName(), "/fast");
       depends.clear();
       commands.clear();
@@ -400,9 +410,9 @@
 
       // Add a local name for the rule to relink the target before
       // installation.
-      if (target->NeedRelinkBeforeInstall(this->ConfigName)) {
-        makeTargetName =
-          cmStrCat(this->GetRelativeTargetDirectory(target), "/preinstall");
+      if (target->NeedRelinkBeforeInstall(this->GetConfigName())) {
+        makeTargetName = cmStrCat(
+          this->GetRelativeTargetDirectory(target.get()), "/preinstall");
         localName = cmStrCat(target->GetName(), "/preinstall");
         depends.clear();
         commands.clear();
@@ -628,7 +638,7 @@
     << "# The command to remove a file.\n"
     << "RM = "
     << cmakeShellCommand
-    << " -E remove -f\n"
+    << " -E rm -f\n"
     << "\n";
   makefileStream
     << "# Escaping for special characters.\n"
@@ -673,9 +683,15 @@
   if (!this->IsNMake() && !this->IsWatcomWMake() &&
       !this->BorlandMakeCurlyHack) {
     // turn off RCS and SCCS automatic stuff from gmake
-    makefileStream
-      << "# Remove some rules from gmake that .SUFFIXES does not remove.\n"
-      << "SUFFIXES =\n\n";
+    constexpr const char* vcs_rules[] = {
+      "%,v", "RCS/%", "RCS/%,v", "SCCS/s.%", "s.%",
+    };
+    for (auto vcs_rule : vcs_rules) {
+      std::vector<std::string> vcs_depend;
+      vcs_depend.emplace_back(vcs_rule);
+      this->WriteMakeRule(makefileStream, "Disable VCS-based implicit rules.",
+                          "%", vcs_depend, no_commands, false);
+    }
   }
   // Add a fake suffix to keep HP happy.  Must be max 32 chars for SGI make.
   std::vector<std::string> depends;
@@ -849,7 +865,7 @@
   // Add a dependency on the rule file itself unless an option to skip
   // it is specifically enabled by the user or project.
   if (!this->Makefile->IsOn("CMAKE_SKIP_RULE_DEPENDENCY")) {
-    cmAppend(depends, ruleFiles);
+    cm::append(depends, ruleFiles);
   }
 }
 
@@ -857,7 +873,7 @@
   std::vector<std::string>& depends, const std::vector<cmCustomCommand>& ccs)
 {
   for (cmCustomCommand const& cc : ccs) {
-    cmCustomCommandGenerator ccg(cc, this->ConfigName, this);
+    cmCustomCommandGenerator ccg(cc, this->GetConfigName(), this);
     this->AppendCustomDepend(depends, ccg);
   }
 }
@@ -868,7 +884,7 @@
   for (std::string const& d : ccg.GetDepends()) {
     // Lookup the real name of the dependency in case it is a CMake target.
     std::string dep;
-    if (this->GetRealDependency(d, this->ConfigName, dep)) {
+    if (this->GetRealDependency(d, this->GetConfigName(), dep)) {
       depends.push_back(std::move(dep));
     }
   }
@@ -879,7 +895,7 @@
   cmGeneratorTarget* target, std::string const& relative)
 {
   for (cmCustomCommand const& cc : ccs) {
-    cmCustomCommandGenerator ccg(cc, this->ConfigName, this);
+    cmCustomCommandGenerator ccg(cc, this->GetConfigName(), this);
     this->AppendCustomCommand(commands, ccg, target, relative, true);
   }
 }
@@ -1022,7 +1038,7 @@
   this->CreateCDCommand(commands1, dir, relative);
 
   // push back the custom commands
-  cmAppend(commands, commands1);
+  cm::append(commands, commands1);
 }
 
 void cmLocalUnixMakefileGenerator3::AppendCleanCommand(
@@ -1093,8 +1109,7 @@
     return;
   }
 
-  cmLocalGenerator* rootLG =
-    this->GetGlobalGenerator()->GetLocalGenerators().at(0);
+  const auto& rootLG = this->GetGlobalGenerator()->GetLocalGenerators().at(0);
   std::string const& binaryDir = rootLG->GetCurrentBinaryDirectory();
   std::string const& currentBinaryDir = this->GetCurrentBinaryDirectory();
   std::string cleanfile =
@@ -1551,8 +1566,8 @@
   this->WriteDivider(ruleFileStream);
   ruleFileStream << "# Targets provided globally by CMake.\n"
                  << "\n";
-  const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
-  for (cmGeneratorTarget* gt : targets) {
+  const auto& targets = this->GetGeneratorTargets();
+  for (const auto& gt : targets) {
     if (gt->GetType() == cmStateEnums::GLOBAL_TARGET) {
       std::string targetString =
         "Special rule for the target " + gt->GetName();
@@ -1564,8 +1579,8 @@
         text = "Running external command ...";
       }
       depends.reserve(gt->GetUtilities().size());
-      for (BT<std::string> const& u : gt->GetUtilities()) {
-        depends.push_back(u.Value);
+      for (BT<std::pair<std::string, bool>> const& u : gt->GetUtilities()) {
+        depends.push_back(u.Value.first);
       }
       this->AppendEcho(commands, text,
                        cmLocalUnixMakefileGenerator3::EchoGlobal);
@@ -1573,10 +1588,10 @@
       // Global targets store their rules in pre- and post-build commands.
       this->AppendCustomDepends(depends, gt->GetPreBuildCommands());
       this->AppendCustomDepends(depends, gt->GetPostBuildCommands());
-      this->AppendCustomCommands(commands, gt->GetPreBuildCommands(), gt,
+      this->AppendCustomCommands(commands, gt->GetPreBuildCommands(), gt.get(),
                                  this->GetCurrentBinaryDirectory());
-      this->AppendCustomCommands(commands, gt->GetPostBuildCommands(), gt,
-                                 this->GetCurrentBinaryDirectory());
+      this->AppendCustomCommands(commands, gt->GetPostBuildCommands(),
+                                 gt.get(), this->GetCurrentBinaryDirectory());
       std::string targetName = gt->GetName();
       this->WriteMakeRule(ruleFileStream, targetString.c_str(), targetName,
                           depends, commands, true);
@@ -1839,7 +1854,7 @@
 
     // Build a list of preprocessor definitions for the target.
     std::set<std::string> defines;
-    this->GetTargetDefines(target, this->ConfigName, implicitLang.first,
+    this->GetTargetDefines(target, this->GetConfigName(), implicitLang.first,
                            defines);
     if (!defines.empty()) {
       /* clang-format off */
@@ -1863,11 +1878,11 @@
     std::vector<std::string> includes;
 
     this->GetIncludeDirectories(includes, target, implicitLang.first,
-                                this->ConfigName);
+                                this->GetConfigName());
     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 << "  \""
@@ -1957,18 +1972,18 @@
 }
 
 void cmLocalUnixMakefileGenerator3::WriteCMakeArgument(std::ostream& os,
-                                                       const char* s)
+                                                       const std::string& s)
 {
   // Write the given string to the stream with escaping to get it back
   // into CMake through the lexical scanner.
   os << "\"";
-  for (const char* c = s; *c; ++c) {
-    if (*c == '\\') {
+  for (char c : s) {
+    if (c == '\\') {
       os << "\\\\";
-    } else if (*c == '"') {
+    } else if (c == '"') {
       os << "\\\"";
     } else {
-      os << *c;
+      os << c;
     }
   }
   os << "\"";
diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h
index f12ae8b..68eeb29 100644
--- a/Source/cmLocalUnixMakefileGenerator3.h
+++ b/Source/cmLocalUnixMakefileGenerator3.h
@@ -33,6 +33,8 @@
   cmLocalUnixMakefileGenerator3(cmGlobalGenerator* gg, cmMakefile* mf);
   ~cmLocalUnixMakefileGenerator3() override;
 
+  std::string GetConfigName() const;
+
   void ComputeHomeRelativeOutputPath() override;
 
   /**
@@ -75,7 +77,7 @@
   void SetBorlandMakeCurlyHack(bool b) { this->BorlandMakeCurlyHack = b; }
 
   // used in writing out Cmake files such as WriteDirectoryInformation
-  static void WriteCMakeArgument(std::ostream& os, const char* s);
+  static void WriteCMakeArgument(std::ostream& os, const std::string& s);
 
   /** creates the common disclaimer text at the top of each makefile */
   void WriteDisclaimer(std::ostream& os);
diff --git a/Source/cmLocalVisualStudio10Generator.cxx b/Source/cmLocalVisualStudio10Generator.cxx
index f3d828b..02e2c6d 100644
--- a/Source/cmLocalVisualStudio10Generator.cxx
+++ b/Source/cmLocalVisualStudio10Generator.cxx
@@ -2,8 +2,11 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmLocalVisualStudio10Generator.h"
 
+#include <cmext/algorithm>
+
 #include "cm_expat.h"
 
+#include "cmAlgorithms.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalVisualStudio10Generator.h"
 #include "cmMakefile.h"
@@ -101,10 +104,11 @@
 
 void cmLocalVisualStudio10Generator::Generate()
 {
-  std::vector<cmGeneratorTarget*> remaining = this->GetGeneratorTargets();
+  std::vector<cmGeneratorTarget*> remaining;
+  cm::append(remaining, this->GetGeneratorTargets());
   for (auto& t : remaining) {
     if (t) {
-      GenerateTargetsDepthFirst(t, remaining);
+      this->GenerateTargetsDepthFirst(t, remaining);
     }
   }
   this->WriteStampFiles();
@@ -124,8 +128,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);
 }
 
 const char* cmLocalVisualStudio10Generator::ReportErrorLabel() const
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index e771a4a..9aa3991 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -64,8 +64,8 @@
 void cmLocalVisualStudio7Generator::AddHelperCommands()
 {
   // Now create GUIDs for targets
-  const std::vector<cmGeneratorTarget*>& tgts = this->GetGeneratorTargets();
-  for (cmGeneratorTarget const* l : tgts) {
+  const auto& tgts = this->GetGeneratorTargets();
+  for (const auto& l : tgts) {
     if (l->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
       continue;
     }
@@ -89,8 +89,8 @@
   // Visual Studio .NET 2003 Service Pack 1 will not run post-build
   // commands for targets in which no sources are built.  Add dummy
   // rules to force these targets to build.
-  const std::vector<cmGeneratorTarget*>& tgts = this->GetGeneratorTargets();
-  for (cmGeneratorTarget* l : tgts) {
+  const auto& tgts = this->GetGeneratorTargets();
+  for (auto& l : tgts) {
     if (l->GetType() == cmStateEnums::GLOBAL_TARGET) {
       std::vector<std::string> no_depends;
       cmCustomCommandLines force_commands =
@@ -102,9 +102,9 @@
             this->Makefile->GetOrCreateGeneratedSource(force)) {
         sf->SetProperty("SYMBOLIC", "1");
       }
-      if (cmSourceFile* file = this->Makefile->AddCustomCommandToOutput(
-            force.c_str(), no_depends, no_main_dependency, force_commands, " ",
-            0, true)) {
+      if (cmSourceFile* file = this->AddCustomCommandToOutput(
+            force, no_depends, no_main_dependency, force_commands, " ",
+            nullptr, true)) {
         l->AddSource(file->ResolveFullPath());
       }
     }
@@ -125,17 +125,17 @@
   }
 
   // Get the set of targets in this directory.
-  const std::vector<cmGeneratorTarget*>& tgts = this->GetGeneratorTargets();
+  const auto& tgts = this->GetGeneratorTargets();
 
   // Create the project file for each target.
-  for (cmGeneratorTarget* l : tgts) {
+  for (const auto& l : tgts) {
     if (l->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
       continue;
     }
     // INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace
     // so don't build a projectfile for it
     if (!l->GetProperty("EXTERNAL_MSPROJECT")) {
-      this->CreateSingleVCProj(l->GetName(), l);
+      this->CreateSingleVCProj(l->GetName(), l.get());
     }
   }
 }
@@ -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";
@@ -194,7 +194,7 @@
   }
 
   // add to the list of projects
-  target->Target->SetProperty("GENERATOR_FILE_NAME", lname.c_str());
+  target->Target->SetProperty("GENERATOR_FILE_NAME", lname);
   // create the dsp.cmake file
   std::string fname;
   fname = cmStrCat(this->GetCurrentBinaryDirectory(), '/', lname);
@@ -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());
-  this->Makefile->AddCustomCommandToOutput(
-    fullpathStampName, listFiles, makefileIn, commandLines, comment.c_str(),
-    no_working_directory, true, false);
-  if (cmSourceFile* file = this->Makefile->GetSource(makefileIn.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)) {
     // 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";
 }
@@ -580,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:
@@ -733,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"
@@ -788,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(
@@ -802,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
@@ -879,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 << "\"";
     }
@@ -946,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;
@@ -985,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: {
@@ -1015,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:
@@ -1057,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=\"";
@@ -1066,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";
       }
@@ -1078,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";
       }
@@ -1086,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\"";
       }
@@ -1132,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()) {
@@ -1167,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 << "\"";
       }
@@ -1175,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:
@@ -1256,8 +1254,8 @@
   for (auto const& lib : libs) {
     if (lib.IsPath) {
       std::string rel =
-        lg->MaybeConvertToRelativePath(currentBinDir, lib.Value.Value.c_str());
-      fout << lg->ConvertToXMLOutputPath(rel.c_str()) << " ";
+        lg->MaybeConvertToRelativePath(currentBinDir, lib.Value.Value);
+      fout << lg->ConvertToXMLOutputPath(rel) << " ";
     } else if (!lib.Target ||
                lib.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
       fout << lib.Value.Value << " ";
@@ -1282,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 = " ";
     }
   }
@@ -1303,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;
       }
@@ -1314,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 = ",";
   }
 }
@@ -1337,7 +1333,7 @@
   // Add CMakeLists.txt file with rule to re-run CMake for user convenience.
   if (target->GetType() != cmStateEnums::GLOBAL_TARGET &&
       target->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
-    if (cmSourceFile const* sf = this->CreateVCProjBuildRule()) {
+    if (cmSourceFile* sf = this->CreateVCProjBuildRule()) {
       cmGeneratorTarget::AllConfigSource acs;
       acs.Source = sf;
       acs.Kind = cmGeneratorTarget::SourceKindCustomCommand;
@@ -1518,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") ||
@@ -1629,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";
@@ -1759,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()) {
@@ -1789,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) << ";";
         }
       }
     }
@@ -1802,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 = ";";
       }
     }
@@ -1948,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";
@@ -1983,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")) {
@@ -2037,7 +2033,7 @@
 }
 
 std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPath(
-  const char* path)
+  const std::string& path)
 {
   std::string ret =
     this->ConvertToOutputFormat(path, cmOutputConverter::SHELL);
@@ -2049,7 +2045,7 @@
 }
 
 std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPathSingle(
-  const char* path)
+  const std::string& path)
 {
   std::string ret =
     this->ConvertToOutputFormat(path, cmOutputConverter::SHELL);
@@ -2061,7 +2057,7 @@
 }
 
 void cmVS7GeneratorOptions::OutputFlag(std::ostream& fout, int indent,
-                                       const char* flag,
+                                       const std::string& flag,
                                        const std::string& content)
 {
   fout.fill('\t');
@@ -2130,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 671783f..745766c 100644
--- a/Source/cmLocalVisualStudio7Generator.h
+++ b/Source/cmLocalVisualStudio7Generator.h
@@ -30,7 +30,7 @@
     : cmVisualStudioGeneratorOptions(lg, tool, table, extraTable)
   {
   }
-  void OutputFlag(std::ostream& fout, int indent, const char* tag,
+  void OutputFlag(std::ostream& fout, int indent, const std::string& tag,
                   const std::string& content) override;
 };
 
@@ -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/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx
index 336e3a5..8d50898 100644
--- a/Source/cmLocalVisualStudioGenerator.cxx
+++ b/Source/cmLocalVisualStudioGenerator.cxx
@@ -104,8 +104,8 @@
   std::vector<std::string> no_depends;
   cmCustomCommandLines commands = cmMakeSingleCommandLine(
     { cmSystemTools::GetCMakeCommand(), "-E", "make_directory", impDir });
-  pcc.reset(new cmCustomCommand(0, no_output, no_byproducts, no_depends,
-                                commands, 0, 0));
+  pcc.reset(new cmCustomCommand(no_output, no_byproducts, no_depends, commands,
+                                cmListFileBacktrace(), nullptr, nullptr));
   pcc->SetEscapeOldStyle(false);
   pcc->SetEscapeAllowMakeVars(true);
   return pcc;
diff --git a/Source/cmLocalXCodeGenerator.cxx b/Source/cmLocalXCodeGenerator.cxx
index 5a06d4a..ac0d35e 100644
--- a/Source/cmLocalXCodeGenerator.cxx
+++ b/Source/cmLocalXCodeGenerator.cxx
@@ -40,7 +40,7 @@
 {
   cmLocalGenerator::Generate();
 
-  for (auto target : this->GetGeneratorTargets()) {
+  for (const auto& target : this->GetGeneratorTargets()) {
     target->HasMacOSXRpathInstallNameDir("");
   }
 }
@@ -49,7 +49,7 @@
 {
   cmLocalGenerator::GenerateInstallRules();
 
-  for (auto target : this->GetGeneratorTargets()) {
+  for (const auto& target : this->GetGeneratorTargets()) {
     target->HasMacOSXRpathInstallNameDir("");
   }
 }
diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx
index ba9947a..0b0d9ac 100644
--- a/Source/cmMacroCommand.cxx
+++ b/Source/cmMacroCommand.cxx
@@ -7,10 +7,10 @@
 
 #include <cm/memory>
 #include <cm/string_view>
+#include <cmext/algorithm>
 
 #include "cm_static_string_view.hxx"
 
-#include "cmAlgorithms.h"
 #include "cmExecutionStatus.h"
 #include "cmFunctionBlocker.h"
 #include "cmListFileCache.h"
@@ -167,7 +167,7 @@
                                     cmExecutionStatus& status)
 {
   cmMakefile& mf = status.GetMakefile();
-  mf.AppendProperty("MACROS", this->Args[0].c_str());
+  mf.AppendProperty("MACROS", this->Args[0]);
   // create a new command and add it to cmake
   cmMacroHelperCommand f;
   f.Args = this->Args;
@@ -190,7 +190,7 @@
   // create a function blocker
   {
     auto fb = cm::make_unique<cmMacroFunctionBlocker>();
-    cmAppend(fb->Args, args);
+    cm::append(fb->Args, args);
     status.GetMakefile().AddFunctionBlocker(std::move(fb));
   }
   return true;
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index f143ef7..18689fa 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -15,10 +15,15 @@
 
 #include <cm/iterator>
 #include <cm/memory>
+#include <cm/optional>
+#include <cm/vector>
+#include <cmext/algorithm>
 
 #include "cmsys/FStream.hxx"
 #include "cmsys/RegularExpression.hxx"
 
+#include "cm_jsoncpp_value.h"
+#include "cm_jsoncpp_writer.h"
 #include "cm_sys_stat.h"
 
 #include "cmAlgorithms.h"
@@ -27,6 +32,7 @@
 #include "cmCustomCommandLines.h"
 #include "cmExecutionStatus.h"
 #include "cmExpandedCommandArgument.h" // IWYU pragma: keep
+#include "cmExportBuildFileGenerator.h"
 #include "cmFileLockPool.h"
 #include "cmFunctionBlocker.h"
 #include "cmGeneratedFileStream.h"
@@ -36,6 +42,7 @@
 #include "cmInstallGenerator.h" // IWYU pragma: keep
 #include "cmInstallSubdirectoryGenerator.h"
 #include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
 #include "cmMessageType.h"
 #include "cmRange.h"
 #include "cmSourceFile.h"
@@ -117,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
 {
@@ -133,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);
 }
@@ -146,7 +145,7 @@
       this->ExecutionStatusStack.back()->SetNestedError();
     }
   }
-  this->GetCMakeInstance()->IssueMessage(t, text, this->GetBacktrace());
+  this->GetCMakeInstance()->IssueMessage(t, text, this->Backtrace);
 }
 
 bool cmMakefile::CheckCMP0037(std::string const& targetName,
@@ -313,21 +312,54 @@
   }
 
   std::ostringstream msg;
-  msg << full_path << "(" << lff.Line << "):  ";
-  msg << lff.Name.Original << "(";
-  bool expand = this->GetCMakeInstance()->GetTraceExpand();
+  std::vector<std::string> args;
   std::string temp;
+  bool expand = this->GetCMakeInstance()->GetTraceExpand();
+
+  args.reserve(lff.Arguments.size());
   for (cmListFileArgument const& arg : lff.Arguments) {
     if (expand) {
       temp = arg.Value;
       this->ExpandVariablesInString(temp);
-      msg << temp;
+      args.push_back(temp);
     } else {
-      msg << arg.Value;
+      args.push_back(arg.Value);
     }
-    msg << " ";
   }
-  msg << ")";
+
+  switch (this->GetCMakeInstance()->GetTraceFormat()) {
+    case cmake::TraceFormat::TRACE_JSON_V1: {
+#ifndef CMAKE_BOOTSTRAP
+      Json::Value val;
+      Json::StreamWriterBuilder builder;
+      builder["indentation"] = "";
+      val["file"] = full_path;
+      val["line"] = static_cast<Json::Value::Int64>(lff.Line);
+      val["cmd"] = lff.Name.Original;
+      val["args"] = Json::Value(Json::arrayValue);
+      for (std::string const& arg : args) {
+        val["args"].append(arg);
+      }
+      val["time"] = cmSystemTools::GetTime();
+      val["frame"] =
+        static_cast<Json::Value::UInt64>(this->ExecutionStatusStack.size());
+      msg << Json::writeString(builder, val);
+#endif
+      break;
+    }
+    case cmake::TraceFormat::TRACE_HUMAN:
+      msg << full_path << "(" << lff.Line << "):  ";
+      msg << lff.Name.Original << "(";
+
+      for (std::string const& arg : args) {
+        msg << arg << " ";
+      }
+      msg << ")";
+      break;
+    case cmake::TraceFormat::TRACE_UNDEFINED:
+      msg << "INTERNAL ERROR: Trace format is TRACE_UNDEFINED";
+      break;
+  }
 
   auto& f = this->GetCMakeInstance()->GetTraceFile();
   if (f) {
@@ -737,18 +769,19 @@
   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;
 }
 
-std::vector<cmExportBuildFileGenerator*>
+std::vector<std::unique_ptr<cmExportBuildFileGenerator>> const&
 cmMakefile::GetExportBuildFileGenerators() const
 {
   return this->ExportBuildFileGenerators;
@@ -757,16 +790,21 @@
 void cmMakefile::RemoveExportBuildFileGeneratorCMP0024(
   cmExportBuildFileGenerator* gen)
 {
-  auto it = std::find(this->ExportBuildFileGenerators.begin(),
-                      this->ExportBuildFileGenerators.end(), gen);
+  auto it =
+    std::find_if(this->ExportBuildFileGenerators.begin(),
+                 this->ExportBuildFileGenerators.end(),
+                 [gen](std::unique_ptr<cmExportBuildFileGenerator> const& p) {
+                   return p.get() == gen;
+                 });
   if (it != this->ExportBuildFileGenerators.end()) {
     this->ExportBuildFileGenerators.erase(it);
   }
 }
 
-void cmMakefile::AddExportBuildFileGenerator(cmExportBuildFileGenerator* gen)
+void cmMakefile::AddExportBuildFileGenerator(
+  std::unique_ptr<cmExportBuildFileGenerator> gen)
 {
-  this->ExportBuildFileGenerators.push_back(gen);
+  this->ExportBuildFileGenerators.emplace_back(std::move(gen));
 }
 
 namespace {
@@ -780,38 +818,42 @@
 };
 }
 
-void cmMakefile::AddFinalAction(FinalAction action)
+void cmMakefile::AddGeneratorAction(GeneratorAction action)
 {
-  this->FinalActions.push_back(std::move(action));
+  assert(!this->GeneratorActionsInvoked);
+  this->GeneratorActions.emplace_back(std::move(action), this->Backtrace);
 }
 
-void cmMakefile::FinalPass()
+void cmMakefile::DoGenerate(cmLocalGenerator& lg)
 {
   // do all the variable expansions here
   this->ExpandVariablesCMP0019();
 
   // give all the commands a chance to do something
   // after the file has been parsed before generation
-  for (FinalAction& action : this->FinalActions) {
-    action(*this);
+  for (const BT<GeneratorAction>& action : this->GeneratorActions) {
+    action.Value(lg, action.Backtrace);
   }
+  this->GeneratorActionsInvoked = true;
+  this->DelayedOutputFiles.clear();
+  this->DelayedOutputFilesHaveGenex = false;
 
   // go through all configured files and see which ones still exist.
   // 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
-void cmMakefile::ConfigureFinalPass()
+void cmMakefile::Generate(cmLocalGenerator& lg)
 {
-  this->FinalPass();
+  this->DoGenerate(lg);
   const char* oldValue = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
   if (oldValue &&
       cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, oldValue, "2.4")) {
@@ -825,6 +867,39 @@
   }
 }
 
+namespace {
+// There are still too many implicit backtraces through cmMakefile.  As a
+// workaround we reset the backtrace temporarily.
+struct BacktraceGuard
+{
+  BacktraceGuard(cmListFileBacktrace& lfbt, cmListFileBacktrace current)
+    : Backtrace(lfbt)
+    , Previous(lfbt)
+  {
+    this->Backtrace = std::move(current);
+  }
+
+  ~BacktraceGuard() { this->Backtrace = std::move(Previous); }
+
+private:
+  cmListFileBacktrace& Backtrace;
+  cmListFileBacktrace Previous;
+};
+
+cm::optional<std::string> MakeOptionalString(const char* str)
+{
+  if (str) {
+    return str;
+  }
+  return cm::nullopt;
+}
+
+const char* GetCStrOrNull(const cm::optional<std::string>& str)
+{
+  return str ? str->c_str() : nullptr;
+}
+}
+
 bool cmMakefile::ValidateCustomCommand(
   const cmCustomCommandLines& commandLines) const
 {
@@ -842,7 +917,8 @@
 }
 
 cmTarget* cmMakefile::GetCustomCommandTarget(
-  const std::string& target, cmObjectLibraryCommands objLibCommands) const
+  const std::string& target, cmObjectLibraryCommands objLibCommands,
+  const cmListFileBacktrace& lfbt) const
 {
   // Find the target to which to add the custom command.
   auto ti = this->Targets.find(target);
@@ -876,7 +952,7 @@
         e << "No TARGET '" << target
           << "' has been created in this directory.";
       }
-      this->IssueMessage(messageType, e.str());
+      this->GetCMakeInstance()->IssueMessage(messageType, e.str(), lfbt);
     }
 
     return nullptr;
@@ -889,7 +965,8 @@
     e << "Target \"" << target
       << "\" is an OBJECT library "
          "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
-    this->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(),
+                                           lfbt);
     return nullptr;
   }
   if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
@@ -897,7 +974,8 @@
     e << "Target \"" << target
       << "\" is an INTERFACE library "
          "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
-    this->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(),
+                                           lfbt);
     return nullptr;
   }
 
@@ -910,9 +988,10 @@
   const cmCustomCommandLines& commandLines, cmCustomCommandType type,
   const char* comment, const char* workingDir, bool escapeOldStyle,
   bool uses_terminal, const std::string& depfile, const std::string& job_pool,
-  bool command_expand_lists, cmObjectLibraryCommands objLibCommands)
+  bool command_expand_lists)
 {
-  cmTarget* t = this->GetCustomCommandTarget(target, objLibCommands);
+  cmTarget* t = this->GetCustomCommandTarget(
+    target, cmObjectLibraryCommands::Reject, this->Backtrace);
 
   // Validate custom commands.
   if (!t || !this->ValidateCustomCommand(commandLines)) {
@@ -920,175 +999,83 @@
   }
 
   // Always create the byproduct sources and mark them generated.
-  this->CreateGeneratedSources(byproducts);
+  this->CreateGeneratedByproducts(byproducts);
 
-  this->CommitCustomCommandToTarget(
-    t, byproducts, depends, commandLines, type, comment, workingDir,
-    escapeOldStyle, uses_terminal, depfile, job_pool, command_expand_lists);
+  // Strings could be moved into the callback function with C++14.
+  cm::optional<std::string> commentStr = MakeOptionalString(comment);
+  cm::optional<std::string> workingStr = MakeOptionalString(workingDir);
+
+  // Dispatch command creation to allow generator expressions in outputs.
+  this->AddGeneratorAction([=](cmLocalGenerator& lg,
+                               const cmListFileBacktrace& lfbt) {
+    BacktraceGuard guard(this->Backtrace, lfbt);
+    detail::AddCustomCommandToTarget(
+      lg, lfbt, cmCommandOrigin::Project, t, byproducts, depends, commandLines,
+      type, GetCStrOrNull(commentStr), GetCStrOrNull(workingStr),
+      escapeOldStyle, uses_terminal, depfile, job_pool, command_expand_lists);
+  });
 
   return t;
 }
 
-void cmMakefile::CommitCustomCommandToTarget(
-  cmTarget* target, const std::vector<std::string>& byproducts,
-  const std::vector<std::string>& depends,
-  const cmCustomCommandLines& commandLines, cmCustomCommandType type,
-  const char* comment, const char* workingDir, bool escapeOldStyle,
-  bool uses_terminal, const std::string& depfile, const std::string& job_pool,
-  bool command_expand_lists)
-{
-  // Add the command to the appropriate build step for the target.
-  std::vector<std::string> no_output;
-  cmCustomCommand cc(this, no_output, byproducts, depends, commandLines,
-                     comment, workingDir);
-  cc.SetEscapeOldStyle(escapeOldStyle);
-  cc.SetEscapeAllowMakeVars(true);
-  cc.SetUsesTerminal(uses_terminal);
-  cc.SetCommandExpandLists(command_expand_lists);
-  cc.SetDepfile(depfile);
-  cc.SetJobPool(job_pool);
-  switch (type) {
-    case cmCustomCommandType::PRE_BUILD:
-      target->AddPreBuildCommand(std::move(cc));
-      break;
-    case cmCustomCommandType::PRE_LINK:
-      target->AddPreLinkCommand(std::move(cc));
-      break;
-    case cmCustomCommandType::POST_BUILD:
-      target->AddPostBuildCommand(std::move(cc));
-      break;
-  }
-
-  this->AddTargetByproducts(target, byproducts);
-}
-
-cmSourceFile* cmMakefile::AddCustomCommandToOutput(
+void cmMakefile::AddCustomCommandToOutput(
   const std::string& output, const std::vector<std::string>& depends,
   const std::string& main_dependency, const cmCustomCommandLines& commandLines,
-  const char* comment, const char* workingDir, bool replace,
-  bool escapeOldStyle, bool uses_terminal, bool command_expand_lists,
-  const std::string& depfile, const std::string& job_pool)
+  const char* comment, const char* workingDir,
+  const CommandSourceCallback& callback, bool replace, bool escapeOldStyle,
+  bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+  const std::string& job_pool)
 {
-  std::vector<std::string> outputs;
-  outputs.push_back(output);
   std::vector<std::string> no_byproducts;
   cmImplicitDependsList no_implicit_depends;
-  return this->AddCustomCommandToOutput(
-    outputs, no_byproducts, depends, main_dependency, no_implicit_depends,
-    commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal,
-    command_expand_lists, depfile, job_pool);
+  this->AddCustomCommandToOutput(
+    { output }, no_byproducts, depends, main_dependency, no_implicit_depends,
+    commandLines, comment, workingDir, callback, replace, escapeOldStyle,
+    uses_terminal, command_expand_lists, depfile, job_pool);
 }
 
-cmSourceFile* cmMakefile::AddCustomCommandToOutput(
+void cmMakefile::AddCustomCommandToOutput(
   const std::vector<std::string>& outputs,
   const std::vector<std::string>& byproducts,
   const std::vector<std::string>& depends, const std::string& main_dependency,
   const cmImplicitDependsList& implicit_depends,
   const cmCustomCommandLines& commandLines, const char* comment,
-  const char* workingDir, bool replace, bool escapeOldStyle,
-  bool uses_terminal, bool command_expand_lists, const std::string& depfile,
-  const std::string& job_pool)
+  const char* workingDir, const CommandSourceCallback& callback, bool replace,
+  bool escapeOldStyle, bool uses_terminal, bool command_expand_lists,
+  const std::string& depfile, const std::string& job_pool)
 {
   // Make sure there is at least one output.
   if (outputs.empty()) {
     cmSystemTools::Error("Attempt to add a custom rule with no output!");
-    return nullptr;
+    return;
   }
 
   // Validate custom commands.
   if (!this->ValidateCustomCommand(commandLines)) {
-    return nullptr;
+    return;
   }
 
   // Always create the output sources and mark them generated.
-  this->CreateGeneratedSources(outputs);
-  this->CreateGeneratedSources(byproducts);
+  this->CreateGeneratedOutputs(outputs);
+  this->CreateGeneratedByproducts(byproducts);
 
-  return this->CommitCustomCommandToOutput(
-    outputs, byproducts, depends, main_dependency, implicit_depends,
-    commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal,
-    command_expand_lists, depfile, job_pool);
-}
+  // Strings could be moved into the callback function with C++14.
+  cm::optional<std::string> commentStr = MakeOptionalString(comment);
+  cm::optional<std::string> workingStr = MakeOptionalString(workingDir);
 
-cmSourceFile* cmMakefile::CommitCustomCommandToOutput(
-  const std::vector<std::string>& outputs,
-  const std::vector<std::string>& byproducts,
-  const std::vector<std::string>& depends, const std::string& main_dependency,
-  const cmImplicitDependsList& implicit_depends,
-  const cmCustomCommandLines& commandLines, const char* comment,
-  const char* workingDir, bool replace, bool escapeOldStyle,
-  bool uses_terminal, bool command_expand_lists, const std::string& depfile,
-  const std::string& job_pool)
-{
-  // Choose a source file on which to store the custom command.
-  cmSourceFile* file = nullptr;
-  if (!commandLines.empty() && !main_dependency.empty()) {
-    // The main dependency was specified.  Use it unless a different
-    // custom command already used it.
-    file = this->GetSource(main_dependency);
-    if (file && file->GetCustomCommand() && !replace) {
-      // The main dependency already has a custom command.
-      if (commandLines == file->GetCustomCommand()->GetCommandLines()) {
-        // The existing custom command is identical.  Silently ignore
-        // the duplicate.
-        return file;
-      }
-      // The existing custom command is different.  We need to
-      // generate a rule file for this new command.
-      file = nullptr;
-    } else if (!file) {
-      file = this->CreateSource(main_dependency);
+  // Dispatch command creation to allow generator expressions in outputs.
+  this->AddGeneratorAction([=](cmLocalGenerator& lg,
+                               const cmListFileBacktrace& lfbt) {
+    BacktraceGuard guard(this->Backtrace, lfbt);
+    cmSourceFile* sf = detail::AddCustomCommandToOutput(
+      lg, lfbt, cmCommandOrigin::Project, outputs, byproducts, depends,
+      main_dependency, implicit_depends, commandLines,
+      GetCStrOrNull(commentStr), GetCStrOrNull(workingStr), replace,
+      escapeOldStyle, uses_terminal, command_expand_lists, depfile, job_pool);
+    if (callback && sf) {
+      callback(sf);
     }
-  }
-
-  // Generate a rule file if the main dependency is not available.
-  if (!file) {
-    cmGlobalGenerator* gg = this->GetGlobalGenerator();
-
-    // Construct a rule file associated with the first output produced.
-    std::string outName = gg->GenerateRuleFile(outputs[0]);
-
-    // Check if the rule file already exists.
-    file = this->GetSource(outName, cmSourceFileLocationKind::Known);
-    if (file && file->GetCustomCommand() && !replace) {
-      // The rule file already exists.
-      if (commandLines != file->GetCustomCommand()->GetCommandLines()) {
-        cmSystemTools::Error("Attempt to add a custom rule to output \"" +
-                             outName + "\" which already has a custom rule.");
-      }
-      return file;
-    }
-
-    // Create a cmSourceFile for the rule file.
-    if (!file) {
-      file =
-        this->CreateSource(outName, true, cmSourceFileLocationKind::Known);
-    }
-    file->SetProperty("__CMAKE_RULE", "1");
-  }
-
-  // Attach the custom command to the file.
-  if (file) {
-    // Construct a complete list of dependencies.
-    std::vector<std::string> depends2(depends);
-    if (!main_dependency.empty()) {
-      depends2.push_back(main_dependency);
-    }
-
-    std::unique_ptr<cmCustomCommand> cc = cm::make_unique<cmCustomCommand>(
-      this, outputs, byproducts, depends2, commandLines, comment, workingDir);
-    cc->SetEscapeOldStyle(escapeOldStyle);
-    cc->SetEscapeAllowMakeVars(true);
-    cc->SetImplicitDepends(implicit_depends);
-    cc->SetUsesTerminal(uses_terminal);
-    cc->SetCommandExpandLists(command_expand_lists);
-    cc->SetDepfile(depfile);
-    cc->SetJobPool(job_pool);
-    file->SetCustomCommand(std::move(cc));
-
-    this->AddSourceOutputs(file, outputs, byproducts);
-  }
-  return file;
+  });
 }
 
 void cmMakefile::AddCustomCommandOldStyle(
@@ -1136,11 +1123,8 @@
   if (sourceFiles.find(source)) {
     // The source looks like a real file.  Use it as the main dependency.
     for (std::string const& output : outputs) {
-      cmSourceFile* sf = this->AddCustomCommandToOutput(
-        output, depends, source, commandLines, comment, nullptr);
-      if (sf) {
-        addRuleFileToTarget(sf);
-      }
+      this->AddCustomCommandToOutput(output, depends, source, commandLines,
+                                     comment, nullptr, addRuleFileToTarget);
     }
   } else {
     std::string no_main_dependency;
@@ -1149,11 +1133,9 @@
 
     // The source may not be a real file.  Do not use a main dependency.
     for (std::string const& output : outputs) {
-      cmSourceFile* sf = this->AddCustomCommandToOutput(
-        output, depends2, no_main_dependency, commandLines, comment, nullptr);
-      if (sf) {
-        addRuleFileToTarget(sf);
-      }
+      this->AddCustomCommandToOutput(output, depends2, no_main_dependency,
+                                     commandLines, comment, nullptr,
+                                     addRuleFileToTarget);
     }
   }
 }
@@ -1170,29 +1152,18 @@
 
   // Validate custom commands.
   if (this->ValidateCustomCommand(commandLines)) {
-    // Add command factory to allow generator expressions in output.
-    this->CommitAppendCustomCommandToOutput(output, depends, implicit_depends,
-                                            commandLines);
+    // Dispatch command creation to allow generator expressions in outputs.
+    this->AddGeneratorAction(
+      [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) {
+        BacktraceGuard guard(this->Backtrace, lfbt);
+        detail::AppendCustomCommandToOutput(lg, lfbt, output, depends,
+                                            implicit_depends, commandLines);
+      });
   }
 
   return true;
 }
 
-void cmMakefile::CommitAppendCustomCommandToOutput(
-  const std::string& output, const std::vector<std::string>& depends,
-  const cmImplicitDependsList& implicit_depends,
-  const cmCustomCommandLines& commandLines)
-{
-  // Lookup an existing command.
-  if (cmSourceFile* sf = this->GetSourceFileWithOutput(output)) {
-    if (cmCustomCommand* cc = sf->GetCustomCommand()) {
-      cc->AppendCommands(commandLines);
-      cc->AppendDepends(depends);
-      cc->AppendImplicitDepends(implicit_depends);
-    }
-  }
-}
-
 cmUtilityOutput cmMakefile::GetUtilityOutput(cmTarget* target)
 {
   std::string force = cmStrCat(this->GetCurrentBinaryDirectory(),
@@ -1215,15 +1186,14 @@
 }
 
 cmTarget* cmMakefile::AddUtilityCommand(
-  const std::string& utilityName, cmCommandOrigin origin, bool excludeFromAll,
-  const char* workingDirectory, const std::vector<std::string>& byproducts,
+  const std::string& utilityName, bool excludeFromAll, const char* workingDir,
+  const std::vector<std::string>& byproducts,
   const std::vector<std::string>& depends,
   const cmCustomCommandLines& commandLines, bool escapeOldStyle,
   const char* comment, bool uses_terminal, bool command_expand_lists,
   const std::string& job_pool)
 {
-  cmTarget* target =
-    this->AddNewUtilityTarget(utilityName, origin, excludeFromAll);
+  cmTarget* target = this->AddNewUtilityTarget(utilityName, excludeFromAll);
 
   // Validate custom commands.
   if ((commandLines.empty() && depends.empty()) ||
@@ -1236,45 +1206,26 @@
   this->GetOrCreateGeneratedSource(force.Name);
 
   // Always create the byproduct sources and mark them generated.
-  this->CreateGeneratedSources(byproducts);
+  this->CreateGeneratedByproducts(byproducts);
 
-  if (!comment) {
-    // Use an empty comment to avoid generation of default comment.
-    comment = "";
-  }
+  // Strings could be moved into the callback function with C++14.
+  cm::optional<std::string> commentStr = MakeOptionalString(comment);
+  cm::optional<std::string> workingStr = MakeOptionalString(workingDir);
 
-  this->CommitUtilityCommand(target, force, workingDirectory, byproducts,
-                             depends, commandLines, escapeOldStyle, comment,
-                             uses_terminal, command_expand_lists, job_pool);
+  // Dispatch command creation to allow generator expressions in outputs.
+  this->AddGeneratorAction(
+    [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) {
+      BacktraceGuard guard(this->Backtrace, lfbt);
+      detail::AddUtilityCommand(lg, lfbt, cmCommandOrigin::Project, target,
+                                force, GetCStrOrNull(workingStr), byproducts,
+                                depends, commandLines, escapeOldStyle,
+                                GetCStrOrNull(commentStr), uses_terminal,
+                                command_expand_lists, job_pool);
+    });
 
   return target;
 }
 
-void cmMakefile::CommitUtilityCommand(
-  cmTarget* target, const cmUtilityOutput& force, const char* workingDirectory,
-  const std::vector<std::string>& byproducts,
-  const std::vector<std::string>& depends,
-  const cmCustomCommandLines& commandLines, bool escapeOldStyle,
-  const char* comment, bool uses_terminal, bool command_expand_lists,
-  const std::string& job_pool)
-{
-  std::vector<std::string> forced;
-  forced.push_back(force.Name);
-  std::string no_main_dependency;
-  cmImplicitDependsList no_implicit_depends;
-  bool no_replace = false;
-  cmSourceFile* sf = this->AddCustomCommandToOutput(
-    forced, byproducts, depends, no_main_dependency, no_implicit_depends,
-    commandLines, comment, workingDirectory, no_replace, escapeOldStyle,
-    uses_terminal, command_expand_lists, /*depfile=*/"", job_pool);
-  if (!force.NameCMP0049.empty()) {
-    target->AddSource(force.NameCMP0049);
-  }
-  if (sf) {
-    this->AddTargetByproducts(target, byproducts);
-  }
-}
-
 static void s_AddDefineFlag(std::string const& flag, std::string& dflags)
 {
   // remove any \n\r
@@ -1342,28 +1293,27 @@
 
 void cmMakefile::AddCompileDefinition(std::string const& option)
 {
-  this->AppendProperty("COMPILE_DEFINITIONS", option.c_str());
+  this->AppendProperty("COMPILE_DEFINITIONS", option);
 }
 
 void cmMakefile::AddCompileOption(std::string const& option)
 {
-  this->AppendProperty("COMPILE_OPTIONS", option.c_str());
+  this->AppendProperty("COMPILE_OPTIONS", option);
 }
 
 void cmMakefile::AddLinkOption(std::string const& option)
 {
-  this->AppendProperty("LINK_OPTIONS", option.c_str());
+  this->AppendProperty("LINK_OPTIONS", option);
 }
 
 void cmMakefile::AddLinkDirectory(std::string const& directory, bool before)
 {
-  cmListFileBacktrace lfbt = this->GetBacktrace();
   if (before) {
-    this->StateSnapshot.GetDirectory().PrependLinkDirectoriesEntry(directory,
-                                                                   lfbt);
+    this->StateSnapshot.GetDirectory().PrependLinkDirectoriesEntry(
+      directory, this->Backtrace);
   } else {
-    this->StateSnapshot.GetDirectory().AppendLinkDirectoriesEntry(directory,
-                                                                  lfbt);
+    this->StateSnapshot.GetDirectory().AppendLinkDirectoriesEntry(
+      directory, this->Backtrace);
   }
 }
 
@@ -1476,6 +1426,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)
 {
@@ -1776,8 +1740,10 @@
 
   cmSystemTools::MakeDirectory(binPath);
 
-  cmMakefile* subMf = new cmMakefile(this->GlobalGenerator, newSnapshot);
-  this->GetGlobalGenerator()->AddMakefile(subMf);
+  auto subMfu =
+    cm::make_unique<cmMakefile>(this->GlobalGenerator, newSnapshot);
+  auto subMf = subMfu.get();
+  this->GetGlobalGenerator()->AddMakefile(std::move(subMfu));
 
   if (excludeFromAll) {
     subMf->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
@@ -1789,8 +1755,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
@@ -1820,20 +1786,19 @@
     return;
   }
 
-  cmListFileBacktrace lfbt = this->GetBacktrace();
   std::string entryString = cmJoin(incs, ";");
   if (before) {
     this->StateSnapshot.GetDirectory().PrependIncludeDirectoriesEntry(
-      entryString, lfbt);
+      entryString, this->Backtrace);
   } else {
     this->StateSnapshot.GetDirectory().AppendIncludeDirectoriesEntry(
-      entryString, lfbt);
+      entryString, this->Backtrace);
   }
 
   // Property on each target:
   for (auto& target : this->Targets) {
     cmTarget& t = target.second;
-    t.InsertInclude(entryString, lfbt, before);
+    t.InsertInclude(entryString, this->Backtrace, before);
   }
 }
 
@@ -2027,7 +1992,7 @@
       target.AddLinkLibrary(*this, libraryName, libType);
       target.AppendProperty(
         "INTERFACE_LINK_LIBRARIES",
-        target.GetDebugGeneratorExpressions(libraryName, libType).c_str());
+        target.GetDebugGeneratorExpressions(libraryName, libType));
     }
   }
 }
@@ -2080,7 +2045,8 @@
 {
   auto it =
     this->Targets
-      .emplace(name, cmTarget(name, type, cmTarget::VisibilityNormal, this))
+      .emplace(name,
+               cmTarget(name, type, cmTarget::VisibilityNormal, this, true))
       .first;
   this->OrderedTargets.push_back(&it->second);
   this->GetGlobalGenerator()->IndexTarget(&it->second);
@@ -2089,11 +2055,9 @@
 }
 
 cmTarget* cmMakefile::AddNewUtilityTarget(const std::string& utilityName,
-                                          cmCommandOrigin origin,
                                           bool excludeFromAll)
 {
   cmTarget* target = this->AddNewTarget(cmStateEnums::UTILITY, utilityName);
-  target->SetIsGeneratorProvided(origin == cmCommandOrigin::Generator);
   if (excludeFromAll) {
     target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
   }
@@ -2155,18 +2119,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();
         }
       }
     }
@@ -2211,8 +2175,8 @@
       (!o->second.Sources.SourceIsByproduct ||
        kind == cmSourceOutputKind::OutputOrByproduct)) {
     // Source file could also be null pointer for example if we found the
-    // byproduct of a utility target or a PRE_BUILD, PRE_LINK, or POST_BUILD
-    // command of a target.
+    // byproduct of a utility target, a PRE_BUILD, PRE_LINK, or POST_BUILD
+    // command of a target, or a not yet created custom command.
     return o->second.Sources.Source;
   }
   return nullptr;
@@ -2220,12 +2184,20 @@
 
 bool cmMakefile::MightHaveCustomCommand(const std::string& name) const
 {
-  // This will have to be changed for delaying custom command creation, because
-  // GetSourceFileWithOutput requires the command to be already created.
-  if (cmSourceFile* sf = this->GetSourceFileWithOutput(name)) {
-    if (sf->GetCustomCommand()) {
-      return true;
-    }
+  if (this->DelayedOutputFilesHaveGenex ||
+      cmGeneratorExpression::Find(name) != std::string::npos) {
+    // Could be more restrictive, but for now we assume that there could always
+    // be a match when generator expressions are involved.
+    return true;
+  }
+  // Also see LinearGetSourceFileWithOutput.
+  if (!cmSystemTools::FileIsFullPath(name)) {
+    return AnyOutputMatches(name, this->DelayedOutputFiles);
+  }
+  // Otherwise we use an efficient lookup map.
+  auto o = this->OutputToSource.find(name);
+  if (o != this->OutputToSource.end()) {
+    return o->second.SourceMightBeOutput;
   }
   return false;
 }
@@ -2278,6 +2250,7 @@
   SourceEntry entry;
   entry.Sources.Source = source;
   entry.Sources.SourceIsByproduct = byproduct;
+  entry.SourceMightBeOutput = !byproduct;
 
   auto pr = this->OutputToSource.emplace(output, entry);
   if (!pr.second) {
@@ -2287,6 +2260,7 @@
         (current.Sources.SourceIsByproduct && !byproduct)) {
       current.Sources.Source = source;
       current.Sources.SourceIsByproduct = false;
+      current.SourceMightBeOutput = true;
     } else {
       // Multiple custom commands produce the same output but may
       // be attached to a different source file (MAIN_DEPENDENCY).
@@ -2478,7 +2452,7 @@
           << "  " << dirs << "\n";
         /* clang-format on */
       }
-      t.SetProperty("INCLUDE_DIRECTORIES", dirs.c_str());
+      t.SetProperty("INCLUDE_DIRECTORIES", dirs);
     }
   }
 
@@ -2739,7 +2713,7 @@
 std::vector<std::string> cmMakefile::GetDefinitions() const
 {
   std::vector<std::string> res = this->StateSnapshot.ClosureKeys();
-  cmAppend(res, this->GetState()->GetCacheEntryKeys());
+  cm::append(res, this->GetState()->GetCacheEntryKeys());
   std::sort(res.begin(), res.end());
   return res;
 }
@@ -3514,24 +3488,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,
@@ -3553,11 +3528,41 @@
   return sf;
 }
 
-void cmMakefile::CreateGeneratedSources(
+void cmMakefile::CreateGeneratedOutputs(
   const std::vector<std::string>& outputs)
 {
-  for (std::string const& output : outputs) {
-    this->GetOrCreateGeneratedSource(output);
+  for (std::string const& o : outputs) {
+    if (cmGeneratorExpression::Find(o) == std::string::npos) {
+      this->GetOrCreateGeneratedSource(o);
+      this->AddDelayedOutput(o);
+    } else {
+      this->DelayedOutputFilesHaveGenex = true;
+    }
+  }
+}
+
+void cmMakefile::CreateGeneratedByproducts(
+  const std::vector<std::string>& byproducts)
+{
+  for (std::string const& o : byproducts) {
+    if (cmGeneratorExpression::Find(o) == std::string::npos) {
+      this->GetOrCreateGeneratedSource(o);
+    }
+  }
+}
+
+void cmMakefile::AddDelayedOutput(std::string const& output)
+{
+  // Note that this vector might contain the output names in a different order
+  // than in source file iteration order.
+  this->DelayedOutputFiles.push_back(output);
+
+  SourceEntry entry;
+  entry.SourceMightBeOutput = true;
+
+  auto pr = this->OutputToSource.emplace(output, entry);
+  if (!pr.second) {
+    pr.first->second.SourceMightBeOutput = true;
   }
 }
 
@@ -3630,8 +3635,7 @@
   // be run that way but the cmake object requires a vailid path
   cmake cm(cmake::RoleProject, cmState::Project);
   cm.SetIsInTryCompile(true);
-  cmGlobalGenerator* gg =
-    cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName());
+  auto gg = cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName());
   if (!gg) {
     this->IssueMessage(MessageType::INTERNAL_ERROR,
                        "Global generator '" +
@@ -3642,7 +3646,7 @@
     return 1;
   }
   gg->RecursionDepth = this->RecursionDepth;
-  cm.SetGlobalGenerator(gg);
+  cm.SetGlobalGenerator(std::move(gg));
 
   // do a configure
   cm.SetHomeDirectory(srcdir);
@@ -3651,7 +3655,7 @@
   cm.SetGeneratorPlatform(this->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM"));
   cm.SetGeneratorToolset(this->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET"));
   cm.LoadCache();
-  if (!gg->IsMultiConfig()) {
+  if (!cm.GetGlobalGenerator()->IsMultiConfig()) {
     if (const char* config =
           this->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION")) {
       // Tell the single-configuration generator which one to use.
@@ -3697,7 +3701,8 @@
     cm.SetCacheArgs(*cmakeArgs);
   }
   // to save time we pass the EnableLanguage info directly
-  gg->EnableLanguagesFromGenerator(this->GetGlobalGenerator(), this);
+  cm.GetGlobalGenerator()->EnableLanguagesFromGenerator(
+    this->GetGlobalGenerator(), this);
   if (this->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
     cm.AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", "TRUE", "",
                      cmStateEnums::INTERNAL);
@@ -3777,7 +3782,8 @@
 }
 
 std::string cmMakefile::GetModulesFile(const std::string& filename,
-                                       bool& system) const
+                                       bool& system, bool debug,
+                                       std::string& debugBuffer) const
 {
   std::string result;
 
@@ -3808,6 +3814,9 @@
         moduleInCMakeModulePath = itempl;
         break;
       }
+      if (debug) {
+        debugBuffer = cmStrCat(debugBuffer, "  ", itempl, "\n");
+      }
     }
   }
 
@@ -3816,6 +3825,9 @@
     cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules/", filename);
   cmSystemTools::ConvertToUnixSlashes(moduleInCMakeRoot);
   if (!cmSystemTools::FileExists(moduleInCMakeRoot)) {
+    if (debug) {
+      debugBuffer = cmStrCat(debugBuffer, "  ", moduleInCMakeRoot, "\n");
+    }
     moduleInCMakeRoot.clear();
   }
 
@@ -4029,16 +4041,14 @@
 
 void cmMakefile::SetProperty(const std::string& prop, const char* value)
 {
-  cmListFileBacktrace lfbt = this->GetBacktrace();
-  this->StateSnapshot.GetDirectory().SetProperty(prop, value, lfbt);
+  this->StateSnapshot.GetDirectory().SetProperty(prop, value, this->Backtrace);
 }
 
-void cmMakefile::AppendProperty(const std::string& prop, const char* value,
-                                bool asString)
+void cmMakefile::AppendProperty(const std::string& prop,
+                                const std::string& value, bool asString)
 {
-  cmListFileBacktrace lfbt = this->GetBacktrace();
   this->StateSnapshot.GetDirectory().AppendProperty(prop, value, asString,
-                                                    lfbt);
+                                                    this->Backtrace);
 }
 
 const char* cmMakefile::GetProperty(const std::string& prop) const
@@ -4090,9 +4100,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;
 }
 
@@ -4100,7 +4111,7 @@
 {
   auto mi = this->Tests.find(testName);
   if (mi != this->Tests.end()) {
-    return mi->second;
+    return mi->second.get();
   }
   return nullptr;
 }
@@ -4108,7 +4119,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,15 +4225,15 @@
     new cmTarget(name, type,
                  global ? cmTarget::VisibilityImportedGlobally
                         : cmTarget::VisibilityImported,
-                 this));
+                 this, true));
 
   // Add to the set of available imported targets.
   this->ImportedTargets[name] = target.get();
   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,
@@ -4487,7 +4498,7 @@
 
   // Deprecate old policies, especially those that require a lot
   // of code to maintain the old behavior.
-  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0067 &&
+  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0069 &&
       !(this->GetCMakeInstance()->GetIsInTryCompile() &&
         (
           // Policies set by cmCoreTryCompile::TryCompileCode.
@@ -4587,17 +4598,21 @@
 
 static const char* const CXX_FEATURES[] = { nullptr FOR_EACH_CXX_FEATURE(
   FEATURE_STRING) };
+
+static const char* const CUDA_FEATURES[] = { nullptr FOR_EACH_CUDA_FEATURE(
+  FEATURE_STRING) };
 #undef FEATURE_STRING
 
 static const char* const C_STANDARDS[] = { "90", "99", "11" };
 static const char* const CXX_STANDARDS[] = { "98", "11", "14", "17", "20" };
+static const char* const CUDA_STANDARDS[] = { "03", "11", "14", "17", "20" };
 
 bool cmMakefile::AddRequiredTargetFeature(cmTarget* target,
                                           const std::string& feature,
                                           std::string* error) const
 {
   if (cmGeneratorExpression::Find(feature) != std::string::npos) {
-    target->AppendProperty("COMPILE_FEATURES", feature.c_str());
+    target->AppendProperty("COMPILE_FEATURES", feature);
     return true;
   }
 
@@ -4628,11 +4643,15 @@
     return false;
   }
 
-  target->AppendProperty("COMPILE_FEATURES", feature.c_str());
+  target->AppendProperty("COMPILE_FEATURES", feature);
 
-  return lang == "C" || lang == "OBJC"
-    ? this->AddRequiredTargetCFeature(target, feature, lang, error)
-    : this->AddRequiredTargetCxxFeature(target, feature, lang, error);
+  if (lang == "C" || lang == "OBJC") {
+    return this->AddRequiredTargetCFeature(target, feature, lang, error);
+  }
+  if (lang == "CUDA") {
+    return this->AddRequiredTargetCudaFeature(target, feature, lang, error);
+  }
+  return this->AddRequiredTargetCxxFeature(target, feature, lang, error);
 }
 
 bool cmMakefile::CompileFeatureKnown(cmTarget const* target,
@@ -4656,6 +4675,13 @@
     lang = "CXX";
     return true;
   }
+  bool isCudaFeature =
+    std::find_if(cm::cbegin(CUDA_FEATURES) + 1, cm::cend(CUDA_FEATURES),
+                 cmStrCmp(feature)) != cm::cend(CUDA_FEATURES);
+  if (isCudaFeature) {
+    lang = "CUDA";
+    return true;
+  }
   std::ostringstream e;
   if (error) {
     e << "specified";
@@ -4724,9 +4750,13 @@
                                        std::string const& lang,
                                        const std::string& feature) const
 {
-  return lang == "C" || lang == "OBJC"
-    ? this->HaveCStandardAvailable(target, feature, lang)
-    : this->HaveCxxStandardAvailable(target, feature, lang);
+  if (lang == "C" || lang == "OBJC") {
+    return this->HaveCStandardAvailable(target, feature, lang);
+  }
+  if (lang == "CUDA") {
+    return this->HaveCudaStandardAvailable(target, feature, lang);
+  }
+  return this->HaveCxxStandardAvailable(target, feature, lang);
 }
 
 bool cmMakefile::HaveCStandardAvailable(cmTarget const* target,
@@ -4809,6 +4839,14 @@
     return std::find_if(rhsIt, cm::cend(C_STANDARDS), cmStrCmp(lhs)) !=
       cm::cend(C_STANDARDS);
   }
+  if (lang == "CUDA") {
+    const char* const* rhsIt = std::find_if(
+      cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS), cmStrCmp(rhs));
+
+    return std::find_if(rhsIt, cm::cend(CUDA_STANDARDS), cmStrCmp(lhs)) !=
+      cm::cend(CUDA_STANDARDS);
+  }
+
   const char* const* rhsIt = std::find_if(
     cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), cmStrCmp(rhs));
 
@@ -4953,27 +4991,6 @@
     }
   }
 
-  const char* existingCudaStandard = target->GetProperty("CUDA_STANDARD");
-  const char* const* existingCudaLevel = nullptr;
-  if (existingCudaStandard) {
-    existingCudaLevel =
-      std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS),
-                   cmStrCmp(existingCudaStandard));
-    if (existingCudaLevel == cm::cend(CXX_STANDARDS)) {
-      std::ostringstream e;
-      e << "The CUDA_STANDARD property on target \"" << target->GetName()
-        << "\" contained an invalid value: \"" << existingCudaStandard
-        << "\".";
-      if (error) {
-        *error = e.str();
-      } else {
-        this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
-                                               e.str(), this->Backtrace);
-      }
-      return false;
-    }
-  }
-
   /* clang-format off */
   const char* const* needCxxLevel =
     needCxx20 ? &CXX_STANDARDS[4]
@@ -4990,11 +5007,164 @@
     if (!existingCxxLevel || existingCxxLevel < needCxxLevel) {
       target->SetProperty(cmStrCat(lang, "_STANDARD"), *needCxxLevel);
     }
+  }
 
+  return true;
+}
+
+bool cmMakefile::HaveCudaStandardAvailable(cmTarget const* target,
+                                           const std::string& feature,
+                                           std::string const& lang) const
+{
+  const char* defaultCudaStandard =
+    this->GetDefinition(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT"));
+  if (!defaultCudaStandard) {
+    this->IssueMessage(
+      MessageType::INTERNAL_ERROR,
+      cmStrCat("CMAKE_", lang,
+               "_STANDARD_DEFAULT is not set.  COMPILE_FEATURES support "
+               "not fully configured for this compiler."));
+    // Return true so the caller does not try to lookup the default standard.
+    return true;
+  }
+  if (std::find_if(cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS),
+                   cmStrCmp(defaultCudaStandard)) ==
+      cm::cend(CUDA_STANDARDS)) {
+    const std::string e =
+      cmStrCat("The CMAKE_", lang, "_STANDARD_DEFAULT variable contains an ",
+               "invalid value: \"", defaultCudaStandard, "\".");
+    this->IssueMessage(MessageType::INTERNAL_ERROR, e);
+    return false;
+  }
+
+  bool needCuda03 = false;
+  bool needCuda11 = false;
+  bool needCuda14 = false;
+  bool needCuda17 = false;
+  bool needCuda20 = false;
+  this->CheckNeededCudaLanguage(feature, lang, needCuda03, needCuda11,
+                                needCuda14, needCuda17, needCuda20);
+
+  const char* existingCudaStandard =
+    target->GetProperty(cmStrCat(lang, "_STANDARD"));
+  if (!existingCudaStandard) {
+    existingCudaStandard = defaultCudaStandard;
+  }
+
+  const char* const* existingCudaLevel =
+    std::find_if(cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS),
+                 cmStrCmp(existingCudaStandard));
+  if (existingCudaLevel == cm::cend(CUDA_STANDARDS)) {
+    const std::string e = cmStrCat(
+      "The ", lang, "_STANDARD property on target \"", target->GetName(),
+      "\" contained an invalid value: \"", existingCudaStandard, "\".");
+    this->IssueMessage(MessageType::FATAL_ERROR, e);
+    return false;
+  }
+
+  /* clang-format off */
+  const char* const* needCudaLevel =
+    needCuda20 ? &CUDA_STANDARDS[4]
+    : needCuda17 ? &CUDA_STANDARDS[3]
+    : needCuda14 ? &CUDA_STANDARDS[2]
+    : needCuda11 ? &CUDA_STANDARDS[1]
+    : needCuda03 ? &CUDA_STANDARDS[0]
+    : nullptr;
+  /* clang-format on */
+
+  return !needCudaLevel || needCudaLevel <= existingCudaLevel;
+}
+
+void cmMakefile::CheckNeededCudaLanguage(const std::string& feature,
+                                         std::string const& lang,
+                                         bool& needCuda03, bool& needCuda11,
+                                         bool& needCuda14, bool& needCuda17,
+                                         bool& needCuda20) const
+{
+  if (const char* propCuda03 =
+        this->GetDefinition(cmStrCat("CMAKE_", lang, "03_COMPILE_FEATURES"))) {
+    std::vector<std::string> props = cmExpandedList(propCuda03);
+    needCuda03 = cmContains(props, feature);
+  }
+  if (const char* propCuda11 =
+        this->GetDefinition(cmStrCat("CMAKE_", lang, "11_COMPILE_FEATURES"))) {
+    std::vector<std::string> props = cmExpandedList(propCuda11);
+    needCuda11 = cmContains(props, feature);
+  }
+  if (const char* propCuda14 =
+        this->GetDefinition(cmStrCat("CMAKE_", lang, "14_COMPILE_FEATURES"))) {
+    std::vector<std::string> props = cmExpandedList(propCuda14);
+    needCuda14 = cmContains(props, feature);
+  }
+  if (const char* propCuda17 =
+        this->GetDefinition(cmStrCat("CMAKE_", lang, "17_COMPILE_FEATURES"))) {
+    std::vector<std::string> props = cmExpandedList(propCuda17);
+    needCuda17 = cmContains(props, feature);
+  }
+  if (const char* propCuda20 =
+        this->GetDefinition(cmStrCat("CMAKE_", lang, "20_COMPILE_FEATURES"))) {
+    std::vector<std::string> props = cmExpandedList(propCuda20);
+    needCuda20 = cmContains(props, feature);
+  }
+}
+
+bool cmMakefile::AddRequiredTargetCudaFeature(cmTarget* target,
+                                              const std::string& feature,
+                                              std::string const& lang,
+                                              std::string* error) const
+{
+  bool needCuda03 = false;
+  bool needCuda11 = false;
+  bool needCuda14 = false;
+  bool needCuda17 = false;
+  bool needCuda20 = false;
+
+  this->CheckNeededCudaLanguage(feature, lang, needCuda03, needCuda11,
+                                needCuda14, needCuda17, needCuda20);
+
+  const char* existingCudaStandard =
+    target->GetProperty(cmStrCat(lang, "_STANDARD"));
+  if (existingCudaStandard == nullptr) {
+    const char* defaultCudaStandard =
+      this->GetDefinition(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT"));
+    if (defaultCudaStandard && *defaultCudaStandard) {
+      existingCudaStandard = defaultCudaStandard;
+    }
+  }
+  const char* const* existingCudaLevel = nullptr;
+  if (existingCudaStandard) {
+    existingCudaLevel =
+      std::find_if(cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS),
+                   cmStrCmp(existingCudaStandard));
+    if (existingCudaLevel == cm::cend(CUDA_STANDARDS)) {
+      const std::string e = cmStrCat(
+        "The ", lang, "_STANDARD property on target \"", target->GetName(),
+        "\" contained an invalid value: \"", existingCudaStandard, "\".");
+      if (error) {
+        *error = e;
+      } else {
+        this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e,
+                                               this->Backtrace);
+      }
+      return false;
+    }
+  }
+
+  /* clang-format off */
+  const char* const* needCudaLevel =
+    needCuda20 ? &CUDA_STANDARDS[4]
+    : needCuda17 ? &CUDA_STANDARDS[3]
+    : needCuda14 ? &CUDA_STANDARDS[2]
+    : needCuda11 ? &CUDA_STANDARDS[1]
+    : needCuda03 ? &CUDA_STANDARDS[0]
+    : nullptr;
+  /* clang-format on */
+
+  if (needCudaLevel) {
     // Ensure the CUDA language level is high enough to support
-    // the needed C++ features.
-    if (!existingCudaLevel || existingCudaLevel < needCxxLevel) {
-      target->SetProperty("CUDA_STANDARD", *needCxxLevel);
+    // the needed CUDA features.
+    if (!existingCudaLevel || existingCudaLevel < needCudaLevel) {
+      target->SetProperty("CUDA_STANDARD", *needCudaLevel);
     }
   }
 
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 6e59494..d918abe 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -49,6 +49,7 @@
 class cmGlobalGenerator;
 class cmImplicitDependsList;
 class cmInstallGenerator;
+class cmLocalGenerator;
 class cmMessenger;
 class cmSourceFile;
 class cmState;
@@ -134,7 +135,7 @@
   std::unique_ptr<cmFunctionBlocker> RemoveFunctionBlocker();
 
   /**
-   * Try running cmake and building a file. This is used for dynalically
+   * Try running cmake and building a file. This is used for dynamically
    * loaded commands, not as part of the usual build process.
    */
   int TryCompile(const std::string& srcdir, const std::string& bindir,
@@ -151,54 +152,64 @@
   bool EnforceUniqueName(std::string const& name, std::string& msg,
                          bool isCustom = false) const;
 
-  using FinalAction = std::function<void(cmMakefile&)>;
+  using GeneratorAction =
+    std::function<void(cmLocalGenerator&, const cmListFileBacktrace&)>;
 
   /**
-   * Register an action that is executed during FinalPass
+   * Register an action that is executed during Generate
    */
-  void AddFinalAction(FinalAction action);
+  void AddGeneratorAction(GeneratorAction action);
 
   /**
-   * Perform FinalPass, Library dependency analysis etc before output of the
-   * makefile.
+   * Perform generate actions, Library dependency analysis etc before output of
+   * the makefile.
    */
-  void ConfigureFinalPass();
-
-  /**
-   * run all FinalActions.
-   */
-  void FinalPass();
+  void Generate(cmLocalGenerator& lg);
 
   /**
    * Get the target for PRE_BUILD, PRE_LINK, or POST_BUILD commands.
    */
-  cmTarget* GetCustomCommandTarget(
-    const std::string& target, cmObjectLibraryCommands objLibCommands) const;
+  cmTarget* GetCustomCommandTarget(const std::string& target,
+                                   cmObjectLibraryCommands objLibCommands,
+                                   const cmListFileBacktrace& lfbt) const;
 
-  /** Add a custom command to the build.  */
+  /**
+   * Dispatch adding a custom PRE_BUILD, PRE_LINK, or POST_BUILD command to a
+   * target.
+   */
   cmTarget* AddCustomCommandToTarget(
     const std::string& target, const std::vector<std::string>& byproducts,
     const std::vector<std::string>& depends,
     const cmCustomCommandLines& commandLines, cmCustomCommandType type,
     const char* comment, const char* workingDir, bool escapeOldStyle = true,
     bool uses_terminal = false, const std::string& depfile = "",
-    const std::string& job_pool = "", bool command_expand_lists = false,
-    cmObjectLibraryCommands objLibCommands = cmObjectLibraryCommands::Reject);
-  cmSourceFile* AddCustomCommandToOutput(
+    const std::string& job_pool = "", bool command_expand_lists = false);
+
+  /**
+   * Called for each file with custom command.
+   */
+  using CommandSourceCallback = std::function<void(cmSourceFile*)>;
+
+  /**
+   * Dispatch adding a custom command to a source file.
+   */
+  void AddCustomCommandToOutput(
     const std::string& output, const std::vector<std::string>& depends,
     const std::string& main_dependency,
     const cmCustomCommandLines& commandLines, const char* comment,
-    const char* workingDir, bool replace = false, bool escapeOldStyle = true,
+    const char* workingDir, const CommandSourceCallback& callback = nullptr,
+    bool replace = false, bool escapeOldStyle = true,
     bool uses_terminal = false, bool command_expand_lists = false,
     const std::string& depfile = "", const std::string& job_pool = "");
-  cmSourceFile* AddCustomCommandToOutput(
+  void AddCustomCommandToOutput(
     const std::vector<std::string>& outputs,
     const std::vector<std::string>& byproducts,
     const std::vector<std::string>& depends,
     const std::string& main_dependency,
     const cmImplicitDependsList& implicit_depends,
     const cmCustomCommandLines& commandLines, const char* comment,
-    const char* workingDir, bool replace = false, bool escapeOldStyle = true,
+    const char* workingDir, const CommandSourceCallback& callback = nullptr,
+    bool replace = false, bool escapeOldStyle = true,
     bool uses_terminal = false, bool command_expand_lists = false,
     const std::string& depfile = "", const std::string& job_pool = "");
   void AddCustomCommandOldStyle(const std::string& target,
@@ -244,7 +255,7 @@
 
   /** Create a target instance for the utility.  */
   cmTarget* AddNewUtilityTarget(const std::string& utilityName,
-                                cmCommandOrigin origin, bool excludeFromAll);
+                                bool excludeFromAll);
 
   /**
    * Add an executable to the build.
@@ -259,13 +270,12 @@
   cmUtilityOutput GetUtilityOutput(cmTarget* target);
 
   /**
-   * Add a utility to the build.  A utility target is a command that
-   * is run every time the target is built.
+   * Dispatch adding a utility to the build.  A utility target is a command
+   * that is run every time the target is built.
    */
   cmTarget* AddUtilityCommand(
-    const std::string& utilityName, cmCommandOrigin origin,
-    bool excludeFromAll, const char* workingDirectory,
-    const std::vector<std::string>& byproducts,
+    const std::string& utilityName, bool excludeFromAll,
+    const char* workingDir, const std::vector<std::string>& byproducts,
     const std::vector<std::string>& depends,
     const cmCustomCommandLines& commandLines, bool escapeOldStyle = true,
     const char* comment = nullptr, bool uses_terminal = false,
@@ -409,9 +419,9 @@
   {
     this->ComplainFileRegularExpression = regex;
   }
-  const char* GetComplainRegularExpression() const
+  const std::string& GetComplainRegularExpression() const
   {
-    return this->ComplainFileRegularExpression.c_str();
+    return this->ComplainFileRegularExpression;
   }
 
   // -- List of targets
@@ -421,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;
   }
@@ -717,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;
   }
@@ -756,14 +766,25 @@
   std::string GetModulesFile(const std::string& name) const
   {
     bool system;
-    return this->GetModulesFile(name, system);
+    std::string debugBuffer;
+    return this->GetModulesFile(name, system, false, debugBuffer);
   }
 
-  std::string GetModulesFile(const std::string& name, bool& system) const;
+  /**
+   * Return a location of a file in cmake or custom modules directory
+   */
+  std::string GetModulesFile(const std::string& name, bool& system) const
+  {
+    std::string debugBuffer;
+    return this->GetModulesFile(name, system, false, debugBuffer);
+  }
+
+  std::string GetModulesFile(const std::string& name, bool& system, bool debug,
+                             std::string& debugBuffer) const;
 
   //! Set/Get a property of this directory
   void SetProperty(const std::string& prop, const char* value);
-  void AppendProperty(const std::string& prop, const char* value,
+  void AppendProperty(const std::string& prop, const std::string& value,
                       bool asString = false);
   const char* GetProperty(const std::string& prop) const;
   const char* GetProperty(const std::string& prop, bool chain) const;
@@ -773,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;
   }
@@ -927,12 +942,14 @@
     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;
+  std::vector<std::unique_ptr<cmExportBuildFileGenerator>> const&
+  GetExportBuildFileGenerators() const;
   void RemoveExportBuildFileGeneratorCMP0024(cmExportBuildFileGenerator* gen);
-  void AddExportBuildFileGenerator(cmExportBuildFileGenerator* gen);
+  void AddExportBuildFileGenerator(
+    std::unique_ptr<cmExportBuildFileGenerator> gen);
 
   // Maintain a stack of package roots to allow nested PACKAGE_ROOT_PATH
   // searches
@@ -962,8 +979,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
@@ -971,14 +987,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.
@@ -987,8 +1004,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;
@@ -1001,7 +1018,6 @@
   size_t ObjectLibrariesSourceGroupIndex;
 #endif
 
-  std::vector<FinalAction> FinalActions;
   cmGlobalGenerator* GlobalGenerator;
   bool IsFunctionBlocked(const cmListFileFunction& lff,
                          cmExecutionStatus& status);
@@ -1011,6 +1027,8 @@
   cmListFileBacktrace Backtrace;
   int RecursionDepth;
 
+  void DoGenerate(cmLocalGenerator& lg);
+
   void ReadListFile(cmListFile const& listFile,
                     const std::string& filenametoread);
 
@@ -1036,15 +1054,17 @@
   mutable cmsys::RegularExpression cmNamedCurly;
 
   std::vector<cmMakefile*> UnConfiguredDirectories;
-  std::vector<cmExportBuildFileGenerator*> ExportBuildFileGenerators;
+  std::vector<std::unique_ptr<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;
 
@@ -1080,38 +1100,15 @@
 
   bool ValidateCustomCommand(const cmCustomCommandLines& commandLines) const;
 
-  void CreateGeneratedSources(const std::vector<std::string>& outputs);
+  void CreateGeneratedOutputs(const std::vector<std::string>& outputs);
+  void CreateGeneratedByproducts(const std::vector<std::string>& byproducts);
 
-  void CommitCustomCommandToTarget(
-    cmTarget* target, const std::vector<std::string>& byproducts,
-    const std::vector<std::string>& depends,
-    const cmCustomCommandLines& commandLines, cmCustomCommandType type,
-    const char* comment, const char* workingDir, bool escapeOldStyle,
-    bool uses_terminal, const std::string& depfile,
-    const std::string& job_pool, bool command_expand_lists);
-  cmSourceFile* CommitCustomCommandToOutput(
-    const std::vector<std::string>& outputs,
-    const std::vector<std::string>& byproducts,
-    const std::vector<std::string>& depends,
-    const std::string& main_dependency,
-    const cmImplicitDependsList& implicit_depends,
-    const cmCustomCommandLines& commandLines, const char* comment,
-    const char* workingDir, bool replace, bool escapeOldStyle,
-    bool uses_terminal, bool command_expand_lists, const std::string& depfile,
-    const std::string& job_pool);
-  void CommitAppendCustomCommandToOutput(
-    const std::string& output, const std::vector<std::string>& depends,
-    const cmImplicitDependsList& implicit_depends,
-    const cmCustomCommandLines& commandLines);
+  std::vector<BT<GeneratorAction>> GeneratorActions;
+  bool GeneratorActionsInvoked = false;
+  bool DelayedOutputFilesHaveGenex = false;
+  std::vector<std::string> DelayedOutputFiles;
 
-  void CommitUtilityCommand(cmTarget* target, const cmUtilityOutput& force,
-                            const char* workingDirectory,
-                            const std::vector<std::string>& byproducts,
-                            const std::vector<std::string>& depends,
-                            const cmCustomCommandLines& commandLines,
-                            bool escapeOldStyle, const char* comment,
-                            bool uses_terminal, bool command_expand_lists,
-                            const std::string& job_pool);
+  void AddDelayedOutput(std::string const& output);
 
   /**
    * See LinearGetSourceFileWithOutput for background information
@@ -1131,6 +1128,7 @@
   struct SourceEntry
   {
     cmSourcesWithOutput Sources;
+    bool SourceMightBeOutput = false;
   };
 
   // A map for fast output to input look up.
@@ -1149,11 +1147,14 @@
   bool AddRequiredTargetCFeature(cmTarget* target, const std::string& feature,
                                  std::string const& lang,
                                  std::string* error = nullptr) const;
-
   bool AddRequiredTargetCxxFeature(cmTarget* target,
                                    const std::string& feature,
                                    std::string const& lang,
                                    std::string* error = nullptr) const;
+  bool AddRequiredTargetCudaFeature(cmTarget* target,
+                                    const std::string& feature,
+                                    std::string const& lang,
+                                    std::string* error = nullptr) const;
 
   void CheckNeededCLanguage(const std::string& feature,
                             std::string const& lang, bool& needC90,
@@ -1162,6 +1163,10 @@
                               std::string const& lang, bool& needCxx98,
                               bool& needCxx11, bool& needCxx14,
                               bool& needCxx17, bool& needCxx20) const;
+  void CheckNeededCudaLanguage(const std::string& feature,
+                               std::string const& lang, bool& needCuda03,
+                               bool& needCuda11, bool& needCuda14,
+                               bool& needCuda17, bool& needCuda20) const;
 
   bool HaveCStandardAvailable(cmTarget const* target,
                               const std::string& feature,
@@ -1169,6 +1174,9 @@
   bool HaveCxxStandardAvailable(cmTarget const* target,
                                 const std::string& feature,
                                 std::string const& lang) const;
+  bool HaveCudaStandardAvailable(cmTarget const* target,
+                                 const std::string& feature,
+                                 std::string const& lang) const;
 
   void CheckForUnusedVariables() const;
 
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index 40265ff..0471a45 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -9,8 +9,8 @@
 #include <vector>
 
 #include <cm/memory>
+#include <cmext/algorithm>
 
-#include "cmAlgorithms.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalUnixMakefileGenerator3.h"
@@ -35,10 +35,9 @@
 {
   this->CustomCommandDriver = OnDepends;
   this->TargetNames =
-    this->GeneratorTarget->GetExecutableNames(this->ConfigName);
+    this->GeneratorTarget->GetExecutableNames(this->GetConfigName());
 
-  this->OSXBundleGenerator =
-    cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName);
+  this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(target);
   this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
 }
 
@@ -64,7 +63,7 @@
 
   // write the link rules
   this->WriteExecutableRule(false);
-  if (this->GeneratorTarget->NeedRelinkBeforeInstall(this->ConfigName)) {
+  if (this->GeneratorTarget->NeedRelinkBeforeInstall(this->GetConfigName())) {
     // Write rules to link an installable version of the target.
     this->WriteExecutableRule(true);
   }
@@ -85,7 +84,7 @@
 {
 #ifndef CMAKE_BOOTSTRAP
   const bool requiresDeviceLinking = requireDeviceLinking(
-    *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
+    *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName());
   if (!requiresDeviceLinking) {
     return;
   }
@@ -141,10 +140,10 @@
 
   // Add language feature flags.
   this->LocalGenerator->AddLanguageFlagsForLinking(
-    flags, this->GeneratorTarget, linkLanguage, this->ConfigName);
+    flags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
 
-  this->LocalGenerator->AddArchitectureFlags(flags, this->GeneratorTarget,
-                                             linkLanguage, this->ConfigName);
+  this->LocalGenerator->AddArchitectureFlags(
+    flags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
 
   // Add target-specific linker flags.
   this->GetTargetLinkFlags(linkFlags, linkLanguage);
@@ -197,6 +196,8 @@
     this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects,
                             buildObjs, depends, useWatcomQuote);
 
+    std::string const& aixExports = this->GetAIXExports(this->GetConfigName());
+
     cmRulePlaceholderExpander::RuleVariables vars;
     std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
 
@@ -213,12 +214,14 @@
         this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutputReal),
       output);
 
-    std::string targetFullPathCompilePDB = this->ComputeTargetCompilePDB();
+    std::string targetFullPathCompilePDB =
+      this->ComputeTargetCompilePDB(this->GetConfigName());
     std::string targetOutPathCompilePDB =
       this->LocalGenerator->ConvertToOutputFormat(targetFullPathCompilePDB,
                                                   cmOutputConverter::SHELL);
 
     vars.Language = linkLanguage.c_str();
+    vars.AIXExports = aixExports.c_str();
     vars.Objects = buildObjs.c_str();
     vars.ObjectDir = objectDir.c_str();
     vars.Target = target.c_str();
@@ -263,7 +266,7 @@
   this->LocalGenerator->CreateCDCommand(
     commands1, this->Makefile->GetCurrentBinaryDirectory(),
     this->LocalGenerator->GetBinaryDirectory());
-  cmAppend(commands, commands1);
+  cm::append(commands, commands1);
   commands1.clear();
 
   // Write the build rule.
@@ -287,12 +290,14 @@
 
   // Get the name of the executable to generate.
   cmGeneratorTarget::Names targetNames =
-    this->GeneratorTarget->GetExecutableNames(this->ConfigName);
+    this->GeneratorTarget->GetExecutableNames(this->GetConfigName());
 
   // Construct the full path version of the names.
-  std::string outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
+  std::string outpath =
+    this->GeneratorTarget->GetDirectory(this->GetConfigName());
   if (this->GeneratorTarget->IsAppBundleOnApple()) {
-    this->OSXBundleGenerator->CreateAppBundle(targetNames.Output, outpath);
+    this->OSXBundleGenerator->CreateAppBundle(targetNames.Output, outpath,
+                                              this->GetConfigName());
   }
   outpath += '/';
   std::string outpathImp;
@@ -308,18 +313,18 @@
     cmSystemTools::MakeDirectory(outpath);
     if (!targetNames.ImportLibrary.empty()) {
       outpathImp = this->GeneratorTarget->GetDirectory(
-        this->ConfigName, cmStateEnums::ImportLibraryArtifact);
+        this->GetConfigName(), cmStateEnums::ImportLibraryArtifact);
       cmSystemTools::MakeDirectory(outpathImp);
       outpathImp += '/';
     }
   }
 
   std::string compilePdbOutputPath =
-    this->GeneratorTarget->GetCompilePDBDirectory(this->ConfigName);
+    this->GeneratorTarget->GetCompilePDBDirectory(this->GetConfigName());
   cmSystemTools::MakeDirectory(compilePdbOutputPath);
 
   std::string pdbOutputPath =
-    this->GeneratorTarget->GetPDBDirectory(this->ConfigName);
+    this->GeneratorTarget->GetPDBDirectory(this->GetConfigName());
   cmSystemTools::MakeDirectory(pdbOutputPath);
   pdbOutputPath += '/';
 
@@ -347,7 +352,7 @@
 
   // Get the language to use for linking this executable.
   std::string linkLanguage =
-    this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
+    this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
 
   // Make sure we have a link language.
   if (linkLanguage.empty()) {
@@ -380,7 +385,7 @@
 
   // Add flags to create an executable.
   this->LocalGenerator->AddConfigVariableFlags(
-    linkFlags, "CMAKE_EXE_LINKER_FLAGS", this->ConfigName);
+    linkFlags, "CMAKE_EXE_LINKER_FLAGS", this->GetConfigName());
 
   if (this->GeneratorTarget->GetPropertyAsBool("WIN32_EXECUTABLE")) {
     this->LocalGenerator->AppendFlags(
@@ -409,25 +414,26 @@
 
   // Add language feature flags.
   this->LocalGenerator->AddLanguageFlagsForLinking(
-    flags, this->GeneratorTarget, linkLanguage, this->ConfigName);
+    flags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
 
-  this->LocalGenerator->AddArchitectureFlags(flags, this->GeneratorTarget,
-                                             linkLanguage, this->ConfigName);
+  this->LocalGenerator->AddArchitectureFlags(
+    flags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
 
   // Add target-specific linker flags.
   this->GetTargetLinkFlags(linkFlags, linkLanguage);
 
   {
-    std::unique_ptr<cmLinkLineComputer> linkLineComputer(
+    std::unique_ptr<cmLinkLineComputer> linkLineComputer =
       this->CreateLinkLineComputer(
         this->LocalGenerator,
-        this->LocalGenerator->GetStateSnapshot().GetDirectory()));
+        this->LocalGenerator->GetStateSnapshot().GetDirectory());
 
-    this->AddModuleDefinitionFlag(linkLineComputer.get(), linkFlags);
+    this->AddModuleDefinitionFlag(linkLineComputer.get(), linkFlags,
+                                  this->GetConfigName());
   }
 
-  this->LocalGenerator->AppendIPOLinkerFlags(linkFlags, this->GeneratorTarget,
-                                             this->ConfigName, linkLanguage);
+  this->LocalGenerator->AppendIPOLinkerFlags(
+    linkFlags, this->GeneratorTarget, this->GetConfigName(), linkLanguage);
 
   // Construct a list of files associated with this executable that
   // may need to be cleaned.
@@ -451,7 +457,7 @@
       targetFullPathImport));
     std::string implib;
     if (this->GeneratorTarget->GetImplibGNUtoMS(
-          this->ConfigName, targetFullPathImport, implib)) {
+          this->GetConfigName(), targetFullPathImport, implib)) {
       exeCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath(
         this->LocalGenerator->GetCurrentBinaryDirectory(), implib));
     }
@@ -479,7 +485,7 @@
   // Construct the main link rule.
   std::vector<std::string> real_link_commands;
   std::string linkRuleVar = this->GeneratorTarget->GetCreateRuleVariable(
-    linkLanguage, this->ConfigName);
+    linkLanguage, this->GetConfigName());
   std::string linkRule = this->GetLinkRule(linkRuleVar);
   std::vector<std::string> commands1;
   cmExpandList(linkRule, real_link_commands);
@@ -506,10 +512,10 @@
     // Set path conversion for link script shells.
     this->LocalGenerator->SetLinkScriptShell(useLinkScript);
 
-    std::unique_ptr<cmLinkLineComputer> linkLineComputer(
+    std::unique_ptr<cmLinkLineComputer> linkLineComputer =
       this->CreateLinkLineComputer(
         this->LocalGenerator,
-        this->LocalGenerator->GetStateSnapshot().GetDirectory()));
+        this->LocalGenerator->GetStateSnapshot().GetDirectory());
     linkLineComputer->SetForResponse(useResponseFileForLibs);
     linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
     linkLineComputer->SetRelink(relink);
@@ -536,7 +542,7 @@
     // maybe create .def file from list of objects
     this->GenDefFile(real_link_commands);
 
-    std::string manifests = this->GetManifests();
+    std::string manifests = this->GetManifests(this->GetConfigName());
 
     cmRulePlaceholderExpander::RuleVariables vars;
     vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
@@ -627,7 +633,7 @@
   this->LocalGenerator->CreateCDCommand(
     commands1, this->Makefile->GetCurrentBinaryDirectory(),
     this->LocalGenerator->GetBinaryDirectory());
-  cmAppend(commands, commands1);
+  cm::append(commands, commands1);
   commands1.clear();
 
   // Add a rule to create necessary symlinks for the library.
@@ -639,7 +645,7 @@
     this->LocalGenerator->CreateCDCommand(
       commands1, this->Makefile->GetCurrentBinaryDirectory(),
       this->LocalGenerator->GetBinaryDirectory());
-    cmAppend(commands, commands1);
+    cm::append(commands, commands1);
     commands1.clear();
   }
 
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index 54a6606..d3f3a4f 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -9,8 +9,8 @@
 #include <vector>
 
 #include <cm/memory>
+#include <cmext/algorithm>
 
-#include "cmAlgorithms.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalUnixMakefileGenerator3.h"
@@ -36,11 +36,10 @@
   this->CustomCommandDriver = OnDepends;
   if (this->GeneratorTarget->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
     this->TargetNames =
-      this->GeneratorTarget->GetLibraryNames(this->ConfigName);
+      this->GeneratorTarget->GetLibraryNames(this->GetConfigName());
   }
 
-  this->OSXBundleGenerator =
-    cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName);
+  this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(target);
   this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
 }
 
@@ -69,14 +68,16 @@
       break;
     case cmStateEnums::SHARED_LIBRARY:
       this->WriteSharedLibraryRules(false);
-      if (this->GeneratorTarget->NeedRelinkBeforeInstall(this->ConfigName)) {
+      if (this->GeneratorTarget->NeedRelinkBeforeInstall(
+            this->GetConfigName())) {
         // Write rules to link an installable version of the target.
         this->WriteSharedLibraryRules(true);
       }
       break;
     case cmStateEnums::MODULE_LIBRARY:
       this->WriteModuleLibraryRules(false);
-      if (this->GeneratorTarget->NeedRelinkBeforeInstall(this->ConfigName)) {
+      if (this->GeneratorTarget->NeedRelinkBeforeInstall(
+            this->GetConfigName())) {
         // Write rules to link an installable version of the target.
         this->WriteModuleLibraryRules(true);
       }
@@ -126,21 +127,21 @@
 void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
 {
   const bool requiresDeviceLinking = requireDeviceLinking(
-    *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
+    *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName());
   if (requiresDeviceLinking) {
     std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
     this->WriteDeviceLibraryRules(linkRuleVar, false);
   }
 
   std::string linkLanguage =
-    this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
+    this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
 
   std::string linkRuleVar = this->GeneratorTarget->GetCreateRuleVariable(
-    linkLanguage, this->ConfigName);
+    linkLanguage, this->GetConfigName());
 
   std::string extraFlags;
   this->LocalGenerator->GetStaticLibraryFlags(
-    extraFlags, cmSystemTools::UpperCase(this->ConfigName), linkLanguage,
+    extraFlags, cmSystemTools::UpperCase(this->GetConfigName()), linkLanguage,
     this->GeneratorTarget);
   this->WriteLibraryRules(linkRuleVar, extraFlags, false);
 }
@@ -154,7 +155,7 @@
 
   if (!relink) {
     const bool requiresDeviceLinking = requireDeviceLinking(
-      *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
+      *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName());
     if (requiresDeviceLinking) {
       std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
       this->WriteDeviceLibraryRules(linkRuleVar, relink);
@@ -162,21 +163,22 @@
   }
 
   std::string linkLanguage =
-    this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
+    this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
   std::string linkRuleVar =
     cmStrCat("CMAKE_", linkLanguage, "_CREATE_SHARED_LIBRARY");
 
   std::string extraFlags;
   this->GetTargetLinkFlags(extraFlags, linkLanguage);
   this->LocalGenerator->AddConfigVariableFlags(
-    extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->ConfigName);
+    extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->GetConfigName());
 
-  std::unique_ptr<cmLinkLineComputer> linkLineComputer(
+  std::unique_ptr<cmLinkLineComputer> linkLineComputer =
     this->CreateLinkLineComputer(
       this->LocalGenerator,
-      this->LocalGenerator->GetStateSnapshot().GetDirectory()));
+      this->LocalGenerator->GetStateSnapshot().GetDirectory());
 
-  this->AddModuleDefinitionFlag(linkLineComputer.get(), extraFlags);
+  this->AddModuleDefinitionFlag(linkLineComputer.get(), extraFlags,
+                                this->GetConfigName());
 
   if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
     this->LocalGenerator->AppendFlags(extraFlags, " -Wl,--no-as-needed");
@@ -188,7 +190,7 @@
 {
   if (!relink) {
     const bool requiresDeviceLinking = requireDeviceLinking(
-      *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
+      *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName());
     if (requiresDeviceLinking) {
       std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
       this->WriteDeviceLibraryRules(linkRuleVar, relink);
@@ -196,21 +198,22 @@
   }
 
   std::string linkLanguage =
-    this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
+    this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
   std::string linkRuleVar =
     cmStrCat("CMAKE_", linkLanguage, "_CREATE_SHARED_MODULE");
 
   std::string extraFlags;
   this->GetTargetLinkFlags(extraFlags, linkLanguage);
   this->LocalGenerator->AddConfigVariableFlags(
-    extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->ConfigName);
+    extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->GetConfigName());
 
-  std::unique_ptr<cmLinkLineComputer> linkLineComputer(
+  std::unique_ptr<cmLinkLineComputer> linkLineComputer =
     this->CreateLinkLineComputer(
       this->LocalGenerator,
-      this->LocalGenerator->GetStateSnapshot().GetDirectory()));
+      this->LocalGenerator->GetStateSnapshot().GetDirectory());
 
-  this->AddModuleDefinitionFlag(linkLineComputer.get(), extraFlags);
+  this->AddModuleDefinitionFlag(linkLineComputer.get(), extraFlags,
+                                this->GetConfigName());
 
   this->WriteLibraryRules(linkRuleVar, extraFlags, relink);
 }
@@ -218,14 +221,14 @@
 void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink)
 {
   std::string linkLanguage =
-    this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
+    this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
   std::string linkRuleVar =
     cmStrCat("CMAKE_", linkLanguage, "_CREATE_MACOSX_FRAMEWORK");
 
   std::string extraFlags;
   this->GetTargetLinkFlags(extraFlags, linkLanguage);
   this->LocalGenerator->AddConfigVariableFlags(
-    extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS", this->ConfigName);
+    extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS", this->GetConfigName());
 
   this->WriteLibraryRules(linkRuleVar, extraFlags, relink);
 }
@@ -331,7 +334,8 @@
         this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutputReal),
       output);
 
-    std::string targetFullPathCompilePDB = this->ComputeTargetCompilePDB();
+    std::string targetFullPathCompilePDB =
+      this->ComputeTargetCompilePDB(this->GetConfigName());
     std::string targetOutPathCompilePDB =
       this->LocalGenerator->ConvertToOutputFormat(targetFullPathCompilePDB,
                                                   cmOutputConverter::SHELL);
@@ -347,7 +351,7 @@
     // Add language-specific flags.
     std::string langFlags;
     this->LocalGenerator->AddLanguageFlagsForLinking(
-      langFlags, this->GeneratorTarget, linkLanguage, this->ConfigName);
+      langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
 
     vars.LanguageCompileFlags = langFlags.c_str();
 
@@ -393,7 +397,7 @@
   this->LocalGenerator->CreateCDCommand(
     commands1, this->Makefile->GetCurrentBinaryDirectory(),
     this->LocalGenerator->GetBinaryDirectory());
-  cmAppend(commands, commands1);
+  cm::append(commands, commands1);
   commands1.clear();
 
   // Compute the list of outputs.
@@ -420,7 +424,7 @@
 
   // Get the language to use for linking this library.
   std::string linkLanguage =
-    this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
+    this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
 
   // Make sure we have a link language.
   if (linkLanguage.empty()) {
@@ -439,8 +443,8 @@
   // Create set of linking flags.
   std::string linkFlags;
   this->LocalGenerator->AppendFlags(linkFlags, extraFlags);
-  this->LocalGenerator->AppendIPOLinkerFlags(linkFlags, this->GeneratorTarget,
-                                             this->ConfigName, linkLanguage);
+  this->LocalGenerator->AppendIPOLinkerFlags(
+    linkFlags, this->GeneratorTarget, this->GetConfigName(), linkLanguage);
 
   // Add OSX version flags, if any.
   if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
@@ -450,20 +454,20 @@
   }
 
   // Construct the name of the library.
-  this->GeneratorTarget->GetLibraryNames(this->ConfigName);
+  this->GeneratorTarget->GetLibraryNames(this->GetConfigName());
 
   // Construct the full path version of the names.
   std::string outpath;
   std::string outpathImp;
   if (this->GeneratorTarget->IsFrameworkOnApple()) {
-    outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
+    outpath = this->GeneratorTarget->GetDirectory(this->GetConfigName());
     this->OSXBundleGenerator->CreateFramework(this->TargetNames.Output,
-                                              outpath);
+                                              outpath, this->GetConfigName());
     outpath += '/';
   } else if (this->GeneratorTarget->IsCFBundleOnApple()) {
-    outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
-    this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output,
-                                             outpath);
+    outpath = this->GeneratorTarget->GetDirectory(this->GetConfigName());
+    this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output, outpath,
+                                             this->GetConfigName());
     outpath += '/';
   } else if (relink) {
     outpath = cmStrCat(this->Makefile->GetCurrentBinaryDirectory(),
@@ -474,23 +478,23 @@
       outpathImp = outpath;
     }
   } else {
-    outpath = this->GeneratorTarget->GetDirectory(this->ConfigName);
+    outpath = this->GeneratorTarget->GetDirectory(this->GetConfigName());
     cmSystemTools::MakeDirectory(outpath);
     outpath += '/';
     if (!this->TargetNames.ImportLibrary.empty()) {
       outpathImp = this->GeneratorTarget->GetDirectory(
-        this->ConfigName, cmStateEnums::ImportLibraryArtifact);
+        this->GetConfigName(), cmStateEnums::ImportLibraryArtifact);
       cmSystemTools::MakeDirectory(outpathImp);
       outpathImp += '/';
     }
   }
 
   std::string compilePdbOutputPath =
-    this->GeneratorTarget->GetCompilePDBDirectory(this->ConfigName);
+    this->GeneratorTarget->GetCompilePDBDirectory(this->GetConfigName());
   cmSystemTools::MakeDirectory(compilePdbOutputPath);
 
   std::string pdbOutputPath =
-    this->GeneratorTarget->GetPDBDirectory(this->ConfigName);
+    this->GeneratorTarget->GetPDBDirectory(this->GetConfigName());
   cmSystemTools::MakeDirectory(pdbOutputPath);
   pdbOutputPath += "/";
 
@@ -567,7 +571,7 @@
     this->LocalGenerator->CreateCDCommand(
       commands1, this->Makefile->GetCurrentBinaryDirectory(),
       this->LocalGenerator->GetBinaryDirectory());
-    cmAppend(commands, commands1);
+    cm::append(commands, commands1);
     commands1.clear();
   }
 
@@ -586,7 +590,7 @@
       targetFullPathImport));
     std::string implib;
     if (this->GeneratorTarget->GetImplibGNUtoMS(
-          this->ConfigName, targetFullPathImport, implib)) {
+          this->GetConfigName(), targetFullPathImport, implib)) {
       libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath(
         this->LocalGenerator->GetCurrentBinaryDirectory(), implib));
     }
@@ -638,7 +642,7 @@
       cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_CREATE");
 
     arCreateVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable(
-      arCreateVar, linkLanguage, this->ConfigName);
+      arCreateVar, linkLanguage, this->GetConfigName());
 
     if (const char* rule = this->Makefile->GetDefinition(arCreateVar)) {
       cmExpandList(rule, archiveCreateCommands);
@@ -647,7 +651,7 @@
       cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_APPEND");
 
     arAppendVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable(
-      arAppendVar, linkLanguage, this->ConfigName);
+      arAppendVar, linkLanguage, this->GetConfigName());
 
     if (const char* rule = this->Makefile->GetDefinition(arAppendVar)) {
       cmExpandList(rule, archiveAppendCommands);
@@ -656,7 +660,7 @@
       cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_FINISH");
 
     arFinishVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable(
-      arFinishVar, linkLanguage, this->ConfigName);
+      arFinishVar, linkLanguage, this->GetConfigName());
 
     if (const char* rule = this->Makefile->GetDefinition(arFinishVar)) {
       cmExpandList(rule, archiveFinishCommands);
@@ -696,10 +700,10 @@
     std::string linkLibs;
     if (this->GeneratorTarget->GetType() != cmStateEnums::STATIC_LIBRARY) {
 
-      std::unique_ptr<cmLinkLineComputer> linkLineComputer(
+      std::unique_ptr<cmLinkLineComputer> linkLineComputer =
         this->CreateLinkLineComputer(
           this->LocalGenerator,
-          this->LocalGenerator->GetStateSnapshot().GetDirectory()));
+          this->LocalGenerator->GetStateSnapshot().GetDirectory());
       linkLineComputer->SetForResponse(useResponseFileForLibs);
       linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
       linkLineComputer->SetRelink(relink);
@@ -723,10 +727,12 @@
           cmOutputConverter::SHELL);
     }
 
+    std::string const& aixExports = this->GetAIXExports(this->GetConfigName());
+
     // maybe create .def file from list of objects
     this->GenDefFile(real_link_commands);
 
-    std::string manifests = this->GetManifests();
+    std::string manifests = this->GetManifests(this->GetConfigName());
 
     cmRulePlaceholderExpander::RuleVariables vars;
     vars.TargetPDB = targetOutPathPDB.c_str();
@@ -752,6 +758,7 @@
     vars.CMTargetType =
       cmState::GetTargetTypeName(this->GeneratorTarget->GetType());
     vars.Language = linkLanguage.c_str();
+    vars.AIXExports = aixExports.c_str();
     vars.Objects = buildObjs.c_str();
     std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
 
@@ -771,7 +778,7 @@
     vars.Target = target.c_str();
     vars.LinkLibraries = linkLibs.c_str();
     vars.ObjectsQuoted = buildObjs.c_str();
-    if (this->GeneratorTarget->HasSOName(this->ConfigName)) {
+    if (this->GeneratorTarget->HasSOName(this->GetConfigName())) {
       vars.SONameFlag = this->Makefile->GetSONameFlag(linkLanguage);
       vars.TargetSOName = this->TargetNames.SharedObject.c_str();
     }
@@ -783,8 +790,8 @@
     std::string install_name_dir;
     if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY) {
       // Get the install_name directory for the build tree.
-      install_name_dir =
-        this->GeneratorTarget->GetInstallNameDirForBuildTree(this->ConfigName);
+      install_name_dir = this->GeneratorTarget->GetInstallNameDirForBuildTree(
+        this->GetConfigName());
 
       // Set the rule variable replacement value.
       if (install_name_dir.empty()) {
@@ -800,10 +807,10 @@
     // Add language-specific flags.
     std::string langFlags;
     this->LocalGenerator->AddLanguageFlagsForLinking(
-      langFlags, this->GeneratorTarget, linkLanguage, this->ConfigName);
+      langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
 
     this->LocalGenerator->AddArchitectureFlags(
-      langFlags, this->GeneratorTarget, linkLanguage, this->ConfigName);
+      langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
 
     vars.LanguageCompileFlags = langFlags.c_str();
 
@@ -903,7 +910,7 @@
   this->LocalGenerator->CreateCDCommand(
     commands1, this->Makefile->GetCurrentBinaryDirectory(),
     this->LocalGenerator->GetBinaryDirectory());
-  cmAppend(commands, commands1);
+  cm::append(commands, commands1);
   commands1.clear();
 
   // Add a rule to create necessary symlinks for the library.
@@ -917,7 +924,7 @@
     this->LocalGenerator->CreateCDCommand(
       commands1, this->Makefile->GetCurrentBinaryDirectory(),
       this->LocalGenerator->GetBinaryDirectory());
-    cmAppend(commands, commands1);
+    cm::append(commands, commands1);
     commands1.clear();
   }
 
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index dd8a389..d7e2de6 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -2,12 +2,14 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmMakefileTargetGenerator.h"
 
+#include <cassert>
 #include <cstdio>
-#include <memory>
 #include <sstream>
 #include <utility>
 
-#include "cmAlgorithms.h"
+#include <cm/memory>
+#include <cmext/algorithm>
+
 #include "cmComputeLinkInformation.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandGenerator.h"
@@ -15,6 +17,7 @@
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLinkLineComputer.h"
 #include "cmLocalCommonGenerator.h"
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmMakefile.h"
@@ -35,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());
@@ -52,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;
@@ -85,6 +80,13 @@
   return result;
 }
 
+std::string cmMakefileTargetGenerator::GetConfigName()
+{
+  auto const& configNames = this->LocalGenerator->GetConfigNames();
+  assert(configNames.size() == 1);
+  return configNames.front();
+}
+
 void cmMakefileTargetGenerator::GetTargetLinkFlags(
   std::string& flags, const std::string& linkLanguage)
 {
@@ -92,17 +94,18 @@
     flags, this->GeneratorTarget->GetSafeProperty("LINK_FLAGS"));
 
   std::string linkFlagsConfig =
-    cmStrCat("LINK_FLAGS_", cmSystemTools::UpperCase(this->ConfigName));
+    cmStrCat("LINK_FLAGS_", cmSystemTools::UpperCase(this->GetConfigName()));
   this->LocalGenerator->AppendFlags(
     flags, this->GeneratorTarget->GetSafeProperty(linkFlagsConfig));
 
   std::vector<std::string> opts;
-  this->GeneratorTarget->GetLinkOptions(opts, this->ConfigName, linkLanguage);
+  this->GeneratorTarget->GetLinkOptions(opts, this->GetConfigName(),
+                                        linkLanguage);
   // LINK_OPTIONS are escaped.
   this->LocalGenerator->AppendCompileOptions(flags, opts);
 
   this->LocalGenerator->AppendPositionIndependentLinkerFlags(
-    flags, this->GeneratorTarget, this->ConfigName, linkLanguage);
+    flags, this->GeneratorTarget, this->GetConfigName(), linkLanguage);
 }
 
 void cmMakefileTargetGenerator::CreateRuleFile()
@@ -128,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;
   }
@@ -154,10 +157,10 @@
   auto evaluatedFiles =
     [this](const char* prop_value) -> std::vector<std::string> {
     std::vector<std::string> files;
-    cmExpandList(
-      cmGeneratorExpression::Evaluate(prop_value, this->LocalGenerator,
-                                      this->ConfigName, this->GeneratorTarget),
-      files);
+    cmExpandList(cmGeneratorExpression::Evaluate(
+                   prop_value, this->LocalGenerator, this->GetConfigName(),
+                   this->GeneratorTarget),
+                 files);
     return files;
   };
 
@@ -187,12 +190,13 @@
   // First generate the object rule files.  Save a list of all object
   // files for this target.
   std::vector<cmSourceFile const*> customCommands;
-  this->GeneratorTarget->GetCustomCommands(customCommands, this->ConfigName);
+  this->GeneratorTarget->GetCustomCommands(customCommands,
+                                           this->GetConfigName());
   std::string currentBinDir =
     this->LocalGenerator->GetCurrentBinaryDirectory();
   for (cmSourceFile const* sf : customCommands) {
-    cmCustomCommandGenerator ccg(*sf->GetCustomCommand(), this->ConfigName,
-                                 this->LocalGenerator);
+    cmCustomCommandGenerator ccg(*sf->GetCustomCommand(),
+                                 this->GetConfigName(), this->LocalGenerator);
     this->GenerateCustomRuleFile(ccg);
     if (clean) {
       const std::vector<std::string>& outputs = ccg.GetOutputs();
@@ -215,12 +219,14 @@
     std::vector<cmCustomCommand> buildEventCommands =
       this->GeneratorTarget->GetPreBuildCommands();
 
-    cmAppend(buildEventCommands, this->GeneratorTarget->GetPreLinkCommands());
-    cmAppend(buildEventCommands,
-             this->GeneratorTarget->GetPostBuildCommands());
+    cm::append(buildEventCommands,
+               this->GeneratorTarget->GetPreLinkCommands());
+    cm::append(buildEventCommands,
+               this->GeneratorTarget->GetPostBuildCommands());
 
     for (const auto& be : buildEventCommands) {
-      cmCustomCommandGenerator beg(be, this->ConfigName, this->LocalGenerator);
+      cmCustomCommandGenerator beg(be, this->GetConfigName(),
+                                   this->LocalGenerator);
       const std::vector<std::string>& byproducts = beg.GetByproducts();
       for (std::string const& byproduct : byproducts) {
         this->CleanFiles.insert(
@@ -230,17 +236,19 @@
     }
   }
   std::vector<cmSourceFile const*> headerSources;
-  this->GeneratorTarget->GetHeaderSources(headerSources, this->ConfigName);
+  this->GeneratorTarget->GetHeaderSources(headerSources,
+                                          this->GetConfigName());
   this->OSXBundleGenerator->GenerateMacOSXContentStatements(
-    headerSources, this->MacOSXContentGenerator);
+    headerSources, this->MacOSXContentGenerator.get(), this->GetConfigName());
   std::vector<cmSourceFile const*> extraSources;
-  this->GeneratorTarget->GetExtraSources(extraSources, this->ConfigName);
+  this->GeneratorTarget->GetExtraSources(extraSources, this->GetConfigName());
   this->OSXBundleGenerator->GenerateMacOSXContentStatements(
-    extraSources, this->MacOSXContentGenerator);
+    extraSources, this->MacOSXContentGenerator.get(), this->GetConfigName());
   const char* pchExtension =
     this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
   std::vector<cmSourceFile const*> externalObjects;
-  this->GeneratorTarget->GetExternalObjects(externalObjects, this->ConfigName);
+  this->GeneratorTarget->GetExternalObjects(externalObjects,
+                                            this->GetConfigName());
   for (cmSourceFile const* sf : externalObjects) {
     auto const& objectFileName = sf->GetFullPath();
     if (!cmSystemTools::StringEndsWith(objectFileName, pchExtension)) {
@@ -248,7 +256,8 @@
     }
   }
   std::vector<cmSourceFile const*> objectSources;
-  this->GeneratorTarget->GetObjectSources(objectSources, this->ConfigName);
+  this->GeneratorTarget->GetObjectSources(objectSources,
+                                          this->GetConfigName());
   for (cmSourceFile const* sf : objectSources) {
     // Generate this object file's rule file.
     this->WriteObjectRuleFiles(*sf);
@@ -299,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;
   }
@@ -334,9 +343,9 @@
   }
 
   for (std::string const& language : languages) {
-    std::string flags = this->GetFlags(language);
-    std::string defines = this->GetDefines(language);
-    std::string includes = this->GetIncludes(language);
+    std::string flags = this->GetFlags(language, this->GetConfigName());
+    std::string defines = this->GetDefines(language, this->GetConfigName());
+    std::string includes = this->GetIncludes(language, this->GetConfigName());
     // Escape comment characters so they do not terminate assignment.
     cmSystemTools::ReplaceString(flags, "#", "\\#");
     cmSystemTools::ReplaceString(defines, "#", "\\#");
@@ -348,7 +357,7 @@
 }
 
 void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()(
-  cmSourceFile const& source, const char* pkgloc)
+  cmSourceFile const& source, const char* pkgloc, const std::string& config)
 {
   // Skip OS X content when not building a Framework or Bundle.
   if (!this->Generator->GetGeneratorTarget()->IsBundleOnApple()) {
@@ -356,7 +365,8 @@
   }
 
   std::string macdir =
-    this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc);
+    this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc,
+                                                                    config);
 
   // Get the input file location.
   std::string const& input = source.GetFullPath();
@@ -451,7 +461,7 @@
   // generate the depend scanning rule
   this->WriteObjectDependRules(source, depends);
 
-  std::string config = this->LocalGenerator->GetConfigName();
+  std::string config = this->GetConfigName();
   std::string configUpper = cmSystemTools::UpperCase(config);
 
   // Add precompile headers dependencies
@@ -593,16 +603,17 @@
   {
     std::string targetFullPathReal;
     std::string targetFullPathPDB;
-    std::string targetFullPathCompilePDB = this->ComputeTargetCompilePDB();
+    std::string targetFullPathCompilePDB =
+      this->ComputeTargetCompilePDB(this->GetConfigName());
     if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE ||
         this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY ||
         this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
         this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
       targetFullPathReal = this->GeneratorTarget->GetFullPath(
-        this->ConfigName, cmStateEnums::RuntimeBinaryArtifact, true);
-      targetFullPathPDB =
-        cmStrCat(this->GeneratorTarget->GetPDBDirectory(this->ConfigName), '/',
-                 this->GeneratorTarget->GetPDBName(this->ConfigName));
+        this->GetConfigName(), cmStateEnums::RuntimeBinaryArtifact, true);
+      targetFullPathPDB = cmStrCat(
+        this->GeneratorTarget->GetPDBDirectory(this->GetConfigName()), '/',
+        this->GeneratorTarget->GetPDBName(this->GetConfigName()));
     }
 
     targetOutPathReal = this->LocalGenerator->ConvertToOutputFormat(
@@ -708,13 +719,15 @@
       std::string workingDirectory = cmSystemTools::CollapseFullPath(
         this->LocalGenerator->GetCurrentBinaryDirectory());
       compileCommand.replace(compileCommand.find(langFlags), langFlags.size(),
-                             this->GetFlags(lang));
+                             this->GetFlags(lang, this->GetConfigName()));
       std::string langDefines = std::string("$(") + lang + "_DEFINES)";
       compileCommand.replace(compileCommand.find(langDefines),
-                             langDefines.size(), this->GetDefines(lang));
+                             langDefines.size(),
+                             this->GetDefines(lang, this->GetConfigName()));
       std::string langIncludes = std::string("$(") + lang + "_INCLUDES)";
       compileCommand.replace(compileCommand.find(langIncludes),
-                             langIncludes.size(), this->GetIncludes(lang));
+                             langIncludes.size(),
+                             this->GetIncludes(lang, this->GetConfigName()));
 
       const char* eliminate[] = {
         this->Makefile->GetDefinition("CMAKE_START_TEMP_FILE"),
@@ -769,7 +782,13 @@
         }
         if (tidy && *tidy) {
           run_iwyu += " --tidy=";
-          run_iwyu += this->LocalGenerator->EscapeForShell(tidy);
+          const char* driverMode = this->Makefile->GetDefinition(
+            "CMAKE_" + lang + "_CLANG_TIDY_DRIVER_MODE");
+          if (!(driverMode && *driverMode)) {
+            driverMode = lang == "C" ? "gcc" : "g++";
+          }
+          run_iwyu += this->LocalGenerator->EscapeForShell(
+            cmStrCat(tidy, ";--extra-arg-before=--driver-mode=", driverMode));
         }
         if (cpplint && *cpplint) {
           run_iwyu += " --cpplint=";
@@ -823,7 +842,7 @@
     this->LocalGenerator->CreateCDCommand(
       compileCommands, this->LocalGenerator->GetCurrentBinaryDirectory(),
       this->LocalGenerator->GetBinaryDirectory());
-    cmAppend(commands, compileCommands);
+    cm::append(commands, compileCommands);
   }
 
   // Check for extra outputs created by the compilation.
@@ -882,7 +901,7 @@
           preprocessCommands,
           this->LocalGenerator->GetCurrentBinaryDirectory(),
           this->LocalGenerator->GetBinaryDirectory());
-        cmAppend(commands, preprocessCommands);
+        cm::append(commands, preprocessCommands);
       } else {
         std::string cmd =
           cmStrCat("$(CMAKE_COMMAND) -E cmake_unimplemented_variable ",
@@ -926,7 +945,7 @@
         this->LocalGenerator->CreateCDCommand(
           assemblyCommands, this->LocalGenerator->GetCurrentBinaryDirectory(),
           this->LocalGenerator->GetBinaryDirectory());
-        cmAppend(commands, assemblyCommands);
+        cm::append(commands, assemblyCommands);
       } else {
         std::string cmd =
           cmStrCat("$(CMAKE_COMMAND) -E cmake_unimplemented_variable ",
@@ -1036,7 +1055,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;
   }
@@ -1068,7 +1088,8 @@
     << "# Targets to which this target links.\n"
     << "set(CMAKE_TARGET_LINKED_INFO_FILES\n";
     /* clang-format on */
-    std::vector<std::string> dirs = this->GetLinkedTargetDirectories();
+    std::vector<std::string> dirs =
+      this->GetLinkedTargetDirectories(this->GetConfigName());
     for (std::string const& d : dirs) {
       *this->InfoFileStream << "  \"" << d << "/DependInfo.cmake\"\n";
     }
@@ -1171,9 +1192,9 @@
     sources, this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
   for (cmSourceFile* source : sources) {
     if (cmCustomCommand* cc = source->GetCustomCommand()) {
-      cmCustomCommandGenerator ccg(*cc, this->ConfigName,
+      cmCustomCommandGenerator ccg(*cc, this->GetConfigName(),
                                    this->LocalGenerator);
-      cmAppend(depends, ccg.GetOutputs());
+      cm::append(depends, ccg.GetOutputs());
     }
   }
 }
@@ -1410,7 +1431,7 @@
     }
 
     // Make sure the extra files are built.
-    cmAppend(depends, this->ExtraFiles);
+    cm::append(depends, this->ExtraFiles);
   }
 
   // Write the driver rule.
@@ -1429,10 +1450,10 @@
   }
 
   // Loop over all library dependencies.
-  const std::string& cfg = this->LocalGenerator->GetConfigName();
+  const std::string& cfg = this->GetConfigName();
   if (cmComputeLinkInformation* cli =
         this->GeneratorTarget->GetLinkInformation(cfg)) {
-    cmAppend(depends, cli->GetDepends());
+    cm::append(depends, cli->GetDepends());
   }
 }
 
@@ -1448,7 +1469,7 @@
   }
 
   // Add dependencies on the external object files.
-  cmAppend(depends, this->ExternalObjects);
+  cm::append(depends, this->ExternalObjects);
 
   // Add a dependency on the rule file itself.
   this->LocalGenerator->AppendRuleDepend(depends,
@@ -1474,13 +1495,13 @@
 
   // Add a dependency on user-specified manifest files, if any.
   std::vector<cmSourceFile const*> manifest_srcs;
-  this->GeneratorTarget->GetManifests(manifest_srcs, this->ConfigName);
+  this->GeneratorTarget->GetManifests(manifest_srcs, this->GetConfigName());
   for (cmSourceFile const* manifest_src : manifest_srcs) {
     depends.push_back(manifest_src->GetFullPath());
   }
 
   // Add user-specified dependencies.
-  this->GeneratorTarget->GetLinkDepends(depends, this->ConfigName,
+  this->GeneratorTarget->GetLinkDepends(depends, this->GetConfigName(),
                                         linkLanguage);
 }
 
@@ -1488,10 +1509,11 @@
   const std::string& linkRuleVar)
 {
   std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar);
-  if (this->GeneratorTarget->HasImplibGNUtoMS(this->ConfigName)) {
-    std::string ruleVar = cmStrCat(
-      "CMAKE_", this->GeneratorTarget->GetLinkerLanguage(this->ConfigName),
-      "_GNUtoMS_RULE");
+  if (this->GeneratorTarget->HasImplibGNUtoMS(this->GetConfigName())) {
+    std::string ruleVar =
+      cmStrCat("CMAKE_",
+               this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()),
+               "_GNUtoMS_RULE");
     if (const char* rule = this->Makefile->GetDefinition(ruleVar)) {
       linkRule += rule;
     }
@@ -1501,9 +1523,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(
@@ -1612,7 +1634,8 @@
   return responseFileName;
 }
 
-cmLinkLineComputer* cmMakefileTargetGenerator::CreateLinkLineComputer(
+std::unique_ptr<cmLinkLineComputer>
+cmMakefileTargetGenerator::CreateLinkLineComputer(
   cmOutputConverter* outputConverter, cmStateDirectory const& stateDir)
 {
   if (this->Makefile->IsOn("MSVC60")) {
@@ -1630,7 +1653,7 @@
   std::string frameworkPath;
   std::string linkPath;
   cmComputeLinkInformation* pcli =
-    this->GeneratorTarget->GetLinkInformation(this->ConfigName);
+    this->GeneratorTarget->GetLinkInformation(this->GetConfigName());
   this->LocalGenerator->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
                                             frameworkPath, linkPath);
   linkLibs = frameworkPath + linkPath + linkLibs;
@@ -1638,9 +1661,10 @@
   if (useResponseFile &&
       linkLibs.find_first_not_of(' ') != std::string::npos) {
     // Lookup the response file reference flag.
-    std::string responseFlagVar = cmStrCat(
-      "CMAKE_", this->GeneratorTarget->GetLinkerLanguage(this->ConfigName),
-      "_RESPONSE_FILE_LINK_FLAG");
+    std::string responseFlagVar =
+      cmStrCat("CMAKE_",
+               this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()),
+               "_RESPONSE_FILE_LINK_FLAG");
     const char* responseFlag = this->Makefile->GetDefinition(responseFlagVar);
     if (!responseFlag) {
       responseFlag = "@";
@@ -1675,9 +1699,10 @@
     this->WriteObjectsStrings(object_strings, responseFileLimit);
 
     // Lookup the response file reference flag.
-    std::string responseFlagVar = cmStrCat(
-      "CMAKE_", this->GeneratorTarget->GetLinkerLanguage(this->ConfigName),
-      "_RESPONSE_FILE_LINK_FLAG");
+    std::string responseFlagVar =
+      cmStrCat("CMAKE_",
+               this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()),
+               "_RESPONSE_FILE_LINK_FLAG");
     const char* responseFlag = this->Makefile->GetDefinition(responseFlagVar);
     if (!responseFlag) {
       responseFlag = "@";
@@ -1716,7 +1741,8 @@
 }
 
 void cmMakefileTargetGenerator::AddIncludeFlags(std::string& flags,
-                                                const std::string& lang)
+                                                const std::string& lang,
+                                                const std::string& /*config*/)
 {
   std::string responseVar =
     cmStrCat("CMAKE_", lang, "_USE_RESPONSE_FILE_FOR_INCLUDES");
@@ -1724,11 +1750,11 @@
 
   std::vector<std::string> includes;
   this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
-                                              lang, this->ConfigName);
+                                              lang, this->GetConfigName());
 
   std::string includeFlags = this->LocalGenerator->GetIncludeFlags(
     includes, this->GeneratorTarget, lang, false, useResponseFile,
-    this->ConfigName);
+    this->GetConfigName());
   if (includeFlags.empty()) {
     return;
   }
diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h
index 7b9c7a5..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 */
@@ -52,6 +57,8 @@
 
   cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; }
 
+  std::string GetConfigName();
+
 protected:
   void GetTargetLinkFlags(std::string& flags, const std::string& linkLanguage);
 
@@ -81,7 +88,8 @@
     {
     }
 
-    void operator()(cmSourceFile const& source, const char* pkgloc) override;
+    void operator()(cmSourceFile const& source, const char* pkgloc,
+                    const std::string& config) override;
 
   private:
     cmMakefileTargetGenerator* Generator;
@@ -137,7 +145,7 @@
                         std::vector<std::string>& makefile_commands,
                         std::vector<std::string>& makefile_depends);
 
-  cmLinkLineComputer* CreateLinkLineComputer(
+  std::unique_ptr<cmLinkLineComputer> CreateLinkLineComputer(
     cmOutputConverter* outputConverter, cmStateDirectory const& stateDir);
 
   /** Create a response file with the given set of options.  Returns
@@ -163,7 +171,8 @@
   /** Add commands for generate def files */
   void GenDefFile(std::vector<std::string>& real_link_commands);
 
-  void AddIncludeFlags(std::string& flags, const std::string& lang) override;
+  void AddIncludeFlags(std::string& flags, const std::string& lang,
+                       const std::string& config) override;
 
   virtual void CloseFileStreams();
   cmLocalUnixMakefileGenerator3* LocalGenerator;
@@ -191,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>
   {
   };
@@ -203,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;
@@ -232,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/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx
index 1625e4f..6c18e48 100644
--- a/Source/cmMakefileUtilityTargetGenerator.cxx
+++ b/Source/cmMakefileUtilityTargetGenerator.cxx
@@ -22,8 +22,7 @@
   : cmMakefileTargetGenerator(target)
 {
   this->CustomCommandDriver = OnUtility;
-  this->OSXBundleGenerator =
-    cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName);
+  this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(target);
   this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
 }
 
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/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx
index 96a6386..bf8183b 100644
--- a/Source/cmMessageCommand.cxx
+++ b/Source/cmMessageCommand.cxx
@@ -3,6 +3,11 @@
 #include "cmMessageCommand.h"
 
 #include <cassert>
+#include <utility>
+
+#include <cm/string_view>
+
+#include "cm_static_string_view.hxx"
 
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
@@ -13,6 +18,55 @@
 #include "cmSystemTools.h"
 #include "cmake.h"
 
+namespace {
+
+enum class CheckingType
+{
+  UNDEFINED,
+  CHECK_START,
+  CHECK_PASS,
+  CHECK_FAIL
+};
+
+std::string IndentText(std::string text, cmMakefile& mf)
+{
+  auto indent =
+    cmJoin(cmExpandedList(mf.GetSafeDefinition("CMAKE_MESSAGE_INDENT")), "");
+
+  const auto showContext = mf.GetCMakeInstance()->GetShowLogContext() ||
+    mf.IsOn("CMAKE_MESSAGE_CONTEXT_SHOW");
+  if (showContext) {
+    auto context = cmJoin(
+      cmExpandedList(mf.GetSafeDefinition("CMAKE_MESSAGE_CONTEXT")), ".");
+    if (!context.empty()) {
+      indent.insert(0u, cmStrCat("["_s, context, "] "_s));
+    }
+  }
+
+  if (!indent.empty()) {
+    cmSystemTools::ReplaceString(text, "\n", "\n" + indent);
+    text.insert(0u, indent);
+  }
+  return text;
+}
+
+void ReportCheckResult(cm::string_view what, std::string result,
+                       cmMakefile& mf)
+{
+  if (mf.GetCMakeInstance()->HasCheckInProgress()) {
+    auto text = mf.GetCMakeInstance()->GetTopCheckInProgressMessage() + " - " +
+      std::move(result);
+    mf.DisplayStatus(IndentText(std::move(text), mf), -1);
+  } else {
+    mf.GetMessenger()->DisplayMessage(
+      MessageType::AUTHOR_WARNING,
+      cmStrCat("Ignored "_s, what, " without CHECK_START"_s),
+      mf.GetBacktrace());
+  }
+}
+
+} // anonymous namespace
+
 // cmLibraryCommand
 bool cmMessageCommand(std::vector<std::string> const& args,
                       cmExecutionStatus& status)
@@ -21,11 +75,15 @@
     status.SetError("called with incorrect number of arguments");
     return false;
   }
+
+  auto& mf = status.GetMakefile();
+
   auto i = args.cbegin();
 
   auto type = MessageType::MESSAGE;
   auto fatal = false;
   auto level = cmake::LogLevel::LOG_UNDEFINED;
+  auto checkingType = CheckingType::UNDEFINED;
   if (*i == "SEND_ERROR") {
     type = MessageType::FATAL_ERROR;
     level = cmake::LogLevel::LOG_ERROR;
@@ -40,19 +98,30 @@
     level = cmake::LogLevel::LOG_WARNING;
     ++i;
   } else if (*i == "AUTHOR_WARNING") {
-    if (status.GetMakefile().IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") &&
-        !status.GetMakefile().IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) {
+    if (mf.IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") &&
+        !mf.IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) {
       fatal = true;
       type = MessageType::AUTHOR_ERROR;
       level = cmake::LogLevel::LOG_ERROR;
-    } else if (!status.GetMakefile().IsOn(
-                 "CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
+    } else if (!mf.IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
       type = MessageType::AUTHOR_WARNING;
       level = cmake::LogLevel::LOG_WARNING;
     } else {
       return true;
     }
     ++i;
+  } else if (*i == "CHECK_START") {
+    level = cmake::LogLevel::LOG_STATUS;
+    checkingType = CheckingType::CHECK_START;
+    ++i;
+  } else if (*i == "CHECK_PASS") {
+    level = cmake::LogLevel::LOG_STATUS;
+    checkingType = CheckingType::CHECK_PASS;
+    ++i;
+  } else if (*i == "CHECK_FAIL") {
+    level = cmake::LogLevel::LOG_STATUS;
+    checkingType = CheckingType::CHECK_FAIL;
+    ++i;
   } else if (*i == "STATUS") {
     level = cmake::LogLevel::LOG_STATUS;
     ++i;
@@ -66,12 +135,12 @@
     level = cmake::LogLevel::LOG_TRACE;
     ++i;
   } else if (*i == "DEPRECATION") {
-    if (status.GetMakefile().IsOn("CMAKE_ERROR_DEPRECATED")) {
+    if (mf.IsOn("CMAKE_ERROR_DEPRECATED")) {
       fatal = true;
       type = MessageType::DEPRECATION_ERROR;
       level = cmake::LogLevel::LOG_ERROR;
-    } else if (!status.GetMakefile().IsSet("CMAKE_WARN_DEPRECATED") ||
-               status.GetMakefile().IsOn("CMAKE_WARN_DEPRECATED")) {
+    } else if (!mf.IsSet("CMAKE_WARN_DEPRECATED") ||
+               mf.IsOn("CMAKE_WARN_DEPRECATED")) {
       type = MessageType::DEPRECATION_WARNING;
       level = cmake::LogLevel::LOG_WARNING;
     } else {
@@ -89,10 +158,19 @@
   assert("Message log level expected to be set" &&
          level != cmake::LogLevel::LOG_UNDEFINED);
 
-  auto desiredLevel = status.GetMakefile().GetCMakeInstance()->GetLogLevel();
+  auto desiredLevel = mf.GetCMakeInstance()->GetLogLevel();
   assert("Expected a valid log level here" &&
          desiredLevel != cmake::LogLevel::LOG_UNDEFINED);
 
+  // Command line option takes precedence over the cache variable
+  if (!mf.GetCMakeInstance()->WasLogLevelSetViaCLI()) {
+    const auto desiredLevelFromCache =
+      cmake::StringToLogLevel(mf.GetSafeDefinition("CMAKE_MESSAGE_LOG_LEVEL"));
+    if (desiredLevelFromCache != cmake::LogLevel::LOG_UNDEFINED) {
+      desiredLevel = desiredLevelFromCache;
+    }
+  }
+
   if (desiredLevel < level) {
     // Suppress the message
     return true;
@@ -100,37 +178,42 @@
 
   auto message = cmJoin(cmMakeRange(i, args.cend()), "");
 
-  if (cmake::LogLevel::LOG_NOTICE <= level) {
-    // Check if any indentation has requested:
-    // `CMAKE_MESSAGE_INDENT` is a list of "padding" pieces
-    // to be joined and prepended to the message lines.
-    auto indent = cmJoin(cmExpandedList(status.GetMakefile().GetSafeDefinition(
-                           "CMAKE_MESSAGE_INDENT")),
-                         "");
-    // Make every line of the `message` indented
-    // NOTE Can't reuse `cmDocumentationFormatter::PrintPreformatted`
-    // here cuz it appends `\n` to the EOM ;-(
-    cmSystemTools::ReplaceString(message, "\n", "\n" + indent);
-    message = indent + message;
-  }
-
   switch (level) {
     case cmake::LogLevel::LOG_ERROR:
     case cmake::LogLevel::LOG_WARNING:
       // we've overridden the message type, above, so display it directly
-      status.GetMakefile().GetMessenger()->DisplayMessage(
-        type, message, status.GetMakefile().GetBacktrace());
+      mf.GetMessenger()->DisplayMessage(type, message, mf.GetBacktrace());
       break;
 
     case cmake::LogLevel::LOG_NOTICE:
-      cmSystemTools::Message(message);
+      cmSystemTools::Message(IndentText(message, mf));
       break;
 
     case cmake::LogLevel::LOG_STATUS:
+      switch (checkingType) {
+        case CheckingType::CHECK_START:
+          mf.DisplayStatus(IndentText(message, mf), -1);
+          mf.GetCMakeInstance()->PushCheckInProgressMessage(message);
+          break;
+
+        case CheckingType::CHECK_PASS:
+          ReportCheckResult("CHECK_PASS"_s, message, mf);
+          break;
+
+        case CheckingType::CHECK_FAIL:
+          ReportCheckResult("CHECK_FAIL"_s, message, mf);
+          break;
+
+        default:
+          mf.DisplayStatus(IndentText(message, mf), -1);
+          break;
+      }
+      break;
+
     case cmake::LogLevel::LOG_VERBOSE:
     case cmake::LogLevel::LOG_DEBUG:
     case cmake::LogLevel::LOG_TRACE:
-      status.GetMakefile().DisplayStatus(message, -1);
+      mf.DisplayStatus(IndentText(message, mf), -1);
       break;
 
     default:
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index a458cac..885703f 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"
@@ -41,33 +41,25 @@
 cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
   cmGeneratorTarget* target)
   : cmNinjaTargetGenerator(target)
-  , TargetLinkLanguage("")
 {
-  this->TargetLinkLanguage = target->GetLinkerLanguage(this->GetConfigName());
-  if (target->GetType() == cmStateEnums::EXECUTABLE) {
-    this->TargetNames = this->GetGeneratorTarget()->GetExecutableNames(
-      GetLocalGenerator()->GetConfigName());
-  } else {
-    this->TargetNames = this->GetGeneratorTarget()->GetLibraryNames(
-      GetLocalGenerator()->GetConfigName());
-  }
-
   if (target->GetType() != cmStateEnums::OBJECT_LIBRARY) {
     // on Windows the output dir is already needed at compile time
     // ensure the directory exists (OutDir test)
-    EnsureDirectoryExists(target->GetDirectory(this->GetConfigName()));
+    for (auto const& config : this->GetConfigNames()) {
+      EnsureDirectoryExists(target->GetDirectory(config));
+    }
   }
 
-  this->OSXBundleGenerator =
-    cm::make_unique<cmOSXBundleGenerator>(target, this->GetConfigName());
+  this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(target);
   this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
 }
 
 cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator() = default;
 
-void cmNinjaNormalTargetGenerator::Generate()
+void cmNinjaNormalTargetGenerator::Generate(const std::string& config)
 {
-  if (this->TargetLinkLanguage.empty()) {
+  std::string lang = this->GeneratorTarget->GetLinkerLanguage(config);
+  if (this->TargetLinkLanguage(config).empty()) {
     cmSystemTools::Error("CMake can not determine linker language for "
                          "target: " +
                          this->GetGeneratorTarget()->GetName());
@@ -75,25 +67,48 @@
   }
 
   // Write the rules for each language.
-  this->WriteLanguagesRules();
+  this->WriteLanguagesRules(config);
 
   // Write the build statements
-  this->WriteObjectBuildStatements();
+  bool firstForConfig = true;
+  for (auto const& fileConfig : this->GetConfigNames()) {
+    if (!this->GetGlobalGenerator()
+           ->GetCrossConfigs(fileConfig)
+           .count(config)) {
+      continue;
+    }
+    this->WriteObjectBuildStatements(config, fileConfig, firstForConfig);
+    firstForConfig = false;
+  }
 
   if (this->GetGeneratorTarget()->GetType() == cmStateEnums::OBJECT_LIBRARY) {
-    this->WriteObjectLibStatement();
+    this->WriteObjectLibStatement(config);
   } else {
-    // If this target has cuda language link inputs, and we need to do
-    // device linking
-    this->WriteDeviceLinkStatement();
-    this->WriteLinkStatement();
+    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;
+    }
+  }
+  if (this->GetGlobalGenerator()->EnableCrossConfigBuild()) {
+    this->GetGlobalGenerator()->AddTargetAlias(
+      this->GetTargetName(), this->GetGeneratorTarget(), "all");
   }
 
   // Find ADDITIONAL_CLEAN_FILES
-  this->AdditionalCleanFiles();
+  this->AdditionalCleanFiles(config);
 }
 
-void cmNinjaNormalTargetGenerator::WriteLanguagesRules()
+void cmNinjaNormalTargetGenerator::WriteLanguagesRules(
+  const std::string& config)
 {
 #ifdef NINJA_GEN_VERBOSE_FILES
   cmGlobalNinjaGenerator::WriteDivider(this->GetRulesFileStream());
@@ -106,8 +121,7 @@
   // Write rules for languages compiled in this target.
   std::set<std::string> languages;
   std::vector<cmSourceFile const*> sourceFiles;
-  this->GetGeneratorTarget()->GetObjectSources(
-    sourceFiles, this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+  this->GetGeneratorTarget()->GetObjectSources(sourceFiles, config);
   for (cmSourceFile const* sf : sourceFiles) {
     std::string const lang = sf->GetLanguage();
     if (!lang.empty()) {
@@ -115,7 +129,7 @@
     }
   }
   for (std::string const& language : languages) {
-    this->WriteLanguageRules(language);
+    this->WriteLanguageRules(language, config);
   }
 }
 
@@ -139,22 +153,26 @@
   }
 }
 
-std::string cmNinjaNormalTargetGenerator::LanguageLinkerRule() const
+std::string cmNinjaNormalTargetGenerator::LanguageLinkerRule(
+  const std::string& config) const
 {
-  return this->TargetLinkLanguage + "_" +
+  return this->TargetLinkLanguage(config) + "_" +
     cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) +
     "_LINKER__" +
     cmGlobalNinjaGenerator::EncodeRuleName(
-           this->GetGeneratorTarget()->GetName());
+           this->GetGeneratorTarget()->GetName()) +
+    "_" + config;
 }
 
-std::string cmNinjaNormalTargetGenerator::LanguageLinkerDeviceRule() const
+std::string cmNinjaNormalTargetGenerator::LanguageLinkerDeviceRule(
+  const std::string& config) const
 {
-  return this->TargetLinkLanguage + "_" +
+  return this->TargetLinkLanguage(config) + "_" +
     cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) +
     "_DEVICE_LINKER__" +
     cmGlobalNinjaGenerator::EncodeRuleName(
-           this->GetGeneratorTarget()->GetName());
+           this->GetGeneratorTarget()->GetName()) +
+    "_" + config;
 }
 
 struct cmNinjaRemoveNoOpCommands
@@ -165,9 +183,10 @@
   }
 };
 
-void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile)
+void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(
+  bool useResponseFile, const std::string& config)
 {
-  cmNinjaRule rule(this->LanguageLinkerDeviceRule());
+  cmNinjaRule rule(this->LanguageLinkerDeviceRule(config));
   if (!this->GetGlobalGenerator()->HasRule(rule.Name)) {
     cmRulePlaceholderExpander::RuleVariables vars;
     vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
@@ -236,35 +255,40 @@
     }
 
     // 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);
 
     // Write the linker rule with response file if needed.
-    rule.Comment = cmStrCat("Rule for linking ", this->TargetLinkLanguage, ' ',
-                            this->GetVisibleTypeName(), '.');
-    rule.Description = cmStrCat("Linking ", this->TargetLinkLanguage, ' ',
-                                this->GetVisibleTypeName(), " $TARGET_FILE");
+    rule.Comment =
+      cmStrCat("Rule for linking ", this->TargetLinkLanguage(config), ' ',
+               this->GetVisibleTypeName(), '.');
+    rule.Description =
+      cmStrCat("Linking ", this->TargetLinkLanguage(config), ' ',
+               this->GetVisibleTypeName(), " $TARGET_FILE");
     rule.Restat = "$RESTAT";
 
     this->GetGlobalGenerator()->AddRule(rule);
   }
 }
 
-void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile)
+void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile,
+                                                 const std::string& config)
 {
   cmStateEnums::TargetType targetType = this->GetGeneratorTarget()->GetType();
 
-  std::string linkRuleName = this->LanguageLinkerRule();
+  std::string linkRuleName = this->LanguageLinkerRule(config);
   if (!this->GetGlobalGenerator()->HasRule(linkRuleName)) {
     cmNinjaRule rule(std::move(linkRuleName));
     cmRulePlaceholderExpander::RuleVariables vars;
     vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
     vars.CMTargetType = cmState::GetTargetTypeName(targetType);
 
-    vars.Language = this->TargetLinkLanguage.c_str();
+    std::string lang = this->TargetLinkLanguage(config);
+    vars.Language = config.c_str();
+    vars.AIXExports = "$AIX_EXPORTS";
 
-    if (this->TargetLinkLanguage == "Swift") {
+    if (this->TargetLinkLanguage(config) == "Swift") {
       vars.SwiftLibraryName = "$SWIFT_LIBRARY_NAME";
       vars.SwiftModule = "$SWIFT_MODULE";
       vars.SwiftModuleName = "$SWIFT_MODULE_NAME";
@@ -278,7 +302,8 @@
 
     std::string responseFlag;
 
-    std::string cmakeVarLang = cmStrCat("CMAKE_", this->TargetLinkLanguage);
+    std::string cmakeVarLang =
+      cmStrCat("CMAKE_", this->TargetLinkLanguage(config));
 
     // build response file name
     std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
@@ -304,7 +329,7 @@
         rule.RspContent = "$in_newline";
       }
       rule.RspContent += " $LINK_PATH $LINK_LIBRARIES";
-      if (this->TargetLinkLanguage == "Swift") {
+      if (this->TargetLinkLanguage(config) == "Swift") {
         vars.SwiftSources = responseFlag.c_str();
       } else {
         vars.Objects = responseFlag.c_str();
@@ -359,7 +384,7 @@
       this->GetLocalGenerator()->CreateRulePlaceholderExpander());
 
     // Rule for linking library/executable.
-    std::vector<std::string> linkCmds = this->ComputeLinkCmd();
+    std::vector<std::string> linkCmds = this->ComputeLinkCmd(config);
     for (std::string& linkCmd : linkCmds) {
       linkCmd = cmStrCat(launcher, linkCmd);
       rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
@@ -367,22 +392,25 @@
     }
 
     // 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");
     rule.Command = this->GetLocalGenerator()->BuildCommandLine(linkCmds);
 
     // Write the linker rule with response file if needed.
-    rule.Comment = cmStrCat("Rule for linking ", this->TargetLinkLanguage, ' ',
-                            this->GetVisibleTypeName(), '.');
-    rule.Description = cmStrCat("Linking ", this->TargetLinkLanguage, ' ',
-                                this->GetVisibleTypeName(), " $TARGET_FILE");
+    rule.Comment =
+      cmStrCat("Rule for linking ", this->TargetLinkLanguage(config), ' ',
+               this->GetVisibleTypeName(), '.');
+    rule.Description =
+      cmStrCat("Linking ", this->TargetLinkLanguage(config), ' ',
+               this->GetVisibleTypeName(), " $TARGET_FILE");
     rule.Restat = "$RESTAT";
     this->GetGlobalGenerator()->AddRule(rule);
   }
 
-  if (this->TargetNames.Output != this->TargetNames.Real &&
+  auto const tgtNames = this->TargetNames(config);
+  if (tgtNames.Output != tgtNames.Real &&
       !this->GetGeneratorTarget()->IsFrameworkOnApple()) {
     std::string cmakeCommand =
       this->GetLocalGenerator()->ConvertToOutputFormat(
@@ -441,7 +469,8 @@
   return linkCmds;
 }
 
-std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd()
+std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd(
+  const std::string& config)
 {
   std::vector<std::string> linkCmds;
   cmMakefile* mf = this->GetMakefile();
@@ -450,14 +479,14 @@
     // this occurs when things like IPO is enabled, and we need to use the
     // CMAKE_<lang>_CREATE_STATIC_LIBRARY_IPO define instead.
     std::string linkCmdVar = this->GetGeneratorTarget()->GetCreateRuleVariable(
-      this->TargetLinkLanguage, this->GetConfigName());
+      this->TargetLinkLanguage(config), config);
     const char* linkCmd = mf->GetDefinition(linkCmdVar);
     if (linkCmd) {
       std::string linkCmdStr = linkCmd;
-      if (this->GetGeneratorTarget()->HasImplibGNUtoMS(this->ConfigName)) {
-        std::string ruleVar = cmStrCat(
-          "CMAKE_", this->GeneratorTarget->GetLinkerLanguage(this->ConfigName),
-          "_GNUtoMS_RULE");
+      if (this->GetGeneratorTarget()->HasImplibGNUtoMS(config)) {
+        std::string ruleVar =
+          cmStrCat("CMAKE_", this->GeneratorTarget->GetLinkerLanguage(config),
+                   "_GNUtoMS_RULE");
         if (const char* rule = this->Makefile->GetDefinition(ruleVar)) {
           linkCmdStr += rule;
         }
@@ -469,9 +498,8 @@
             cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL),
           " -E __run_co_compile --lwyu=");
         cmGeneratorTarget& gt = *this->GetGeneratorTarget();
-        const std::string cfgName = this->GetConfigName();
         std::string targetOutputReal = this->ConvertToNinjaPath(
-          gt.GetFullPath(cfgName, cmStateEnums::RuntimeBinaryArtifact,
+          gt.GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact,
                          /*realname=*/true));
         cmakeCommand += targetOutputReal;
         linkCmds.push_back(std::move(cmakeCommand));
@@ -486,25 +514,25 @@
         std::string cmakeCommand =
           this->GetLocalGenerator()->ConvertToOutputFormat(
             cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
-        linkCmds.push_back(cmakeCommand + " -E remove $TARGET_FILE");
+        linkCmds.push_back(cmakeCommand + " -E rm -f $TARGET_FILE");
       }
       // TODO: Use ARCHIVE_APPEND for archives over a certain size.
       {
-        std::string linkCmdVar =
-          cmStrCat("CMAKE_", this->TargetLinkLanguage, "_ARCHIVE_CREATE");
+        std::string linkCmdVar = cmStrCat(
+          "CMAKE_", this->TargetLinkLanguage(config), "_ARCHIVE_CREATE");
 
         linkCmdVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable(
-          linkCmdVar, this->TargetLinkLanguage, this->GetConfigName());
+          linkCmdVar, this->TargetLinkLanguage(config), config);
 
         std::string const& linkCmd = mf->GetRequiredDefinition(linkCmdVar);
         cmExpandList(linkCmd, linkCmds);
       }
       {
-        std::string linkCmdVar =
-          cmStrCat("CMAKE_", this->TargetLinkLanguage, "_ARCHIVE_FINISH");
+        std::string linkCmdVar = cmStrCat(
+          "CMAKE_", this->TargetLinkLanguage(config), "_ARCHIVE_FINISH");
 
         linkCmdVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable(
-          linkCmdVar, this->TargetLinkLanguage, this->GetConfigName());
+          linkCmdVar, this->TargetLinkLanguage(config), config);
 
         std::string const& linkCmd = mf->GetRequiredDefinition(linkCmdVar);
         cmExpandList(linkCmd, linkCmds);
@@ -523,19 +551,28 @@
         linkCmds.push_back(cmakeCommand + " -E touch $TARGET_FILE");
       }
 #endif
-      return linkCmds;
-    }
+    } break;
     case cmStateEnums::SHARED_LIBRARY:
     case cmStateEnums::MODULE_LIBRARY:
+      break;
     case cmStateEnums::EXECUTABLE:
+      if (this->TargetLinkLanguage(config) == "Swift") {
+        if (this->GeneratorTarget->IsExecutableWithExports()) {
+          const std::string flags =
+            this->Makefile->GetSafeDefinition("CMAKE_EXE_EXPORTS_Swift_FLAG");
+          cmExpandList(flags, linkCmds);
+        }
+      }
       break;
     default:
       assert(false && "Unexpected target type");
   }
-  return std::vector<std::string>();
+  return linkCmds;
 }
 
-void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
+void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement(
+  const std::string& config, const std::string& fileConfig,
+  bool firstForConfig)
 {
   cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator();
   if (!globalGen->GetLanguageEnabled("CUDA")) {
@@ -545,7 +582,7 @@
   cmGeneratorTarget* genTarget = this->GetGeneratorTarget();
 
   bool requiresDeviceLinking = requireDeviceLinking(
-    *this->GeneratorTarget, *this->GetLocalGenerator(), this->ConfigName);
+    *this->GeneratorTarget, *this->GetLocalGenerator(), config);
   if (!requiresDeviceLinking) {
     return;
   }
@@ -558,24 +595,53 @@
   std::string const& objExt =
     this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION");
 
-  std::string const cfgName = this->GetConfigName();
-  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(
-    genTarget->GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact));
+  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.
-  cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
+  cmGlobalNinjaGenerator::WriteDivider(this->GetCommonFileStream());
   const cmStateEnums::TargetType targetType = genTarget->GetType();
-  this->GetBuildFileStream() << "# Device Link build statements for "
-                             << cmState::GetTargetTypeName(targetType)
-                             << " target " << this->GetTargetName() << "\n\n";
+  this->GetCommonFileStream() << "# Device Link build statements for "
+                              << cmState::GetTargetTypeName(targetType)
+                              << " target " << this->GetTargetName() << "\n\n";
 
   // Compute the comment.
-  cmNinjaBuild build(this->LanguageLinkerDeviceRule());
+  cmNinjaBuild build(this->LanguageLinkerDeviceRule(config));
   build.Comment =
     cmStrCat("Link the ", this->GetVisibleTypeName(), ' ', targetOutputReal);
 
@@ -584,14 +650,15 @@
   // Compute outputs.
   build.Outputs.push_back(targetOutputReal);
   // Compute specific libraries to link with.
-  build.ExplicitDeps = this->GetObjects();
-  build.ImplicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage);
+  build.ExplicitDeps = this->GetObjects(config);
+  build.ImplicitDeps =
+    this->ComputeLinkDeps(this->TargetLinkLanguage(config), config);
 
   std::string frameworkPath;
   std::string linkPath;
 
-  std::string createRule = genTarget->GetCreateRuleVariable(
-    this->TargetLinkLanguage, this->GetConfigName());
+  std::string createRule =
+    genTarget->GetCreateRuleVariable(this->TargetLinkLanguage(config), config);
   const bool useWatcomQuote =
     this->GetMakefile()->IsOn(createRule + "_USE_WATCOM_QUOTE");
   cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator();
@@ -605,17 +672,17 @@
       this->GetLocalGenerator()->GetStateSnapshot().GetDirectory(),
       globalGen));
   linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
+  linkLineComputer->SetUseNinjaMulti(globalGen->IsMultiConfig());
 
   localGen.GetTargetFlags(
-    linkLineComputer.get(), this->GetConfigName(), vars["LINK_LIBRARIES"],
-    vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath, linkPath, genTarget);
+    linkLineComputer.get(), config, vars["LINK_LIBRARIES"], vars["FLAGS"],
+    vars["LINK_FLAGS"], frameworkPath, linkPath, genTarget);
 
   this->addPoolNinjaVariable("JOB_POOL_LINK", genTarget, vars);
 
-  vars["LINK_FLAGS"] =
-    cmGlobalNinjaGenerator::EncodeLiteral(vars["LINK_FLAGS"]);
+  vars["LINK_FLAGS"] = globalGen->EncodeLiteral(vars["LINK_FLAGS"]);
 
-  vars["MANIFESTS"] = this->GetManifests();
+  vars["MANIFESTS"] = this->GetManifests(config);
 
   vars["LINK_PATH"] = frameworkPath + linkPath;
 
@@ -624,24 +691,25 @@
   // code between the Makefile executable and library generators.
   if (targetType == cmStateEnums::EXECUTABLE) {
     std::string t = vars["FLAGS"];
-    localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, cfgName);
+    localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, config);
     vars["FLAGS"] = t;
   } else {
     std::string t = vars["ARCH_FLAGS"];
-    localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, cfgName);
+    localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, config);
     vars["ARCH_FLAGS"] = t;
     t.clear();
     localGen.AddLanguageFlagsForLinking(t, genTarget, cudaLinkLanguage,
-                                        cfgName);
+                                        config);
     vars["LANGUAGE_COMPILE_FLAGS"] = t;
   }
-  if (genTarget->HasSOName(cfgName)) {
+  auto const tgtNames = this->TargetNames(config);
+  if (genTarget->HasSOName(config)) {
     vars["SONAME_FLAG"] =
-      this->GetMakefile()->GetSONameFlag(this->TargetLinkLanguage);
-    vars["SONAME"] = this->TargetNames.SharedObject;
+      this->GetMakefile()->GetSONameFlag(this->TargetLinkLanguage(config));
+    vars["SONAME"] = tgtNames.SharedObject;
     if (targetType == cmStateEnums::SHARED_LIBRARY) {
       std::string install_dir =
-        this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName);
+        this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(config);
       if (!install_dir.empty()) {
         vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat(
           install_dir, cmOutputConverter::SHELL);
@@ -649,25 +717,28 @@
     }
   }
 
-  if (!this->TargetNames.ImportLibrary.empty()) {
+  if (!tgtNames.ImportLibrary.empty()) {
     const std::string impLibPath = localGen.ConvertToOutputFormat(
       targetOutputImplib, cmOutputConverter::SHELL);
     vars["TARGET_IMPLIB"] = impLibPath;
     EnsureParentDirectoryExists(impLibPath);
   }
 
-  const std::string objPath = GetGeneratorTarget()->GetSupportDirectory();
+  const std::string objPath =
+    cmStrCat(GetGeneratorTarget()->GetSupportDirectory(),
+             globalGen->ConfigDirectory(config));
+
   vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
     this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL);
   EnsureDirectoryExists(objPath);
 
-  this->SetMsvcTargetPdbVariable(vars);
+  this->SetMsvcTargetPdbVariable(vars, config);
 
+  std::string& linkLibraries = vars["LINK_LIBRARIES"];
+  std::string& link_path = vars["LINK_PATH"];
   if (globalGen->IsGCCOnWindows()) {
     // ar.exe can't handle backslashes in rsp files (implicitly used by gcc)
-    std::string& linkLibraries = vars["LINK_LIBRARIES"];
     std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/');
-    std::string& link_path = vars["LINK_PATH"];
     std::replace(link_path.begin(), link_path.end(), '\\', '/');
   }
 
@@ -675,65 +746,88 @@
   // do not check if the user has explicitly forced a response file.
   int const commandLineLengthLimit =
     static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
-    globalGen->GetRuleCmdLength(this->LanguageLinkerDeviceRule());
+    globalGen->GetRuleCmdLength(this->LanguageLinkerDeviceRule(config));
 
   build.RspFile = this->ConvertToNinjaPath(std::string("CMakeFiles/") +
                                            genTarget->GetName() + ".rsp");
 
   // Gather order-only dependencies.
-  this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(),
-                                                 build.OrderOnlyDeps);
+  this->GetLocalGenerator()->AppendTargetDepends(
+    this->GetGeneratorTarget(), build.OrderOnlyDeps, config, config);
 
   // Write the build statement for this target.
   bool usedResponseFile = false;
-  globalGen->WriteBuild(this->GetBuildFileStream(), build,
+  globalGen->WriteBuild(this->GetCommonFileStream(), build,
                         commandLineLengthLimit, &usedResponseFile);
-  this->WriteDeviceLinkRule(usedResponseFile);
+  this->WriteDeviceLinkRule(usedResponseFile, config);
 }
 
-void cmNinjaNormalTargetGenerator::WriteLinkStatement()
+void cmNinjaNormalTargetGenerator::WriteLinkStatement(
+  const std::string& config, const std::string& fileConfig,
+  bool firstForConfig)
 {
   cmMakefile* mf = this->GetMakefile();
   cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator();
   cmGeneratorTarget* gt = this->GetGeneratorTarget();
 
-  const std::string cfgName = this->GetConfigName();
-  std::string targetOutput = ConvertToNinjaPath(gt->GetFullPath(cfgName));
+  std::string targetOutput = ConvertToNinjaPath(gt->GetFullPath(config));
   std::string targetOutputReal = ConvertToNinjaPath(
-    gt->GetFullPath(cfgName, cmStateEnums::RuntimeBinaryArtifact,
+    gt->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact,
                     /*realname=*/true));
   std::string targetOutputImplib = ConvertToNinjaPath(
-    gt->GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact));
+    gt->GetFullPath(config, cmStateEnums::ImportLibraryArtifact));
 
+  if (config != fileConfig) {
+    if (targetOutput == ConvertToNinjaPath(gt->GetFullPath(fileConfig))) {
+      return;
+    }
+    if (targetOutputReal ==
+        ConvertToNinjaPath(gt->GetFullPath(fileConfig,
+                                           cmStateEnums::RuntimeBinaryArtifact,
+                                           /*realname=*/true))) {
+      return;
+    }
+    if (!gt->GetFullName(config, cmStateEnums::ImportLibraryArtifact)
+           .empty() &&
+        !gt->GetFullName(fileConfig, cmStateEnums::ImportLibraryArtifact)
+           .empty() &&
+        targetOutputImplib ==
+          ConvertToNinjaPath(gt->GetFullPath(
+            fileConfig, cmStateEnums::ImportLibraryArtifact))) {
+      return;
+    }
+  }
+
+  auto const tgtNames = this->TargetNames(config);
   if (gt->IsAppBundleOnApple()) {
     // Create the app bundle
-    std::string outpath = gt->GetDirectory(cfgName);
-    this->OSXBundleGenerator->CreateAppBundle(this->TargetNames.Output,
-                                              outpath);
+    std::string outpath = gt->GetDirectory(config);
+    this->OSXBundleGenerator->CreateAppBundle(tgtNames.Output, outpath,
+                                              config);
 
     // Calculate the output path
-    targetOutput = cmStrCat(outpath, '/', this->TargetNames.Output);
+    targetOutput = cmStrCat(outpath, '/', tgtNames.Output);
     targetOutput = this->ConvertToNinjaPath(targetOutput);
-    targetOutputReal = cmStrCat(outpath, '/', this->TargetNames.Real);
+    targetOutputReal = cmStrCat(outpath, '/', tgtNames.Real);
     targetOutputReal = this->ConvertToNinjaPath(targetOutputReal);
   } else if (gt->IsFrameworkOnApple()) {
     // Create the library framework.
-    this->OSXBundleGenerator->CreateFramework(this->TargetNames.Output,
-                                              gt->GetDirectory(cfgName));
+    this->OSXBundleGenerator->CreateFramework(
+      tgtNames.Output, gt->GetDirectory(config), config);
   } else if (gt->IsCFBundleOnApple()) {
     // Create the core foundation bundle.
-    this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output,
-                                             gt->GetDirectory(cfgName));
+    this->OSXBundleGenerator->CreateCFBundle(tgtNames.Output,
+                                             gt->GetDirectory(config), config);
   }
 
   // Write comments.
-  cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
+  cmGlobalNinjaGenerator::WriteDivider(this->GetImplFileStream(fileConfig));
   const cmStateEnums::TargetType targetType = gt->GetType();
-  this->GetBuildFileStream()
+  this->GetImplFileStream(fileConfig)
     << "# Link build statements for " << cmState::GetTargetTypeName(targetType)
     << " target " << this->GetTargetName() << "\n\n";
 
-  cmNinjaBuild linkBuild(this->LanguageLinkerRule());
+  cmNinjaBuild linkBuild(this->LanguageLinkerRule(config));
   cmNinjaVars& vars = linkBuild.Variables;
 
   // Compute the comment.
@@ -742,11 +836,14 @@
 
   // Compute outputs.
   linkBuild.Outputs.push_back(targetOutputReal);
+  if (firstForConfig) {
+    globalGen->GetByproductsForCleanTarget(config).push_back(targetOutputReal);
+  }
 
-  if (this->TargetLinkLanguage == "Swift") {
-    vars["SWIFT_LIBRARY_NAME"] = [this]() -> std::string {
+  if (this->TargetLinkLanguage(config) == "Swift") {
+    vars["SWIFT_LIBRARY_NAME"] = [this, config]() -> std::string {
       cmGeneratorTarget::Names targetNames =
-        this->GetGeneratorTarget()->GetLibraryNames(this->GetConfigName());
+        this->GetGeneratorTarget()->GetLibraryNames(config);
       return targetNames.Base;
     }();
 
@@ -776,18 +873,17 @@
         cmOutputConverter::SHELL);
     }(vars["SWIFT_MODULE_NAME"]);
 
+    const std::string map = cmStrCat(gt->GetSupportDirectory(), '/', config,
+                                     '/', "output-file-map.json");
     vars["SWIFT_OUTPUT_FILE_MAP"] =
       this->GetLocalGenerator()->ConvertToOutputFormat(
-        this->ConvertToNinjaPath(gt->GetSupportDirectory() +
-                                 "/output-file-map.json"),
-        cmOutputConverter::SHELL);
+        this->ConvertToNinjaPath(map), cmOutputConverter::SHELL);
 
-    vars["SWIFT_SOURCES"] = [this]() -> std::string {
+    vars["SWIFT_SOURCES"] = [this, config]() -> std::string {
       std::vector<cmSourceFile const*> sources;
       std::stringstream oss;
 
-      this->GetGeneratorTarget()->GetObjectSources(sources,
-                                                   this->GetConfigName());
+      this->GetGeneratorTarget()->GetObjectSources(sources, config);
       cmLocalGenerator const* LocalGen = this->GetLocalGenerator();
       for (const auto& source : sources) {
         oss << " "
@@ -801,27 +897,28 @@
     // Since we do not perform object builds, compute the
     // defines/flags/includes here so that they can be passed along
     // appropriately.
-    vars["DEFINES"] = this->GetDefines("Swift");
-    vars["FLAGS"] = this->GetFlags("Swift");
-    vars["INCLUDES"] = this->GetIncludes("Swift");
+    vars["DEFINES"] = this->GetDefines("Swift", config);
+    vars["FLAGS"] = this->GetFlags("Swift", config);
+    vars["INCLUDES"] = this->GetIncludes("Swift", config);
   }
 
   // Compute specific libraries to link with.
-  if (this->TargetLinkLanguage == "Swift") {
+  if (this->TargetLinkLanguage(config) == "Swift") {
     std::vector<cmSourceFile const*> sources;
-    gt->GetObjectSources(sources, this->GetConfigName());
+    gt->GetObjectSources(sources, config);
     for (const auto& source : sources) {
       linkBuild.Outputs.push_back(
-        this->ConvertToNinjaPath(this->GetObjectFilePath(source)));
+        this->ConvertToNinjaPath(this->GetObjectFilePath(source, config)));
       linkBuild.ExplicitDeps.push_back(
         this->ConvertToNinjaPath(this->GetSourceFilePath(source)));
     }
 
     linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]);
   } else {
-    linkBuild.ExplicitDeps = this->GetObjects();
+    linkBuild.ExplicitDeps = this->GetObjects(config);
   }
-  linkBuild.ImplicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage);
+  linkBuild.ImplicitDeps =
+    this->ComputeLinkDeps(this->TargetLinkLanguage(config), config);
 
   if (!this->DeviceLinkObject.empty()) {
     linkBuild.ExplicitDeps.push_back(this->DeviceLinkObject);
@@ -831,39 +928,42 @@
   std::string linkPath;
 
   std::string createRule =
-    gt->GetCreateRuleVariable(this->TargetLinkLanguage, this->GetConfigName());
+    gt->GetCreateRuleVariable(this->TargetLinkLanguage(config), config);
   bool useWatcomQuote = mf->IsOn(createRule + "_USE_WATCOM_QUOTE");
   cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator();
 
   vars["TARGET_FILE"] =
     localGen.ConvertToOutputFormat(targetOutputReal, cmOutputConverter::SHELL);
 
-  std::unique_ptr<cmLinkLineComputer> linkLineComputer(
+  std::unique_ptr<cmLinkLineComputer> linkLineComputer =
     globalGen->CreateLinkLineComputer(
       this->GetLocalGenerator(),
-      this->GetLocalGenerator()->GetStateSnapshot().GetDirectory()));
+      this->GetLocalGenerator()->GetStateSnapshot().GetDirectory());
   linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
+  linkLineComputer->SetUseNinjaMulti(globalGen->IsMultiConfig());
 
-  localGen.GetTargetFlags(linkLineComputer.get(), this->GetConfigName(),
+  localGen.GetTargetFlags(linkLineComputer.get(), config,
                           vars["LINK_LIBRARIES"], vars["FLAGS"],
                           vars["LINK_FLAGS"], frameworkPath, linkPath, gt);
 
   // Add OS X version flags, if any.
   if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
       this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
-    this->AppendOSXVerFlag(vars["LINK_FLAGS"], this->TargetLinkLanguage,
-                           "COMPATIBILITY", true);
-    this->AppendOSXVerFlag(vars["LINK_FLAGS"], this->TargetLinkLanguage,
-                           "CURRENT", false);
+    this->AppendOSXVerFlag(vars["LINK_FLAGS"],
+                           this->TargetLinkLanguage(config), "COMPATIBILITY",
+                           true);
+    this->AppendOSXVerFlag(vars["LINK_FLAGS"],
+                           this->TargetLinkLanguage(config), "CURRENT", false);
   }
 
   this->addPoolNinjaVariable("JOB_POOL_LINK", gt, vars);
 
-  this->AddModuleDefinitionFlag(linkLineComputer.get(), vars["LINK_FLAGS"]);
-  vars["LINK_FLAGS"] =
-    cmGlobalNinjaGenerator::EncodeLiteral(vars["LINK_FLAGS"]);
+  this->AddModuleDefinitionFlag(linkLineComputer.get(), vars["LINK_FLAGS"],
+                                config);
+  vars["LINK_FLAGS"] = globalGen->EncodeLiteral(vars["LINK_FLAGS"]);
 
-  vars["MANIFESTS"] = this->GetManifests();
+  vars["MANIFESTS"] = this->GetManifests(config);
+  vars["AIX_EXPORTS"] = this->GetAIXExports(config);
 
   vars["LINK_PATH"] = frameworkPath + linkPath;
   std::string lwyuFlags;
@@ -876,23 +976,26 @@
   // code between the Makefile executable and library generators.
   if (targetType == cmStateEnums::EXECUTABLE) {
     std::string t = vars["FLAGS"];
-    localGen.AddArchitectureFlags(t, gt, TargetLinkLanguage, cfgName);
+    localGen.AddArchitectureFlags(t, gt, this->TargetLinkLanguage(config),
+                                  config);
     t += lwyuFlags;
     vars["FLAGS"] = t;
   } else {
     std::string t = vars["ARCH_FLAGS"];
-    localGen.AddArchitectureFlags(t, gt, TargetLinkLanguage, cfgName);
+    localGen.AddArchitectureFlags(t, gt, this->TargetLinkLanguage(config),
+                                  config);
     vars["ARCH_FLAGS"] = t;
     t.clear();
     t += lwyuFlags;
-    localGen.AddLanguageFlagsForLinking(t, gt, TargetLinkLanguage, cfgName);
+    localGen.AddLanguageFlagsForLinking(
+      t, gt, this->TargetLinkLanguage(config), config);
     vars["LANGUAGE_COMPILE_FLAGS"] = t;
   }
-  if (gt->HasSOName(cfgName)) {
-    vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage);
-    vars["SONAME"] = this->TargetNames.SharedObject;
+  if (gt->HasSOName(config)) {
+    vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage(config));
+    vars["SONAME"] = tgtNames.SharedObject;
     if (targetType == cmStateEnums::SHARED_LIBRARY) {
-      std::string install_dir = gt->GetInstallNameDirForBuildTree(cfgName);
+      std::string install_dir = gt->GetInstallNameDirForBuildTree(config);
       if (!install_dir.empty()) {
         vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat(
           install_dir, cmOutputConverter::SHELL);
@@ -902,17 +1005,21 @@
 
   cmNinjaDeps byproducts;
 
-  if (!this->TargetNames.ImportLibrary.empty()) {
+  if (!tgtNames.ImportLibrary.empty()) {
     const std::string impLibPath = localGen.ConvertToOutputFormat(
       targetOutputImplib, cmOutputConverter::SHELL);
     vars["TARGET_IMPLIB"] = impLibPath;
     EnsureParentDirectoryExists(impLibPath);
-    if (gt->HasImportLibrary(cfgName)) {
+    if (gt->HasImportLibrary(config)) {
       byproducts.push_back(targetOutputImplib);
+      if (firstForConfig) {
+        globalGen->GetByproductsForCleanTarget(config).push_back(
+          targetOutputImplib);
+      }
     }
   }
 
-  if (!this->SetMsvcTargetPdbVariable(vars)) {
+  if (!this->SetMsvcTargetPdbVariable(vars, config)) {
     // It is common to place debug symbols at a specific place,
     // so we need a plain target name in the rule available.
     std::string prefix;
@@ -927,16 +1034,17 @@
     vars["TARGET_PDB"] = base + suffix + dbg_suffix;
   }
 
-  const std::string objPath = gt->GetSupportDirectory();
+  const std::string objPath =
+    cmStrCat(gt->GetSupportDirectory(), globalGen->ConfigDirectory(config));
   vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
     this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL);
   EnsureDirectoryExists(objPath);
 
+  std::string& linkLibraries = vars["LINK_LIBRARIES"];
+  std::string& link_path = vars["LINK_PATH"];
   if (globalGen->IsGCCOnWindows()) {
     // ar.exe can't handle backslashes in rsp files (implicitly used by gcc)
-    std::string& linkLibraries = vars["LINK_LIBRARIES"];
     std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/');
-    std::string& link_path = vars["LINK_PATH"];
     std::replace(link_path.begin(), link_path.end(), '\\', '/');
   }
 
@@ -947,23 +1055,30 @@
 
   std::vector<std::string> preLinkCmdLines;
   std::vector<std::string> postBuildCmdLines;
-  std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines,
-                                                &preLinkCmdLines,
-                                                &postBuildCmdLines };
 
-  for (unsigned i = 0; i != 3; ++i) {
-    for (cmCustomCommand const& cc : *cmdLists[i]) {
-      cmCustomCommandGenerator ccg(cc, cfgName, this->GetLocalGenerator());
-      localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]);
-      std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
-      std::transform(ccByproducts.begin(), ccByproducts.end(),
-                     std::back_inserter(byproducts), MapToNinjaPath());
+  if (config == fileConfig) {
+    std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines,
+                                                  &preLinkCmdLines,
+                                                  &postBuildCmdLines };
+
+    for (unsigned i = 0; i != 3; ++i) {
+      for (cmCustomCommand const& cc : *cmdLists[i]) {
+        cmCustomCommandGenerator ccg(cc, config, this->GetLocalGenerator());
+        localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]);
+        std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
+        std::transform(ccByproducts.begin(), ccByproducts.end(),
+                       std::back_inserter(byproducts), MapToNinjaPath());
+        std::transform(
+          ccByproducts.begin(), ccByproducts.end(),
+          std::back_inserter(globalGen->GetByproductsForCleanTarget()),
+          MapToNinjaPath());
+      }
     }
   }
 
   // maybe create .def file from list of objects
   cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
-    gt->GetModuleDefinitionInfo(this->GetConfigName());
+    gt->GetModuleDefinitionInfo(config);
   if (mdi && mdi->DefFileGenerated) {
     std::string cmakeCommand =
       this->GetLocalGenerator()->ConvertToOutputFormat(
@@ -989,7 +1104,7 @@
     cmGeneratedFileStream fout(obj_list_file);
 
     if (mdi->WindowsExportAllSymbols) {
-      cmNinjaDeps objs = this->GetObjects();
+      cmNinjaDeps objs = this->GetObjects(config);
       for (std::string const& obj : objs) {
         if (cmHasLiteralSuffix(obj, ".obj")) {
           fout << obj << "\n";
@@ -1024,7 +1139,8 @@
     symlinkVars["POST_BUILD"] = postBuildCmdLine;
   }
 
-  std::string cmakeVarLang = cmStrCat("CMAKE_", this->TargetLinkLanguage);
+  std::string cmakeVarLang =
+    cmStrCat("CMAKE_", this->TargetLinkLanguage(config));
 
   // build response file name
   std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
@@ -1032,8 +1148,8 @@
   const char* flag = GetMakefile()->GetDefinition(cmakeLinkVar);
 
   bool const lang_supports_response =
-    !(this->TargetLinkLanguage == "RC" ||
-      (this->TargetLinkLanguage == "CUDA" && !flag));
+    !(this->TargetLinkLanguage(config) == "RC" ||
+      (this->TargetLinkLanguage(config) == "CUDA" && !flag));
   int commandLineLengthLimit = -1;
   if (!lang_supports_response || !this->ForceResponseFile()) {
     commandLineLengthLimit =
@@ -1045,18 +1161,19 @@
                                                gt->GetName() + ".rsp");
 
   // Gather order-only dependencies.
-  this->GetLocalGenerator()->AppendTargetDepends(gt, linkBuild.OrderOnlyDeps);
+  this->GetLocalGenerator()->AppendTargetDepends(gt, linkBuild.OrderOnlyDeps,
+                                                 config, fileConfig);
 
   // Add order-only dependencies on versioning symlinks of shared libs we link.
   if (!this->GeneratorTarget->IsDLLPlatform()) {
     if (cmComputeLinkInformation* cli =
-          this->GeneratorTarget->GetLinkInformation(this->GetConfigName())) {
+          this->GeneratorTarget->GetLinkInformation(config)) {
       for (auto const& item : cli->GetItems()) {
         if (item.Target &&
             item.Target->GetType() == cmStateEnums::SHARED_LIBRARY &&
             !item.Target->IsFrameworkOnApple()) {
-          std::string const& lib = this->ConvertToNinjaPath(
-            item.Target->GetFullPath(this->GetConfigName()));
+          std::string const& lib =
+            this->ConvertToNinjaPath(item.Target->GetFullPath(config));
           if (std::find(linkBuild.ImplicitDeps.begin(),
                         linkBuild.ImplicitDeps.end(),
                         lib) == linkBuild.ImplicitDeps.end()) {
@@ -1077,24 +1194,27 @@
 
   // Write the build statement for this target.
   bool usedResponseFile = false;
-  globalGen->WriteBuild(this->GetBuildFileStream(), linkBuild,
+  globalGen->WriteBuild(this->GetImplFileStream(fileConfig), linkBuild,
                         commandLineLengthLimit, &usedResponseFile);
-  this->WriteLinkRule(usedResponseFile);
+  this->WriteLinkRule(usedResponseFile, config);
 
   if (symlinkNeeded) {
     if (targetType == cmStateEnums::EXECUTABLE) {
       cmNinjaBuild build("CMAKE_SYMLINK_EXECUTABLE");
       build.Comment = "Create executable symlink " + targetOutput;
       build.Outputs.push_back(targetOutput);
+      if (firstForConfig) {
+        globalGen->GetByproductsForCleanTarget(config).push_back(targetOutput);
+      }
       build.ExplicitDeps.push_back(targetOutputReal);
       build.Variables = std::move(symlinkVars);
-      globalGen->WriteBuild(this->GetBuildFileStream(), build);
+      globalGen->WriteBuild(this->GetImplFileStream(fileConfig), build);
     } else {
       cmNinjaBuild build("CMAKE_SYMLINK_LIBRARY");
       build.Comment = "Create library symlink " + targetOutput;
 
       std::string const soName = this->ConvertToNinjaPath(
-        this->GetTargetFilePath(this->TargetNames.SharedObject));
+        this->GetTargetFilePath(tgtNames.SharedObject, config));
       // If one link has to be created.
       if (targetOutputReal == soName || targetOutput == soName) {
         symlinkVars["SONAME"] =
@@ -1103,33 +1223,58 @@
       } else {
         symlinkVars["SONAME"].clear();
         build.Outputs.push_back(soName);
+        if (firstForConfig) {
+          globalGen->GetByproductsForCleanTarget(config).push_back(soName);
+        }
       }
       build.Outputs.push_back(targetOutput);
+      if (firstForConfig) {
+        globalGen->GetByproductsForCleanTarget(config).push_back(targetOutput);
+      }
       build.ExplicitDeps.push_back(targetOutputReal);
       build.Variables = std::move(symlinkVars);
 
-      globalGen->WriteBuild(this->GetBuildFileStream(), build);
+      globalGen->WriteBuild(this->GetImplFileStream(fileConfig), build);
     }
   }
 
   // Add aliases for the file name and the target name.
-  globalGen->AddTargetAlias(this->TargetNames.Output, gt);
-  globalGen->AddTargetAlias(this->GetTargetName(), gt);
+  globalGen->AddTargetAlias(tgtNames.Output, gt, config);
+  globalGen->AddTargetAlias(this->GetTargetName(), gt, config);
 }
 
-void cmNinjaNormalTargetGenerator::WriteObjectLibStatement()
+void cmNinjaNormalTargetGenerator::WriteObjectLibStatement(
+  const std::string& config)
 {
   // Write a phony output that depends on all object files.
   {
     cmNinjaBuild build("phony");
     build.Comment = "Object library " + this->GetTargetName();
     this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(),
-                                                   build.Outputs);
-    build.ExplicitDeps = this->GetObjects();
-    this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build);
+                                                   build.Outputs, config);
+    this->GetLocalGenerator()->AppendTargetOutputs(
+      this->GetGeneratorTarget(),
+      this->GetGlobalGenerator()->GetByproductsForCleanTarget(config), config);
+    build.ExplicitDeps = this->GetObjects(config);
+    this->GetGlobalGenerator()->WriteBuild(this->GetCommonFileStream(), build);
   }
 
   // Add aliases for the target name.
-  this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
-                                             this->GetGeneratorTarget());
+  this->GetGlobalGenerator()->AddTargetAlias(
+    this->GetTargetName(), this->GetGeneratorTarget(), config);
+}
+
+cmGeneratorTarget::Names cmNinjaNormalTargetGenerator::TargetNames(
+  const std::string& config) const
+{
+  if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
+    return this->GeneratorTarget->GetExecutableNames(config);
+  }
+  return this->GeneratorTarget->GetLibraryNames(config);
+}
+
+std::string cmNinjaNormalTargetGenerator::TargetLinkLanguage(
+  const std::string& config) const
+{
+  return this->GeneratorTarget->GetLinkerLanguage(config);
 }
diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h
index ebc1268..9de99b9 100644
--- a/Source/cmNinjaNormalTargetGenerator.h
+++ b/Source/cmNinjaNormalTargetGenerator.h
@@ -17,30 +17,33 @@
   cmNinjaNormalTargetGenerator(cmGeneratorTarget* target);
   ~cmNinjaNormalTargetGenerator() override;
 
-  void Generate() override;
+  void Generate(const std::string& config) override;
 
 private:
-  std::string LanguageLinkerRule() const;
-  std::string LanguageLinkerDeviceRule() const;
+  std::string LanguageLinkerRule(const std::string& config) const;
+  std::string LanguageLinkerDeviceRule(const std::string& config) const;
 
   const char* GetVisibleTypeName() const;
-  void WriteLanguagesRules();
+  void WriteLanguagesRules(const std::string& config);
 
-  void WriteLinkRule(bool useResponseFile);
-  void WriteDeviceLinkRule(bool useResponseFile);
+  void WriteLinkRule(bool useResponseFile, const std::string& config);
+  void WriteDeviceLinkRule(bool useResponseFile, const std::string& config);
 
-  void WriteLinkStatement();
-  void WriteDeviceLinkStatement();
+  void WriteLinkStatement(const std::string& config,
+                          const std::string& fileConfig, bool firstForConfig);
+  void WriteDeviceLinkStatement(const std::string& config,
+                                const std::string& fileConfig,
+                                bool firstForConfig);
 
-  void WriteObjectLibStatement();
+  void WriteObjectLibStatement(const std::string& config);
 
-  std::vector<std::string> ComputeLinkCmd();
+  std::vector<std::string> ComputeLinkCmd(const std::string& config);
   std::vector<std::string> ComputeDeviceLinkCmd();
 
 private:
   // Target name info.
-  cmGeneratorTarget::Names TargetNames;
-  std::string TargetLinkLanguage;
+  cmGeneratorTarget::Names TargetNames(const std::string& config) const;
+  std::string TargetLinkLanguage(const std::string& config) const;
   std::string DeviceLinkObject;
 };
 
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 0aab912..abf12f8 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -10,11 +10,11 @@
 #include <utility>
 
 #include <cm/memory>
+#include <cmext/algorithm>
 
 #include "cm_jsoncpp_value.h"
 #include "cm_jsoncpp_writer.h"
 
-#include "cmAlgorithms.h"
 #include "cmComputeLinkInformation.h"
 #include "cmCustomCommandGenerator.h"
 #include "cmGeneratedFileStream.h"
@@ -58,19 +58,27 @@
 
 cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmGeneratorTarget* target)
   : cmCommonTargetGenerator(target)
-  , MacOSXContentGenerator(nullptr)
   , OSXBundleGenerator(nullptr)
   , LocalGenerator(
       static_cast<cmLocalNinjaGenerator*>(target->GetLocalGenerator()))
 {
-  MacOSXContentGenerator = cm::make_unique<MacOSXContentGeneratorType>(this);
+  for (auto const& fileConfig : target->Makefile->GetGeneratorConfigs()) {
+    this->Configs[fileConfig].MacOSXContentGenerator =
+      cm::make_unique<MacOSXContentGeneratorType>(this, fileConfig);
+  }
 }
 
 cmNinjaTargetGenerator::~cmNinjaTargetGenerator() = default;
 
-cmGeneratedFileStream& cmNinjaTargetGenerator::GetBuildFileStream() const
+cmGeneratedFileStream& cmNinjaTargetGenerator::GetImplFileStream(
+  const std::string& config) const
 {
-  return *this->GetGlobalGenerator()->GetBuildFileStream();
+  return *this->GetGlobalGenerator()->GetImplFileStream(config);
+}
+
+cmGeneratedFileStream& cmNinjaTargetGenerator::GetCommonFileStream() const
+{
+  return *this->GetGlobalGenerator()->GetCommonFileStream();
 }
 
 cmGeneratedFileStream& cmNinjaTargetGenerator::GetRulesFileStream() const
@@ -84,17 +92,19 @@
 }
 
 std::string cmNinjaTargetGenerator::LanguageCompilerRule(
-  const std::string& lang) const
+  const std::string& lang, const std::string& config) const
 {
   return lang + "_COMPILER__" +
-    cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
+    cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()) +
+    "_" + config;
 }
 
 std::string cmNinjaTargetGenerator::LanguagePreprocessRule(
-  std::string const& lang) const
+  std::string const& lang, const std::string& config) const
 {
   return lang + "_PREPROCESS__" +
-    cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
+    cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()) +
+    "_" + config;
 }
 
 bool cmNinjaTargetGenerator::NeedExplicitPreprocessing(
@@ -117,10 +127,11 @@
 }
 
 std::string cmNinjaTargetGenerator::LanguageDyndepRule(
-  const std::string& lang) const
+  const std::string& lang, const std::string& config) const
 {
   return lang + "_DYNDEP__" +
-    cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
+    cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()) +
+    "_" + config;
 }
 
 bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang) const
@@ -128,9 +139,11 @@
   return lang == "Fortran";
 }
 
-std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget()
+std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget(
+  const std::string& config)
 {
-  return "cmake_object_order_depends_target_" + this->GetTargetName();
+  return cmGlobalNinjaGenerator::OrderDependsTargetForTarget(
+    this->GeneratorTarget, config);
 }
 
 // TODO: Most of the code is picked up from
@@ -138,10 +151,10 @@
 // void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
 // Refactor it.
 std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
-  cmSourceFile const* source, const std::string& language)
+  cmSourceFile const* source, const std::string& language,
+  const std::string& config)
 {
-  std::string flags = this->GetFlags(language);
-  const std::string configName = this->LocalGenerator->GetConfigName();
+  std::string flags = this->GetFlags(language, config);
 
   // Add Fortran format flags.
   if (language == "Fortran") {
@@ -150,7 +163,7 @@
 
   // Add source file specific flags.
   cmGeneratorExpressionInterpreter genexInterpreter(
-    this->LocalGenerator, configName, this->GeneratorTarget, language);
+    this->LocalGenerator, config, this->GeneratorTarget, language);
 
   const std::string COMPILE_FLAGS("COMPILE_FLAGS");
   if (const char* cflags = source->GetProperty(COMPILE_FLAGS)) {
@@ -166,16 +179,16 @@
 
   // Add precompile headers compile options.
   const std::string pchSource =
-    this->GeneratorTarget->GetPchSource(configName, language);
+    this->GeneratorTarget->GetPchSource(config, language);
 
   if (!pchSource.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
     std::string pchOptions;
     if (source->GetFullPath() == pchSource) {
-      pchOptions = this->GeneratorTarget->GetPchCreateCompileOptions(
-        configName, language);
+      pchOptions =
+        this->GeneratorTarget->GetPchCreateCompileOptions(config, language);
     } else {
       pchOptions =
-        this->GeneratorTarget->GetPchUseCompileOptions(configName, language);
+        this->GeneratorTarget->GetPchUseCompileOptions(config, language);
     }
 
     this->LocalGenerator->AppendCompileOptions(
@@ -186,16 +199,17 @@
 }
 
 void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags,
-                                             std::string const& language)
+                                             std::string const& language,
+                                             const std::string& config)
 {
   std::vector<std::string> includes;
   this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
-                                              language, this->GetConfigName());
+                                              language, config);
   // Add include directory flags.
   std::string includeFlags = this->LocalGenerator->GetIncludeFlags(
     includes, this->GeneratorTarget, language,
     language == "RC", // full include paths for RC needed by cmcldeps
-    false, this->GetConfigName());
+    false, config);
   if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
     std::replace(includeFlags.begin(), includeFlags.end(), '\\', '/');
   }
@@ -232,13 +246,18 @@
 // TODO: Refactor with
 // void cmMakefileTargetGenerator::WriteTargetLanguageFlags().
 std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source,
-                                                   const std::string& language)
+                                                   const std::string& language,
+                                                   const std::string& config)
 {
   std::set<std::string> defines;
-  const std::string config = this->LocalGenerator->GetConfigName();
   cmGeneratorExpressionInterpreter genexInterpreter(
     this->LocalGenerator, config, this->GeneratorTarget, language);
 
+  // Seriously??
+  if (this->GetGlobalGenerator()->IsMultiConfig()) {
+    defines.insert(cmStrCat("CMAKE_INTDIR=\"", config, '"'));
+  }
+
   const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
   if (const char* compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) {
     this->LocalGenerator->AppendDefines(
@@ -253,17 +272,17 @@
       genexInterpreter.Evaluate(config_compile_defs, COMPILE_DEFINITIONS));
   }
 
-  std::string definesString = this->GetDefines(language);
+  std::string definesString = this->GetDefines(language, config);
   this->LocalGenerator->JoinDefines(defines, definesString, language);
 
   return definesString;
 }
 
 std::string cmNinjaTargetGenerator::ComputeIncludes(
-  cmSourceFile const* source, const std::string& language)
+  cmSourceFile const* source, const std::string& language,
+  const std::string& config)
 {
   std::vector<std::string> includes;
-  const std::string config = this->LocalGenerator->GetConfigName();
   cmGeneratorExpressionInterpreter genexInterpreter(
     this->LocalGenerator, config, this->GeneratorTarget, language);
 
@@ -277,13 +296,13 @@
   std::string includesString = this->LocalGenerator->GetIncludeFlags(
     includes, this->GeneratorTarget, language, true, false, config);
   this->LocalGenerator->AppendFlags(includesString,
-                                    this->GetIncludes(language));
+                                    this->GetIncludes(language, config));
 
   return includesString;
 }
 
 cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps(
-  const std::string& linkLanguage) const
+  const std::string& linkLanguage, const std::string& config) const
 {
   // Static libraries never depend on other targets for linking.
   if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY ||
@@ -292,7 +311,7 @@
   }
 
   cmComputeLinkInformation* cli =
-    this->GeneratorTarget->GetLinkInformation(this->GetConfigName());
+    this->GeneratorTarget->GetLinkInformation(config);
   if (!cli) {
     return cmNinjaDeps();
   }
@@ -303,8 +322,7 @@
 
   // Add a dependency on the link definitions file, if any.
   if (cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
-        this->GeneratorTarget->GetModuleDefinitionInfo(
-          this->GetConfigName())) {
+        this->GeneratorTarget->GetModuleDefinitionInfo(config)) {
     for (cmSourceFile const* src : mdi->Sources) {
       result.push_back(this->ConvertToNinjaPath(src->GetFullPath()));
     }
@@ -312,15 +330,14 @@
 
   // Add a dependency on user-specified manifest files, if any.
   std::vector<cmSourceFile const*> manifest_srcs;
-  this->GeneratorTarget->GetManifests(manifest_srcs, this->ConfigName);
+  this->GeneratorTarget->GetManifests(manifest_srcs, config);
   for (cmSourceFile const* manifest_src : manifest_srcs) {
     result.push_back(this->ConvertToNinjaPath(manifest_src->GetFullPath()));
   }
 
   // Add user-specified dependencies.
   std::vector<std::string> linkDeps;
-  this->GeneratorTarget->GetLinkDepends(linkDeps, this->ConfigName,
-                                        linkLanguage);
+  this->GeneratorTarget->GetLinkDepends(linkDeps, config, linkLanguage);
   std::transform(linkDeps.begin(), linkDeps.end(), std::back_inserter(result),
                  MapToNinjaPath());
 
@@ -334,7 +351,7 @@
 }
 
 std::string cmNinjaTargetGenerator::GetObjectFilePath(
-  cmSourceFile const* source) const
+  cmSourceFile const* source, const std::string& config) const
 {
   std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
   if (!path.empty()) {
@@ -342,13 +359,14 @@
   }
   std::string const& objectName = this->GeneratorTarget->GetObjectName(source);
   path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+  path += this->GetGlobalGenerator()->ConfigDirectory(config);
   path += "/";
   path += objectName;
   return path;
 }
 
 std::string cmNinjaTargetGenerator::GetPreprocessedFilePath(
-  cmSourceFile const* source) const
+  cmSourceFile const* source, const std::string& config) const
 {
   // Choose an extension to compile already-preprocessed source.
   std::string ppExt = source->GetExtension();
@@ -378,19 +396,21 @@
     path += "/";
   }
   path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+  path += this->GetGlobalGenerator()->ConfigDirectory(config);
   path += "/";
   path += ppName;
   return path;
 }
 
 std::string cmNinjaTargetGenerator::GetDyndepFilePath(
-  std::string const& lang) const
+  std::string const& lang, const std::string& config) const
 {
   std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
   if (!path.empty()) {
     path += "/";
   }
   path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+  path += this->GetGlobalGenerator()->ConfigDirectory(config);
   path += "/";
   path += lang;
   path += ".dd";
@@ -398,25 +418,27 @@
 }
 
 std::string cmNinjaTargetGenerator::GetTargetDependInfoPath(
-  std::string const& lang) const
+  std::string const& lang, const std::string& config) const
 {
   std::string path =
     cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/',
              this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget),
-             '/', lang, "DependInfo.json");
+             this->GetGlobalGenerator()->ConfigDirectory(config), '/', lang,
+             "DependInfo.json");
   return path;
 }
 
-std::string cmNinjaTargetGenerator::GetTargetOutputDir() const
+std::string cmNinjaTargetGenerator::GetTargetOutputDir(
+  const std::string& config) const
 {
-  std::string dir = this->GeneratorTarget->GetDirectory(this->GetConfigName());
+  std::string dir = this->GeneratorTarget->GetDirectory(config);
   return ConvertToNinjaPath(dir);
 }
 
 std::string cmNinjaTargetGenerator::GetTargetFilePath(
-  const std::string& name) const
+  const std::string& name, const std::string& config) const
 {
-  std::string path = this->GetTargetOutputDir();
+  std::string path = this->GetTargetOutputDir(config);
   if (path.empty() || path == ".") {
     return name;
   }
@@ -430,21 +452,21 @@
   return this->GeneratorTarget->GetName();
 }
 
-bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(cmNinjaVars& vars) const
+bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(
+  cmNinjaVars& vars, const std::string& config) const
 {
   cmMakefile* mf = this->GetMakefile();
   if (mf->GetDefinition("MSVC_C_ARCHITECTURE_ID") ||
       mf->GetDefinition("MSVC_CXX_ARCHITECTURE_ID") ||
       mf->GetDefinition("MSVC_CUDA_ARCHITECTURE_ID")) {
     std::string pdbPath;
-    std::string compilePdbPath = this->ComputeTargetCompilePDB();
+    std::string compilePdbPath = this->ComputeTargetCompilePDB(config);
     if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE ||
         this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY ||
         this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
         this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
-      pdbPath = cmStrCat(
-        this->GeneratorTarget->GetPDBDirectory(this->GetConfigName()), '/',
-        this->GeneratorTarget->GetPDBName(this->GetConfigName()));
+      pdbPath = cmStrCat(this->GeneratorTarget->GetPDBDirectory(config), '/',
+                         this->GeneratorTarget->GetPDBName(config));
     }
 
     vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat(
@@ -460,15 +482,17 @@
   return false;
 }
 
-void cmNinjaTargetGenerator::WriteLanguageRules(const std::string& language)
+void cmNinjaTargetGenerator::WriteLanguageRules(const std::string& language,
+                                                const std::string& config)
 {
 #ifdef NINJA_GEN_VERBOSE_FILES
   this->GetRulesFileStream() << "# Rules for language " << language << "\n\n";
 #endif
-  this->WriteCompileRule(language);
+  this->WriteCompileRule(language, config);
 }
 
-void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
+void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
+                                              const std::string& config)
 {
   cmRulePlaceholderExpander::RuleVariables vars;
   vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
@@ -509,7 +533,7 @@
     this->GetLocalGenerator()->CreateRulePlaceholderExpander());
 
   std::string const tdi = this->GetLocalGenerator()->ConvertToOutputFormat(
-    ConvertToNinjaPath(this->GetTargetDependInfoPath(lang)),
+    ConvertToNinjaPath(this->GetTargetDependInfoPath(lang, config)),
     cmLocalGenerator::SHELL);
 
   std::string launcher;
@@ -524,7 +548,7 @@
       cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
 
   if (explicitPP) {
-    cmNinjaRule rule(this->LanguagePreprocessRule(lang));
+    cmNinjaRule rule(this->LanguagePreprocessRule(lang, config));
     // Explicit preprocessing always uses a depfile.
     rule.DepType = ""; // no deps= for multiple outputs
     rule.DepFile = "$DEP_FILE";
@@ -604,7 +628,7 @@
 
   if (needDyndep) {
     // Write the rule for ninja dyndep file generation.
-    cmNinjaRule rule(this->LanguageDyndepRule(lang));
+    cmNinjaRule rule(this->LanguageDyndepRule(lang, config));
     // Command line length is almost always limited -> use response file for
     // dyndep rules
     rule.RspFile = "$out.rsp";
@@ -628,7 +652,7 @@
     this->GetGlobalGenerator()->AddRule(rule);
   }
 
-  cmNinjaRule rule(this->LanguageCompilerRule(lang));
+  cmNinjaRule rule(this->LanguageCompilerRule(lang, config));
   // If using a response file, move defines, includes, and flags into it.
   if (!responseFlag.empty()) {
     rule.RspFile = "$RSP_FILE";
@@ -737,7 +761,13 @@
       }
       if (tidy && *tidy) {
         run_iwyu += " --tidy=";
-        run_iwyu += this->GetLocalGenerator()->EscapeForShell(tidy);
+        const char* driverMode = this->Makefile->GetDefinition(
+          "CMAKE_" + lang + "_CLANG_TIDY_DRIVER_MODE");
+        if (!(driverMode && *driverMode)) {
+          driverMode = lang == "C" ? "gcc" : "g++";
+        }
+        run_iwyu += this->GetLocalGenerator()->EscapeForShell(
+          cmStrCat(tidy, ";--extra-arg-before=--driver-mode=", driverMode));
       }
       if (cpplint && *cpplint) {
         run_iwyu += " --cpplint=";
@@ -788,50 +818,54 @@
   this->GetGlobalGenerator()->AddRule(rule);
 }
 
-void cmNinjaTargetGenerator::WriteObjectBuildStatements()
+void cmNinjaTargetGenerator::WriteObjectBuildStatements(
+  const std::string& config, const std::string& fileConfig,
+  bool firstForConfig)
 {
   // Write comments.
-  cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
-  this->GetBuildFileStream()
+  cmGlobalNinjaGenerator::WriteDivider(this->GetImplFileStream(fileConfig));
+  this->GetImplFileStream(fileConfig)
     << "# Object build statements for "
     << cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType())
     << " target " << this->GetTargetName() << "\n\n";
 
   {
     std::vector<cmSourceFile const*> customCommands;
-    this->GeneratorTarget->GetCustomCommands(customCommands, this->ConfigName);
+    this->GeneratorTarget->GetCustomCommands(customCommands, config);
     for (cmSourceFile const* sf : customCommands) {
       cmCustomCommand const* cc = sf->GetCustomCommand();
       this->GetLocalGenerator()->AddCustomCommandTarget(
         cc, this->GetGeneratorTarget());
       // Record the custom commands for this target. The container is used
       // in WriteObjectBuildStatement when called in a loop below.
-      this->CustomCommands.push_back(cc);
+      this->Configs[config].CustomCommands.push_back(cc);
     }
   }
   {
     std::vector<cmSourceFile const*> headerSources;
-    this->GeneratorTarget->GetHeaderSources(headerSources, this->ConfigName);
+    this->GeneratorTarget->GetHeaderSources(headerSources, config);
     this->OSXBundleGenerator->GenerateMacOSXContentStatements(
-      headerSources, this->MacOSXContentGenerator.get());
+      headerSources, this->Configs[fileConfig].MacOSXContentGenerator.get(),
+      config);
   }
   {
     std::vector<cmSourceFile const*> extraSources;
-    this->GeneratorTarget->GetExtraSources(extraSources, this->ConfigName);
+    this->GeneratorTarget->GetExtraSources(extraSources, config);
     this->OSXBundleGenerator->GenerateMacOSXContentStatements(
-      extraSources, this->MacOSXContentGenerator.get());
+      extraSources, this->Configs[fileConfig].MacOSXContentGenerator.get(),
+      config);
   }
-  {
+  if (firstForConfig) {
     const char* pchExtension =
       GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION");
 
     std::vector<cmSourceFile const*> externalObjects;
-    this->GeneratorTarget->GetExternalObjects(externalObjects,
-                                              this->ConfigName);
+    this->GeneratorTarget->GetExternalObjects(externalObjects, config);
     for (cmSourceFile const* sf : externalObjects) {
-      const auto objectFileName = this->GetSourceFilePath(sf);
+      auto objectFileName = this->GetGlobalGenerator()->ExpandCFGIntDir(
+        this->GetSourceFilePath(sf), config);
       if (!cmSystemTools::StringEndsWith(objectFileName, pchExtension)) {
-        this->Objects.push_back(objectFileName);
+        this->Configs[config].Objects.push_back(objectFileName);
       }
     }
   }
@@ -839,19 +873,19 @@
   {
     cmNinjaBuild build("phony");
     build.Comment = "Order-only phony target for " + this->GetTargetName();
-    build.Outputs.push_back(this->OrderDependsTargetForTarget());
+    build.Outputs.push_back(this->OrderDependsTargetForTarget(config));
 
     cmNinjaDeps& orderOnlyDeps = build.OrderOnlyDeps;
     this->GetLocalGenerator()->AppendTargetDepends(
-      this->GeneratorTarget, orderOnlyDeps, DependOnTargetOrdering);
+      this->GeneratorTarget, orderOnlyDeps, config, fileConfig,
+      DependOnTargetOrdering);
 
     // Add order-only dependencies on other files associated with the target.
-    cmAppend(orderOnlyDeps, this->ExtraFiles);
+    cm::append(orderOnlyDeps, this->Configs[config].ExtraFiles);
 
     // Add order-only dependencies on custom command outputs.
-    for (cmCustomCommand const* cc : this->CustomCommands) {
-      cmCustomCommandGenerator ccg(*cc, this->GetConfigName(),
-                                   this->GetLocalGenerator());
+    for (cmCustomCommand const* cc : this->Configs[config].CustomCommands) {
+      cmCustomCommandGenerator ccg(*cc, config, this->GetLocalGenerator());
       const std::vector<std::string>& ccoutputs = ccg.GetOutputs();
       const std::vector<std::string>& ccbyproducts = ccg.GetByproducts();
       std::transform(ccoutputs.begin(), ccoutputs.end(),
@@ -877,26 +911,27 @@
       orderOnlyDeps.push_back(this->ConvertToNinjaPath(tgtDir));
     }
 
-    this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build);
+    this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
+                                           build);
   }
 
   {
     std::vector<cmSourceFile const*> objectSources;
-    this->GeneratorTarget->GetObjectSources(objectSources, this->ConfigName);
+    this->GeneratorTarget->GetObjectSources(objectSources, config);
     for (cmSourceFile const* sf : objectSources) {
-      this->WriteObjectBuildStatement(sf);
+      this->WriteObjectBuildStatement(sf, config, fileConfig, firstForConfig);
     }
   }
 
-  for (auto const& langDDIFiles : this->DDIFiles) {
+  for (auto const& langDDIFiles : this->Configs[config].DDIFiles) {
     std::string const& language = langDDIFiles.first;
     cmNinjaDeps const& ddiFiles = langDDIFiles.second;
 
-    cmNinjaBuild build(this->LanguageDyndepRule(language));
-    build.Outputs.push_back(this->GetDyndepFilePath(language));
+    cmNinjaBuild build(this->LanguageDyndepRule(language, config));
+    build.Outputs.push_back(this->GetDyndepFilePath(language, config));
     build.ExplicitDeps = ddiFiles;
 
-    this->WriteTargetDependInfo(language);
+    this->WriteTargetDependInfo(language, config);
 
     // Make sure dyndep files for all our dependencies have already
     // been generated so that the '<LANG>Modules.json' files they
@@ -907,46 +942,52 @@
     // refactoring the Ninja generator to generate targets in
     // dependency order so that we can collect the needed information.
     this->GetLocalGenerator()->AppendTargetDepends(
-      this->GeneratorTarget, build.OrderOnlyDeps, DependOnTargetArtifact);
+      this->GeneratorTarget, build.OrderOnlyDeps, config, fileConfig,
+      DependOnTargetArtifact);
 
-    this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build);
+    this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
+                                           build);
   }
 
-  this->GetBuildFileStream() << "\n";
+  this->GetImplFileStream(fileConfig) << "\n";
 
-  if (!this->SwiftOutputMap.empty()) {
+  if (!this->Configs[config].SwiftOutputMap.empty()) {
     std::string const mapFilePath =
-      this->GeneratorTarget->GetSupportDirectory() + "/output-file-map.json";
-    std::string const targetSwiftDepsPath = [this]() -> std::string {
+      cmStrCat(this->GeneratorTarget->GetSupportDirectory(), '/', config, '/',
+               "output-file-map.json");
+    std::string const targetSwiftDepsPath = [this, config]() -> std::string {
       cmGeneratorTarget const* target = this->GeneratorTarget;
       if (const char* name = target->GetProperty("Swift_DEPENDENCIES_FILE")) {
         return name;
       }
       return this->ConvertToNinjaPath(target->GetSupportDirectory() + "/" +
-                                      target->GetName() + ".swiftdeps");
+                                      config + "/" + target->GetName() +
+                                      ".swiftdeps");
     }();
 
     // build the global target dependencies
     // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps
     Json::Value deps(Json::objectValue);
     deps["swift-dependencies"] = targetSwiftDepsPath;
-    this->SwiftOutputMap[""] = deps;
+    this->Configs[config].SwiftOutputMap[""] = deps;
 
     cmGeneratedFileStream output(mapFilePath);
-    output << this->SwiftOutputMap;
+    output << this->Configs[config].SwiftOutputMap;
   }
 }
 
 void cmNinjaTargetGenerator::WriteObjectBuildStatement(
-  cmSourceFile const* source)
+  cmSourceFile const* source, const std::string& config,
+  const std::string& fileConfig, bool firstForConfig)
 {
   std::string const language = source->GetLanguage();
   std::string const sourceFileName =
     language == "RC" ? source->GetFullPath() : this->GetSourceFilePath(source);
-  std::string const objectDir =
-    this->ConvertToNinjaPath(this->GeneratorTarget->GetSupportDirectory());
+  std::string const objectDir = this->ConvertToNinjaPath(
+    cmStrCat(this->GeneratorTarget->GetSupportDirectory(),
+             this->GetGlobalGenerator()->ConfigDirectory(config)));
   std::string const objectFileName =
-    this->ConvertToNinjaPath(this->GetObjectFilePath(source));
+    this->ConvertToNinjaPath(this->GetObjectFilePath(source, config));
   std::string const objectFileDir =
     cmSystemTools::GetFilenamePath(objectFileName);
 
@@ -962,11 +1003,11 @@
   int const commandLineLengthLimit =
     ((lang_supports_response && this->ForceResponseFile())) ? -1 : 0;
 
-  cmNinjaBuild objBuild(this->LanguageCompilerRule(language));
+  cmNinjaBuild objBuild(this->LanguageCompilerRule(language, config));
   cmNinjaVars& vars = objBuild.Variables;
-  vars["FLAGS"] = this->ComputeFlagsForObject(source, language);
-  vars["DEFINES"] = this->ComputeDefines(source, language);
-  vars["INCLUDES"] = this->ComputeIncludes(source, language);
+  vars["FLAGS"] = this->ComputeFlagsForObject(source, language, config);
+  vars["DEFINES"] = this->ComputeDefines(source, language, config);
+  vars["INCLUDES"] = this->ComputeIncludes(source, language, config);
 
   if (!this->NeedDepTypeMSVC(language)) {
     bool replaceExt(false);
@@ -994,11 +1035,13 @@
     vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"]);
 
   objBuild.Outputs.push_back(objectFileName);
-  const char* pchExtension =
-    this->GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION");
-  if (!cmSystemTools::StringEndsWith(objectFileName, pchExtension)) {
-    // Add this object to the list of object files.
-    this->Objects.push_back(objectFileName);
+  if (firstForConfig) {
+    const char* pchExtension =
+      this->GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION");
+    if (!cmSystemTools::StringEndsWith(objectFileName, pchExtension)) {
+      // Add this object to the list of object files.
+      this->Configs[config].Objects.push_back(objectFileName);
+    }
   }
 
   objBuild.ExplicitDeps.push_back(sourceFileName);
@@ -1007,13 +1050,11 @@
   std::vector<std::string> depList;
 
   const std::string pchSource =
-    this->GeneratorTarget->GetPchSource(this->GetConfigName(), language);
+    this->GeneratorTarget->GetPchSource(config, language);
   if (!pchSource.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
-    depList.push_back(
-      this->GeneratorTarget->GetPchHeader(this->GetConfigName(), language));
+    depList.push_back(this->GeneratorTarget->GetPchHeader(config, language));
     if (source->GetFullPath() != pchSource) {
-      depList.push_back(
-        this->GeneratorTarget->GetPchFile(this->GetConfigName(), language));
+      depList.push_back(this->GeneratorTarget->GetPchFile(config, language));
     }
   }
 
@@ -1034,7 +1075,7 @@
                    MapToNinjaPath());
   }
 
-  objBuild.OrderOnlyDeps.push_back(this->OrderDependsTargetForTarget());
+  objBuild.OrderOnlyDeps.push_back(this->OrderDependsTargetForTarget(config));
 
   // If the source file is GENERATED and does not have a custom command
   // (either attached to this source file or another one), assume that one of
@@ -1054,10 +1095,10 @@
   // For some cases we do an explicit preprocessor invocation.
   bool const explicitPP = this->NeedExplicitPreprocessing(language);
   if (explicitPP) {
-    cmNinjaBuild ppBuild(this->LanguagePreprocessRule(language));
+    cmNinjaBuild ppBuild(this->LanguagePreprocessRule(language, config));
 
     std::string const ppFileName =
-      this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source));
+      this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source, config));
     ppBuild.Outputs.push_back(ppFileName);
 
     ppBuild.RspFile = ppFileName + ".rsp";
@@ -1115,7 +1156,7 @@
 
       std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags(
         sourceDirectory, this->GeneratorTarget, language, false, false,
-        this->GetConfigName());
+        config);
 
       vars["INCLUDES"] = sourceDirectoryFlag + " " + vars["INCLUDES"];
     }
@@ -1139,17 +1180,19 @@
       std::string const ddiFile = objectFileName + ".ddi";
       ppBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
       ppBuild.ImplicitOuts.push_back(ddiFile);
-      this->DDIFiles[language].push_back(ddiFile);
+      if (firstForConfig) {
+        this->Configs[config].DDIFiles[language].push_back(ddiFile);
+      }
     }
 
     this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
                                ppBuild.Variables);
 
-    this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), ppBuild,
-                                           commandLineLengthLimit);
+    this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
+                                           ppBuild, commandLineLengthLimit);
   }
   if (needDyndep) {
-    std::string const dyndep = this->GetDyndepFilePath(language);
+    std::string const dyndep = this->GetDyndepFilePath(language, config);
     objBuild.OrderOnlyDeps.push_back(dyndep);
     vars["dyndep"] = dyndep;
   }
@@ -1164,14 +1207,21 @@
   this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
                              vars);
 
-  this->SetMsvcTargetPdbVariable(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";
 
   if (language == "Swift") {
-    this->EmitSwiftDependencyInfo(source);
+    this->EmitSwiftDependencyInfo(source, config);
   } else {
-    this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(),
+    this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
                                            objBuild, commandLineLengthLimit);
   }
 
@@ -1182,11 +1232,13 @@
     std::transform(build.Outputs.begin(), build.Outputs.end(),
                    build.Outputs.begin(), MapToNinjaPath());
     build.ExplicitDeps = objBuild.Outputs;
-    this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build);
+    this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
+                                           build);
   }
 }
 
-void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang)
+void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang,
+                                                   const std::string& config)
 {
   Json::Value tdi(Json::objectValue);
   tdi["language"] = lang;
@@ -1214,7 +1266,7 @@
   Json::Value& tdi_include_dirs = tdi["include-dirs"] = Json::arrayValue;
   std::vector<std::string> includes;
   this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
-                                              lang, this->GetConfigName());
+                                              lang, config);
   for (std::string const& i : includes) {
     // Convert the include directories the same way we do for -I flags.
     // See upstream ninja issue 1251.
@@ -1223,22 +1275,22 @@
 
   Json::Value& tdi_linked_target_dirs = tdi["linked-target-dirs"] =
     Json::arrayValue;
-  for (std::string const& l : this->GetLinkedTargetDirectories()) {
+  for (std::string const& l : this->GetLinkedTargetDirectories(config)) {
     tdi_linked_target_dirs.append(l);
   }
 
-  std::string const tdin = this->GetTargetDependInfoPath(lang);
+  std::string const tdin = this->GetTargetDependInfoPath(lang, config);
   cmGeneratedFileStream tdif(tdin);
   tdif << tdi;
 }
 
 void cmNinjaTargetGenerator::EmitSwiftDependencyInfo(
-  cmSourceFile const* source)
+  cmSourceFile const* source, const std::string& config)
 {
   std::string const sourceFilePath =
     this->ConvertToNinjaPath(this->GetSourceFilePath(source));
   std::string const objectFilePath =
-    this->ConvertToNinjaPath(this->GetObjectFilePath(source));
+    this->ConvertToNinjaPath(this->GetObjectFilePath(source, config));
   std::string const swiftDepsPath = [source, objectFilePath]() -> std::string {
     if (const char* name = source->GetProperty("Swift_DEPENDENCIES_FILE")) {
       return name;
@@ -1251,10 +1303,10 @@
     }
     return objectFilePath + ".dia";
   }();
-  std::string const makeDepsPath = [this, source]() -> std::string {
+  std::string const makeDepsPath = [this, source, config]() -> std::string {
     cmLocalNinjaGenerator const* local = this->GetLocalGenerator();
     std::string const objectFileName =
-      this->ConvertToNinjaPath(this->GetObjectFilePath(source));
+      this->ConvertToNinjaPath(this->GetObjectFilePath(source, config));
     std::string const objectFileDir =
       cmSystemTools::GetFilenamePath(objectFileName);
 
@@ -1275,7 +1327,7 @@
   entry["dependencies"] = makeDepsPath;
   entry["swift-dependencies"] = swiftDepsPath;
   entry["diagnostics"] = swiftDiaPath;
-  SwiftOutputMap[sourceFilePath] = entry;
+  this->Configs[config].SwiftOutputMap[sourceFilePath] = entry;
 }
 
 void cmNinjaTargetGenerator::ExportObjectCompileCommand(
@@ -1350,27 +1402,34 @@
   this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine, sourceFileName);
 }
 
-void cmNinjaTargetGenerator::AdditionalCleanFiles()
+void cmNinjaTargetGenerator::AdditionalCleanFiles(const std::string& config)
 {
   if (const char* prop_value =
         this->GeneratorTarget->GetProperty("ADDITIONAL_CLEAN_FILES")) {
     cmLocalNinjaGenerator* lg = this->LocalGenerator;
     std::vector<std::string> cleanFiles;
-    cmExpandList(cmGeneratorExpression::Evaluate(
-                   prop_value, lg,
-                   this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"),
-                   this->GeneratorTarget),
+    cmExpandList(cmGeneratorExpression::Evaluate(prop_value, lg, config,
+                                                 this->GeneratorTarget),
                  cleanFiles);
     std::string const& binaryDir = lg->GetCurrentBinaryDirectory();
     cmGlobalNinjaGenerator* gg = lg->GetGlobalNinjaGenerator();
     for (std::string const& cleanFile : cleanFiles) {
       // Support relative paths
       gg->AddAdditionalCleanFile(
-        cmSystemTools::CollapseFullPath(cleanFile, binaryDir));
+        cmSystemTools::CollapseFullPath(cleanFile, binaryDir), config);
     }
   }
 }
 
+cmNinjaDeps cmNinjaTargetGenerator::GetObjects(const std::string& config) const
+{
+  auto const it = this->Configs.find(config);
+  if (it != this->Configs.end()) {
+    return it->second.Objects;
+  }
+  return {};
+}
+
 void cmNinjaTargetGenerator::EnsureDirectoryExists(
   const std::string& path) const
 {
@@ -1393,7 +1452,7 @@
 }
 
 void cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()(
-  cmSourceFile const& source, const char* pkgloc)
+  cmSourceFile const& source, const char* pkgloc, const std::string& config)
 {
   // Skip OS X content when not building a Framework or Bundle.
   if (!this->Generator->GetGeneratorTarget()->IsBundleOnApple()) {
@@ -1401,7 +1460,18 @@
   }
 
   std::string macdir =
-    this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc);
+    this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc,
+                                                                    config);
+
+  // Reject files that collide with files from the Ninja file's native config.
+  if (config != this->FileConfig) {
+    std::string nativeMacdir =
+      this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(
+        pkgloc, this->FileConfig);
+    if (macdir == nativeMacdir) {
+      return;
+    }
+  }
 
   // Get the input file location.
   std::string input = source.GetFullPath();
@@ -1413,11 +1483,11 @@
   output = this->Generator->GetGlobalGenerator()->ConvertToNinjaPath(output);
 
   // Write a build statement to copy the content into the bundle.
-  this->Generator->GetGlobalGenerator()->WriteMacOSXContentBuild(input,
-                                                                 output);
+  this->Generator->GetGlobalGenerator()->WriteMacOSXContentBuild(
+    input, output, this->FileConfig);
 
   // Add as a dependency to the target so that it gets called.
-  this->Generator->ExtraFiles.push_back(std::move(output));
+  this->Generator->Configs[config].ExtraFiles.push_back(std::move(output));
 }
 
 void cmNinjaTargetGenerator::addPoolNinjaVariable(
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index 4627bcd..8678dc3 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -9,6 +9,7 @@
 #include <memory>
 #include <set>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "cm_jsoncpp_value.h"
@@ -38,16 +39,17 @@
   /// Destructor.
   ~cmNinjaTargetGenerator() override;
 
-  virtual void Generate() = 0;
+  virtual void Generate(const std::string& config) = 0;
 
   std::string GetTargetName() const;
 
   bool NeedDepTypeMSVC(const std::string& lang) const;
 
 protected:
-  bool SetMsvcTargetPdbVariable(cmNinjaVars&) const;
+  bool SetMsvcTargetPdbVariable(cmNinjaVars&, const std::string& config) const;
 
-  cmGeneratedFileStream& GetBuildFileStream() const;
+  cmGeneratedFileStream& GetImplFileStream(const std::string& config) const;
+  cmGeneratedFileStream& GetCommonFileStream() const;
   cmGeneratedFileStream& GetRulesFileStream() const;
 
   cmGeneratorTarget* GetGeneratorTarget() const
@@ -64,15 +66,18 @@
 
   cmMakefile* GetMakefile() const { return this->Makefile; }
 
-  std::string LanguageCompilerRule(const std::string& lang) const;
-  std::string LanguagePreprocessRule(std::string const& lang) const;
+  std::string LanguageCompilerRule(const std::string& lang,
+                                   const std::string& config) const;
+  std::string LanguagePreprocessRule(std::string const& lang,
+                                     const std::string& config) const;
   bool NeedExplicitPreprocessing(std::string const& lang) const;
-  std::string LanguageDyndepRule(std::string const& lang) const;
+  std::string LanguageDyndepRule(std::string const& lang,
+                                 const std::string& config) const;
   bool NeedDyndep(std::string const& lang) const;
   bool UsePreprocessedSource(std::string const& lang) const;
   bool CompilePreprocessedSourceWithDefines(std::string const& lang) const;
 
-  std::string OrderDependsTargetForTarget();
+  std::string OrderDependsTargetForTarget(const std::string& config);
 
   std::string ComputeOrderDependsForTarget();
 
@@ -82,15 +87,19 @@
    *       by LanguageFlagsVarName().
    */
   std::string ComputeFlagsForObject(cmSourceFile const* source,
-                                    const std::string& language);
+                                    const std::string& language,
+                                    const std::string& config);
 
-  void AddIncludeFlags(std::string& flags, std::string const& lang) override;
+  void AddIncludeFlags(std::string& flags, std::string const& lang,
+                       const std::string& config) override;
 
   std::string ComputeDefines(cmSourceFile const* source,
-                             const std::string& language);
+                             const std::string& language,
+                             const std::string& config);
 
   std::string ComputeIncludes(cmSourceFile const* source,
-                              const std::string& language);
+                              const std::string& language,
+                              const std::string& config);
 
   std::string ConvertToNinjaPath(const std::string& path) const
   {
@@ -102,36 +111,51 @@
   }
 
   /// @return the list of link dependency for the given target @a target.
-  cmNinjaDeps ComputeLinkDeps(const std::string& linkLanguage) const;
+  cmNinjaDeps ComputeLinkDeps(const std::string& linkLanguage,
+                              const std::string& config) const;
 
   /// @return the source file path for the given @a source.
   std::string GetSourceFilePath(cmSourceFile const* source) const;
 
   /// @return the object file path for the given @a source.
-  std::string GetObjectFilePath(cmSourceFile const* source) const;
+  std::string GetObjectFilePath(cmSourceFile const* source,
+                                const std::string& config) const;
 
   /// @return the preprocessed source file path for the given @a source.
-  std::string GetPreprocessedFilePath(cmSourceFile const* source) const;
+  std::string GetPreprocessedFilePath(cmSourceFile const* source,
+                                      const std::string& config) const;
 
   /// @return the dyndep file path for this target.
-  std::string GetDyndepFilePath(std::string const& lang) const;
+  std::string GetDyndepFilePath(std::string const& lang,
+                                const std::string& config) const;
 
   /// @return the target dependency scanner info file path
-  std::string GetTargetDependInfoPath(std::string const& lang) const;
+  std::string GetTargetDependInfoPath(std::string const& lang,
+                                      const std::string& config) const;
 
   /// @return the file path where the target named @a name is generated.
-  std::string GetTargetFilePath(const std::string& name) const;
+  std::string GetTargetFilePath(const std::string& name,
+                                const std::string& config) const;
 
   /// @return the output path for the target.
-  virtual std::string GetTargetOutputDir() const;
+  virtual std::string GetTargetOutputDir(const std::string& config) const;
 
-  void WriteLanguageRules(const std::string& language);
-  void WriteCompileRule(const std::string& language);
-  void WriteObjectBuildStatements();
-  void WriteObjectBuildStatement(cmSourceFile const* source);
-  void WriteTargetDependInfo(std::string const& lang);
+  void WriteLanguageRules(const std::string& language,
+                          const std::string& config);
+  void WriteCompileRule(const std::string& language,
+                        const std::string& config);
+  void WriteObjectBuildStatements(const std::string& config,
+                                  const std::string& fileConfig,
+                                  bool firstForConfig);
+  void WriteObjectBuildStatement(cmSourceFile const* source,
+                                 const std::string& config,
+                                 const std::string& fileConfig,
+                                 bool firstForConfig);
+  void WriteTargetDependInfo(std::string const& lang,
+                             const std::string& config);
 
-  void EmitSwiftDependencyInfo(cmSourceFile const* source);
+  void EmitSwiftDependencyInfo(cmSourceFile const* source,
+                               const std::string& config);
 
   void ExportObjectCompileCommand(
     std::string const& language, std::string const& sourceFileName,
@@ -139,9 +163,9 @@
     std::string const& objectFileDir, std::string const& flags,
     std::string const& defines, std::string const& includes);
 
-  void AdditionalCleanFiles();
+  void AdditionalCleanFiles(const std::string& config);
 
-  cmNinjaDeps GetObjects() const { return this->Objects; }
+  cmNinjaDeps GetObjects(const std::string& config) const;
 
   void EnsureDirectoryExists(const std::string& dir) const;
   void EnsureParentDirectoryExists(const std::string& path) const;
@@ -150,19 +174,22 @@
   struct MacOSXContentGeneratorType
     : cmOSXBundleGenerator::MacOSXContentGeneratorType
   {
-    MacOSXContentGeneratorType(cmNinjaTargetGenerator* g)
+    MacOSXContentGeneratorType(cmNinjaTargetGenerator* g,
+                               std::string fileConfig)
       : Generator(g)
+      , FileConfig(std::move(fileConfig))
     {
     }
 
-    void operator()(cmSourceFile const& source, const char* pkgloc) override;
+    void operator()(cmSourceFile const& source, const char* pkgloc,
+                    const std::string& config) override;
 
   private:
     cmNinjaTargetGenerator* Generator;
+    std::string FileConfig;
   };
   friend struct MacOSXContentGeneratorType;
 
-  std::unique_ptr<MacOSXContentGeneratorType> MacOSXContentGenerator;
   // Properly initialized by sub-classes.
   std::unique_ptr<cmOSXBundleGenerator> OSXBundleGenerator;
   std::set<std::string> MacContentFolders;
@@ -174,14 +201,21 @@
 
 private:
   cmLocalNinjaGenerator* LocalGenerator;
-  /// List of object files for this target.
-  cmNinjaDeps Objects;
-  // Fortran Support
-  std::map<std::string, cmNinjaDeps> DDIFiles;
-  // Swift Support
-  Json::Value SwiftOutputMap;
-  std::vector<cmCustomCommand const*> CustomCommands;
-  cmNinjaDeps ExtraFiles;
+
+  struct ByConfig
+  {
+    /// List of object files for this target.
+    cmNinjaDeps Objects;
+    // Fortran Support
+    std::map<std::string, cmNinjaDeps> DDIFiles;
+    // Swift Support
+    Json::Value SwiftOutputMap;
+    std::vector<cmCustomCommand const*> CustomCommands;
+    cmNinjaDeps ExtraFiles;
+    std::unique_ptr<MacOSXContentGeneratorType> MacOSXContentGenerator;
+  };
+
+  std::map<std::string, ByConfig> Configs;
 };
 
 #endif // ! cmNinjaTargetGenerator_h
diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx
index 5259037..a42d65d 100644
--- a/Source/cmNinjaUtilityTargetGenerator.cxx
+++ b/Source/cmNinjaUtilityTargetGenerator.cxx
@@ -15,13 +15,13 @@
 #include "cmGeneratorTarget.h"
 #include "cmGlobalNinjaGenerator.h"
 #include "cmLocalNinjaGenerator.h"
-#include "cmMakefile.h"
 #include "cmNinjaTypes.h"
 #include "cmOutputConverter.h"
 #include "cmSourceFile.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmTarget.h"
 
 cmNinjaUtilityTargetGenerator::cmNinjaUtilityTargetGenerator(
   cmGeneratorTarget* target)
@@ -31,14 +31,18 @@
 
 cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator() = default;
 
-void cmNinjaUtilityTargetGenerator::Generate()
+void cmNinjaUtilityTargetGenerator::Generate(const std::string& config)
 {
   cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator();
   cmLocalNinjaGenerator* lg = this->GetLocalGenerator();
   cmGeneratorTarget* genTarget = this->GetGeneratorTarget();
 
+  std::string configDir;
+  if (genTarget->Target->IsPerConfig()) {
+    configDir = gg->ConfigDirectory(config);
+  }
   std::string utilCommandName =
-    cmStrCat(lg->GetCurrentBinaryDirectory(), "/CMakeFiles/",
+    cmStrCat(lg->GetCurrentBinaryDirectory(), "/CMakeFiles", configDir, "/",
              this->GetTargetName(), ".util");
   utilCommandName = this->ConvertToNinjaPath(utilCommandName);
 
@@ -55,8 +59,8 @@
 
     for (std::vector<cmCustomCommand> const* cmdList : cmdLists) {
       for (cmCustomCommand const& ci : *cmdList) {
-        cmCustomCommandGenerator ccg(ci, this->GetConfigName(), lg);
-        lg->AppendCustomCommandDeps(ccg, deps);
+        cmCustomCommandGenerator ccg(ci, config, lg);
+        lg->AppendCustomCommandDeps(ccg, deps, config);
         lg->AppendCustomCommandLines(ccg, commands);
         std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
         std::transform(ccByproducts.begin(), ccByproducts.end(),
@@ -69,13 +73,11 @@
   }
 
   {
-    std::string const& config =
-      this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
     std::vector<cmSourceFile*> sources;
     genTarget->GetSourceFiles(sources, config);
     for (cmSourceFile const* source : sources) {
       if (cmCustomCommand const* cc = source->GetCustomCommand()) {
-        cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), lg);
+        cmCustomCommandGenerator ccg(*cc, config, lg);
         lg->AddCustomCommandTarget(cc, genTarget);
 
         // Depend on all custom command outputs.
@@ -89,13 +91,21 @@
     }
   }
 
-  lg->AppendTargetOutputs(genTarget, phonyBuild.Outputs);
-  lg->AppendTargetDepends(genTarget, deps);
+  std::string outputConfig;
+  if (genTarget->Target->IsPerConfig()) {
+    outputConfig = config;
+  }
+  lg->AppendTargetOutputs(genTarget, phonyBuild.Outputs, outputConfig);
+  if (genTarget->Target->GetType() != cmStateEnums::GLOBAL_TARGET) {
+    lg->AppendTargetOutputs(genTarget, gg->GetByproductsForCleanTarget(),
+                            config);
+  }
+  lg->AppendTargetDepends(genTarget, deps, config, config);
 
   if (commands.empty()) {
     phonyBuild.Comment = "Utility command for " + this->GetTargetName();
     phonyBuild.ExplicitDeps = std::move(deps);
-    gg->WriteBuild(this->GetBuildFileStream(), phonyBuild);
+    gg->WriteBuild(this->GetCommonFileStream(), phonyBuild);
   } else {
     std::string command =
       lg->BuildCommandLine(commands, "utility", this->GeneratorTarget);
@@ -118,6 +128,7 @@
       lg->ConvertToOutputFormat(lg->GetBinaryDirectory(),
                                 cmOutputConverter::SHELL));
     cmSystemTools::ReplaceString(command, "$(ARGS)", "");
+    command = gg->ExpandCFGIntDir(command, config);
 
     if (command.find('$') != std::string::npos) {
       return;
@@ -127,22 +138,32 @@
       gg->SeenCustomCommandOutput(util_output);
     }
 
+    std::string ccConfig;
+    if (genTarget->Target->IsPerConfig() &&
+        genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) {
+      ccConfig = config;
+    }
     gg->WriteCustomCommandBuild(command, desc,
                                 "Utility command for " + this->GetTargetName(),
                                 /*depfile*/ "", /*job_pool*/ "", uses_terminal,
-                                /*restat*/ true, util_outputs, deps);
+                                /*restat*/ true, util_outputs, ccConfig, deps);
 
     phonyBuild.ExplicitDeps.push_back(utilCommandName);
-    gg->WriteBuild(this->GetBuildFileStream(), phonyBuild);
+    gg->WriteBuild(this->GetCommonFileStream(), phonyBuild);
   }
 
   // Find ADDITIONAL_CLEAN_FILES
-  this->AdditionalCleanFiles();
+  this->AdditionalCleanFiles(config);
 
   // Add an alias for the logical target name regardless of what directory
   // contains it.  Skip this for GLOBAL_TARGET because they are meant to
   // be per-directory and have one at the top-level anyway.
   if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) {
-    gg->AddTargetAlias(this->GetTargetName(), genTarget);
+    gg->AddTargetAlias(this->GetTargetName(), genTarget, config);
+  } else if (gg->IsMultiConfig() && genTarget->Target->IsPerConfig()) {
+    cmNinjaBuild phonyAlias("phony");
+    gg->AppendTargetOutputs(genTarget, phonyAlias.Outputs, "");
+    phonyAlias.ExplicitDeps = phonyBuild.Outputs;
+    gg->WriteBuild(this->GetImplFileStream(config), phonyAlias);
   }
 }
diff --git a/Source/cmNinjaUtilityTargetGenerator.h b/Source/cmNinjaUtilityTargetGenerator.h
index 01cc459..ca3f0a4 100644
--- a/Source/cmNinjaUtilityTargetGenerator.h
+++ b/Source/cmNinjaUtilityTargetGenerator.h
@@ -5,6 +5,8 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include <string>
+
 #include "cmNinjaTargetGenerator.h"
 
 class cmGeneratorTarget;
@@ -15,7 +17,7 @@
   cmNinjaUtilityTargetGenerator(cmGeneratorTarget* target);
   ~cmNinjaUtilityTargetGenerator() override;
 
-  void Generate() override;
+  void Generate(const std::string& config) override;
 };
 
 #endif // ! cmNinjaUtilityTargetGenerator_h
diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx
index a6f4e51..382b563 100644
--- a/Source/cmOSXBundleGenerator.cxx
+++ b/Source/cmOSXBundleGenerator.cxx
@@ -3,7 +3,6 @@
 #include "cmOSXBundleGenerator.h"
 
 #include <cassert>
-#include <utility>
 
 #include "cmGeneratorTarget.h"
 #include "cmLocalGenerator.h"
@@ -15,12 +14,10 @@
 
 class cmSourceFile;
 
-cmOSXBundleGenerator::cmOSXBundleGenerator(cmGeneratorTarget* target,
-                                           std::string configName)
+cmOSXBundleGenerator::cmOSXBundleGenerator(cmGeneratorTarget* target)
   : GT(target)
   , Makefile(target->Target->GetMakefile())
   , LocalGenerator(target->GetLocalGenerator())
-  , ConfigName(std::move(configName))
   , MacContentFolders(nullptr)
 {
   if (this->MustSkip()) {
@@ -34,34 +31,34 @@
 }
 
 void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName,
-                                           std::string& outpath)
+                                           std::string& outpath,
+                                           const std::string& config)
 {
   if (this->MustSkip()) {
     return;
   }
 
   // Compute bundle directory names.
-  std::string out =
-    cmStrCat(outpath, '/',
-             this->GT->GetAppBundleDirectory(this->ConfigName,
-                                             cmGeneratorTarget::FullLevel));
+  std::string out = cmStrCat(
+    outpath, '/',
+    this->GT->GetAppBundleDirectory(config, cmGeneratorTarget::FullLevel));
   cmSystemTools::MakeDirectory(out);
   this->Makefile->AddCMakeOutputFile(out);
 
   // Configure the Info.plist file.  Note that it needs the executable name
   // to be set.
-  std::string plist =
-    cmStrCat(outpath, '/',
-             this->GT->GetAppBundleDirectory(this->ConfigName,
-                                             cmGeneratorTarget::ContentLevel),
-             "/Info.plist");
+  std::string plist = cmStrCat(
+    outpath, '/',
+    this->GT->GetAppBundleDirectory(config, cmGeneratorTarget::ContentLevel),
+    "/Info.plist");
   this->LocalGenerator->GenerateAppleInfoPList(this->GT, targetName, plist);
   this->Makefile->AddCMakeOutputFile(plist);
   outpath = out;
 }
 
 void cmOSXBundleGenerator::CreateFramework(const std::string& targetName,
-                                           const std::string& outpath)
+                                           const std::string& outpath,
+                                           const std::string& config)
 {
   if (this->MustSkip()) {
     return;
@@ -70,15 +67,13 @@
   assert(this->MacContentFolders);
 
   // Compute the location of the top-level foo.framework directory.
-  std::string contentdir =
-    cmStrCat(outpath, '/',
-             this->GT->GetFrameworkDirectory(this->ConfigName,
-                                             cmGeneratorTarget::ContentLevel),
-             '/');
+  std::string contentdir = cmStrCat(
+    outpath, '/',
+    this->GT->GetFrameworkDirectory(config, cmGeneratorTarget::ContentLevel),
+    '/');
 
   std::string newoutpath = outpath + "/" +
-    this->GT->GetFrameworkDirectory(this->ConfigName,
-                                    cmGeneratorTarget::FullLevel);
+    this->GT->GetFrameworkDirectory(config, cmGeneratorTarget::FullLevel);
 
   std::string frameworkVersion = this->GT->GetFrameworkVersion();
 
@@ -156,27 +151,26 @@
 }
 
 void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName,
-                                          const std::string& root)
+                                          const std::string& root,
+                                          const std::string& config)
 {
   if (this->MustSkip()) {
     return;
   }
 
   // Compute bundle directory names.
-  std::string out =
-    cmStrCat(root, '/',
-             this->GT->GetCFBundleDirectory(this->ConfigName,
-                                            cmGeneratorTarget::FullLevel));
+  std::string out = cmStrCat(
+    root, '/',
+    this->GT->GetCFBundleDirectory(config, cmGeneratorTarget::FullLevel));
   cmSystemTools::MakeDirectory(out);
   this->Makefile->AddCMakeOutputFile(out);
 
   // Configure the Info.plist file.  Note that it needs the executable name
   // to be set.
-  std::string plist =
-    cmStrCat(root, '/',
-             this->GT->GetCFBundleDirectory(this->ConfigName,
-                                            cmGeneratorTarget::ContentLevel),
-             "/Info.plist");
+  std::string plist = cmStrCat(
+    root, '/',
+    this->GT->GetCFBundleDirectory(config, cmGeneratorTarget::ContentLevel),
+    "/Info.plist");
   std::string name = cmSystemTools::GetFilenameName(targetName);
   this->LocalGenerator->GenerateAppleInfoPList(this->GT, name, plist);
   this->Makefile->AddCMakeOutputFile(plist);
@@ -184,7 +178,7 @@
 
 void cmOSXBundleGenerator::GenerateMacOSXContentStatements(
   std::vector<cmSourceFile const*> const& sources,
-  MacOSXContentGeneratorType* generator)
+  MacOSXContentGeneratorType* generator, const std::string& config)
 {
   if (this->MustSkip()) {
     return;
@@ -194,20 +188,19 @@
     cmGeneratorTarget::SourceFileFlags tsFlags =
       this->GT->GetTargetSourceFileFlags(source);
     if (tsFlags.Type != cmGeneratorTarget::SourceFileTypeNormal) {
-      (*generator)(*source, tsFlags.MacFolder);
+      (*generator)(*source, tsFlags.MacFolder, config);
     }
   }
 }
 
 std::string cmOSXBundleGenerator::InitMacOSXContentDirectory(
-  const char* pkgloc)
+  const char* pkgloc, const std::string& config)
 {
   // Construct the full path to the content subdirectory.
 
-  std::string macdir =
-    cmStrCat(this->GT->GetMacContentDirectory(
-               this->ConfigName, cmStateEnums::RuntimeBinaryArtifact),
-             '/', pkgloc);
+  std::string macdir = cmStrCat(this->GT->GetMacContentDirectory(
+                                  config, cmStateEnums::RuntimeBinaryArtifact),
+                                '/', pkgloc);
   cmSystemTools::MakeDirectory(macdir);
 
   // Record use of this content location.  Only the first level
diff --git a/Source/cmOSXBundleGenerator.h b/Source/cmOSXBundleGenerator.h
index 3dea6cc..232be48 100644
--- a/Source/cmOSXBundleGenerator.h
+++ b/Source/cmOSXBundleGenerator.h
@@ -17,29 +17,33 @@
 class cmOSXBundleGenerator
 {
 public:
-  cmOSXBundleGenerator(cmGeneratorTarget* target, std::string configName);
+  cmOSXBundleGenerator(cmGeneratorTarget* target);
 
   // create an app bundle at a given root, and return
   // the directory within the bundle that contains the executable
-  void CreateAppBundle(const std::string& targetName, std::string& root);
+  void CreateAppBundle(const std::string& targetName, std::string& root,
+                       const std::string& config);
 
   // create a framework at a given root
-  void CreateFramework(const std::string& targetName, const std::string& root);
+  void CreateFramework(const std::string& targetName, const std::string& root,
+                       const std::string& config);
 
   // create a cf bundle at a given root
-  void CreateCFBundle(const std::string& targetName, const std::string& root);
+  void CreateCFBundle(const std::string& targetName, const std::string& root,
+                      const std::string& config);
 
   struct MacOSXContentGeneratorType
   {
     virtual ~MacOSXContentGeneratorType() = default;
-    virtual void operator()(cmSourceFile const& source,
-                            const char* pkgloc) = 0;
+    virtual void operator()(cmSourceFile const& source, const char* pkgloc,
+                            const std::string& config) = 0;
   };
 
   void GenerateMacOSXContentStatements(
     std::vector<cmSourceFile const*> const& sources,
-    MacOSXContentGeneratorType* generator);
-  std::string InitMacOSXContentDirectory(const char* pkgloc);
+    MacOSXContentGeneratorType* generator, const std::string& config);
+  std::string InitMacOSXContentDirectory(const char* pkgloc,
+                                         const std::string& config);
 
   void SetMacContentFolders(std::set<std::string>* macContentFolders)
   {
@@ -53,7 +57,6 @@
   cmGeneratorTarget* GT;
   cmMakefile* Makefile;
   cmLocalGenerator* LocalGenerator;
-  std::string ConfigName;
   std::set<std::string>* MacContentFolders;
 };
 
diff --git a/Source/cmOrderDirectories.cxx b/Source/cmOrderDirectories.cxx
index 073222c..0369af0 100644
--- a/Source/cmOrderDirectories.cxx
+++ b/Source/cmOrderDirectories.cxx
@@ -8,7 +8,9 @@
 #include <sstream>
 #include <vector>
 
-#include "cmAlgorithms.h"
+#include <cm/memory>
+#include <cmext/algorithm>
+
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
 #include "cmMessageType.h"
@@ -248,11 +250,7 @@
   this->Computed = false;
 }
 
-cmOrderDirectories::~cmOrderDirectories()
-{
-  cmDeleteAll(this->ConstraintEntries);
-  cmDeleteAll(this->ImplicitDirEntries);
-}
+cmOrderDirectories::~cmOrderDirectories() = default;
 
 std::vector<std::string> const& cmOrderDirectories::GetOrderedDirectories()
 {
@@ -286,14 +284,16 @@
 
       if (this->IsImplicitDirectory(dir)) {
         this->ImplicitDirEntries.push_back(
-          new cmOrderDirectoriesConstraintSOName(this, fullPath, soname));
+          cm::make_unique<cmOrderDirectoriesConstraintSOName>(this, fullPath,
+                                                              soname));
         return;
       }
     }
 
     // Construct the runtime information entry for this library.
     this->ConstraintEntries.push_back(
-      new cmOrderDirectoriesConstraintSOName(this, fullPath, soname));
+      cm::make_unique<cmOrderDirectoriesConstraintSOName>(this, fullPath,
+                                                          soname));
   } else {
     // This can happen if the same library is linked multiple times.
     // In that case the runtime information check need be done only
@@ -314,27 +314,28 @@
       std::string dir = cmSystemTools::GetFilenamePath(fullPath);
       if (this->IsImplicitDirectory(dir)) {
         this->ImplicitDirEntries.push_back(
-          new cmOrderDirectoriesConstraintLibrary(this, fullPath));
+          cm::make_unique<cmOrderDirectoriesConstraintLibrary>(this,
+                                                               fullPath));
         return;
       }
     }
 
     // Construct the link library entry.
     this->ConstraintEntries.push_back(
-      new cmOrderDirectoriesConstraintLibrary(this, fullPath));
+      cm::make_unique<cmOrderDirectoriesConstraintLibrary>(this, fullPath));
   }
 }
 
 void cmOrderDirectories::AddUserDirectories(
   std::vector<std::string> const& extra)
 {
-  cmAppend(this->UserDirectories, extra);
+  cm::append(this->UserDirectories, extra);
 }
 
 void cmOrderDirectories::AddLanguageDirectories(
   std::vector<std::string> const& dirs)
 {
-  cmAppend(this->LanguageDirectories, dirs);
+  cm::append(this->LanguageDirectories, dirs);
 }
 
 void cmOrderDirectories::SetImplicitDirectories(
@@ -369,7 +370,7 @@
   this->AddOriginalDirectories(this->UserDirectories);
 
   // Add directories containing constraints.
-  for (cmOrderDirectoriesConstraint* entry : this->ConstraintEntries) {
+  for (const auto& entry : this->ConstraintEntries) {
     entry->AddDirectory();
   }
 
@@ -454,7 +455,7 @@
   // Check for items in implicit link directories that have conflicts
   // in the explicit directories.
   std::ostringstream conflicts;
-  for (cmOrderDirectoriesConstraint* entry : this->ImplicitDirEntries) {
+  for (const auto& entry : this->ImplicitDirEntries) {
     entry->FindImplicitConflicts(conflicts);
   }
 
diff --git a/Source/cmOrderDirectories.h b/Source/cmOrderDirectories.h
index 23c5145..8ce53e0 100644
--- a/Source/cmOrderDirectories.h
+++ b/Source/cmOrderDirectories.h
@@ -6,6 +6,7 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <map>
+#include <memory>
 #include <set>
 #include <string>
 #include <utility>
@@ -46,8 +47,9 @@
 
   std::vector<std::string> OrderedDirectories;
 
-  std::vector<cmOrderDirectoriesConstraint*> ConstraintEntries;
-  std::vector<cmOrderDirectoriesConstraint*> ImplicitDirEntries;
+  std::vector<std::unique_ptr<cmOrderDirectoriesConstraint>> ConstraintEntries;
+  std::vector<std::unique_ptr<cmOrderDirectoriesConstraint>>
+    ImplicitDirEntries;
   std::vector<std::string> UserDirectories;
   std::vector<std::string> LanguageDirectories;
   cmsys::RegularExpression RemoveLibraryExtension;
diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx
index e602a6d..1c6fad1 100644
--- a/Source/cmOutputConverter.cxx
+++ b/Source/cmOutputConverter.cxx
@@ -43,9 +43,10 @@
 {
   std::string result(source);
   // Convert it to an output path.
-  if (output == SHELL || output == WATCOMQUOTE) {
+  if (output == SHELL || output == WATCOMQUOTE || output == NINJAMULTI) {
     result = this->ConvertDirectorySeparatorsForShell(source);
-    result = this->EscapeForShell(result, true, false, output == WATCOMQUOTE);
+    result = this->EscapeForShell(result, true, false, output == WATCOMQUOTE,
+                                  output == NINJAMULTI);
   } else if (output == RESPONSE) {
     result = this->EscapeForShell(result, false, false, false);
   }
@@ -79,9 +80,9 @@
   return (shellOperators.count(str) != 0);
 }
 
-std::string cmOutputConverter::EscapeForShell(cm::string_view str,
-                                              bool makeVars, bool forEcho,
-                                              bool useWatcomQuote) const
+std::string cmOutputConverter::EscapeForShell(
+  cm::string_view str, bool makeVars, bool forEcho, bool useWatcomQuote,
+  bool unescapeNinjaConfiguration) const
 {
   // Do not escape shell operators.
   if (cmOutputConverterIsShellOperator(str)) {
@@ -95,6 +96,9 @@
   } else if (!this->LinkScriptShell) {
     flags |= Shell_Flag_Make;
   }
+  if (unescapeNinjaConfiguration) {
+    flags |= Shell_Flag_UnescapeNinjaConfiguration;
+  }
   if (makeVars) {
     flags |= Shell_Flag_AllowMakeVariables;
   }
@@ -511,5 +515,14 @@
     }
   }
 
+  if (flags & Shell_Flag_UnescapeNinjaConfiguration) {
+    std::string ninjaConfigReplace;
+    if (flags & Shell_Flag_IsUnix) {
+      ninjaConfigReplace += '\\';
+    }
+    ninjaConfigReplace += "$${CONFIGURATION}";
+    cmSystemTools::ReplaceString(out, ninjaConfigReplace, "${CONFIGURATION}");
+  }
+
   return out;
 }
diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h
index 349a069..6583ab5 100644
--- a/Source/cmOutputConverter.h
+++ b/Source/cmOutputConverter.h
@@ -22,6 +22,7 @@
   {
     SHELL,
     WATCOMQUOTE,
+    NINJAMULTI,
     RESPONSE
   };
   std::string ConvertToOutputFormat(cm::string_view source,
@@ -70,12 +71,14 @@
     /** The target shell quoting uses extra single Quotes for Watcom tools.  */
     Shell_Flag_WatcomQuote = (1 << 7),
 
-    Shell_Flag_IsUnix = (1 << 8)
+    Shell_Flag_IsUnix = (1 << 8),
+
+    Shell_Flag_UnescapeNinjaConfiguration = (1 << 9),
   };
 
   std::string EscapeForShell(cm::string_view str, bool makeVars = false,
-                             bool forEcho = false,
-                             bool useWatcomQuote = false) const;
+                             bool forEcho = false, bool useWatcomQuote = false,
+                             bool unescapeNinjaConfiguration = false) const;
 
   static std::string EscapeForCMake(cm::string_view str);
 
diff --git a/Source/cmOutputRequiredFilesCommand.cxx b/Source/cmOutputRequiredFilesCommand.cxx
index e093be0..147f97f 100644
--- a/Source/cmOutputRequiredFilesCommand.cxx
+++ b/Source/cmOutputRequiredFilesCommand.cxx
@@ -7,10 +7,11 @@
 #include <set>
 #include <utility>
 
+#include <cm/memory>
+
 #include "cmsys/FStream.hxx"
 #include "cmsys/RegularExpression.hxx"
 
-#include "cmAlgorithms.h"
 #include "cmExecutionStatus.h"
 #include "cmGeneratorExpression.h"
 #include "cmMakefile.h"
@@ -94,7 +95,7 @@
   /**
    * Destructor.
    */
-  ~cmLBDepend() { cmDeleteAll(this->DependInformationMap); }
+  ~cmLBDepend() = default;
 
   cmLBDepend(const cmLBDepend&) = delete;
   cmLBDepend& operator=(const cmLBDepend&) = delete;
@@ -152,9 +153,9 @@
    * Generate dependencies for the file given.  Returns a pointer to
    * the cmDependInformation object for the file.
    */
-  const cmDependInformation* FindDependencies(const char* file)
+  const cmDependInformation* FindDependencies(const std::string& file)
   {
-    cmDependInformation* info = this->GetDependInformation(file, nullptr);
+    cmDependInformation* info = this->GetDependInformation(file, "");
     this->GenerateDependInformation(info);
     return info;
   }
@@ -203,7 +204,7 @@
         }
 
         // Add this file and all its dependencies.
-        this->AddDependency(info, includeFile.c_str());
+        this->AddDependency(info, includeFile);
         /// add the cxx file if it exists
         std::string cxxFile = includeFile;
         std::string::size_type pos = cxxFile.rfind('.');
@@ -254,7 +255,7 @@
             }
           }
           if (found) {
-            this->AddDependency(info, cxxFile.c_str());
+            this->AddDependency(info, cxxFile);
           }
         }
       }
@@ -264,10 +265,10 @@
   /**
    * Add a dependency.  Possibly walk it for more dependencies.
    */
-  void AddDependency(cmDependInformation* info, const char* file)
+  void AddDependency(cmDependInformation* info, const std::string& file)
   {
     cmDependInformation* dependInfo =
-      this->GetDependInformation(file, info->PathOnly.c_str());
+      this->GetDependInformation(file, info->PathOnly);
     this->GenerateDependInformation(dependInfo);
     info->AddDependencies(dependInfo);
   }
@@ -313,7 +314,7 @@
         // Dependency hints have been given.  Use them to begin the
         // recursion.
         for (std::string const& file : cFile.GetDepends()) {
-          this->AddDependency(info, file.c_str());
+          this->AddDependency(info, file);
         }
 
         // Found dependency information.  We are done.
@@ -361,8 +362,8 @@
    * Get an instance of cmDependInformation corresponding to the given file
    * name.
    */
-  cmDependInformation* GetDependInformation(const char* file,
-                                            const char* extraPath)
+  cmDependInformation* GetDependInformation(const std::string& file,
+                                            const std::string& extraPath)
   {
     // Get the full path for the file so that lookup is unambiguous.
     std::string fullPath = this->FullPath(file, extraPath);
@@ -371,15 +372,16 @@
     auto result = this->DependInformationMap.find(fullPath);
     if (result != this->DependInformationMap.end()) {
       // Found an instance, return it.
-      return result->second;
+      return result->second.get();
     }
     // Didn't find an instance.  Create a new one and save it.
-    cmDependInformation* info = new cmDependInformation;
+    auto info = cm::make_unique<cmDependInformation>();
+    auto ptr = info.get();
     info->FullPath = fullPath;
     info->PathOnly = cmSystemTools::GetFilenamePath(fullPath);
     info->IncludeName = file;
-    this->DependInformationMap[fullPath] = info;
-    return info;
+    this->DependInformationMap[fullPath] = std::move(info);
+    return ptr;
   }
 
   /**
@@ -387,14 +389,9 @@
    * This uses the include directories.
    * TODO: Cache path conversions to reduce FileExists calls.
    */
-  std::string FullPath(const char* fname, const char* extraPath)
+  std::string FullPath(const std::string& fname, const std::string& extraPath)
   {
-    DirectoryToFileToPathMapType::iterator m;
-    if (extraPath) {
-      m = this->DirectoryToFileToPathMap.find(extraPath);
-    } else {
-      m = this->DirectoryToFileToPathMap.find("");
-    }
+    auto m = this->DirectoryToFileToPathMap.find(extraPath);
 
     if (m != this->DirectoryToFileToPathMap.end()) {
       FileToPathMapType& map = m->second;
@@ -406,7 +403,7 @@
 
     if (cmSystemTools::FileExists(fname, true)) {
       std::string fp = cmSystemTools::CollapseFullPath(fname);
-      this->DirectoryToFileToPathMap[extraPath ? extraPath : ""][fname] = fp;
+      this->DirectoryToFileToPathMap[extraPath][fname] = fp;
       return fp;
     }
 
@@ -418,12 +415,12 @@
       if (cmSystemTools::FileExists(path, true) &&
           !cmSystemTools::FileIsDirectory(path)) {
         std::string fp = cmSystemTools::CollapseFullPath(path);
-        this->DirectoryToFileToPathMap[extraPath ? extraPath : ""][fname] = fp;
+        this->DirectoryToFileToPathMap[extraPath][fname] = fp;
         return fp;
       }
     }
 
-    if (extraPath) {
+    if (!extraPath.empty()) {
       std::string path = extraPath;
       if (!path.empty() && path.back() != '/') {
         path = path + "/";
@@ -438,7 +435,7 @@
     }
 
     // Couldn't find the file.
-    return std::string(fname);
+    return fname;
   }
 
   cmMakefile* Makefile;
@@ -449,7 +446,8 @@
   using FileToPathMapType = std::map<std::string, std::string>;
   using DirectoryToFileToPathMapType =
     std::map<std::string, FileToPathMapType>;
-  using DependInformationMapType = std::map<std::string, cmDependInformation*>;
+  using DependInformationMapType =
+    std::map<std::string, std::unique_ptr<cmDependInformation>>;
   DependInformationMapType DependInformationMap;
   DirectoryToFileToPathMapType DirectoryToFileToPathMap;
 };
@@ -476,7 +474,7 @@
   md.SetMakefile(&status.GetMakefile());
   md.AddSearchPath(status.GetMakefile().GetCurrentSourceDirectory());
   // find the depends for a file
-  const cmDependInformation* info = md.FindDependencies(file.c_str());
+  const cmDependInformation* info = md.FindDependencies(file);
   if (info) {
     // write them out
     FILE* fout = cmsys::SystemTools::Fopen(outputFile, "w");
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 92c80bb..1366ff0 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -290,7 +290,22 @@
   SELECT(POLICY, CMP0097,                                                     \
          "ExternalProject_Add with GIT_SUBMODULES \"\" initializes no "       \
          "submodules.",                                                       \
-         3, 16, 0, cmPolicies::WARN)
+         3, 16, 0, cmPolicies::WARN)                                          \
+  SELECT(POLICY, CMP0098,                                                     \
+         "FindFLEX runs flex in CMAKE_CURRENT_BINARY_DIR when executing.", 3, \
+         17, 0, cmPolicies::WARN)                                             \
+  SELECT(POLICY, CMP0099,                                                     \
+         "Link properties are transitive over private dependency on static "  \
+         "libraries.",                                                        \
+         3, 17, 0, cmPolicies::WARN)                                          \
+  SELECT(POLICY, CMP0100, "Let AUTOMOC and AUTOUIC process .hh files.", 3,    \
+         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)                                         \
@@ -319,7 +334,8 @@
   F(CMP0076)                                                                  \
   F(CMP0081)                                                                  \
   F(CMP0083)                                                                  \
-  F(CMP0095)
+  F(CMP0095)                                                                  \
+  F(CMP0099)
 
 /** \class cmPolicies
  * \brief Handles changes in CMake behavior and policies
diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx
index 7bb5209..a25fd42 100644
--- a/Source/cmProjectCommand.cxx
+++ b/Source/cmProjectCommand.cxx
@@ -39,6 +39,11 @@
 
   std::string const& projectName = args[0];
 
+  if (!IncludeByVariable(status,
+                         "CMAKE_PROJECT_" + projectName + "_INCLUDE_BEFORE")) {
+    return false;
+  }
+
   mf.SetProjectName(projectName);
 
   mf.AddCacheDefinition(projectName + "_BINARY_DIR",
diff --git a/Source/cmPropertyMap.cxx b/Source/cmPropertyMap.cxx
index a3d4946..d4b3552 100644
--- a/Source/cmPropertyMap.cxx
+++ b/Source/cmPropertyMap.cxx
@@ -20,11 +20,11 @@
   Map_[name] = value;
 }
 
-void cmPropertyMap::AppendProperty(const std::string& name, const char* value,
-                                   bool asString)
+void cmPropertyMap::AppendProperty(const std::string& name,
+                                   const std::string& value, bool asString)
 {
   // Skip if nothing to append.
-  if (!value || !*value) {
+  if (value.empty()) {
     return;
   }
 
diff --git a/Source/cmPropertyMap.h b/Source/cmPropertyMap.h
index 9aed349..bea4372 100644
--- a/Source/cmPropertyMap.h
+++ b/Source/cmPropertyMap.h
@@ -27,7 +27,7 @@
   void SetProperty(const std::string& name, const char* value);
 
   //! Append to the property value
-  void AppendProperty(const std::string& name, const char* value,
+  void AppendProperty(const std::string& name, const std::string& value,
                       bool asString = false);
 
   //! Get the property value
diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx
index eb7c900..d5891c4 100644
--- a/Source/cmQtAutoGen.cxx
+++ b/Source/cmQtAutoGen.cxx
@@ -8,6 +8,8 @@
 #include <sstream>
 #include <utility>
 
+#include <cmext/algorithm>
+
 #include "cmsys/FStream.hxx"
 #include "cmsys/RegularExpression.hxx"
 
@@ -67,7 +69,7 @@
     }
   }
   // Append options
-  cmAppend(baseOpts, extraOpts);
+  cm::append(baseOpts, extraOpts);
 }
 
 // - Class definitions
@@ -328,7 +330,7 @@
     {
       std::vector<std::string> cmd;
       cmd.emplace_back(this->RccExcutable_);
-      cmAppend(cmd, this->ListOptions_);
+      cm::append(cmd, this->ListOptions_);
       cmd.emplace_back(cmSystemTools::GetFilenameName(qrcFile));
 
       // Log command
diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx
index ef6b886..7a6cb42 100644
--- a/Source/cmQtAutoGenGlobalInitializer.cxx
+++ b/Source/cmQtAutoGenGlobalInitializer.cxx
@@ -7,7 +7,6 @@
 #include <cm/memory>
 
 #include "cmCustomCommandLines.h"
-#include "cmCustomCommandTypes.h"
 #include "cmDuration.h"
 #include "cmGeneratorTarget.h"
 #include "cmLocalGenerator.h"
@@ -41,9 +40,9 @@
 }
 
 cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
-  std::vector<cmLocalGenerator*> const& localGenerators)
+  std::vector<std::unique_ptr<cmLocalGenerator>> const& localGenerators)
 {
-  for (cmLocalGenerator* localGen : localGenerators) {
+  for (const auto& localGen : localGenerators) {
     // Detect global autogen and autorcc target names
     bool globalAutoGenTarget = false;
     bool globalAutoRccTarget = false;
@@ -56,7 +55,7 @@
         if (targetName.empty()) {
           targetName = "autogen";
         }
-        GlobalAutoGenTargets_.emplace(localGen, std::move(targetName));
+        GlobalAutoGenTargets_.emplace(localGen.get(), std::move(targetName));
         globalAutoGenTarget = true;
       }
 
@@ -67,13 +66,13 @@
         if (targetName.empty()) {
           targetName = "autorcc";
         }
-        GlobalAutoRccTargets_.emplace(localGen, std::move(targetName));
+        GlobalAutoRccTargets_.emplace(localGen.get(), std::move(targetName));
         globalAutoRccTarget = true;
       }
     }
 
     // Find targets that require AUTOMOC/UIC/RCC processing
-    for (cmGeneratorTarget* target : localGen->GetGeneratorTargets()) {
+    for (const auto& target : localGen->GetGeneratorTargets()) {
       // Process only certain target types
       switch (target->GetType()) {
         case cmStateEnums::EXECUTABLE:
@@ -104,7 +103,7 @@
           target->GetSafeProperty(kw().AUTORCC_EXECUTABLE);
 
         // We support Qt4, Qt5 and Qt6
-        auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target);
+        auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target.get());
         bool const validQt = (qtVersion.first.Major == 4) ||
           (qtVersion.first.Major == 5) || (qtVersion.first.Major == 6);
 
@@ -135,8 +134,8 @@
         if (mocIsValid || uicIsValid || rccIsValid) {
           // Create autogen target initializer
           Initializers_.emplace_back(cm::make_unique<cmQtAutoGenInitializer>(
-            this, target, qtVersion.first, mocIsValid, uicIsValid, rccIsValid,
-            globalAutoGenTarget, globalAutoRccTarget));
+            this, target.get(), qtVersion.first, mocIsValid, uicIsValid,
+            rccIsValid, globalAutoGenTarget, globalAutoRccTarget));
         }
       }
     }
@@ -154,13 +153,14 @@
     cmMakefile* makefile = localGen->GetMakefile();
 
     // Create utility target
-    cmTarget* target = makefile->AddUtilityCommand(
-      name, cmCommandOrigin::Generator, true,
-      makefile->GetHomeOutputDirectory().c_str() /*work dir*/,
-      std::vector<std::string>() /*output*/,
-      std::vector<std::string>() /*depends*/, cmCustomCommandLines(), false,
-      comment.c_str());
-    localGen->AddGeneratorTarget(new cmGeneratorTarget(target, localGen));
+    std::vector<std::string> no_byproducts;
+    std::vector<std::string> no_depends;
+    cmCustomCommandLines no_commands;
+    cmTarget* target = localGen->AddUtilityCommand(
+      name, true, makefile->GetHomeOutputDirectory().c_str(), no_byproducts,
+      no_depends, no_commands, false, comment.c_str());
+    localGen->AddGeneratorTarget(
+      cm::make_unique<cmGeneratorTarget>(target, localGen));
 
     // Set FOLDER property in the target
     {
@@ -180,7 +180,7 @@
   if (it != GlobalAutoGenTargets_.end()) {
     cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second);
     if (target != nullptr) {
-      target->Target->AddUtility(targetName, localGen->GetMakefile());
+      target->Target->AddUtility(targetName, false, localGen->GetMakefile());
     }
   }
 }
@@ -192,7 +192,7 @@
   if (it != GlobalAutoRccTargets_.end()) {
     cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second);
     if (target != nullptr) {
-      target->Target->AddUtility(targetName, localGen->GetMakefile());
+      target->Target->AddUtility(targetName, false, localGen->GetMakefile());
     }
   }
 }
diff --git a/Source/cmQtAutoGenGlobalInitializer.h b/Source/cmQtAutoGenGlobalInitializer.h
index 806725a..2f6e581 100644
--- a/Source/cmQtAutoGenGlobalInitializer.h
+++ b/Source/cmQtAutoGenGlobalInitializer.h
@@ -48,7 +48,7 @@
 
 public:
   cmQtAutoGenGlobalInitializer(
-    std::vector<cmLocalGenerator*> const& localGenerators);
+    std::vector<std::unique_ptr<cmLocalGenerator>> const& localGenerators);
   ~cmQtAutoGenGlobalInitializer();
 
   Keywords const& kw() const { return Keywords_; };
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 5eb04f7..629367d 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -25,7 +25,6 @@
 #include "cmAlgorithms.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
-#include "cmCustomCommandTypes.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
@@ -355,24 +354,38 @@
     }
   }
 
-  // Check status of policy CMP0071
-  {
-    cmPolicies::PolicyStatus const CMP0071_status =
-      this->Makefile->GetPolicyStatus(cmPolicies::CMP0071);
-    switch (CMP0071_status) {
-      case cmPolicies::WARN:
-        this->CMP0071Warn = true;
-        CM_FALLTHROUGH;
-      case cmPolicies::OLD:
-        // Ignore GENERATED file
-        break;
-      case cmPolicies::REQUIRED_IF_USED:
-      case cmPolicies::REQUIRED_ALWAYS:
-      case cmPolicies::NEW:
-        // Process GENERATED file
-        this->CMP0071Accept = true;
-        break;
-    }
+  // Check status of policy CMP0071 regarding handling of GENERATED files
+  switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0071)) {
+    case cmPolicies::WARN:
+      // Ignore GENERATED files but warn
+      this->CMP0071Warn = true;
+      CM_FALLTHROUGH;
+    case cmPolicies::OLD:
+      // Ignore GENERATED files
+      break;
+    case cmPolicies::REQUIRED_IF_USED:
+    case cmPolicies::REQUIRED_ALWAYS:
+    case cmPolicies::NEW:
+      // Process GENERATED files
+      this->CMP0071Accept = true;
+      break;
+  }
+
+  // Check status of policy CMP0100 regarding handling of .hh headers
+  switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0100)) {
+    case cmPolicies::WARN:
+      // Ignore but .hh files but warn
+      this->CMP0100Warn = true;
+      CM_FALLTHROUGH;
+    case cmPolicies::OLD:
+      // Ignore .hh files
+      break;
+    case cmPolicies::REQUIRED_IF_USED:
+    case cmPolicies::REQUIRED_ALWAYS:
+    case cmPolicies::NEW:
+      // Process .hh file
+      this->CMP0100Accept = true;
+      break;
   }
 
   // Common directories
@@ -734,15 +747,26 @@
     return muf;
   };
 
-  auto addMUFile = [&](MUFileHandle&& muf, bool isHeader) {
+  auto addMUHeader = [this](MUFileHandle&& muf, cm::string_view extension) {
+    cmSourceFile* sf = muf->SF;
+    const bool muIt = (muf->MocIt || muf->UicIt);
+    if (this->CMP0100Accept || (extension != "hh")) {
+      // Accept
+      if (muIt && muf->Generated) {
+        this->AutogenTarget.FilesGenerated.emplace_back(muf.get());
+      }
+      this->AutogenTarget.Headers.emplace(sf, std::move(muf));
+    } else if (muIt && this->CMP0100Warn) {
+      // Store file for warning message
+      this->AutogenTarget.CMP0100HeadersWarn.push_back(sf);
+    }
+  };
+
+  auto addMUSource = [this](MUFileHandle&& muf) {
     if ((muf->MocIt || muf->UicIt) && muf->Generated) {
       this->AutogenTarget.FilesGenerated.emplace_back(muf.get());
     }
-    if (isHeader) {
-      this->AutogenTarget.Headers.emplace(muf->SF, std::move(muf));
-    } else {
-      this->AutogenTarget.Sources.emplace(muf->SF, std::move(muf));
-    }
+    this->AutogenTarget.Sources.emplace(muf->SF, std::move(muf));
   };
 
   // Scan through target files
@@ -764,11 +788,10 @@
 
       // Register files that will be scanned by moc or uic
       if (this->MocOrUicEnabled()) {
-        // FIXME: Add a policy to include .hh files.
-        if (cm->IsHeaderExtension(extLower) && extLower != "hh") {
-          addMUFile(makeMUFile(sf, fullPath, true), true);
+        if (cm->IsHeaderExtension(extLower)) {
+          addMUHeader(makeMUFile(sf, fullPath, true), extLower);
         } else if (cm->IsSourceExtension(extLower)) {
-          addMUFile(makeMUFile(sf, fullPath, true), false);
+          addMUSource(makeMUFile(sf, fullPath, true));
         }
       }
 
@@ -802,8 +825,6 @@
 
   // For source files find additional headers and private headers
   if (this->MocOrUicEnabled()) {
-    std::vector<MUFileHandle> extraHeaders;
-    extraHeaders.reserve(this->AutogenTarget.Sources.size() * 2);
     // Header search suffixes and extensions
     static std::initializer_list<cm::string_view> const suffixes{ "", "_p" };
     auto const& exts = cm->GetHeaderExtensions();
@@ -848,16 +869,12 @@
               if (!muf.UicIt) {
                 eMuf->UicIt = false;
               }
-              extraHeaders.emplace_back(std::move(eMuf));
+              addMUHeader(std::move(eMuf), ext);
             }
           }
         }
       }
     }
-    // Move generated files to main headers list
-    for (auto& eMuf : extraHeaders) {
-      addMUFile(std::move(eMuf), true);
-    }
   }
 
   // Scan through all source files in the makefile to extract moc and uic
@@ -865,7 +882,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).
@@ -877,19 +894,18 @@
       std::string const& extLower =
         cmSystemTools::LowerCase(sf->GetExtension());
 
-      // FIXME: Add a policy to include .hh files.
-      if (cm->IsHeaderExtension(extLower) && extLower != "hh") {
-        if (!cmContains(this->AutogenTarget.Headers, sf)) {
-          auto muf = makeMUFile(sf, fullPath, false);
+      if (cm->IsHeaderExtension(extLower)) {
+        if (!cmContains(this->AutogenTarget.Headers, sf.get())) {
+          auto muf = makeMUFile(sf.get(), fullPath, false);
           if (muf->SkipMoc || muf->SkipUic) {
-            this->AutogenTarget.Headers.emplace(sf, std::move(muf));
+            addMUHeader(std::move(muf), extLower);
           }
         }
       } else if (cm->IsSourceExtension(extLower)) {
-        if (!cmContains(this->AutogenTarget.Headers, 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) {
-            this->AutogenTarget.Sources.emplace(sf, std::move(muf));
+            addMUSource(std::move(muf));
           }
         }
       } else if (this->Uic.Enabled && (extLower == kw.ui)) {
@@ -947,6 +963,35 @@
     }
   }
 
+  // Generate CMP0100 warning
+  if (this->MocOrUicEnabled() &&
+      !this->AutogenTarget.CMP0100HeadersWarn.empty()) {
+    cm::string_view property;
+    if (this->Moc.Enabled && this->Uic.Enabled) {
+      property = "SKIP_AUTOGEN";
+    } else if (this->Moc.Enabled) {
+      property = "SKIP_AUTOMOC";
+    } else if (this->Uic.Enabled) {
+      property = "SKIP_AUTOUIC";
+    }
+    std::string files;
+    for (cmSourceFile* sf : this->AutogenTarget.CMP0100HeadersWarn) {
+      files += cmStrCat("  ", Quoted(sf->GetFullPath()), '\n');
+    }
+    this->Makefile->IssueMessage(
+      MessageType::AUTHOR_WARNING,
+      cmStrCat(
+        cmPolicies::GetPolicyWarning(cmPolicies::CMP0100), '\n',
+        "For compatibility, CMake is excluding the header file(s):\n", files,
+        "from processing by ",
+        cmQtAutoGen::Tools(this->Moc.Enabled, this->Uic.Enabled, false),
+        ".  If any of the files should be processed, set CMP0100 to NEW.  "
+        "If any of the files should not be processed, "
+        "explicitly exclude them by setting the source file property ",
+        property, ":\n  set_property(SOURCE file.hh PROPERTY ", property,
+        " ON)\n"));
+  }
+
   // Process qrc files
   if (!this->Rcc.Qrcs.empty()) {
     const bool modernQt = (this->QtVersion.Major >= 5);
@@ -1045,9 +1090,16 @@
   }
 
   // Compose command lines
-  cmCustomCommandLines commandLines = cmMakeSingleCommandLine(
-    { cmSystemTools::GetCMakeCommand(), "-E", "cmake_autogen",
-      this->AutogenTarget.InfoFile, "$<CONFIGURATION>" });
+  // TODO: Refactor autogen to output a per-config mocs_compilation.cpp instead
+  // of fiddling with the include directories
+  std::vector<std::string> configs;
+  this->GlobalGen->GetQtAutoGenConfigs(configs);
+  cmCustomCommandLines commandLines;
+  for (auto const& config : configs) {
+    commandLines.push_back(cmMakeCommandLine(
+      { cmSystemTools::GetCMakeCommand(), "-E", "cmake_autogen",
+        this->AutogenTarget.InfoFile, config }));
+  }
 
   // Use PRE_BUILD on demand
   bool usePRE_BUILD = false;
@@ -1073,7 +1125,7 @@
   if (usePRE_BUILD) {
     // Add additional autogen target dependencies to origin target
     for (cmTarget* depTarget : this->AutogenTarget.DependTargets) {
-      this->GenTarget->Target->AddUtility(depTarget->GetName(),
+      this->GenTarget->Target->AddUtility(depTarget->GetName(), false,
                                           this->Makefile);
     }
 
@@ -1084,8 +1136,8 @@
     // PRE_BUILD does not support file dependencies!
     const std::vector<std::string> no_output;
     const std::vector<std::string> no_deps;
-    cmCustomCommand cc(this->Makefile, no_output, autogenProvides, no_deps,
-                       commandLines, autogenComment.c_str(),
+    cmCustomCommand cc(no_output, autogenProvides, no_deps, commandLines,
+                       this->Makefile->GetBacktrace(), autogenComment.c_str(),
                        this->Dir.Work.c_str());
     cc.SetEscapeOldStyle(false);
     cc.SetEscapeAllowMakeVars(true);
@@ -1119,35 +1171,83 @@
       }
     }
 
+    std::vector<std::string> dependencies(
+      this->AutogenTarget.DependFiles.begin(),
+      this->AutogenTarget.DependFiles.end());
+
+    const bool useNinjaDepfile = this->QtVersion >= IntegerVersion(5, 15) &&
+      this->GlobalGen->GetName().find("Ninja") != std::string::npos;
+    if (useNinjaDepfile) {
+      // Create a custom command that generates a timestamp file and
+      // has a depfile assigned. The depfile is created by JobDepFilesMergeT.
+
+      // Add additional autogen target dependencies
+      for (const cmTarget* t : this->AutogenTarget.DependTargets) {
+        dependencies.push_back(t->GetName());
+      }
+      const char timestampFileName[] = "timestamp";
+      const std::string outputFile =
+        cmStrCat(this->Dir.Build, "/", timestampFileName);
+      this->AutogenTarget.DepFile = cmStrCat(this->Dir.Build, "/deps");
+      auto relativeBinaryDir = cmSystemTools::RelativePath(
+        this->LocalGen->GetBinaryDirectory(),
+        this->LocalGen->GetCurrentBinaryDirectory());
+      if (!relativeBinaryDir.empty()) {
+        relativeBinaryDir = cmStrCat(relativeBinaryDir, "/");
+      }
+      this->AutogenTarget.DepFileRuleName =
+        cmStrCat(relativeBinaryDir, this->GenTarget->GetName(), "_autogen/",
+                 timestampFileName);
+      commandLines.push_back(cmMakeCommandLine(
+        { cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile }));
+
+      this->AddGeneratedSource(outputFile, this->Moc);
+      const std::string no_main_dependency;
+      this->LocalGen->AddCustomCommandToOutput(
+        outputFile, dependencies, no_main_dependency, commandLines,
+        autogenComment.c_str(), this->Dir.Work.c_str(), /*replace=*/false,
+        /*escapeOldStyle=*/false,
+        /*uses_terminal=*/false,
+        /*command_expand_lists=*/false, this->AutogenTarget.DepFile);
+
+      // Alter variables for the autogen target which now merely wraps the
+      // custom command
+      dependencies.clear();
+      dependencies.push_back(outputFile);
+      commandLines.clear();
+      autogenComment.clear();
+    }
+
     // Create autogen target
-    cmTarget* autogenTarget = this->Makefile->AddUtilityCommand(
-      this->AutogenTarget.Name, cmCommandOrigin::Generator, true,
-      this->Dir.Work.c_str(), /*byproducts=*/autogenProvides,
-      std::vector<std::string>(this->AutogenTarget.DependFiles.begin(),
-                               this->AutogenTarget.DependFiles.end()),
-      commandLines, false, autogenComment.c_str());
+    cmTarget* autogenTarget = this->LocalGen->AddUtilityCommand(
+      this->AutogenTarget.Name, true, this->Dir.Work.c_str(),
+      /*byproducts=*/autogenProvides,
+      /*depends=*/dependencies, commandLines, false, autogenComment.c_str());
     // Create autogen generator target
     this->LocalGen->AddGeneratorTarget(
-      new cmGeneratorTarget(autogenTarget, this->LocalGen));
+      cm::make_unique<cmGeneratorTarget>(autogenTarget, this->LocalGen));
 
     // Forward origin utilities to autogen target
     if (this->AutogenTarget.DependOrigin) {
-      for (BT<std::string> const& depName : this->GenTarget->GetUtilities()) {
-        autogenTarget->AddUtility(depName.Value, this->Makefile);
+      for (BT<std::pair<std::string, bool>> const& depName :
+           this->GenTarget->GetUtilities()) {
+        autogenTarget->AddUtility(depName.Value.first, false, this->Makefile);
       }
     }
-    // Add additional autogen target dependencies to autogen target
-    for (cmTarget* depTarget : this->AutogenTarget.DependTargets) {
-      autogenTarget->AddUtility(depTarget->GetName(), this->Makefile);
+    if (!useNinjaDepfile) {
+      // Add additional autogen target dependencies to autogen target
+      for (cmTarget* depTarget : this->AutogenTarget.DependTargets) {
+        autogenTarget->AddUtility(depTarget->GetName(), false, this->Makefile);
+      }
     }
 
     // Set FOLDER property in autogen target
     if (!this->TargetsFolder.empty()) {
-      autogenTarget->SetProperty("FOLDER", this->TargetsFolder.c_str());
+      autogenTarget->SetProperty("FOLDER", this->TargetsFolder);
     }
 
     // Add autogen target to the origin target dependencies
-    this->GenTarget->Target->AddUtility(this->AutogenTarget.Name,
+    this->GenTarget->Target->AddUtility(this->AutogenTarget.Name, false,
                                         this->Makefile);
 
     // Add autogen target to the global autogen target dependencies
@@ -1205,25 +1305,25 @@
           ccName += cmStrCat('_', qrc.QrcPathChecksum);
         }
 
-        cmTarget* autoRccTarget = this->Makefile->AddUtilityCommand(
-          ccName, cmCommandOrigin::Generator, true, this->Dir.Work.c_str(),
-          ccOutput, ccDepends, commandLines, false, ccComment.c_str());
+        cmTarget* autoRccTarget = this->LocalGen->AddUtilityCommand(
+          ccName, true, this->Dir.Work.c_str(), ccOutput, ccDepends,
+          commandLines, false, ccComment.c_str());
 
         // Create autogen generator target
         this->LocalGen->AddGeneratorTarget(
-          new cmGeneratorTarget(autoRccTarget, this->LocalGen));
+          cm::make_unique<cmGeneratorTarget>(autoRccTarget, this->LocalGen));
 
         // Set FOLDER property in autogen target
         if (!this->TargetsFolder.empty()) {
-          autoRccTarget->SetProperty("FOLDER", this->TargetsFolder.c_str());
+          autoRccTarget->SetProperty("FOLDER", this->TargetsFolder);
         }
         if (!this->Rcc.ExecutableTargetName.empty()) {
-          autoRccTarget->AddUtility(this->Rcc.ExecutableTargetName,
+          autoRccTarget->AddUtility(this->Rcc.ExecutableTargetName, false,
                                     this->Makefile);
         }
       }
       // Add autogen target to the origin target dependencies
-      this->GenTarget->Target->AddUtility(ccName, this->Makefile);
+      this->GenTarget->Target->AddUtility(ccName, false, this->Makefile);
 
       // Add autogen target to the global autogen target dependencies
       if (this->Rcc.GlobalTarget) {
@@ -1244,7 +1344,7 @@
         }
         std::string no_main_dependency;
         cmImplicitDependsList no_implicit_depends;
-        this->Makefile->AddCustomCommandToOutput(
+        this->LocalGen->AddCustomCommandToOutput(
           ccOutput, ccByproducts, ccDepends, no_main_dependency,
           no_implicit_depends, commandLines, ccComment.c_str(),
           this->Dir.Work.c_str());
@@ -1356,12 +1456,15 @@
   info.SetConfig("INCLUDE_DIR", this->Dir.Include);
 
   info.SetUInt("QT_VERSION_MAJOR", this->QtVersion.Major);
+  info.SetUInt("QT_VERSION_MINOR", this->QtVersion.Minor);
   info.Set("QT_MOC_EXECUTABLE", this->Moc.Executable);
   info.Set("QT_UIC_EXECUTABLE", this->Uic.Executable);
 
   info.Set("CMAKE_EXECUTABLE", cmSystemTools::GetCMakeCommand());
   info.SetConfig("SETTINGS_FILE", this->AutogenTarget.SettingsFile);
   info.SetConfig("PARSE_CACHE_FILE", this->AutogenTarget.ParseCacheFile);
+  info.Set("DEP_FILE", this->AutogenTarget.DepFile);
+  info.Set("DEP_FILE_RULE_NAME", this->AutogenTarget.DepFileRuleName);
   info.SetArray("HEADER_EXTENSIONS",
                 this->Makefile->GetCMakeInstance()->GetHeaderExtensions());
   info.SetArrayArray(
@@ -1528,8 +1631,8 @@
 
 void cmQtAutoGenInitializer::AddCleanFile(std::string const& fileName)
 {
-  this->GenTarget->Target->AppendProperty("ADDITIONAL_CLEAN_FILES",
-                                          fileName.c_str(), false);
+  this->GenTarget->Target->AppendProperty("ADDITIONAL_CLEAN_FILES", fileName,
+                                          false);
 }
 
 void cmQtAutoGenInitializer::ConfigFileNames(ConfigString& configString,
@@ -1632,21 +1735,39 @@
   if (!muf.MocIt) {
     return res;
   }
-  {
-    std::string const basePath =
-      cmStrCat(this->PathCheckSum.getPart(muf.FullPath), "/moc_",
-               FileNameWithoutLastExtension(muf.FullPath));
-    std::string suffix;
-    constexpr std::size_t num_tries_max = 256;
-    for (std::size_t ii = 0; ii != num_tries_max; ++ii) {
-      res = cmStrCat(basePath, suffix, ".cpp");
-      if (this->Moc.EmittedBuildPaths.emplace(res).second) {
-        break;
-      }
-      // Compute new suffix
-      suffix = cmStrCat('_', ii + 1);
+
+  std::string basePath =
+    cmStrCat(this->PathCheckSum.getPart(muf.FullPath), "/moc_",
+             FileNameWithoutLastExtension(muf.FullPath));
+
+  res = cmStrCat(basePath, ".cpp");
+  if (this->Moc.EmittedBuildPaths.emplace(res).second) {
+    return res;
+  }
+
+  // File name already emitted.
+  // Try appending the header suffix to the base path.
+  basePath = cmStrCat(basePath, '_', muf.SF->GetExtension());
+  res = cmStrCat(basePath, ".cpp");
+  if (this->Moc.EmittedBuildPaths.emplace(res).second) {
+    return res;
+  }
+
+  // File name with header extension already emitted.
+  // Try adding a number to the base path.
+  constexpr std::size_t number_begin = 2;
+  constexpr std::size_t number_end = 256;
+  for (std::size_t ii = number_begin; ii != number_end; ++ii) {
+    res = cmStrCat(basePath, '_', ii, ".cpp");
+    if (this->Moc.EmittedBuildPaths.emplace(res).second) {
+      return res;
     }
   }
+
+  // Output file name conflict (unlikely, but still...)
+  cmSystemTools::Error(
+    cmStrCat("moc output file name conflict for ", muf.FullPath));
+
   return res;
 }
 
diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h
index d55259c..48ec1a0 100644
--- a/Source/cmQtAutoGenInitializer.h
+++ b/Source/cmQtAutoGenInitializer.h
@@ -160,6 +160,8 @@
   bool MultiConfig = false;
   bool CMP0071Accept = false;
   bool CMP0071Warn = false;
+  bool CMP0100Accept = false;
+  bool CMP0100Warn = false;
   std::string ConfigDefault;
   std::vector<std::string> ConfigsList;
   std::string TargetsFolder;
@@ -189,10 +191,13 @@
     bool DependOrigin = false;
     std::set<std::string> DependFiles;
     std::set<cmTarget*> DependTargets;
+    std::string DepFile;
+    std::string DepFileRuleName;
     // Sources to process
     std::unordered_map<cmSourceFile*, MUFileHandle> Headers;
     std::unordered_map<cmSourceFile*, MUFileHandle> Sources;
     std::vector<MUFile*> FilesGenerated;
+    std::vector<cmSourceFile*> CMP0100HeadersWarn;
   } AutogenTarget;
 
   /** moc variables.  */
diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx
index f8b8981..893bd6b 100644
--- a/Source/cmQtAutoMocUic.cxx
+++ b/Source/cmQtAutoMocUic.cxx
@@ -16,15 +16,17 @@
 
 #include <cm/memory>
 #include <cm/string_view>
+#include <cmext/algorithm>
 
 #include "cmsys/FStream.hxx"
 #include "cmsys/RegularExpression.hxx"
 
 #include "cm_jsoncpp_value.h"
 
-#include "cmAlgorithms.h"
 #include "cmCryptoHash.h"
 #include "cmFileTime.h"
+#include "cmGccDepfileReader.h"
+#include "cmGccDepfileReaderTypes.h"
 #include "cmGeneratedFileStream.h"
 #include "cmQtAutoGen.h"
 #include "cmQtAutoGenerator.h"
@@ -170,7 +172,7 @@
     // -- Attributes
     // - Config
     bool MultiConfig = false;
-    unsigned int QtVersionMajor = 4;
+    IntegerVersion QtVersion = { 4, 0 };
     unsigned int ThreadCount = 0;
     // - Directories
     std::string AutogenBuildDir;
@@ -179,6 +181,8 @@
     std::string CMakeExecutable;
     cmFileTime CMakeExecutableTime;
     std::string ParseCacheFile;
+    std::string DepFile;
+    std::string DepFileRuleName;
     std::vector<std::string> HeaderExtensions;
   };
 
@@ -216,6 +220,7 @@
     bool SettingsChanged = false;
     bool RelaxedMode = false;
     bool PathPrefix = false;
+    bool CanOutputDependencies = false;
     cmFileTime ExecutableTime;
     std::string Executable;
     std::string CompFileAbs;
@@ -485,8 +490,17 @@
   class JobCompileMocT : public JobCompileT
   {
   public:
-    using JobCompileT::JobCompileT;
+    JobCompileMocT(MappingHandleT uicMapping,
+                   std::unique_ptr<std::string> reason,
+                   ParseCacheT::FileHandleT cacheEntry)
+      : JobCompileT(std::move(uicMapping), std::move(reason))
+      , CacheEntry(std::move(cacheEntry))
+    {
+    }
     void Process() override;
+
+  protected:
+    ParseCacheT::FileHandleT CacheEntry;
   };
 
   /** uic compiles a file.  */
@@ -504,6 +518,12 @@
     void Process() override;
   };
 
+  class JobDepFilesMergeT : public JobFenceT
+  {
+  private:
+    void Process() override;
+  };
+
   /** @brief The last job.  */
   class JobFinishT : public JobFenceT
   {
@@ -546,6 +566,9 @@
   void Abort(bool error);
   // -- Generation
   bool CreateDirectories();
+  // -- Support for depfiles
+  static std::vector<std::string> dependenciesFromDepFile(
+    const char* filePath);
 
 private:
   // -- Settings
@@ -808,9 +831,9 @@
       // Compose command
       std::vector<std::string> cmd = MocConst().PredefsCmd;
       // Add definitions
-      cmAppend(cmd, MocConst().OptionsDefinitions);
+      cm::append(cmd, MocConst().OptionsDefinitions);
       // Add includes
-      cmAppend(cmd, MocConst().OptionsIncludes);
+      cm::append(cmd, MocConst().OptionsIncludes);
       // Execute command
       if (!RunProcess(GenT::MOC, result, cmd, reason.get())) {
         LogCommandError(GenT::MOC,
@@ -951,7 +974,7 @@
 
 void cmQtAutoMocUicT::JobParseT::MocDependecies()
 {
-  if (MocConst().DependFilters.empty()) {
+  if (MocConst().DependFilters.empty() || MocConst().CanOutputDependencies) {
     return;
   }
 
@@ -1674,8 +1697,13 @@
   if (Probe(*mapping, reason.get())) {
     // Register the parent directory for creation
     MocEval().OutputDirs.emplace(cmQtAutoGen::ParentDir(mapping->OutputFile));
+    // Fetch the cache entry for the source file
+    std::string const& sourceFile = mapping->SourceFile->FileName;
+    ParseCacheT::GetOrInsertT cacheEntry =
+      BaseEval().ParseCache.GetOrInsert(sourceFile);
     // Add moc job
-    Gen()->WorkerPool().EmplaceJob<JobCompileMocT>(mapping, std::move(reason));
+    Gen()->WorkerPool().EmplaceJob<JobCompileMocT>(
+      mapping, std::move(reason), std::move(cacheEntry.first));
     // Check if a moc job for a mocs_compilation.cpp entry was generated
     if (compFile) {
       MocEval().CompUpdated = true;
@@ -1779,6 +1807,14 @@
   std::string const& sourceDir, std::string const& includeString) const
 {
   using ResPair = std::pair<std::string, cmFileTime>;
+  // moc's dependency file contains absolute paths
+  if (MocConst().CanOutputDependencies) {
+    ResPair res{ includeString, {} };
+    if (res.second.Load(res.first)) {
+      return res;
+    }
+    return {};
+  }
   // Search in vicinity of the source
   {
     ResPair res{ sourceDir + includeString, {} };
@@ -1898,6 +1934,11 @@
     Gen()->WorkerPool().EmplaceJob<JobMocsCompilationT>();
   }
 
+  if (!BaseConst().DepFile.empty()) {
+    // Add job to merge dep files
+    Gen()->WorkerPool().EmplaceJob<JobDepFilesMergeT>();
+  }
+
   // Add finish job
   Gen()->WorkerPool().EmplaceJob<JobFinishT>();
 }
@@ -1916,9 +1957,9 @@
                 MocConst().OptionsExtra.size() + 16);
     cmd.push_back(MocConst().Executable);
     // Add definitions
-    cmAppend(cmd, MocConst().OptionsDefinitions);
+    cm::append(cmd, MocConst().OptionsDefinitions);
     // Add includes
-    cmAppend(cmd, MocConst().OptionsIncludes);
+    cm::append(cmd, MocConst().OptionsIncludes);
     // Add predefs include
     if (!MocConst().PredefsFileAbs.empty()) {
       cmd.emplace_back("--include");
@@ -1946,7 +1987,10 @@
       }
     }
     // Add extra options
-    cmAppend(cmd, MocConst().OptionsExtra);
+    cm::append(cmd, MocConst().OptionsExtra);
+    if (MocConst().CanOutputDependencies) {
+      cmd.emplace_back("--output-dep-file");
+    }
     // Add output file
     cmd.emplace_back("-o");
     cmd.push_back(outputFile);
@@ -1956,12 +2000,7 @@
 
   // Execute moc command
   cmWorkerPool::ProcessResultT result;
-  if (RunProcess(GenT::MOC, result, cmd, Reason.get())) {
-    // Moc command success. Print moc output.
-    if (!result.StdOut.empty()) {
-      Log().Info(GenT::MOC, result.StdOut);
-    }
-  } else {
+  if (!RunProcess(GenT::MOC, result, cmd, Reason.get())) {
     // Moc command failed
     std::string includers;
     if (!Mapping->IncluderFiles.empty()) {
@@ -1976,6 +2015,28 @@
                              MessagePath(outputFile), '\n', includers,
                              result.ErrorMessage),
                     cmd, result.StdOut);
+    return;
+  }
+
+  // Moc command success. Print moc output.
+  if (!result.StdOut.empty()) {
+    Log().Info(GenT::MOC, result.StdOut);
+  }
+
+  // Extract dependencies from the dep file moc generated for us
+  if (MocConst().CanOutputDependencies) {
+    const std::string depfile = outputFile + ".d";
+    if (Log().Verbose()) {
+      Log().Info(GenT::MOC,
+                 "Reading dependencies from " + MessagePath(depfile));
+    }
+    if (!cmSystemTools::FileExists(depfile)) {
+      Log().Warning(GenT::MOC,
+                    "Dependency file " + MessagePath(depfile) +
+                      " does not exist.");
+      return;
+    }
+    CacheEntry->Moc.Depends = dependenciesFromDepFile(depfile.c_str());
   }
 }
 
@@ -1992,9 +2053,9 @@
     auto optionIt = UicConst().UiFiles.find(sourceFile);
     if (optionIt != UicConst().UiFiles.end()) {
       UicMergeOptions(allOpts, optionIt->second.Options,
-                      (BaseConst().QtVersionMajor == 5));
+                      (BaseConst().QtVersion.Major == 5));
     }
-    cmAppend(cmd, allOpts);
+    cm::append(cmd, allOpts);
   }
   cmd.emplace_back("-o");
   cmd.emplace_back(outputFile);
@@ -2067,6 +2128,106 @@
   }
 }
 
+/*
+ * Escapes paths for Ninja depfiles.
+ * This is a re-implementation of what moc does when writing depfiles.
+ */
+std::string escapeDependencyPath(cm::string_view path)
+{
+  std::string escapedPath;
+  escapedPath.reserve(path.size());
+  const size_t s = path.size();
+  int backslashCount = 0;
+  for (size_t i = 0; i < s; ++i) {
+    if (path[i] == '\\') {
+      ++backslashCount;
+    } else {
+      if (path[i] == '$') {
+        escapedPath.push_back('$');
+      } else if (path[i] == '#') {
+        escapedPath.push_back('\\');
+      } else if (path[i] == ' ') {
+        // Double the amount of written backslashes,
+        // and add one more to escape the space.
+        while (backslashCount-- >= 0) {
+          escapedPath.push_back('\\');
+        }
+      }
+      backslashCount = 0;
+    }
+    escapedPath.push_back(path[i]);
+  }
+  return escapedPath;
+}
+
+void cmQtAutoMocUicT::JobDepFilesMergeT::Process()
+{
+  if (Log().Verbose()) {
+    Log().Info(GenT::MOC, "Merging MOC dependencies");
+  }
+  auto processDepFile =
+    [](const std::string& mocOutputFile) -> std::vector<std::string> {
+    std::string f = mocOutputFile + ".d";
+    if (!cmSystemTools::FileExists(f)) {
+      return {};
+    }
+    return dependenciesFromDepFile(f.c_str());
+  };
+
+  std::vector<std::string> dependencies;
+  ParseCacheT& parseCache = BaseEval().ParseCache;
+  auto processMappingEntry = [&](const MappingMapT::value_type& m) {
+    auto cacheEntry = parseCache.GetOrInsert(m.first);
+    if (cacheEntry.first->Moc.Depends.empty()) {
+      cacheEntry.first->Moc.Depends = processDepFile(m.second->OutputFile);
+    }
+    dependencies.insert(dependencies.end(),
+                        cacheEntry.first->Moc.Depends.begin(),
+                        cacheEntry.first->Moc.Depends.end());
+  };
+
+  std::for_each(MocEval().HeaderMappings.begin(),
+                MocEval().HeaderMappings.end(), processMappingEntry);
+  std::for_each(MocEval().SourceMappings.begin(),
+                MocEval().SourceMappings.end(), processMappingEntry);
+
+  // Remove duplicates to make the depfile smaller
+  std::sort(dependencies.begin(), dependencies.end());
+  dependencies.erase(std::unique(dependencies.begin(), dependencies.end()),
+                     dependencies.end());
+
+  // Add form files
+  for (const auto& uif : UicEval().UiFiles) {
+    dependencies.push_back(uif.first);
+  }
+
+  // Write the file
+  cmsys::ofstream ofs;
+  ofs.open(BaseConst().DepFile.c_str(),
+           (std::ios::out | std::ios::binary | std::ios::trunc));
+  if (!ofs) {
+    LogError(GenT::GEN,
+             cmStrCat("Cannot open ", MessagePath(BaseConst().DepFile),
+                      " for writing."));
+    return;
+  }
+  ofs << BaseConst().DepFileRuleName << ": \\" << std::endl;
+  for (const std::string& file : dependencies) {
+    ofs << '\t' << escapeDependencyPath(file) << " \\" << std::endl;
+    if (!ofs.good()) {
+      LogError(GenT::GEN,
+               cmStrCat("Writing depfile", MessagePath(BaseConst().DepFile),
+                        " failed."));
+      return;
+    }
+  }
+
+  // Add the CMake executable to re-new cache data if necessary.
+  // Also, this is the last entry, so don't add a backslash.
+  ofs << '\t' << escapeDependencyPath(BaseConst().CMakeExecutable)
+      << std::endl;
+}
+
 void cmQtAutoMocUicT::JobFinishT::Process()
 {
   Gen()->AbortSuccess();
@@ -2082,7 +2243,8 @@
 {
   // -- Required settings
   if (!info.GetBool("MULTI_CONFIG", BaseConst_.MultiConfig, true) ||
-      !info.GetUInt("QT_VERSION_MAJOR", BaseConst_.QtVersionMajor, true) ||
+      !info.GetUInt("QT_VERSION_MAJOR", BaseConst_.QtVersion.Major, true) ||
+      !info.GetUInt("QT_VERSION_MINOR", BaseConst_.QtVersion.Minor, true) ||
       !info.GetUInt("PARALLEL", BaseConst_.ThreadCount, false) ||
       !info.GetString("BUILD_DIR", BaseConst_.AutogenBuildDir, true) ||
       !info.GetStringConfig("INCLUDE_DIR", BaseConst_.AutogenIncludeDir,
@@ -2090,6 +2252,9 @@
       !info.GetString("CMAKE_EXECUTABLE", BaseConst_.CMakeExecutable, true) ||
       !info.GetStringConfig("PARSE_CACHE_FILE", BaseConst_.ParseCacheFile,
                             true) ||
+      !info.GetString("DEP_FILE", BaseConst_.DepFile, false) ||
+      !info.GetString("DEP_FILE_RULE_NAME", BaseConst_.DepFileRuleName,
+                      false) ||
       !info.GetStringConfig("SETTINGS_FILE", SettingsFile_, true) ||
       !info.GetArray("HEADER_EXTENSIONS", BaseConst_.HeaderExtensions, true) ||
       !info.GetString("QT_MOC_EXECUTABLE", MocConst_.Executable, false) ||
@@ -2143,8 +2308,10 @@
       MocConst_.MacroFilters.emplace_back(
         item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]"));
     }
-    // Dependency filters
-    {
+    // Can moc output dependencies or do we need to setup dependency filters?
+    if (BaseConst_.QtVersion >= IntegerVersion(5, 15)) {
+      MocConst_.CanOutputDependencies = true;
+    } else {
       Json::Value const& val = info.GetValue("MOC_DEPEND_FILTERS");
       if (!val.isArray()) {
         return info.LogError("MOC_DEPEND_FILTERS JSON value is not an array.");
@@ -2660,6 +2827,19 @@
   return true;
 }
 
+std::vector<std::string> cmQtAutoMocUicT::dependenciesFromDepFile(
+  const char* filePath)
+{
+  cmGccDepfileContent content = cmReadGccDepfile(filePath);
+  if (content.empty()) {
+    return {};
+  }
+
+  // Moc outputs a depfile with exactly one rule.
+  // Discard the rule and return the dependencies.
+  return content.front().paths;
+}
+
 void cmQtAutoMocUicT::Abort(bool error)
 {
   if (error) {
diff --git a/Source/cmQtAutoRcc.cxx b/Source/cmQtAutoRcc.cxx
index 3af81ad..08eb4b5 100644
--- a/Source/cmQtAutoRcc.cxx
+++ b/Source/cmQtAutoRcc.cxx
@@ -6,7 +6,8 @@
 #include <string>
 #include <vector>
 
-#include "cmAlgorithms.h"
+#include <cmext/algorithm>
+
 #include "cmCryptoHash.h"
 #include "cmDuration.h"
 #include "cmFileLock.h"
@@ -405,7 +406,7 @@
   // Compose rcc command
   std::vector<std::string> cmd;
   cmd.push_back(RccExecutable_);
-  cmAppend(cmd, Options_);
+  cm::append(cmd, Options_);
   cmd.emplace_back("-o");
   cmd.push_back(RccFileOutput_);
   cmd.push_back(QrcFile_);
diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx
index 0a1d109..5ab1b3a 100644
--- a/Source/cmRulePlaceholderExpander.cxx
+++ b/Source/cmRulePlaceholderExpander.cxx
@@ -85,6 +85,11 @@
       return replaceValues.ObjectsQuoted;
     }
   }
+  if (replaceValues.AIXExports) {
+    if (variable == "AIX_EXPORTS") {
+      return replaceValues.AIXExports;
+    }
+  }
   if (replaceValues.Defines && variable == "DEFINES") {
     return replaceValues.Defines;
   }
diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h
index 8f36196..09e8a3b 100644
--- a/Source/cmRulePlaceholderExpander.h
+++ b/Source/cmRulePlaceholderExpander.h
@@ -36,6 +36,7 @@
     const char* TargetVersionMajor;
     const char* TargetVersionMinor;
     const char* Language;
+    const char* AIXExports;
     const char* Objects;
     const char* Target;
     const char* LinkLibraries;
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/cmSearchPath.cxx b/Source/cmSearchPath.cxx
index d15ce57..766d347 100644
--- a/Source/cmSearchPath.cxx
+++ b/Source/cmSearchPath.cxx
@@ -181,7 +181,13 @@
       const char* arch =
         this->FC->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE");
       if (arch && *arch) {
-        this->AddPathInternal(dir + subdir + "/" + arch, base);
+        if (this->FC->Makefile->IsDefinitionSet("CMAKE_SYSROOT") &&
+            this->FC->Makefile->IsDefinitionSet(
+              "CMAKE_PREFIX_LIBRARY_ARCHITECTURE")) {
+          this->AddPathInternal(cmStrCat('/', arch, dir, subdir), base);
+        } else {
+          this->AddPathInternal(cmStrCat(dir, subdir, '/', arch), base);
+        }
       }
     }
     std::string add = dir + subdir;
diff --git a/Source/cmSearchPath.h b/Source/cmSearchPath.h
index 2a576ed..3ecc73b 100644
--- a/Source/cmSearchPath.h
+++ b/Source/cmSearchPath.h
@@ -5,6 +5,7 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include <cstddef>
 #include <set>
 #include <string>
 #include <vector>
@@ -27,6 +28,7 @@
   ~cmSearchPath();
 
   const std::vector<std::string>& GetPaths() const { return this->Paths; }
+  std::size_t size() const { return this->Paths.size(); }
 
   void ExtractWithout(const std::set<std::string>& ignore,
                       std::vector<std::string>& outPaths,
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index 56003df..1d4ea01 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -744,7 +744,7 @@
   cm->SetHomeDirectory(SourceDirectory);
   cm->SetHomeOutputDirectory(BuildDirectory);
 
-  cmGlobalGenerator* gg = cm->CreateGlobalGenerator(fullGeneratorName);
+  auto gg = cm->CreateGlobalGenerator(fullGeneratorName);
   if (!gg) {
     setErrorMessage(
       errorMessage,
@@ -753,7 +753,7 @@
     return;
   }
 
-  cm->SetGlobalGenerator(gg);
+  cm->SetGlobalGenerator(std::move(gg));
 
   cm->SetGeneratorToolset(Toolset);
   cm->SetGeneratorPlatform(Platform);
diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx
index 8c3a4cb..5e2a146 100644
--- a/Source/cmSetCommand.cxx
+++ b/Source/cmSetCommand.cxx
@@ -121,7 +121,7 @@
 
   if (cache) {
     std::string::size_type cacheStart = args.size() - 3 - (force ? 1 : 0);
-    if (!cmState::StringToCacheEntryType(args[cacheStart + 1].c_str(), type)) {
+    if (!cmState::StringToCacheEntryType(args[cacheStart + 1], type)) {
       std::string m = "implicitly converting '" + args[cacheStart + 1] +
         "' to 'STRING' type.";
       status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, m);
diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx
index 112d832..3705727 100644
--- a/Source/cmSetPropertyCommand.cxx
+++ b/Source/cmSetPropertyCommand.cxx
@@ -194,9 +194,8 @@
 bool HandleGlobalMode(cmExecutionStatus& status,
                       const std::set<std::string>& names,
                       const std::string& propertyName,
-                      const std::string& propertyValue,
-                      const bool appendAsString, const bool appendMode,
-                      const bool remove)
+                      const std::string& propertyValue, bool appendAsString,
+                      bool appendMode, bool remove)
 {
   if (!names.empty()) {
     status.SetError("given names for GLOBAL scope.");
@@ -205,14 +204,14 @@
 
   // Set or append the property.
   cmake* cm = status.GetMakefile().GetCMakeInstance();
-  const char* value = propertyValue.c_str();
-  if (remove) {
-    value = nullptr;
-  }
   if (appendMode) {
-    cm->AppendProperty(propertyName, value ? value : "", appendAsString);
+    cm->AppendProperty(propertyName, propertyValue, appendAsString);
   } else {
-    cm->SetProperty(propertyName, value);
+    if (remove) {
+      cm->SetProperty(propertyName, nullptr);
+    } else {
+      cm->SetProperty(propertyName, propertyValue.c_str());
+    }
   }
 
   return true;
@@ -221,9 +220,8 @@
 bool HandleDirectoryMode(cmExecutionStatus& status,
                          const std::set<std::string>& names,
                          const std::string& propertyName,
-                         const std::string& propertyValue,
-                         const bool appendAsString, const bool appendMode,
-                         const bool remove)
+                         const std::string& propertyValue, bool appendAsString,
+                         bool appendMode, bool remove)
 {
   if (names.size() > 1) {
     status.SetError("allows at most one name for DIRECTORY scope.");
@@ -258,14 +256,14 @@
   }
 
   // Set or append the property.
-  const char* value = propertyValue.c_str();
-  if (remove) {
-    value = nullptr;
-  }
   if (appendMode) {
-    mf->AppendProperty(propertyName, value ? value : "", appendAsString);
+    mf->AppendProperty(propertyName, propertyValue, appendAsString);
   } else {
-    mf->SetProperty(propertyName, value);
+    if (remove) {
+      mf->SetProperty(propertyName, nullptr);
+    } else {
+      mf->SetProperty(propertyName, propertyValue.c_str());
+    }
   }
 
   return true;
@@ -274,9 +272,8 @@
 bool HandleTargetMode(cmExecutionStatus& status,
                       const std::set<std::string>& names,
                       const std::string& propertyName,
-                      const std::string& propertyValue,
-                      const bool appendAsString, const bool appendMode,
-                      const bool remove)
+                      const std::string& propertyValue, bool appendAsString,
+                      bool appendMode, bool remove)
 {
   for (std::string const& name : names) {
     if (status.GetMakefile().IsAlias(name)) {
@@ -300,18 +297,18 @@
 
 bool HandleTarget(cmTarget* target, cmMakefile& makefile,
                   const std::string& propertyName,
-                  const std::string& propertyValue, const bool appendAsString,
-                  const bool appendMode, const bool remove)
+                  const std::string& propertyValue, bool appendAsString,
+                  bool appendMode, bool remove)
 {
   // Set or append the property.
-  const char* value = propertyValue.c_str();
-  if (remove) {
-    value = nullptr;
-  }
   if (appendMode) {
-    target->AppendProperty(propertyName, value, appendAsString);
+    target->AppendProperty(propertyName, propertyValue, appendAsString);
   } else {
-    target->SetProperty(propertyName, value);
+    if (remove) {
+      target->SetProperty(propertyName, nullptr);
+    } else {
+      target->SetProperty(propertyName, propertyValue.c_str());
+    }
   }
 
   // Check the resulting value.
@@ -323,9 +320,8 @@
 bool HandleSourceMode(cmExecutionStatus& status,
                       const std::set<std::string>& names,
                       const std::string& propertyName,
-                      const std::string& propertyValue,
-                      const bool appendAsString, const bool appendMode,
-                      const bool remove)
+                      const std::string& propertyValue, bool appendAsString,
+                      bool appendMode, bool remove)
 {
   for (std::string const& name : names) {
     // Get the source file.
@@ -344,28 +340,26 @@
 }
 
 bool HandleSource(cmSourceFile* sf, const std::string& propertyName,
-                  const std::string& propertyValue, const bool appendAsString,
-                  const bool appendMode, const bool remove)
+                  const std::string& propertyValue, bool appendAsString,
+                  bool appendMode, bool remove)
 {
   // Set or append the property.
-  const char* value = propertyValue.c_str();
-  if (remove) {
-    value = nullptr;
-  }
-
   if (appendMode) {
-    sf->AppendProperty(propertyName, value, appendAsString);
+    sf->AppendProperty(propertyName, propertyValue, appendAsString);
   } else {
-    sf->SetProperty(propertyName, value);
+    if (remove) {
+      sf->SetProperty(propertyName, nullptr);
+    } else {
+      sf->SetProperty(propertyName, propertyValue.c_str());
+    }
   }
   return true;
 }
 
 bool HandleTestMode(cmExecutionStatus& status, std::set<std::string>& names,
                     const std::string& propertyName,
-                    const std::string& propertyValue,
-                    const bool appendAsString, const bool appendMode,
-                    const bool remove)
+                    const std::string& propertyValue, bool appendAsString,
+                    bool appendMode, bool remove)
 {
   // Look for tests with all names given.
   std::set<std::string>::iterator next;
@@ -396,18 +390,18 @@
 }
 
 bool HandleTest(cmTest* test, const std::string& propertyName,
-                const std::string& propertyValue, const bool appendAsString,
-                const bool appendMode, const bool remove)
+                const std::string& propertyValue, bool appendAsString,
+                bool appendMode, bool remove)
 {
   // Set or append the property.
-  const char* value = propertyValue.c_str();
-  if (remove) {
-    value = nullptr;
-  }
   if (appendMode) {
-    test->AppendProperty(propertyName, value, appendAsString);
+    test->AppendProperty(propertyName, propertyValue, appendAsString);
   } else {
-    test->SetProperty(propertyName, value);
+    if (remove) {
+      test->SetProperty(propertyName, nullptr);
+    } else {
+      test->SetProperty(propertyName, propertyValue.c_str());
+    }
   }
 
   return true;
@@ -416,9 +410,8 @@
 bool HandleCacheMode(cmExecutionStatus& status,
                      const std::set<std::string>& names,
                      const std::string& propertyName,
-                     const std::string& propertyValue,
-                     const bool appendAsString, const bool appendMode,
-                     const bool remove)
+                     const std::string& propertyValue, bool appendAsString,
+                     bool appendMode, bool remove)
 {
   if (propertyName == "ADVANCED") {
     if (!remove && !cmIsOn(propertyValue) && !cmIsOff(propertyValue)) {
@@ -463,9 +456,8 @@
 
 bool HandleCacheEntry(std::string const& cacheKey, const cmMakefile& makefile,
                       const std::string& propertyName,
-                      const std::string& propertyValue,
-                      const bool appendAsString, const bool appendMode,
-                      const bool remove)
+                      const std::string& propertyValue, bool appendAsString,
+                      bool appendMode, bool remove)
 {
   // Set or append the property.
   const char* value = propertyValue.c_str();
@@ -486,9 +478,8 @@
 bool HandleInstallMode(cmExecutionStatus& status,
                        const std::set<std::string>& names,
                        const std::string& propertyName,
-                       const std::string& propertyValue,
-                       const bool appendAsString, const bool appendMode,
-                       const bool remove)
+                       const std::string& propertyValue, bool appendAsString,
+                       bool appendMode, bool remove)
 {
   cmake* cm = status.GetMakefile().GetCMakeInstance();
 
@@ -510,8 +501,8 @@
 
 bool HandleInstall(cmInstalledFile* file, cmMakefile& makefile,
                    const std::string& propertyName,
-                   const std::string& propertyValue, const bool appendAsString,
-                   const bool appendMode, const bool remove)
+                   const std::string& propertyValue, bool appendAsString,
+                   bool appendMode, bool remove)
 {
   // Set or append the property.
   const char* value = propertyValue.c_str();
diff --git a/Source/cmSetTargetPropertiesCommand.cxx b/Source/cmSetTargetPropertiesCommand.cxx
index 8d917db..cd0fa40 100644
--- a/Source/cmSetTargetPropertiesCommand.cxx
+++ b/Source/cmSetTargetPropertiesCommand.cxx
@@ -4,7 +4,8 @@
 
 #include <iterator>
 
-#include "cmAlgorithms.h"
+#include <cmext/algorithm>
+
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmStringAlgorithms.h"
@@ -33,7 +34,7 @@
         status.SetError("called with incorrect number of arguments.");
         return false;
       }
-      cmAppend(propertyPairs, j, args.end());
+      cm::append(propertyPairs, j, args.end());
       break;
     }
     numFiles++;
@@ -70,7 +71,7 @@
     // now loop through all the props and set them
     unsigned int k;
     for (k = 0; k < propertyPairs.size(); k = k + 2) {
-      target->SetProperty(propertyPairs[k], propertyPairs[k + 1].c_str());
+      target->SetProperty(propertyPairs[k], propertyPairs[k + 1]);
       target->CheckProperty(propertyPairs[k], mf);
     }
   }
diff --git a/Source/cmSetTestsPropertiesCommand.cxx b/Source/cmSetTestsPropertiesCommand.cxx
index de61eda..2e7aeca 100644
--- a/Source/cmSetTestsPropertiesCommand.cxx
+++ b/Source/cmSetTestsPropertiesCommand.cxx
@@ -4,7 +4,8 @@
 
 #include <iterator>
 
-#include "cmAlgorithms.h"
+#include <cmext/algorithm>
+
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmStringAlgorithms.h"
@@ -36,7 +37,7 @@
         status.SetError("called with incorrect number of arguments.");
         return false;
       }
-      cmAppend(propertyPairs, j, args.end());
+      cm::append(propertyPairs, j, args.end());
       break;
     }
     numFiles++;
diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx
index 2a345eb..fd9cacd 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);
@@ -260,21 +260,21 @@
   }
 }
 
-void cmSourceFile::AppendProperty(const std::string& prop, const char* value,
-                                  bool asString)
+void cmSourceFile::AppendProperty(const std::string& prop,
+                                  const std::string& value, bool asString)
 {
   if (prop == propINCLUDE_DIRECTORIES) {
-    if (value && *value) {
+    if (!value.empty()) {
       cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
       this->IncludeDirectories.emplace_back(value, lfbt);
     }
   } else if (prop == propCOMPILE_OPTIONS) {
-    if (value && *value) {
+    if (!value.empty()) {
       cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
       this->CompileOptions.emplace_back(value, lfbt);
     }
   } else if (prop == propCOMPILE_DEFINITIONS) {
-    if (value && *value) {
+    if (!value.empty()) {
       cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
       this->CompileDefinitions.emplace_back(value, lfbt);
     }
diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h
index 82a3625..e22829f 100644
--- a/Source/cmSourceFile.h
+++ b/Source/cmSourceFile.h
@@ -42,7 +42,7 @@
 
   //! Set/Get a property of this source file
   void SetProperty(const std::string& prop, const char* value);
-  void AppendProperty(const std::string& prop, const char* value,
+  void AppendProperty(const std::string& prop, const std::string& value,
                       bool asString = false);
   //! Might return a nullptr if the property is not set or invalid
   const char* GetProperty(const std::string& prop) const;
@@ -154,9 +154,8 @@
 #define CM_HEADER_REGEX "\\.(h|hh|h\\+\\+|hm|hpp|hxx|in|txx|inl)$"
 
 #define CM_SOURCE_REGEX                                                       \
-  "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|cu|f|f90|for|fpp|ftn|m|mm|rc|def|r|odl|idl|"  \
-  "hpj"                                                                       \
-  "|bat)$"
+  "\\.(C|F|M|c|c\\+\\+|cc|cpp|cxx|cu|f|f90|for|fpp|ftn|m|mm|"                 \
+  "rc|def|r|odl|idl|hpj|bat)$"
 
 #define CM_PCH_REGEX "cmake_pch\\.(h|hxx)$"
 
diff --git a/Source/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 f9b5ed1..9fc7615 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -3,9 +3,9 @@
 #include "cmState.h"
 
 #include <algorithm>
+#include <array>
 #include <cassert>
 #include <cstdlib>
-#include <cstring>
 #include <utility>
 
 #include <cm/memory>
@@ -60,43 +60,44 @@
   return nullptr;
 }
 
-const char* cmCacheEntryTypes[] = { "BOOL",          "PATH",     "FILEPATH",
-                                    "STRING",        "INTERNAL", "STATIC",
-                                    "UNINITIALIZED", nullptr };
+static const std::array<std::string, 7> cmCacheEntryTypes = {
+  { "BOOL", "PATH", "FILEPATH", "STRING", "INTERNAL", "STATIC",
+    "UNINITIALIZED" }
+};
 
-const char* cmState::CacheEntryTypeToString(cmStateEnums::CacheEntryType type)
+const std::string& cmState::CacheEntryTypeToString(
+  cmStateEnums::CacheEntryType type)
 {
-  if (type > 6) {
-    return cmCacheEntryTypes[6];
+  if (type < cmStateEnums::BOOL || type > cmStateEnums::UNINITIALIZED) {
+    type = cmStateEnums::UNINITIALIZED;
   }
   return cmCacheEntryTypes[type];
 }
 
-cmStateEnums::CacheEntryType cmState::StringToCacheEntryType(const char* s)
+cmStateEnums::CacheEntryType cmState::StringToCacheEntryType(
+  const std::string& s)
 {
   cmStateEnums::CacheEntryType type = cmStateEnums::STRING;
   StringToCacheEntryType(s, type);
   return type;
 }
 
-bool cmState::StringToCacheEntryType(const char* s,
+bool cmState::StringToCacheEntryType(const std::string& s,
                                      cmStateEnums::CacheEntryType& type)
 {
-  int i = 0;
-  while (cmCacheEntryTypes[i]) {
-    if (strcmp(s, cmCacheEntryTypes[i]) == 0) {
+  for (size_t i = 0; i < cmCacheEntryTypes.size(); ++i) {
+    if (s == cmCacheEntryTypes[i]) {
       type = static_cast<cmStateEnums::CacheEntryType>(i);
       return true;
     }
-    ++i;
   }
   return false;
 }
 
 bool cmState::IsCacheEntryType(std::string const& key)
 {
-  for (int i = 0; cmCacheEntryTypes[i]; ++i) {
-    if (key == cmCacheEntryTypes[i]) {
+  for (const std::string& i : cmCacheEntryTypes) {
+    if (key == i) {
       return true;
     }
   }
@@ -140,6 +141,16 @@
   return e->Value.c_str();
 }
 
+std::string cmState::GetSafeCacheEntryValue(std::string const& key) const
+{
+  std::string retval;
+  auto val = this->GetCacheEntryValue(key);
+  if (val) {
+    retval = val;
+  }
+  return retval;
+}
+
 const std::string* cmState::GetInitializedCacheValue(
   std::string const& key) const
 {
@@ -149,8 +160,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();
 }
 
@@ -164,8 +174,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());
 }
 
@@ -173,24 +182,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;
   }
@@ -200,8 +206,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,
@@ -253,15 +259,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()
@@ -562,8 +567,8 @@
   this->GlobalProperties.SetProperty(prop, value);
 }
 
-void cmState::AppendGlobalProperty(const std::string& prop, const char* value,
-                                   bool asString)
+void cmState::AppendGlobalProperty(const std::string& prop,
+                                   const std::string& value, bool asString)
 {
   this->GlobalProperties.AppendProperty(prop, value, asString);
 }
@@ -615,6 +620,9 @@
   if (prop == "CMAKE_CXX14_KNOWN_FEATURES") {
     return &FOR_EACH_CXX14_FEATURE(STRING_LIST_ELEMENT)[1];
   }
+  if (prop == "CMAKE_CUDA_KNOWN_FEATURES") {
+    return &FOR_EACH_CUDA_FEATURE(STRING_LIST_ELEMENT)[1];
+  }
 
 #undef STRING_LIST_ELEMENT
   return this->GlobalProperties.GetPropertyValue(prop);
@@ -712,6 +720,16 @@
   return this->MSYSShell;
 }
 
+void cmState::SetNinjaMulti(bool ninjaMulti)
+{
+  this->NinjaMulti = ninjaMulti;
+}
+
+bool cmState::UseNinjaMulti() const
+{
+  return this->NinjaMulti;
+}
+
 unsigned int cmState::GetCacheMajorVersion() const
 {
   return this->CacheManager->GetCacheMajorVersion();
@@ -993,12 +1011,12 @@
   bool flag = false;
   if (regQuoted.find(entry)) {
     var = regQuoted.match(1);
-    type = cmState::StringToCacheEntryType(regQuoted.match(2).c_str());
+    type = cmState::StringToCacheEntryType(regQuoted.match(2));
     value = regQuoted.match(3);
     flag = true;
   } else if (reg.find(entry)) {
     var = reg.match(1);
-    type = cmState::StringToCacheEntryType(reg.match(2).c_str());
+    type = cmState::StringToCacheEntryType(reg.match(2));
     value = reg.match(3);
     flag = true;
   }
diff --git a/Source/cmState.h b/Source/cmState.h
index a7ca015..6ee2b0c 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -70,10 +70,12 @@
     cmStateSnapshot const& originSnapshot);
   cmStateSnapshot Pop(cmStateSnapshot const& originSnapshot);
 
-  static cmStateEnums::CacheEntryType StringToCacheEntryType(const char*);
-  static bool StringToCacheEntryType(const char*,
+  static cmStateEnums::CacheEntryType StringToCacheEntryType(
+    const std::string&);
+  static bool StringToCacheEntryType(const std::string&,
                                      cmStateEnums::CacheEntryType& type);
-  static const char* CacheEntryTypeToString(cmStateEnums::CacheEntryType);
+  static const std::string& CacheEntryTypeToString(
+    cmStateEnums::CacheEntryType);
   static bool IsCacheEntryType(std::string const& key);
 
   bool LoadCache(const std::string& path, bool internal,
@@ -86,6 +88,7 @@
 
   std::vector<std::string> GetCacheEntryKeys() const;
   const char* GetCacheEntryValue(std::string const& key) const;
+  std::string GetSafeCacheEntryValue(std::string const& key) const;
   const std::string* GetInitializedCacheValue(std::string const& key) const;
   cmStateEnums::CacheEntryType GetCacheEntryType(std::string const& key) const;
   void SetCacheEntryValue(std::string const& key, std::string const& value);
@@ -166,7 +169,7 @@
   std::vector<std::string> GetCommandNames() const;
 
   void SetGlobalProperty(const std::string& prop, const char* value);
-  void AppendGlobalProperty(const std::string& prop, const char* value,
+  void AppendGlobalProperty(const std::string& prop, const std::string& value,
                             bool asString = false);
   const char* GetGlobalProperty(const std::string& prop);
   bool GetGlobalPropertyAsBool(const std::string& prop);
@@ -190,6 +193,8 @@
   bool UseNMake() const;
   void SetMSYSShell(bool mSYSShell);
   bool UseMSYSShell() const;
+  void SetNinjaMulti(bool ninjaMulti);
+  bool UseNinjaMulti() const;
 
   unsigned int GetCacheMajorVersion() const;
   unsigned int GetCacheMinorVersion() const;
@@ -245,6 +250,7 @@
   bool MinGWMake = false;
   bool NMake = false;
   bool MSYSShell = false;
+  bool NinjaMulti = false;
   Mode CurrentMode = Unknown;
 };
 
diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx
index 1262f53..4f003ed 100644
--- a/Source/cmStateDirectory.cxx
+++ b/Source/cmStateDirectory.cxx
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include <cm/iterator>
+#include <cmext/algorithm>
 
 #include "cmAlgorithms.h"
 #include "cmProperty.h"
@@ -520,7 +521,7 @@
 }
 
 void cmStateDirectory::AppendProperty(const std::string& prop,
-                                      const char* value, bool asString,
+                                      const std::string& value, bool asString,
                                       cmListFileBacktrace const& lfbt)
 {
   if (prop == "INCLUDE_DIRECTORIES") {
@@ -607,7 +608,7 @@
   }
   if (prop == "VARIABLES") {
     std::vector<std::string> res = this->Snapshot_.ClosureKeys();
-    cmAppend(res, this->Snapshot_.State->GetCacheEntryKeys());
+    cm::append(res, this->Snapshot_.State->GetCacheEntryKeys());
     std::sort(res.begin(), res.end());
     output = cmJoin(res, ";");
     return output.c_str();
diff --git a/Source/cmStateDirectory.h b/Source/cmStateDirectory.h
index fe15563..53a2d54 100644
--- a/Source/cmStateDirectory.h
+++ b/Source/cmStateDirectory.h
@@ -84,7 +84,7 @@
 
   void SetProperty(const std::string& prop, const char* value,
                    cmListFileBacktrace const& lfbt);
-  void AppendProperty(const std::string& prop, const char* value,
+  void AppendProperty(const std::string& prop, const std::string& value,
                       bool asString, cmListFileBacktrace const& lfbt);
   const char* GetProperty(const std::string& prop) const;
   const char* GetProperty(const std::string& prop, bool chain) const;
diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx
index 645907c..832e74e 100644
--- a/Source/cmStateSnapshot.cxx
+++ b/Source/cmStateSnapshot.cxx
@@ -315,10 +315,14 @@
   this->SetDefinition("UNIX", "1");
   this->SetDefinition("CMAKE_HOST_UNIX", "1");
 
+#  if defined(__ANDROID__)
+  this->SetDefinition("CMAKE_HOST_SYSTEM_NAME", "Android");
+#  else
   struct utsname uts_name;
   if (uname(&uts_name) >= 0) {
     this->SetDefinition("CMAKE_HOST_SYSTEM_NAME", uts_name.sysname);
   }
+#  endif
 #endif
 #if defined(__CYGWIN__)
   std::string legacy;
diff --git a/Source/cmString.hxx b/Source/cmString.hxx
index 073f4c9..9e91986 100644
--- a/Source/cmString.hxx
+++ b/Source/cmString.hxx
@@ -88,18 +88,6 @@
 };
 
 template <>
-struct IntoString<string_view> : std::true_type
-{
-  static std::string into_string(string_view s) { return std::string(s); }
-};
-
-template <>
-struct IntoString<static_string_view> : std::true_type
-{
-  static string_view into_string(static_string_view s) { return s; }
-};
-
-template <>
 struct IntoString<char> : std::true_type
 {
   static std::string into_string(char const& c) { return std::string(1, c); }
@@ -239,6 +227,25 @@
   {
   }
 
+  /**
+   * Construct via static_string_view constructor.
+   * explicit is required to avoid ambiguous overloaded operators (i.e ==,
+   * etc...) with the ones provided by string_view.
+   */
+  explicit String(static_string_view s)
+    : String(s, Private())
+  {
+  }
+  /**
+   * Construct via string_view constructor.
+   * explicit is required to avoid ambiguous overloaded operators (i.e ==,
+   * etc...) with the ones provided by string_view.
+   */
+  explicit String(string_view s)
+    : String(std::string(s), Private())
+  {
+  }
+
   /** Construct via std::string initializer list constructor.  */
   String(std::initializer_list<char> il)
     : String(std::string(il))
@@ -306,6 +313,17 @@
       This shares ownership of the other string's buffer.  */
   String& operator=(String const&) noexcept = default;
 
+  String& operator=(static_string_view s)
+  {
+    *this = String(s);
+    return *this;
+  }
+  String& operator=(string_view s)
+  {
+    *this = String(s);
+    return *this;
+  }
+
   /** Assign from any type implementing the IntoString trait.  */
   template <typename T>
   typename // NOLINT(*)
@@ -328,6 +346,7 @@
 
   /** Return a view of the string.  */
   string_view view() const noexcept { return view_; }
+  operator string_view() const noexcept { return this->view(); }
 
   /** Return true if the instance is an empty stringn or null string.  */
   bool empty() const noexcept { return view_.empty(); }
@@ -638,58 +657,155 @@
   string_view view_;
 };
 
-template <typename L, typename R>
-typename std::enable_if<AsStringView<L>::value && AsStringView<R>::value,
-                        bool>::type
-operator==(L&& l, R&& r)
+/**
+ * Trait for comparable types.
+ */
+template <typename T>
+struct IsComparable : std::false_type
 {
-  return (AsStringView<L>::view(std::forward<L>(l)) ==
-          AsStringView<R>::view(std::forward<R>(r)));
+};
+
+template <typename T>
+struct IsComparable<T&> : IsComparable<T>
+{
+};
+
+template <typename T>
+struct IsComparable<T const> : IsComparable<T>
+{
+};
+
+template <typename T>
+struct IsComparable<T const*> : IsComparable<T*>
+{
+};
+
+template <typename T, std::string::size_type N>
+struct IsComparable<T const[N]> : IsComparable<T[N]>
+{
+};
+
+template <>
+struct IsComparable<char*> : std::true_type
+{
+};
+
+template <std::string::size_type N>
+struct IsComparable<char[N]> : std::true_type
+{
+};
+
+template <>
+struct IsComparable<std::string> : std::true_type
+{
+};
+
+template <>
+struct IsComparable<char> : std::true_type
+{
+};
+
+/** comparison operators */
+inline bool operator==(const String& l, const String& r)
+{
+  return l.view() == r.view();
+}
+template <typename L>
+typename std::enable_if<IsComparable<L>::value, bool>::type operator==(
+  L&& l, const String& r)
+{
+  return AsStringView<L>::view(std::forward<L>(l)) == r.view();
+}
+template <typename R>
+typename std::enable_if<IsComparable<R>::value, bool>::type operator==(
+  const String& l, R&& r)
+{
+  return l.view() == AsStringView<R>::view(std::forward<R>(r));
 }
 
-template <typename L, typename R>
-typename std::enable_if<AsStringView<L>::value && AsStringView<R>::value,
-                        bool>::type
-operator!=(L&& l, R&& r)
+inline bool operator!=(const String& l, const String& r)
 {
-  return (AsStringView<L>::view(std::forward<L>(l)) !=
-          AsStringView<R>::view(std::forward<R>(r)));
+  return l.view() != r.view();
+}
+template <typename L>
+typename std::enable_if<IsComparable<L>::value, bool>::type operator!=(
+  L&& l, const String& r)
+{
+  return AsStringView<L>::view(std::forward<L>(l)) != r.view();
+}
+template <typename R>
+typename std::enable_if<IsComparable<R>::value, bool>::type operator!=(
+  const String& l, R&& r)
+{
+  return l.view() != AsStringView<R>::view(std::forward<R>(r));
 }
 
-template <typename L, typename R>
-typename std::enable_if<AsStringView<L>::value && AsStringView<R>::value,
-                        bool>::type
-operator<(L&& l, R&& r)
+inline bool operator<(const String& l, const String& r)
 {
-  return (AsStringView<L>::view(std::forward<L>(l)) <
-          AsStringView<R>::view(std::forward<R>(r)));
+  return l.view() < r.view();
+}
+template <typename L>
+typename std::enable_if<IsComparable<L>::value, bool>::type operator<(
+  L&& l, const String& r)
+{
+  return AsStringView<L>::view(std::forward<L>(l)) < r.view();
+}
+template <typename R>
+typename std::enable_if<IsComparable<R>::value, bool>::type operator<(
+  const String& l, R&& r)
+{
+  return l.view() < AsStringView<R>::view(std::forward<R>(r));
 }
 
-template <typename L, typename R>
-typename std::enable_if<AsStringView<L>::value && AsStringView<R>::value,
-                        bool>::type
-operator<=(L&& l, R&& r)
+inline bool operator<=(const String& l, const String& r)
 {
-  return (AsStringView<L>::view(std::forward<L>(l)) <=
-          AsStringView<R>::view(std::forward<R>(r)));
+  return l.view() <= r.view();
+}
+template <typename L>
+typename std::enable_if<IsComparable<L>::value, bool>::type operator<=(
+  L&& l, const String& r)
+{
+  return AsStringView<L>::view(std::forward<L>(l)) <= r.view();
+}
+template <typename R>
+typename std::enable_if<IsComparable<R>::value, bool>::type operator<=(
+  const String& l, R&& r)
+{
+  return l.view() <= AsStringView<R>::view(std::forward<R>(r));
 }
 
-template <typename L, typename R>
-typename std::enable_if<AsStringView<L>::value && AsStringView<R>::value,
-                        bool>::type
-operator>(L&& l, R&& r)
+inline bool operator>(const String& l, const String& r)
 {
-  return (AsStringView<L>::view(std::forward<L>(l)) >
-          AsStringView<R>::view(std::forward<R>(r)));
+  return l.view() > r.view();
+}
+template <typename L>
+typename std::enable_if<IsComparable<L>::value, bool>::type operator>(
+  L&& l, const String& r)
+{
+  return AsStringView<L>::view(std::forward<L>(l)) > r.view();
+}
+template <typename R>
+typename std::enable_if<IsComparable<R>::value, bool>::type operator>(
+  const String& l, R&& r)
+{
+  return l.view() > AsStringView<R>::view(std::forward<R>(r));
 }
 
-template <typename L, typename R>
-typename std::enable_if<AsStringView<L>::value && AsStringView<R>::value,
-                        bool>::type
-operator>=(L&& l, R&& r)
+inline bool operator>=(const String& l, const String& r)
 {
-  return (AsStringView<L>::view(std::forward<L>(l)) >=
-          AsStringView<R>::view(std::forward<R>(r)));
+  return l.view() >= r.view();
+}
+template <typename L>
+typename std::enable_if<IsComparable<L>::value, bool>::type operator>=(
+  L&& l, const String& r)
+{
+  return AsStringView<L>::view(std::forward<L>(l)) >= r.view();
+}
+template <typename R>
+typename std::enable_if<IsComparable<R>::value, bool>::type operator>=(
+  const String& l, R&& r)
+{
+  return l.view() >= AsStringView<R>::view(std::forward<R>(r));
 }
 
 std::ostream& operator<<(std::ostream& os, String const& s);
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index c4a4220..9127c50 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -2,9 +2,10 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmSystemTools.h"
 
+#include <cmext/algorithm>
+
 #include "cm_uv.h"
 
-#include "cmAlgorithms.h"
 #include "cmDuration.h"
 #include "cmProcessOutput.h"
 #include "cmRange.h"
@@ -360,7 +361,7 @@
 #else
         cmSystemTools::ParseUnixCommandLine(line.c_str(), args2);
 #endif
-        cmAppend(arg_full, args2);
+        cm::append(arg_full, args2);
       }
     } else {
       arg_full.push_back(arg);
@@ -585,7 +586,7 @@
           cmSystemTools::Stdout(strdata);
         }
         if (captureStdOut) {
-          cmAppend(tempStdOut, data, data + length);
+          cm::append(tempStdOut, data, data + length);
         }
       } else if (pipe == cmsysProcess_Pipe_STDERR) {
         if (outputflag != OUTPUT_NONE) {
@@ -593,7 +594,7 @@
           cmSystemTools::Stderr(strdata);
         }
         if (captureStdErr) {
-          cmAppend(tempStdErr, data, data + length);
+          cm::append(tempStdErr, data, data + length);
         }
       }
     }
@@ -814,6 +815,8 @@
 #  else
   _fmode = _O_TEXT;
 #  endif
+  // Replace libuv's report handler with our own to suppress popups.
+  cmSystemTools::EnableMSVCDebugHook();
 #endif
 }
 
@@ -1710,26 +1713,26 @@
       processOutput.DecodeText(data, length, strdata, 1);
       // Append to the stdout buffer.
       std::vector<char>::size_type size = out.size();
-      cmAppend(out, strdata);
+      cm::append(out, strdata);
       outiter = out.begin() + size;
     } else if (pipe == cmsysProcess_Pipe_STDERR) {
       processOutput.DecodeText(data, length, strdata, 2);
       // Append to the stderr buffer.
       std::vector<char>::size_type size = err.size();
-      cmAppend(err, strdata);
+      cm::append(err, strdata);
       erriter = err.begin() + size;
     } else if (pipe == cmsysProcess_Pipe_None) {
       // Both stdout and stderr pipes have broken.  Return leftover data.
       processOutput.DecodeText(std::string(), strdata, 1);
       if (!strdata.empty()) {
         std::vector<char>::size_type size = out.size();
-        cmAppend(out, strdata);
+        cm::append(out, strdata);
         outiter = out.begin() + size;
       }
       processOutput.DecodeText(std::string(), strdata, 2);
       if (!strdata.empty()) {
         std::vector<char>::size_type size = err.size();
-        cmAppend(err, strdata);
+        cm::append(err, strdata);
         erriter = err.begin() + size;
       }
       if (!out.empty()) {
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 80986fc..97d7fce 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -12,6 +12,7 @@
 #include <unordered_set>
 
 #include <cm/memory>
+#include <cmext/algorithm>
 
 #include "cmsys/RegularExpression.hxx"
 
@@ -38,13 +39,13 @@
 #include "cmake.h"
 
 template <>
-const char* cmTargetPropertyComputer::ComputeLocationForBuild<cmTarget>(
+const std::string& cmTargetPropertyComputer::ComputeLocationForBuild<cmTarget>(
   cmTarget const* tgt)
 {
   static std::string loc;
   if (tgt->IsImported()) {
     loc = tgt->ImportedGetFullPath("", cmStateEnums::RuntimeBinaryArtifact);
-    return loc.c_str();
+    return loc;
   }
 
   cmGlobalGenerator* gg = tgt->GetGlobalGenerator();
@@ -53,18 +54,18 @@
   }
   cmGeneratorTarget* gt = gg->FindGeneratorTarget(tgt->GetName());
   loc = gt->GetLocationForBuild();
-  return loc.c_str();
+  return loc;
 }
 
 template <>
-const char* cmTargetPropertyComputer::ComputeLocation<cmTarget>(
+const std::string& cmTargetPropertyComputer::ComputeLocation<cmTarget>(
   cmTarget const* tgt, const std::string& config)
 {
   static std::string loc;
   if (tgt->IsImported()) {
     loc =
       tgt->ImportedGetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
-    return loc.c_str();
+    return loc;
   }
 
   cmGlobalGenerator* gg = tgt->GetGlobalGenerator();
@@ -73,7 +74,7 @@
   }
   cmGeneratorTarget* gt = gg->FindGeneratorTarget(tgt->GetName());
   loc = gt->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
-  return loc.c_str();
+  return loc;
 }
 
 template <>
@@ -176,7 +177,8 @@
   bool IsImportedTarget;
   bool ImportedGloballyVisible;
   bool BuildInterfaceIncludesAppended;
-  std::set<BT<std::string>> Utilities;
+  bool PerConfig;
+  std::set<BT<std::pair<std::string, bool>>> Utilities;
   std::vector<cmCustomCommand> PreBuildCommands;
   std::vector<cmCustomCommand> PreLinkCommands;
   std::vector<cmCustomCommand> PostBuildCommands;
@@ -213,7 +215,7 @@
 };
 
 cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
-                   Visibility vis, cmMakefile* mf)
+                   Visibility vis, cmMakefile* mf, bool perConfig)
   : impl(cm::make_unique<cmTargetInternals>())
 {
   assert(mf);
@@ -229,6 +231,7 @@
     (vis == VisibilityImported || vis == VisibilityImportedGlobally);
   impl->ImportedGloballyVisible = vis == VisibilityImportedGlobally;
   impl->BuildInterfaceIncludesAppended = false;
+  impl->PerConfig = perConfig;
 
   // Check whether this is a DLL platform.
   impl->IsDLLPlatform =
@@ -355,9 +358,9 @@
     initProp("CUDA_COMPILER_LAUNCHER");
     initProp("CUDA_SEPARABLE_COMPILATION");
     initProp("CUDA_RESOLVE_DEVICE_SYMBOLS");
+    initProp("CUDA_RUNTIME_LIBRARY");
     initProp("LINK_SEARCH_START_STATIC");
     initProp("LINK_SEARCH_END_STATIC");
-    initProp("FOLDER");
     initProp("Swift_LANGUAGE_VERSION");
     initProp("Swift_MODULE_DIRECTORY");
     initProp("VS_JUST_MY_CODE_DEBUGGING");
@@ -373,6 +376,7 @@
       initProp("XCODE_SCHEME_THREAD_SANITIZER_STOP");
       initProp("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER");
       initProp("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP");
+      initProp("XCODE_SCHEME_WORKING_DIRECTORY");
       initProp("XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER");
       initProp("XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP");
       initProp("XCODE_SCHEME_MALLOC_SCRIBBLE");
@@ -382,11 +386,14 @@
       initProp("XCODE_SCHEME_MALLOC_STACK");
       initProp("XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE");
       initProp("XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS");
+      initProp("XCODE_SCHEME_ENVIRONMENT");
     }
 #endif
   }
 
   if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
+    initProp("FOLDER");
+
     if (this->GetGlobalGenerator()->IsXcode()) {
       initProp("XCODE_GENERATE_SCHEME");
     }
@@ -437,30 +444,30 @@
   if (!this->IsImported()) {
     // Initialize the INCLUDE_DIRECTORIES property based on the current value
     // of the same directory property:
-    cmAppend(impl->IncludeDirectoriesEntries,
-             impl->Makefile->GetIncludeDirectoriesEntries());
-    cmAppend(impl->IncludeDirectoriesBacktraces,
-             impl->Makefile->GetIncludeDirectoriesBacktraces());
+    cm::append(impl->IncludeDirectoriesEntries,
+               impl->Makefile->GetIncludeDirectoriesEntries());
+    cm::append(impl->IncludeDirectoriesBacktraces,
+               impl->Makefile->GetIncludeDirectoriesBacktraces());
 
     {
       auto const& sysInc = impl->Makefile->GetSystemIncludeDirectories();
       impl->SystemIncludeDirectories.insert(sysInc.begin(), sysInc.end());
     }
 
-    cmAppend(impl->CompileOptionsEntries,
-             impl->Makefile->GetCompileOptionsEntries());
-    cmAppend(impl->CompileOptionsBacktraces,
-             impl->Makefile->GetCompileOptionsBacktraces());
+    cm::append(impl->CompileOptionsEntries,
+               impl->Makefile->GetCompileOptionsEntries());
+    cm::append(impl->CompileOptionsBacktraces,
+               impl->Makefile->GetCompileOptionsBacktraces());
 
-    cmAppend(impl->LinkOptionsEntries,
-             impl->Makefile->GetLinkOptionsEntries());
-    cmAppend(impl->LinkOptionsBacktraces,
-             impl->Makefile->GetLinkOptionsBacktraces());
+    cm::append(impl->LinkOptionsEntries,
+               impl->Makefile->GetLinkOptionsEntries());
+    cm::append(impl->LinkOptionsBacktraces,
+               impl->Makefile->GetLinkOptionsBacktraces());
 
-    cmAppend(impl->LinkDirectoriesEntries,
-             impl->Makefile->GetLinkDirectoriesEntries());
-    cmAppend(impl->LinkDirectoriesBacktraces,
-             impl->Makefile->GetLinkDirectoriesBacktraces());
+    cm::append(impl->LinkDirectoriesEntries,
+               impl->Makefile->GetLinkDirectoriesEntries());
+    cm::append(impl->LinkDirectoriesBacktraces,
+               impl->Makefile->GetLinkDirectoriesBacktraces());
   }
 
   if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
@@ -484,6 +491,7 @@
   }
   if (impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
       impl->TargetType == cmStateEnums::EXECUTABLE) {
+    initProp("AIX_EXPORT_ALL_SYMBOLS");
     initProp("WINDOWS_EXPORT_ALL_SYMBOLS");
   }
 
@@ -507,14 +515,15 @@
       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");
   }
 
-  if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
-      this->GetType() != cmStateEnums::UTILITY) {
+  if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
 
     // check for "CMAKE_VS_GLOBALS" variable and set up target properties
     // if any
@@ -574,13 +583,14 @@
   return impl->Makefile->GetGlobalGenerator();
 }
 
-void cmTarget::AddUtility(std::string const& name, cmMakefile* mf)
+void cmTarget::AddUtility(std::string const& name, bool cross, cmMakefile* mf)
 {
-  impl->Utilities.insert(
-    BT<std::string>(name, mf ? mf->GetBacktrace() : cmListFileBacktrace()));
+  impl->Utilities.insert(BT<std::pair<std::string, bool>>(
+    { name, cross }, mf ? mf->GetBacktrace() : cmListFileBacktrace()));
 }
 
-std::set<BT<std::string>> const& cmTarget::GetUtilities() const
+std::set<BT<std::pair<std::string, bool>>> const& cmTarget::GetUtilities()
+  const
 {
   return impl->Utilities;
 }
@@ -932,14 +942,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);
@@ -948,14 +951,13 @@
 
     const std::string libName =
       (isNonImportedTarget && llt != GENERAL_LibraryType)
-      ? targetNameGenex(libRef)
-      : libRef;
-    this->AppendProperty(
-      "LINK_LIBRARIES",
-      this->GetDebugGeneratorExpressions(libName, llt).c_str());
+      ? 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)) ||
@@ -1286,20 +1288,20 @@
 
     impl->Properties.SetProperty(prop, reusedFrom.c_str());
 
-    reusedTarget->SetProperty("COMPILE_PDB_NAME", reusedFrom.c_str());
+    reusedTarget->SetProperty("COMPILE_PDB_NAME", reusedFrom);
     reusedTarget->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
-                              cmStrCat(reusedFrom, ".dir/").c_str());
+                              cmStrCat(reusedFrom, ".dir/"));
 
     this->SetProperty("COMPILE_PDB_NAME",
                       reusedTarget->GetProperty("COMPILE_PDB_NAME"));
-    this->AddUtility(reusedFrom, impl->Makefile);
+    this->AddUtility(reusedFrom, false, impl->Makefile);
   } else {
     impl->Properties.SetProperty(prop, value);
   }
 }
 
-void cmTarget::AppendProperty(const std::string& prop, const char* value,
-                              bool asString)
+void cmTarget::AppendProperty(const std::string& prop,
+                              const std::string& value, bool asString)
 {
   if (!cmTargetPropertyComputer::PassesWhitelist(
         this->GetType(), prop, impl->Makefile->GetMessenger(),
@@ -1334,37 +1336,37 @@
     return;
   }
   if (prop == "INCLUDE_DIRECTORIES") {
-    if (value && *value) {
+    if (!value.empty()) {
       impl->IncludeDirectoriesEntries.emplace_back(value);
       cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
       impl->IncludeDirectoriesBacktraces.push_back(lfbt);
     }
   } else if (prop == "COMPILE_OPTIONS") {
-    if (value && *value) {
+    if (!value.empty()) {
       impl->CompileOptionsEntries.emplace_back(value);
       cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
       impl->CompileOptionsBacktraces.push_back(lfbt);
     }
   } else if (prop == "COMPILE_FEATURES") {
-    if (value && *value) {
+    if (!value.empty()) {
       impl->CompileFeaturesEntries.emplace_back(value);
       cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
       impl->CompileFeaturesBacktraces.push_back(lfbt);
     }
   } else if (prop == "COMPILE_DEFINITIONS") {
-    if (value && *value) {
+    if (!value.empty()) {
       impl->CompileDefinitionsEntries.emplace_back(value);
       cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
       impl->CompileDefinitionsBacktraces.push_back(lfbt);
     }
   } else if (prop == "LINK_OPTIONS") {
-    if (value && *value) {
+    if (!value.empty()) {
       impl->LinkOptionsEntries.emplace_back(value);
       cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
       impl->LinkOptionsBacktraces.push_back(lfbt);
     }
   } else if (prop == "LINK_DIRECTORIES") {
-    if (value && *value) {
+    if (!value.empty()) {
       impl->LinkDirectoriesEntries.emplace_back(value);
       cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
       impl->LinkDirectoriesBacktraces.push_back(lfbt);
@@ -1378,13 +1380,13 @@
       impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
       return;
     }
-    if (value && *value) {
+    if (!value.empty()) {
       impl->PrecompileHeadersEntries.emplace_back(value);
       cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
       impl->PrecompileHeadersBacktraces.push_back(lfbt);
     }
   } else if (prop == "LINK_LIBRARIES") {
-    if (value && *value) {
+    if (!value.empty()) {
       cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
       impl->LinkImplementationPropertyEntries.emplace_back(value);
       impl->LinkImplementationPropertyBacktraces.push_back(lfbt);
@@ -1423,7 +1425,7 @@
     dirs += impl->Makefile->GetCurrentSourceDirectory();
     if (!dirs.empty()) {
       this->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
-                           ("$<BUILD_INTERFACE:" + dirs + ">").c_str());
+                           ("$<BUILD_INTERFACE:" + dirs + ">"));
     }
   }
 }
@@ -1558,8 +1560,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()
@@ -1715,7 +1721,14 @@
       }
 
       static std::string output;
-      output = cmJoin(impl->Utilities, ";");
+      static std::vector<std::string> utilities;
+      utilities.resize(impl->Utilities.size());
+      std::transform(
+        impl->Utilities.cbegin(), impl->Utilities.cend(), utilities.begin(),
+        [](const BT<std::pair<std::string, bool>>& item) -> std::string {
+          return item.Value.first;
+        });
+      output = cmJoin(utilities, ";");
       return output.c_str();
     }
     if (prop == propPRECOMPILE_HEADERS) {
@@ -1801,6 +1814,11 @@
   return impl->ImportedGloballyVisible;
 }
 
+bool cmTarget::IsPerConfig() const
+{
+  return impl->PerConfig;
+}
+
 const char* cmTarget::GetSuffixVariableInternal(
   cmStateEnums::ArtifactType artifact) const
 {
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 65a1ce3..286933b 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -44,7 +44,7 @@
   };
 
   cmTarget(std::string const& name, cmStateEnums::TargetType type,
-           Visibility vis, cmMakefile* mf);
+           Visibility vis, cmMakefile* mf, bool perConfig);
 
   cmTarget(cmTarget const&) = delete;
   cmTarget(cmTarget&&) noexcept;
@@ -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
   {
@@ -158,13 +156,18 @@
    * name as would be specified to the ADD_EXECUTABLE or UTILITY_SOURCE
    * commands. It is not a full path nor does it have an extension.
    */
-  void AddUtility(std::string const& name, cmMakefile* mf = nullptr);
+  void AddUtility(std::string const& name, bool cross,
+                  cmMakefile* mf = nullptr);
   //! Get the utilities used by this target
-  std::set<BT<std::string>> const& GetUtilities() const;
+  std::set<BT<std::pair<std::string, bool>>> const& GetUtilities() const;
 
   //! Set/Get a property of this target file
   void SetProperty(const std::string& prop, const char* value);
-  void AppendProperty(const std::string& prop, const char* value,
+  void SetProperty(const std::string& prop, const std::string& value)
+  {
+    SetProperty(prop, value.c_str());
+  }
+  void AppendProperty(const std::string& prop, const std::string& value,
                       bool asString = false);
   //! Might return a nullptr if the property is not set or invalid
   const char* GetProperty(const std::string& prop) const;
@@ -186,6 +189,7 @@
 
   bool IsImported() const;
   bool IsImportedGloballyVisible() const;
+  bool IsPerConfig() const;
 
   bool GetMappedConfig(std::string const& desired_config, const char** loc,
                        const char** imp, std::string& suffix) const;
diff --git a/Source/cmTargetCompileDefinitionsCommand.cxx b/Source/cmTargetCompileDefinitionsCommand.cxx
index edee167..b56b245 100644
--- a/Source/cmTargetCompileDefinitionsCommand.cxx
+++ b/Source/cmTargetCompileDefinitionsCommand.cxx
@@ -28,7 +28,7 @@
                            const std::vector<std::string>& content,
                            bool /*prepend*/, bool /*system*/) override
   {
-    tgt->AppendProperty("COMPILE_DEFINITIONS", this->Join(content).c_str());
+    tgt->AppendProperty("COMPILE_DEFINITIONS", this->Join(content));
     return true; // Successfully handled.
   }
 
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/cmTargetDepend.h b/Source/cmTargetDepend.h
index 4ca78fa..5452cc7 100644
--- a/Source/cmTargetDepend.h
+++ b/Source/cmTargetDepend.h
@@ -19,6 +19,7 @@
   // mutable members to achieve a map with set syntax.
   mutable bool Link;
   mutable bool Util;
+  mutable bool Cross;
   mutable cmListFileBacktrace Backtrace;
 
 public:
@@ -26,6 +27,7 @@
     : Target(t)
     , Link(false)
     , Util(false)
+    , Cross(false)
   {
   }
   operator cmGeneratorTarget const*() const { return this->Target; }
@@ -43,12 +45,14 @@
       this->Link = true;
     }
   }
+  void SetCross(bool cross) const { this->Cross = cross; }
   void SetBacktrace(cmListFileBacktrace const& bt) const
   {
     this->Backtrace = bt;
   }
   bool IsLink() const { return this->Link; }
   bool IsUtil() const { return this->Util; }
+  bool IsCross() const { return this->Cross; }
   cmListFileBacktrace const& GetBacktrace() const { return this->Backtrace; }
 };
 
diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx
index 95b69f3..35635b9 100644
--- a/Source/cmTargetIncludeDirectoriesCommand.cxx
+++ b/Source/cmTargetIncludeDirectoriesCommand.cxx
@@ -88,8 +88,7 @@
                                                   system);
   if (system) {
     std::string joined = this->Join(content);
-    tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES",
-                        joined.c_str());
+    tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", joined);
   }
 }
 
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index 0d2383a..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.c_str());
+      this->AppendProperty("INTERFACE_LINK_LIBRARIES", configLib);
     }
     return true;
   }
@@ -488,9 +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).c_str());
+  this->AppendProperty("INTERFACE_LINK_LIBRARIES",
+                       this->Target->GetDebugGeneratorExpressions(lib, llt));
 
   // Stop processing if called without any keyword.
   if (currentProcessingState == ProcessingLinkLibraries) {
@@ -498,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;
   }
 
@@ -514,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.
@@ -522,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.c_str());
+        this->AppendProperty(prop, lib);
       }
     }
     if (llt == OPTIMIZED_LibraryType || llt == GENERAL_LibraryType) {
       // Put in the non-DEBUG configuration interfaces.
-      target->AppendProperty("LINK_INTERFACE_LIBRARIES", libRef.c_str());
+      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/cmTargetPrecompileHeadersCommand.cxx b/Source/cmTargetPrecompileHeadersCommand.cxx
index c6e2e5c..0670bd9 100644
--- a/Source/cmTargetPrecompileHeadersCommand.cxx
+++ b/Source/cmTargetPrecompileHeadersCommand.cxx
@@ -47,9 +47,8 @@
                            bool /*prepend*/, bool /*system*/) override
   {
     std::string const& base = this->Makefile->GetCurrentSourceDirectory();
-    tgt->AppendProperty(
-      "PRECOMPILE_HEADERS",
-      this->Join(ConvertToAbsoluteContent(content, base)).c_str());
+    tgt->AppendProperty("PRECOMPILE_HEADERS",
+                        this->Join(ConvertToAbsoluteContent(content, base)));
     return true;
   }
 
diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx
index bbc1e16..0de8d6d 100644
--- a/Source/cmTargetPropCommandBase.cxx
+++ b/Source/cmTargetPropCommandBase.cxx
@@ -84,9 +84,7 @@
     }
     ++argIndex;
 
-    this->Target->SetProperty("PRECOMPILE_HEADERS_REUSE_FROM",
-                              args[argIndex].c_str());
-
+    this->Target->SetProperty("PRECOMPILE_HEADERS_REUSE_FROM", args[argIndex]);
     ++argIndex;
   }
 
@@ -162,9 +160,8 @@
     const char* propValue = tgt->GetProperty(propName);
     const std::string totalContent = this->Join(content) +
       (propValue ? std::string(";") + propValue : std::string());
-    tgt->SetProperty(propName, totalContent.c_str());
+    tgt->SetProperty(propName, totalContent);
   } else {
-    tgt->AppendProperty("INTERFACE_" + this->Property,
-                        this->Join(content).c_str());
+    tgt->AppendProperty("INTERFACE_" + this->Property, this->Join(content));
   }
 }
diff --git a/Source/cmTargetPropertyComputer.cxx b/Source/cmTargetPropertyComputer.cxx
index baab8da..f37995c 100644
--- a/Source/cmTargetPropertyComputer.cxx
+++ b/Source/cmTargetPropertyComputer.cxx
@@ -62,6 +62,7 @@
     "COMPATIBLE_INTERFACE_NUMBER_MAX",
     "COMPATIBLE_INTERFACE_NUMBER_MIN",
     "COMPATIBLE_INTERFACE_STRING",
+    "DEPRECATION",
     "EXPORT_NAME",
     "EXPORT_PROPERTIES",
     "IMPORTED",
diff --git a/Source/cmTargetPropertyComputer.h b/Source/cmTargetPropertyComputer.h
index 3b11acd..df34f18 100644
--- a/Source/cmTargetPropertyComputer.h
+++ b/Source/cmTargetPropertyComputer.h
@@ -46,10 +46,10 @@
                                            cmListFileBacktrace const& context);
 
   template <typename Target>
-  static const char* ComputeLocationForBuild(Target const* tgt);
+  static const std::string& ComputeLocationForBuild(Target const* tgt);
   template <typename Target>
-  static const char* ComputeLocation(Target const* tgt,
-                                     std::string const& config);
+  static const std::string& ComputeLocation(Target const* tgt,
+                                            std::string const& config);
 
   template <typename Target>
   static const char* GetLocation(Target const* tgt, std::string const& prop,
@@ -71,7 +71,7 @@
                                           context)) {
           return nullptr;
         }
-        return ComputeLocationForBuild(tgt);
+        return ComputeLocationForBuild(tgt).c_str();
       }
 
       // Support "LOCATION_<CONFIG>".
@@ -82,7 +82,7 @@
           return nullptr;
         }
         std::string configName = prop.substr(9);
-        return ComputeLocation(tgt, configName);
+        return ComputeLocation(tgt, configName).c_str();
       }
 
       // Support "<CONFIG>_LOCATION".
@@ -95,7 +95,7 @@
                                             context)) {
             return nullptr;
           }
-          return ComputeLocation(tgt, configName);
+          return ComputeLocation(tgt, configName).c_str();
         }
       }
     }
diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx
index c2e0b28..a1fbc9b 100644
--- a/Source/cmTargetSourcesCommand.cxx
+++ b/Source/cmTargetSourcesCommand.cxx
@@ -43,8 +43,7 @@
                            bool /*prepend*/, bool /*system*/) override
   {
     tgt->AppendProperty(
-      "SOURCES",
-      this->Join(ConvertToAbsoluteContent(tgt, content, false)).c_str());
+      "SOURCES", this->Join(ConvertToAbsoluteContent(tgt, content, false)));
     return true; // Successfully handled.
   }
 
diff --git a/Source/cmTest.cxx b/Source/cmTest.cxx
index d5c61c1..3b731cc 100644
--- a/Source/cmTest.cxx
+++ b/Source/cmTest.cxx
@@ -55,7 +55,7 @@
   this->Properties.SetProperty(prop, value);
 }
 
-void cmTest::AppendProperty(const std::string& prop, const char* value,
+void cmTest::AppendProperty(const std::string& prop, const std::string& value,
                             bool asString)
 {
   this->Properties.AppendProperty(prop, value, asString);
diff --git a/Source/cmTest.h b/Source/cmTest.h
index dd246c4..72d4ed9 100644
--- a/Source/cmTest.h
+++ b/Source/cmTest.h
@@ -35,7 +35,7 @@
 
   //! Set/Get a property of this source file
   void SetProperty(const std::string& prop, const char* value);
-  void AppendProperty(const std::string& prop, const char* value,
+  void AppendProperty(const std::string& prop, const std::string& value,
                       bool asString = false);
   const char* GetProperty(const std::string& prop) const;
   bool GetPropertyAsBool(const std::string& prop) const;
diff --git a/Source/cmVariableWatch.cxx b/Source/cmVariableWatch.cxx
index 4995da9..35e1c8c 100644
--- a/Source/cmVariableWatch.cxx
+++ b/Source/cmVariableWatch.cxx
@@ -2,19 +2,19 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmVariableWatch.h"
 
+#include <array>
 #include <memory>
 #include <utility>
 #include <vector>
 
-static const char* const cmVariableWatchAccessStrings[] = {
-  "READ_ACCESS",     "UNKNOWN_READ_ACCESS", "UNKNOWN_DEFINED_ACCESS",
-  "MODIFIED_ACCESS", "REMOVED_ACCESS",      "NO_ACCESS"
-};
-
-const char* cmVariableWatch::GetAccessAsString(int access_type)
+const std::string& cmVariableWatch::GetAccessAsString(int access_type)
 {
+  static const std::array<std::string, 6> cmVariableWatchAccessStrings = {
+    { "READ_ACCESS", "UNKNOWN_READ_ACCESS", "UNKNOWN_DEFINED_ACCESS",
+      "MODIFIED_ACCESS", "REMOVED_ACCESS", "NO_ACCESS" }
+  };
   if (access_type < 0 || access_type >= cmVariableWatch::NO_ACCESS) {
-    return "NO_ACCESS";
+    access_type = cmVariableWatch::NO_ACCESS;
   }
   return cmVariableWatchAccessStrings[access_type];
 }
diff --git a/Source/cmVariableWatch.h b/Source/cmVariableWatch.h
index e4b3b7c..6c418ed 100644
--- a/Source/cmVariableWatch.h
+++ b/Source/cmVariableWatch.h
@@ -46,7 +46,7 @@
    */
   enum
   {
-    VARIABLE_READ_ACCESS = 0,
+    VARIABLE_READ_ACCESS,
     UNKNOWN_VARIABLE_READ_ACCESS,
     UNKNOWN_VARIABLE_DEFINED_ACCESS,
     VARIABLE_MODIFIED_ACCESS,
@@ -57,7 +57,7 @@
   /**
    * Return the access as string
    */
-  static const char* GetAccessAsString(int access_type);
+  static const std::string& GetAccessAsString(int access_type);
 
 protected:
   struct Pair
diff --git a/Source/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx
index f2c8f3c..35b9a1d 100644
--- a/Source/cmVariableWatchCommand.cxx
+++ b/Source/cmVariableWatchCommand.cxx
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmVariableWatchCommand.h"
 
+#include <limits>
 #include <memory>
 #include <utility>
 
@@ -14,17 +15,19 @@
 #include "cmVariableWatch.h"
 #include "cmake.h"
 
+class cmLocalGenerator;
+
+namespace {
 struct cmVariableWatchCallbackData
 {
   bool InCallback;
   std::string Command;
 };
 
-static void cmVariableWatchCommandVariableAccessed(const std::string& variable,
-                                                   int access_type,
-                                                   void* client_data,
-                                                   const char* newValue,
-                                                   const cmMakefile* mf)
+void cmVariableWatchCommandVariableAccessed(const std::string& variable,
+                                            int access_type, void* client_data,
+                                            const char* newValue,
+                                            const cmMakefile* mf)
 {
   cmVariableWatchCallbackData* data =
     static_cast<cmVariableWatchCallbackData*>(client_data);
@@ -34,40 +37,35 @@
   }
   data->InCallback = true;
 
-  cmListFileFunction newLFF;
-  cmListFileArgument arg;
-  bool processed = false;
-  const char* accessString = cmVariableWatch::GetAccessAsString(access_type);
-  const char* currentListFile = mf->GetDefinition("CMAKE_CURRENT_LIST_FILE");
+  auto accessString = cmVariableWatch::GetAccessAsString(access_type);
 
   /// Ultra bad!!
   cmMakefile* makefile = const_cast<cmMakefile*>(mf);
 
   std::string stack = makefile->GetProperty("LISTFILE_STACK");
   if (!data->Command.empty()) {
-    newLFF.Arguments.clear();
-    newLFF.Arguments.emplace_back(variable, cmListFileArgument::Quoted, 9999);
-    newLFF.Arguments.emplace_back(accessString, cmListFileArgument::Quoted,
-                                  9999);
-    newLFF.Arguments.emplace_back(newValue ? newValue : "",
-                                  cmListFileArgument::Quoted, 9999);
-    newLFF.Arguments.emplace_back(currentListFile, cmListFileArgument::Quoted,
-                                  9999);
-    newLFF.Arguments.emplace_back(stack, cmListFileArgument::Quoted, 9999);
+    cmListFileFunction newLFF;
+    const char* const currentListFile =
+      mf->GetDefinition("CMAKE_CURRENT_LIST_FILE");
+    const auto fakeLineNo =
+      std::numeric_limits<decltype(cmListFileArgument::Line)>::max();
+    newLFF.Arguments = {
+      { variable, cmListFileArgument::Quoted, fakeLineNo },
+      { accessString, cmListFileArgument::Quoted, fakeLineNo },
+      { newValue ? newValue : "", cmListFileArgument::Quoted, fakeLineNo },
+      { currentListFile, cmListFileArgument::Quoted, fakeLineNo },
+      { stack, cmListFileArgument::Quoted, fakeLineNo }
+    };
     newLFF.Name = data->Command;
-    newLFF.Line = 9999;
+    newLFF.Line = fakeLineNo;
     cmExecutionStatus status(*makefile);
     if (!makefile->ExecuteCommand(newLFF, status)) {
       cmSystemTools::Error(
         cmStrCat("Error in cmake code at\nUnknown:0:\nA command failed "
                  "during the invocation of callback \"",
                  data->Command, "\"."));
-      data->InCallback = false;
-      return;
     }
-    processed = true;
-  }
-  if (!processed) {
+  } else {
     makefile->IssueMessage(
       MessageType::LOG,
       cmStrCat("Variable \"", variable, "\" was accessed using ", accessString,
@@ -77,7 +75,7 @@
   data->InCallback = false;
 }
 
-static void deleteVariableWatchCallbackData(void* client_data)
+void deleteVariableWatchCallbackData(void* client_data)
 {
   cmVariableWatchCallbackData* data =
     static_cast<cmVariableWatchCallbackData*>(client_data);
@@ -91,18 +89,18 @@
 public:
   /* NOLINTNEXTLINE(performance-unnecessary-value-param) */
   FinalAction(cmMakefile* makefile, std::string variable)
-    : Action(std::make_shared<Impl>(makefile, std::move(variable)))
+    : Action{ std::make_shared<Impl>(makefile, std::move(variable)) }
   {
   }
 
-  void operator()(cmMakefile&) const {}
+  void operator()(cmLocalGenerator&, const cmListFileBacktrace&) const {}
 
 private:
   struct Impl
   {
     Impl(cmMakefile* makefile, std::string variable)
-      : Makefile(makefile)
-      , Variable(std::move(variable))
+      : Makefile{ makefile }
+      , Variable{ std::move(variable) }
     {
     }
 
@@ -112,12 +110,13 @@
         this->Variable, cmVariableWatchCommandVariableAccessed);
     }
 
-    cmMakefile* Makefile;
-    std::string Variable;
+    cmMakefile* const Makefile;
+    std::string const Variable;
   };
 
   std::shared_ptr<Impl const> Action;
 };
+} // anonymous namespace
 
 bool cmVariableWatchCommand(std::vector<std::string> const& args,
                             cmExecutionStatus& status)
@@ -136,10 +135,10 @@
     return false;
   }
 
-  cmVariableWatchCallbackData* data = new cmVariableWatchCallbackData;
+  auto* const data = new cmVariableWatchCallbackData;
 
   data->InCallback = false;
-  data->Command = command;
+  data->Command = std::move(command);
 
   if (!status.GetMakefile().GetCMakeInstance()->GetVariableWatch()->AddWatch(
         variable, cmVariableWatchCommandVariableAccessed, data,
@@ -148,7 +147,7 @@
     return false;
   }
 
-  status.GetMakefile().AddFinalAction(
-    FinalAction(&status.GetMakefile(), variable));
+  status.GetMakefile().AddGeneratorAction(
+    FinalAction{ &status.GetMakefile(), variable });
   return true;
 }
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index f220ea5..8da113e 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -6,6 +6,7 @@
 #include <set>
 
 #include <cm/memory>
+#include <cm/vector>
 
 #include "windows.h"
 
@@ -52,7 +53,7 @@
   bool HasContent = false;
   std::string Tag;
 
-  Elem(std::ostream& s, const char* tag)
+  Elem(std::ostream& s, const std::string& tag)
     : S(s)
     , Indent(0)
     , Tag(tag)
@@ -60,7 +61,7 @@
     this->StartElement();
   }
   Elem(const Elem&) = delete;
-  Elem(Elem& par, const char* tag)
+  Elem(Elem& par, const std::string& tag)
     : S(par.S)
     , Indent(par.Indent + 1)
     , Tag(tag)
@@ -71,13 +72,13 @@
   void SetHasElements()
   {
     if (!HasElements) {
-      this->S << ">\n";
+      this->S << ">";
       HasElements = true;
     }
   }
   std::ostream& WriteString(const char* line);
   void StartElement() { this->WriteString("<") << this->Tag; }
-  void Element(const char* tag, const std::string& val)
+  void Element(const std::string& tag, const std::string& val)
   {
     Elem(*this, tag).Content(val);
   }
@@ -103,19 +104,14 @@
 
     if (HasElements) {
       this->WriteString("</") << this->Tag << ">";
-      if (this->Indent > 0) {
-        this->S << '\n';
-      } else {
-        // special case: don't print EOL at EOF
-      }
     } else if (HasContent) {
-      this->S << "</" << this->Tag << ">\n";
+      this->S << "</" << this->Tag << ">";
     } else {
-      this->S << " />\n";
+      this->S << " />";
     }
   }
 
-  void WritePlatformConfigTag(const char* tag, const std::string& cond,
+  void WritePlatformConfigTag(const std::string& tag, const std::string& cond,
                               const std::string& content);
 };
 
@@ -131,8 +127,8 @@
   {
   }
 
-  void OutputFlag(std::ostream& /*fout*/, int /*indent*/, const char* tag,
-                  const std::string& content) override
+  void OutputFlag(std::ostream& /*fout*/, int /*indent*/,
+                  const std::string& tag, const std::string& content) override
   {
     if (!this->GetConfiguration().empty()) {
       // if there are configuration specific flags, then
@@ -274,7 +270,7 @@
 }
 
 void cmVisualStudio10TargetGenerator::Elem::WritePlatformConfigTag(
-  const char* tag, const std::string& cond, const std::string& content)
+  const std::string& tag, const std::string& cond, const std::string& content)
 {
   Elem(*this, tag).Attribute("Condition", cond).Content(content);
 }
@@ -282,6 +278,7 @@
 std::ostream& cmVisualStudio10TargetGenerator::Elem::WriteString(
   const char* line)
 {
+  this->S << '\n';
   this->S.fill(' ');
   this->S.width(this->Indent * 2);
   // write an empty string to get the fill level indent to print
@@ -334,9 +331,9 @@
   }
   // Tell the global generator the name of the project file
   this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME",
-                                             this->Name.c_str());
+                                             this->Name);
   this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME_EXT",
-                                             ProjectFileExtension.c_str());
+                                             ProjectFileExtension);
   this->DotNetHintReferences.clear();
   this->AdditionalUsingDirectories.clear();
   if (this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
@@ -376,8 +373,7 @@
   char magic[] = { char(0xEF), char(0xBB), char(0xBF) };
   BuildFileStream.write(magic, 3);
   BuildFileStream << "<?xml version=\"1.0\" encoding=\""
-                  << this->GlobalGenerator->Encoding() << "\"?>"
-                  << "\n";
+                  << this->GlobalGenerator->Encoding() << "\"?>";
   {
     Elem e0(BuildFileStream, "Project");
     e0.Attribute("DefaultTargets", "Build");
@@ -488,23 +484,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()) {
@@ -543,6 +549,11 @@
         e1.Element("VCProjectUpgraderObjectName", "NoUpgrade");
       }
 
+      if (const char* vcTargetsPath =
+            this->GlobalGenerator->GetCustomVCTargetsPath()) {
+        e1.Element("VCTargetsPath", vcTargetsPath);
+      }
+
       std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys();
       for (std::string const& keyIt : keys) {
         static const char* prefix = "VS_GLOBAL_";
@@ -557,7 +568,7 @@
         const char* value = this->GeneratorTarget->GetProperty(keyIt);
         if (!value)
           continue;
-        e1.Element(globalKey.c_str(), value);
+        e1.Element(globalKey, value);
       }
 
       if (this->Managed) {
@@ -676,6 +687,8 @@
 
       this->WritePlatformExtensions(e1);
     }
+
+    this->WriteDotNetDocumentationFile(e0);
     Elem(e0, "PropertyGroup").Attribute("Label", "UserMacros");
     this->WriteWinRTPackageCertificateKeyFile(e0);
     this->WritePathAndIncrementalLinkOptions(e0);
@@ -906,7 +919,19 @@
     }
   }
   for (auto const& tag : tags) {
-    e2.Element(tag.first.c_str(), tag.second);
+    e2.Element(tag.first, tag.second);
+  }
+}
+
+void cmVisualStudio10TargetGenerator::WriteDotNetDocumentationFile(Elem& e0)
+{
+  std::string const documentationFile =
+    this->GeneratorTarget->GetSafeProperty("VS_DOTNET_DOCUMENTATION_FILE");
+
+  if (this->ProjectType == csproj && !documentationFile.empty()) {
+    Elem e1(e0, "PropertyGroup");
+    Elem e2(e1, "DocumentationFile");
+    e2.Content(documentationFile);
   }
 }
 
@@ -1000,7 +1025,7 @@
             if (!tagName.empty()) {
               std::string value = props.GetPropertyValue(p);
               if (!value.empty()) {
-                e2.Element(tagName.c_str(), value);
+                e2.Element(tagName, value);
               }
             }
           }
@@ -1598,8 +1623,7 @@
   fout.write(magic, 3);
 
   fout << "<?xml version=\"1.0\" encoding=\""
-       << this->GlobalGenerator->Encoding() << "\"?>"
-       << "\n";
+       << this->GlobalGenerator->Encoding() << "\"?>";
   {
     Elem e0(fout, "Project");
     e0.Attribute("ToolsVersion", this->GlobalGenerator->GetToolsVersion());
@@ -1738,7 +1762,7 @@
     std::string const& filter = sourceGroup->GetFullName();
     std::string path = this->ConvertPath(source, s.RelativePath);
     ConvertToWindowsSlash(path);
-    Elem e2(e1, name.c_str());
+    Elem e2(e1, name);
     e2.Attribute("Include", path);
     if (!filter.empty()) {
       e2.Element("Filter", filter);
@@ -2624,9 +2648,9 @@
 
   // Some link options belong here.  Use them now and remove them so that
   // WriteLinkOptions does not use them.
-  const char* flags[] = { "LinkDelaySign", "LinkKeyFile", 0 };
-  for (const char** f = flags; *f; ++f) {
-    const char* flag = *f;
+  static const std::vector<std::string> flags{ "LinkDelaySign",
+                                               "LinkKeyFile" };
+  for (const std::string& flag : flags) {
     if (const char* value = linkOptions.GetFlag(flag)) {
       e1.WritePlatformConfigTag(flag, cond, value);
       linkOptions.RemoveFlag(flag);
@@ -2790,6 +2814,9 @@
     case csproj:
       this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName,
                                                    "CSharp");
+      cm::erase_if(targetDefines, [](std::string const& def) {
+        return def.find('=') != std::string::npos;
+      });
       break;
   }
   clOptions.AddDefines(targetDefines);
@@ -2818,10 +2845,8 @@
   }
 
   if (this->MSTools) {
-    // If we have the VS_WINRT_COMPONENT or CMAKE_VS_WINRT_BY_DEFAULT
-    // set then force Compile as WinRT.
-    if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT") ||
-        this->Makefile->IsOn("CMAKE_VS_WINRT_BY_DEFAULT")) {
+    // If we have the VS_WINRT_COMPONENT set then force Compile as WinRT
+    if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT")) {
       clOptions.AddFlag("CompileAsWinRT", "true");
       // For WinRT components, add the _WINRT_DLL define to produce a lib
       if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
@@ -2829,7 +2854,8 @@
         clOptions.AddDefine("_WINRT_DLL");
       }
     } else if (this->GlobalGenerator->TargetsWindowsStore() ||
-               this->GlobalGenerator->TargetsWindowsPhone()) {
+               this->GlobalGenerator->TargetsWindowsPhone() ||
+               this->Makefile->IsOn("CMAKE_VS_WINRT_BY_DEFAULT")) {
       if (!clOptions.IsWinRt()) {
         clOptions.AddFlag("CompileAsWinRT", "false");
       }
@@ -3626,18 +3652,7 @@
   this->AddLibraries(cli, libVec, vsTargetVec, config);
   if (cmContains(linkClosure->Languages, "CUDA") &&
       this->CudaOptions[config] != nullptr) {
-    switch (this->CudaOptions[config]->GetCudaRuntime()) {
-      case cmVisualStudioGeneratorOptions::CudaRuntimeStatic:
-        libVec.push_back("cudadevrt.lib");
-        libVec.push_back("cudart_static.lib");
-        break;
-      case cmVisualStudioGeneratorOptions::CudaRuntimeShared:
-        libVec.push_back("cudadevrt.lib");
-        libVec.push_back("cudart.lib");
-        break;
-      case cmVisualStudioGeneratorOptions::CudaRuntimeNone:
-        break;
-    }
+    this->CudaOptions[config]->FixCudaRuntime(this->GeneratorTarget);
   }
   std::string standardLibsVar =
     cmStrCat("CMAKE_", linkLanguage, "_STANDARD_LIBRARIES");
@@ -4027,8 +4042,8 @@
 }
 
 void cmVisualStudio10TargetGenerator::WriteEvent(
-  Elem& e1, const char* name, std::vector<cmCustomCommand> const& commands,
-  std::string const& configName)
+  Elem& e1, const std::string& name,
+  std::vector<cmCustomCommand> const& commands, std::string const& configName)
 {
   if (commands.empty()) {
     return;
@@ -4100,6 +4115,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) {
@@ -4847,7 +4865,7 @@
   Elem& e2, const std::map<std::string, std::string>& tags)
 {
   for (const auto& i : tags) {
-    e2.Element(i.first.c_str(), i.second);
+    e2.Element(i.first, i.second);
   }
 }
 
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index a18a33d..30027c9 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -79,6 +79,7 @@
   void WriteDotNetReference(Elem& e1, std::string const& ref,
                             std::string const& hint,
                             std::string const& config);
+  void WriteDotNetDocumentationFile(Elem& e0);
   void WriteImports(Elem& e0);
   void WriteDotNetReferenceCustomTags(Elem& e2, std::string const& ref);
   void WriteEmbeddedResourceGroup(Elem& e0);
@@ -164,7 +165,7 @@
   void WriteLibOptions(Elem& e1, std::string const& config);
   void WriteManifestOptions(Elem& e1, std::string const& config);
   void WriteEvents(Elem& e1, std::string const& configName);
-  void WriteEvent(Elem& e1, const char* name,
+  void WriteEvent(Elem& e1, std::string const& name,
                   std::vector<cmCustomCommand> const& commands,
                   std::string const& configName);
   void WriteGroupSources(Elem& e0, std::string const& name,
diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx
index 1139aa9..4004b66 100644
--- a/Source/cmVisualStudioGeneratorOptions.cxx
+++ b/Source/cmVisualStudioGeneratorOptions.cxx
@@ -3,6 +3,8 @@
 #include <cm/iterator>
 
 #include "cmAlgorithms.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
 #include "cmLocalVisualStudioGenerator.h"
 #include "cmOutputConverter.h"
 #include "cmSystemTools.h"
@@ -149,25 +151,33 @@
   return false;
 }
 
-cmVisualStudioGeneratorOptions::CudaRuntime
-cmVisualStudioGeneratorOptions::GetCudaRuntime() const
+void cmVisualStudioGeneratorOptions::FixCudaRuntime(cmGeneratorTarget* target)
 {
   std::map<std::string, FlagValue>::const_iterator i =
     this->FlagMap.find("CudaRuntime");
-  if (i != this->FlagMap.end() && i->second.size() == 1) {
-    std::string const& cudaRuntime = i->second[0];
-    if (cudaRuntime == "Static") {
-      return CudaRuntimeStatic;
-    }
-    if (cudaRuntime == "Shared") {
-      return CudaRuntimeShared;
-    }
-    if (cudaRuntime == "None") {
-      return CudaRuntimeNone;
+  if (i == this->FlagMap.end()) {
+    // User didn't provide am override so get the property value
+    const char* runtimeLibraryValue =
+      target->GetProperty("CUDA_RUNTIME_LIBRARY");
+    if (runtimeLibraryValue) {
+      std::string cudaRuntime =
+        cmSystemTools::UpperCase(cmGeneratorExpression::Evaluate(
+          runtimeLibraryValue, this->LocalGenerator, this->Configuration,
+          target));
+      if (cudaRuntime == "STATIC") {
+        this->AddFlag("CudaRuntime", "Static");
+      }
+      if (cudaRuntime == "SHARED") {
+        this->AddFlag("CudaRuntime", "Shared");
+      }
+      if (cudaRuntime == "NONE") {
+        this->AddFlag("CudaRuntime", "None");
+      }
+    } else {
+      // nvcc default is static
+      this->AddFlag("CudaRuntime", "Static");
     }
   }
-  // nvcc default is static
-  return CudaRuntimeStatic;
 }
 
 void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration()
@@ -431,7 +441,7 @@
   if (this->Defines.empty()) {
     return;
   }
-  const char* tag = "PreprocessorDefinitions";
+  std::string tag = "PreprocessorDefinitions";
   if (lang == "CUDA") {
     tag = "Defines";
   }
@@ -473,7 +483,7 @@
     return;
   }
 
-  const char* tag = "AdditionalIncludeDirectories";
+  std::string tag = "AdditionalIncludeDirectories";
   if (lang == "CUDA") {
     tag = "Include";
   } else if (lang == "ASM_MASM" || lang == "ASM_NASM") {
@@ -528,6 +538,6 @@
       sep = ";";
     }
 
-    this->OutputFlag(fout, indent, m.first.c_str(), oss.str());
+    this->OutputFlag(fout, indent, m.first, oss.str());
   }
 }
diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h
index 560593e..b335694 100644
--- a/Source/cmVisualStudioGeneratorOptions.h
+++ b/Source/cmVisualStudioGeneratorOptions.h
@@ -13,6 +13,7 @@
 #include "cmIDEOptions.h"
 
 class cmLocalVisualStudioGenerator;
+class cmGeneratorTarget;
 
 using cmVS7FlagTable = cmIDEFlagTable;
 
@@ -61,15 +62,8 @@
   bool UsingUnicode() const;
   bool UsingSBCS() const;
 
-  enum CudaRuntime
-  {
-    CudaRuntimeStatic,
-    CudaRuntimeShared,
-    CudaRuntimeNone
-  };
-  CudaRuntime GetCudaRuntime() const;
-
   void FixCudaCodeGeneration();
+  void FixCudaRuntime(cmGeneratorTarget* target);
 
   void FixManifestUACFlags();
 
@@ -86,7 +80,8 @@
   const std::string& GetConfiguration() const;
 
 protected:
-  virtual void OutputFlag(std::ostream& fout, int indent, const char* tag,
+  virtual void OutputFlag(std::ostream& fout, int indent,
+                          const std::string& tag,
                           const std::string& content) = 0;
 
 private:
diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx
index afc95f5..b34c2f6 100644
--- a/Source/cmXCodeScheme.cxx
+++ b/Source/cmXCodeScheme.cxx
@@ -8,13 +8,16 @@
 #include <utility>
 
 #include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmXMLSafe.h"
 
-cmXCodeScheme::cmXCodeScheme(cmXCodeObject* xcObj, TestObjects tests,
+cmXCodeScheme::cmXCodeScheme(cmLocalGenerator* lg, cmXCodeObject* xcObj,
+                             TestObjects tests,
                              const std::vector<std::string>& configList,
                              unsigned int xcVersion)
-  : Target(xcObj)
+  : LocalGenerator(lg)
+  , Target(xcObj)
   , Tests(std::move(tests))
   , TargetName(xcObj->GetTarget()->GetName())
   , ConfigList(configList)
@@ -135,7 +138,8 @@
   xout.Attribute("selectedLauncherIdentifier",
                  "Xcode.DebuggerFoundation.Launcher.LLDB");
   xout.Attribute("launchStyle", "0");
-  xout.Attribute("useCustomWorkingDirectory", "NO");
+  WriteCustomWorkingDirectory(xout, configuration);
+
   xout.Attribute("ignoresPersistentStateOnLaunch", "NO");
   WriteLaunchActionBooleanAttribute(xout, "debugDocumentVersioning",
                                     "XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING",
@@ -355,7 +359,7 @@
   xout.Attribute("buildConfiguration", configuration);
   xout.Attribute("shouldUseLaunchSchemeArgsEnv", "YES");
   xout.Attribute("savedToolIdentifier", "");
-  xout.Attribute("useCustomWorkingDirectory", "NO");
+  WriteCustomWorkingDirectory(xout, configuration);
   WriteLaunchActionBooleanAttribute(xout, "debugDocumentVersioning",
                                     "XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING",
                                     true);
@@ -395,6 +399,22 @@
   xout.EndElement();
 }
 
+void cmXCodeScheme::WriteCustomWorkingDirectory(
+  cmXMLWriter& xout, const std::string& configuration)
+{
+  std::string propertyValue = this->Target->GetTarget()->GetSafeProperty(
+    "XCODE_SCHEME_WORKING_DIRECTORY");
+  if (propertyValue.empty()) {
+    xout.Attribute("useCustomWorkingDirectory", "NO");
+  } else {
+    xout.Attribute("useCustomWorkingDirectory", "YES");
+
+    auto customWorkingDirectory = cmGeneratorExpression::Evaluate(
+      propertyValue, this->LocalGenerator, configuration);
+    xout.Attribute("customWorkingDirectory", customWorkingDirectory);
+  }
+}
+
 std::string cmXCodeScheme::WriteVersionString()
 {
   std::ostringstream v;
diff --git a/Source/cmXCodeScheme.h b/Source/cmXCodeScheme.h
index dff5e35..da40856 100644
--- a/Source/cmXCodeScheme.h
+++ b/Source/cmXCodeScheme.h
@@ -20,7 +20,7 @@
 public:
   using TestObjects = std::vector<const cmXCodeObject*>;
 
-  cmXCodeScheme(cmXCodeObject* xcObj, TestObjects tests,
+  cmXCodeScheme(cmLocalGenerator* lg, cmXCodeObject* xcObj, TestObjects tests,
                 const std::vector<std::string>& configList,
                 unsigned int xcVersion);
 
@@ -28,6 +28,7 @@
                               const std::string& container);
 
 private:
+  cmLocalGenerator* const LocalGenerator;
   const cmXCodeObject* const Target;
   const TestObjects Tests;
   const std::string& TargetName;
@@ -63,6 +64,9 @@
   void WriteBuildableReference(cmXMLWriter& xout, const cmXCodeObject* xcObj,
                                const std::string& container);
 
+  void WriteCustomWorkingDirectory(cmXMLWriter& xout,
+                                   const std::string& configuration);
+
   std::string WriteVersionString();
   std::string FindConfiguration(const std::string& name);
 
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index f63a264..a99d9a6 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -2,12 +2,27 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmake.h"
 
+#include <algorithm>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <initializer_list>
+#include <iostream>
+#include <sstream>
+#include <utility>
+
 #include <cm/memory>
 #include <cm/string_view>
 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
 #  include <cm/iterator>
 #endif
 
+#include <cmext/algorithm>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/Glob.hxx"
+#include "cmsys/RegularExpression.hxx"
+
 #include "cm_sys_stat.h"
 
 #include "cmAlgorithms.h"
@@ -56,6 +71,8 @@
 // include the generator
 #if defined(_WIN32) && !defined(__CYGWIN__)
 #  if !defined(CMAKE_BOOT_MINGW)
+#    include <cmext/memory>
+
 #    include "cmGlobalBorlandMakefileGenerator.h"
 #    include "cmGlobalJOMMakefileGenerator.h"
 #    include "cmGlobalNMakeMakefileGenerator.h"
@@ -106,19 +123,6 @@
 #  include <sys/time.h>
 #endif
 
-#include <algorithm>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <initializer_list>
-#include <iostream>
-#include <sstream>
-#include <utility>
-
-#include "cmsys/FStream.hxx"
-#include "cmsys/Glob.hxx"
-#include "cmsys/RegularExpression.hxx"
-
 namespace {
 
 #if !defined(CMAKE_BOOTSTRAP)
@@ -201,14 +205,7 @@
   }
 }
 
-cmake::~cmake()
-{
-  if (this->GlobalGenerator) {
-    delete this->GlobalGenerator;
-    this->GlobalGenerator = nullptr;
-  }
-  cmDeleteAll(this->Generators);
-}
+cmake::~cmake() = default;
 
 #if !defined(CMAKE_BOOTSTRAP)
 Json::Value cmake::ReportVersionJson() const
@@ -330,9 +327,8 @@
           }
         }
       } else {
-        std::cerr << "Parse error in command line argument: " << arg << "\n"
-                  << "Should be: VAR:type=value\n";
-        cmSystemTools::Error("No cmake script provided.");
+        cmSystemTools::Error("Parse error in command line argument: " + arg +
+                             "\n" + "Should be: VAR:type=value\n");
         return false;
       }
     } else if (cmHasLiteralPrefix(arg, "-W")) {
@@ -393,7 +389,7 @@
         }
       }
       cmsys::RegularExpression regex(
-        cmsys::Glob::PatternToRegex(entryPattern, true, true).c_str());
+        cmsys::Glob::PatternToRegex(entryPattern, true, true));
       // go through all cache entries and collect the vars which will be
       // removed
       std::vector<std::string> entriesToDelete;
@@ -422,7 +418,7 @@
           return false;
         }
       }
-      std::cout << "loading initial cache file " << path << "\n";
+      cmSystemTools::Stdout("loading initial cache file " + path + "\n");
       // Resolve script path specified on command line relative to $PWD.
       path = cmSystemTools::CollapseFullPath(path);
       this->ReadListFile(args, path);
@@ -462,12 +458,12 @@
 {
   // if a generator was not yet created, temporarily create one
   cmGlobalGenerator* gg = this->GetGlobalGenerator();
-  bool created = false;
 
   // if a generator was not specified use a generic one
+  std::unique_ptr<cmGlobalGenerator> gen;
   if (!gg) {
-    gg = new cmGlobalGenerator(this);
-    created = true;
+    gen = cm::make_unique<cmGlobalGenerator>(this);
+    gg = gen.get();
   }
 
   // read in the list file to fill the cache
@@ -489,11 +485,6 @@
       cmSystemTools::Error("Error processing file: " + path);
     }
   }
-
-  // free generic one if generated
-  if (created) {
-    delete gg;
-  }
 }
 
 bool cmake::FindPackage(const std::vector<std::string>& args)
@@ -501,9 +492,7 @@
   this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
   this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
 
-  // if a generator was not yet created, temporarily create one
-  cmGlobalGenerator* gg = new cmGlobalGenerator(this);
-  this->SetGlobalGenerator(gg);
+  this->SetGlobalGenerator(cm::make_unique<cmGlobalGenerator>(this));
 
   cmStateSnapshot snapshot = this->GetCurrentSnapshot();
   snapshot.GetDirectory().SetCurrentBinary(
@@ -512,8 +501,9 @@
     cmSystemTools::GetCurrentWorkingDirectory());
   // read in the list file to fill the cache
   snapshot.SetDefaultDefinitions();
-  cmMakefile* mf = new cmMakefile(gg, snapshot);
-  gg->AddMakefile(mf);
+  auto mfu = cm::make_unique<cmMakefile>(this->GetGlobalGenerator(), snapshot);
+  cmMakefile* mf = mfu.get();
+  this->GlobalGenerator->AddMakefile(std::move(mfu));
 
   mf->SetArgcArgv(args);
 
@@ -538,8 +528,8 @@
     std::string includes = mf->GetSafeDefinition("PACKAGE_INCLUDE_DIRS");
     std::vector<std::string> includeDirs = cmExpandedList(includes);
 
-    gg->CreateGenerationObjects();
-    cmLocalGenerator* lg = gg->LocalGenerators[0];
+    this->GlobalGenerator->CreateGenerationObjects();
+    const auto& lg = this->GlobalGenerator->LocalGenerators[0];
     std::string includeFlags =
       lg->GetIncludeFlags(includeDirs, nullptr, language);
 
@@ -549,7 +539,7 @@
     const char* targetName = "dummy";
     std::vector<std::string> srcs;
     cmTarget* tgt = mf->AddExecutable(targetName, srcs, true);
-    tgt->SetProperty("LINKER_LANGUAGE", language.c_str());
+    tgt->SetProperty("LINKER_LANGUAGE", language);
 
     std::string libs = mf->GetSafeDefinition("PACKAGE_LIBRARIES");
     std::vector<std::string> libList = cmExpandedList(libs);
@@ -565,8 +555,9 @@
     std::string linkPath;
     std::string flags;
     std::string linkFlags;
-    gg->CreateGenerationObjects();
-    cmGeneratorTarget* gtgt = gg->FindGeneratorTarget(tgt->GetName());
+    this->GlobalGenerator->CreateGenerationObjects();
+    cmGeneratorTarget* gtgt =
+      this->GlobalGenerator->FindGeneratorTarget(tgt->GetName());
     cmLocalGenerator* lg = gtgt->GetLocalGenerator();
     cmLinkLineComputer linkLineComputer(lg,
                                         lg->GetStateSnapshot().GetDirectory());
@@ -586,10 +577,6 @@
           }*/
   }
 
-  // free generic one if generated
-  //  this->SetGlobalGenerator(0); // setting 0-pointer is not possible
-  //  delete gg; // this crashes inside the cmake instance
-
   return packageFound;
 }
 
@@ -676,6 +663,8 @@
     } else if ((i < args.size() - 1) &&
                (arg.find("--check-stamp-list", 0) == 0)) {
       this->CheckStampList = args[++i];
+    } else if (arg == "--regenerate-during-build") {
+      this->RegenerateDuringBuild = true;
     }
 #if defined(CMAKE_HAVE_VS_GENERATORS)
     else if ((i < args.size() - 1) &&
@@ -735,6 +724,7 @@
         return;
       }
       this->SetLogLevel(logLevel);
+      this->LogLevelWasSetViaCLI = true;
     } else if (arg.find("--loglevel=", 0) == 0) {
       // This is supported for backward compatibility. This option only
       // appeared in the 3.15.x release series and was renamed to
@@ -746,10 +736,26 @@
         return;
       }
       this->SetLogLevel(logLevel);
+      this->LogLevelWasSetViaCLI = true;
+    } else if (arg == "--log-context") {
+      this->SetShowLogContext(true);
+    } else if (arg.find("--debug-find", 0) == 0) {
+      std::cout << "Running with debug output on for the `find` commands.\n";
+      this->SetDebugFindOutputOn(true);
     } else if (arg.find("--trace-expand", 0) == 0) {
       std::cout << "Running with expanded trace output on.\n";
       this->SetTrace(true);
       this->SetTraceExpand(true);
+    } else if (arg.find("--trace-format=", 0) == 0) {
+      this->SetTrace(true);
+      const auto traceFormat =
+        StringToTraceFormat(arg.substr(strlen("--trace-format=")));
+      if (traceFormat == TraceFormat::TRACE_UNDEFINED) {
+        cmSystemTools::Error("Invalid format specified for --trace-format. "
+                             "Valid formats are human, json-v1.");
+        return;
+      }
+      this->SetTraceFormat(traceFormat);
     } else if (arg.find("--trace-source=", 0) == 0) {
       std::string file = arg.substr(strlen("--trace-source="));
       cmSystemTools::ConvertToUnixSlashes(file);
@@ -821,7 +827,7 @@
         }
         value = args[i];
       }
-      cmGlobalGenerator* gen = this->CreateGlobalGenerator(value);
+      auto gen = this->CreateGlobalGenerator(value);
       if (!gen) {
         std::string kdevError;
         if (value.find("KDevelop3", 0) != std::string::npos) {
@@ -833,7 +839,7 @@
         this->PrintGeneratorList();
         return;
       }
-      this->SetGlobalGenerator(gen);
+      this->SetGlobalGenerator(std::move(gen));
     }
     // no option assume it is the path to the source or an existing build
     else {
@@ -890,6 +896,23 @@
   return (it != levels.cend()) ? it->second : LogLevel::LOG_UNDEFINED;
 }
 
+cmake::TraceFormat cmake::StringToTraceFormat(const std::string& traceStr)
+{
+  using TracePair = std::pair<std::string, TraceFormat>;
+  static const std::vector<TracePair> levels = {
+    { "human", TraceFormat::TRACE_HUMAN },
+    { "json-v1", TraceFormat::TRACE_JSON_V1 },
+  };
+
+  const auto traceStrLowCase = cmSystemTools::LowerCase(traceStr);
+
+  const auto it = std::find_if(levels.cbegin(), levels.cend(),
+                               [&traceStrLowCase](const TracePair& p) {
+                                 return p.first == traceStrLowCase;
+                               });
+  return (it != levels.cend()) ? it->second : TraceFormat::TRACE_UNDEFINED;
+}
+
 void cmake::SetTraceFile(const std::string& file)
 {
   this->TraceFile.close();
@@ -904,6 +927,48 @@
   std::cout << "Trace will be written to " << file << "\n";
 }
 
+void cmake::PrintTraceFormatVersion()
+{
+  if (!this->GetTrace()) {
+    return;
+  }
+
+  std::string msg;
+
+  switch (this->GetTraceFormat()) {
+    case TraceFormat::TRACE_JSON_V1: {
+#ifndef CMAKE_BOOTSTRAP
+      Json::Value val;
+      Json::Value version;
+      Json::StreamWriterBuilder builder;
+      builder["indentation"] = "";
+      version["major"] = 1;
+      version["minor"] = 0;
+      val["version"] = version;
+      msg = Json::writeString(builder, val);
+#endif
+      break;
+    }
+    case TraceFormat::TRACE_HUMAN:
+      msg = "";
+      break;
+    case TraceFormat::TRACE_UNDEFINED:
+      msg = "INTERNAL ERROR: Trace format is TRACE_UNDEFINED";
+      break;
+  }
+
+  if (msg.empty()) {
+    return;
+  }
+
+  auto& f = this->GetTraceFile();
+  if (f) {
+    f << msg << '\n';
+  } else {
+    cmSystemTools::Message(msg);
+  }
+}
+
 void cmake::SetDirectoriesFromFile(const std::string& arg)
 {
   // Check if the argument refers to a CMakeCache.txt or
@@ -1042,11 +1107,11 @@
 void cmake::GetRegisteredGenerators(std::vector<GeneratorInfo>& generators,
                                     bool includeNamesWithPlatform) const
 {
-  for (cmGlobalGeneratorFactory* gen : this->Generators) {
+  for (const auto& gen : this->Generators) {
     std::vector<std::string> names = gen->GetGeneratorNames();
 
     if (includeNamesWithPlatform) {
-      cmAppend(names, gen->GetGeneratorNamesWithPlatform());
+      cm::append(names, gen->GetGeneratorNamesWithPlatform());
     }
 
     for (std::string const& name : names) {
@@ -1091,7 +1156,8 @@
   }
 }
 
-static std::pair<cmExternalMakefileProjectGenerator*, std::string>
+static std::pair<std::unique_ptr<cmExternalMakefileProjectGenerator>,
+                 std::string>
 createExtraGenerator(
   const std::vector<cmExternalMakefileProjectGeneratorFactory*>& in,
   const std::string& name)
@@ -1114,15 +1180,17 @@
   return { nullptr, name };
 }
 
-cmGlobalGenerator* cmake::CreateGlobalGenerator(const std::string& gname)
+std::unique_ptr<cmGlobalGenerator> cmake::CreateGlobalGenerator(
+  const std::string& gname)
 {
-  std::pair<cmExternalMakefileProjectGenerator*, std::string> extra =
-    createExtraGenerator(this->ExtraGenerators, gname);
-  cmExternalMakefileProjectGenerator* extraGenerator = extra.first;
-  const std::string name = extra.second;
+  std::pair<std::unique_ptr<cmExternalMakefileProjectGenerator>, std::string>
+    extra = createExtraGenerator(this->ExtraGenerators, gname);
+  std::unique_ptr<cmExternalMakefileProjectGenerator>& extraGenerator =
+    extra.first;
+  const std::string& name = extra.second;
 
-  cmGlobalGenerator* generator = nullptr;
-  for (cmGlobalGeneratorFactory* g : this->Generators) {
+  std::unique_ptr<cmGlobalGenerator> generator;
+  for (const auto& g : this->Generators) {
     generator = g->CreateGlobalGenerator(name, this);
     if (generator) {
       break;
@@ -1130,9 +1198,7 @@
   }
 
   if (generator) {
-    generator->SetExternalMakefileProjectGenerator(extraGenerator);
-  } else {
-    delete extraGenerator;
+    generator->SetExternalMakefileProjectGenerator(std::move(extraGenerator));
   }
 
   return generator;
@@ -1184,15 +1250,13 @@
   return cachePath;
 }
 
-void cmake::SetGlobalGenerator(cmGlobalGenerator* gg)
+void cmake::SetGlobalGenerator(std::unique_ptr<cmGlobalGenerator> gg)
 {
   if (!gg) {
     cmSystemTools::Error("Error SetGlobalGenerator called with null");
     return;
   }
-  // delete the old generator
   if (this->GlobalGenerator) {
-    delete this->GlobalGenerator;
     // restore the original environment variables CXX and CC
     // Restore CC
     std::string env = "CC=";
@@ -1208,7 +1272,7 @@
   }
 
   // set the new
-  this->GlobalGenerator = gg;
+  this->GlobalGenerator = std::move(gg);
 
   // set the global flag for unix style paths on cmSystemTools as soon as
   // the generator is set.  This allows gmake to be used on windows.
@@ -1571,7 +1635,7 @@
     }
   }
 
-  cmMakefile* mf = this->GlobalGenerator->GetMakefiles()[0];
+  auto& mf = this->GlobalGenerator->GetMakefiles()[0];
   if (mf->IsOn("CTEST_USE_LAUNCHERS") &&
       !this->State->GetGlobalProperty("RULE_LAUNCH_COMPILE")) {
     cmSystemTools::Error(
@@ -1592,13 +1656,12 @@
 std::unique_ptr<cmGlobalGenerator> cmake::EvaluateDefaultGlobalGenerator()
 {
   if (!this->EnvironmentGenerator.empty()) {
-    cmGlobalGenerator* gen =
-      this->CreateGlobalGenerator(this->EnvironmentGenerator);
+    auto gen = this->CreateGlobalGenerator(this->EnvironmentGenerator);
     if (!gen) {
       cmSystemTools::Error("CMAKE_GENERATOR was set but the specified "
                            "generator doesn't exist. Using CMake default.");
     } else {
-      return std::unique_ptr<cmGlobalGenerator>(gen);
+      return gen;
     }
   }
 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
@@ -1648,13 +1711,14 @@
       }
     }
   }
-  cmGlobalGenerator* gen = this->CreateGlobalGenerator(found);
+  auto gen = this->CreateGlobalGenerator(found);
   if (!gen) {
-    gen = new cmGlobalNMakeMakefileGenerator(this);
+    gen = cm::make_unique<cmGlobalNMakeMakefileGenerator>(this);
   }
-  return std::unique_ptr<cmGlobalGenerator>(gen);
+  return std::unique_ptr<cmGlobalGenerator>(std::move(gen));
 #else
-  return cm::make_unique<cmGlobalUnixMakefileGenerator3>(this);
+  return std::unique_ptr<cmGlobalGenerator>(
+    cm::make_unique<cmGlobalUnixMakefileGenerator3>(this));
 #endif
 }
 
@@ -1665,7 +1729,7 @@
   // This print could be unified for all platforms
   std::cout << "-- Building for: " << gen->GetName() << "\n";
 #endif
-  this->SetGlobalGenerator(gen.release());
+  this->SetGlobalGenerator(std::move(gen));
 }
 
 void cmake::PreLoadCMakeFiles()
@@ -1696,6 +1760,11 @@
     return -1;
   }
 
+  // Log the trace format version to the desired output
+  if (this->GetTrace()) {
+    this->PrintTraceFormatVersion();
+  }
+
   // If we are given a stamp list file check if it is really out of date.
   if (!this->CheckStampList.empty() &&
       cmakeCheckStampList(this->CheckStampList)) {
@@ -1763,10 +1832,11 @@
       cmSystemTools::Message("CMake Configure step failed.  "
                              "Build files cannot be regenerated correctly.  "
                              "Attempting to stop IDE build.");
-      cmGlobalVisualStudioGenerator* gg =
-        static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator);
-      gg->CallVisualStudioMacro(cmGlobalVisualStudioGenerator::MacroStop,
-                                this->VSSolutionFile);
+      cmGlobalVisualStudioGenerator& gg =
+        cm::static_reference_cast<cmGlobalVisualStudioGenerator>(
+          this->GlobalGenerator);
+      gg.CallVisualStudioMacro(cmGlobalVisualStudioGenerator::MacroStop,
+                               this->VSSolutionFile);
     }
 #endif
     return ret;
@@ -1916,6 +1986,7 @@
   this->Generators.push_back(cmGlobalGhsMultiGenerator::NewFactory());
 #  endif
   this->Generators.push_back(cmGlobalNinjaGenerator::NewFactory());
+  this->Generators.push_back(cmGlobalNinjaMultiGenerator::NewFactory());
 #endif
 #if defined(CMAKE_USE_WMAKE)
   this->Generators.push_back(cmGlobalWatcomWMakeGenerator::NewFactory());
@@ -2021,7 +2092,7 @@
   const std::string defaultName = defaultGenerator->GetName();
   bool foundDefaultOne = false;
 
-  for (cmGlobalGeneratorFactory* g : this->Generators) {
+  for (const auto& g : this->Generators) {
     cmDocumentationEntry e;
     g->GetDocumentation(e);
     if (!foundDefaultOne && cmHasPrefix(e.Name, defaultName)) {
@@ -2161,12 +2232,12 @@
     }
 
     // Create the generator and use it to clear the dependencies.
-    std::unique_ptr<cmGlobalGenerator> ggd(
-      this->CreateGlobalGenerator(genName));
+    std::unique_ptr<cmGlobalGenerator> ggd =
+      this->CreateGlobalGenerator(genName);
     if (ggd) {
       cm.GetCurrentSnapshot().SetDefaultDefinitions();
       cmMakefile mfd(ggd.get(), cm.GetCurrentSnapshot());
-      std::unique_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator(&mfd));
+      auto lgd = ggd->CreateLocalGenerator(&mfd);
       lgd->ClearDependencies(&mfd, verbose);
     }
   }
@@ -2287,7 +2358,7 @@
 void cmake::GenerateGraphViz(const std::string& fileName) const
 {
 #ifndef CMAKE_BOOTSTRAP
-  cmGraphVizWriter gvWriter(this->GetGlobalGenerator());
+  cmGraphVizWriter gvWriter(fileName, this->GetGlobalGenerator());
 
   std::string settingsFile =
     cmStrCat(this->GetHomeOutputDirectory(), "/CMakeGraphVizOptions.cmake");
@@ -2295,9 +2366,8 @@
     cmStrCat(this->GetHomeDirectory(), "/CMakeGraphVizOptions.cmake");
 
   gvWriter.ReadSettings(settingsFile, fallbackSettingsFile);
-  gvWriter.WritePerTargetFiles(fileName);
-  gvWriter.WriteTargetDependersFiles(fileName);
-  gvWriter.WriteGlobalFile(fileName);
+
+  gvWriter.Write();
 
 #endif
 }
@@ -2307,7 +2377,7 @@
   this->State->SetGlobalProperty(prop, value);
 }
 
-void cmake::AppendProperty(const std::string& prop, const char* value,
+void cmake::AppendProperty(const std::string& prop, const std::string& value,
                            bool asString)
 {
   this->State->AppendGlobalProperty(prop, value, asString);
@@ -2376,12 +2446,12 @@
         }
         value = args[i];
       }
-      cmGlobalGenerator* gen = this->CreateGlobalGenerator(value);
+      auto gen = this->CreateGlobalGenerator(value);
       if (!gen) {
         cmSystemTools::Error("Could not create named generator " + value);
         this->PrintGeneratorList();
       } else {
-        this->SetGlobalGenerator(gen);
+        this->SetGlobalGenerator(std::move(gen));
       }
     }
     // no option assume it is the output file
@@ -2593,26 +2663,37 @@
     std::cerr << "Error: could not find CMAKE_GENERATOR in Cache\n";
     return 1;
   }
-  cmGlobalGenerator* gen = this->CreateGlobalGenerator(cachedGenerator);
+  auto gen = this->CreateGlobalGenerator(cachedGenerator);
   if (!gen) {
     std::cerr << "Error: could create CMAKE_GENERATOR \"" << cachedGenerator
               << "\"\n";
     return 1;
   }
-  this->SetGlobalGenerator(gen);
+  this->SetGlobalGenerator(std::move(gen));
   const char* cachedGeneratorInstance =
     this->State->GetCacheEntryValue("CMAKE_GENERATOR_INSTANCE");
   if (cachedGeneratorInstance) {
-    cmMakefile mf(gen, this->GetCurrentSnapshot());
-    if (!gen->SetGeneratorInstance(cachedGeneratorInstance, &mf)) {
+    cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot());
+    if (!this->GlobalGenerator->SetGeneratorInstance(cachedGeneratorInstance,
+                                                     &mf)) {
       return 1;
     }
   }
   const char* cachedGeneratorPlatform =
     this->State->GetCacheEntryValue("CMAKE_GENERATOR_PLATFORM");
   if (cachedGeneratorPlatform) {
-    cmMakefile mf(gen, this->GetCurrentSnapshot());
-    if (!gen->SetGeneratorPlatform(cachedGeneratorPlatform, &mf)) {
+    cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot());
+    if (!this->GlobalGenerator->SetGeneratorPlatform(cachedGeneratorPlatform,
+                                                     &mf)) {
+      return 1;
+    }
+  }
+  const char* cachedGeneratorToolset =
+    this->State->GetCacheEntryValue("CMAKE_GENERATOR_TOOLSET");
+  if (cachedGeneratorToolset) {
+    cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot());
+    if (!this->GlobalGenerator->SetGeneratorToolset(cachedGeneratorToolset,
+                                                    true, &mf)) {
       return 1;
     }
   }
@@ -2687,10 +2768,15 @@
   }
 #endif
 
-  gen->PrintBuildCommandAdvice(std::cerr, jobs);
-  return gen->Build(jobs, "", dir, projName, targets, output, "", config,
-                    clean, false, verbose, cmDuration::zero(),
-                    cmSystemTools::OUTPUT_PASSTHROUGH, nativeOptions);
+  if (!this->GlobalGenerator->ReadCacheEntriesForBuild(*this->State)) {
+    return 1;
+  }
+
+  this->GlobalGenerator->PrintBuildCommandAdvice(std::cerr, jobs);
+  return this->GlobalGenerator->Build(
+    jobs, "", dir, projName, targets, output, "", config, clean, false,
+    verbose, cmDuration::zero(), cmSystemTools::OUTPUT_PASSTHROUGH,
+    nativeOptions);
 }
 
 bool cmake::Open(const std::string& dir, bool dryRun)
@@ -2718,8 +2804,8 @@
     cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
       genName, extraGenName ? *extraGenName : "");
 
-  std::unique_ptr<cmGlobalGenerator> gen(
-    this->CreateGlobalGenerator(fullName));
+  std::unique_ptr<cmGlobalGenerator> gen =
+    this->CreateGlobalGenerator(fullName);
   if (!gen) {
     std::cerr << "Error: could create CMAKE_GENERATOR \"" << fullName
               << "\"\n";
diff --git a/Source/cmake.h b/Source/cmake.h
index 687c105..35425ec 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -5,12 +5,15 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include <cstddef>
 #include <functional>
 #include <map>
 #include <memory>
 #include <set>
+#include <stack>
 #include <string>
 #include <unordered_set>
+#include <utility>
 #include <vector>
 
 #include "cmGeneratedFileStream.h"
@@ -110,6 +113,14 @@
     LOG_TRACE
   };
 
+  /** \brief Define supported trace formats **/
+  enum TraceFormat
+  {
+    TRACE_UNDEFINED,
+    TRACE_HUMAN,
+    TRACE_JSON_V1,
+  };
+
   struct GeneratorInfo
   {
     std::string name;
@@ -202,21 +213,25 @@
   void PreLoadCMakeFiles();
 
   //! Create a GlobalGenerator
-  cmGlobalGenerator* CreateGlobalGenerator(const std::string& name);
+  std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
+    const std::string& name);
 
   //! Return the global generator assigned to this instance of cmake
-  cmGlobalGenerator* GetGlobalGenerator() { return this->GlobalGenerator; }
+  cmGlobalGenerator* GetGlobalGenerator()
+  {
+    return this->GlobalGenerator.get();
+  }
   //! Return the global generator assigned to this instance of cmake, const
   const cmGlobalGenerator* GetGlobalGenerator() const
   {
-    return this->GlobalGenerator;
+    return this->GlobalGenerator.get();
   }
 
   //! Return the full path to where the CMakeCache.txt file should be.
   static std::string FindCacheFile(const std::string& binaryDir);
 
   //! Return the global generator assigned to this instance of cmake
-  void SetGlobalGenerator(cmGlobalGenerator*);
+  void SetGlobalGenerator(std::unique_ptr<cmGlobalGenerator>);
 
   //! Get the names of the current registered generators
   void GetRegisteredGenerators(std::vector<GeneratorInfo>& generators,
@@ -344,7 +359,7 @@
 
   //! Set/Get a property of this target file
   void SetProperty(const std::string& prop, const char* value);
-  void AppendProperty(const std::string& prop, const char* value,
+  void AppendProperty(const std::string& prop, const std::string& value,
                       bool asString = false);
   const char* GetProperty(const std::string& prop);
   bool GetPropertyAsBool(const std::string& prop);
@@ -380,20 +395,52 @@
    */
   cmFileTimeCache* GetFileTimeCache() { return this->FileTimeCache.get(); }
 
+  bool WasLogLevelSetViaCLI() const { return this->LogLevelWasSetViaCLI; }
+
   //! Get the selected log level for `message()` commands during the cmake run.
   LogLevel GetLogLevel() const { return this->MessageLogLevel; }
   void SetLogLevel(LogLevel level) { this->MessageLogLevel = level; }
   static LogLevel StringToLogLevel(const std::string& levelStr);
+  static TraceFormat StringToTraceFormat(const std::string& levelStr);
+
+  bool HasCheckInProgress() const
+  {
+    return !this->CheckInProgressMessages.empty();
+  }
+  std::size_t GetCheckInProgressSize() const
+  {
+    return this->CheckInProgressMessages.size();
+  }
+  std::string GetTopCheckInProgressMessage()
+  {
+    auto message = this->CheckInProgressMessages.top();
+    this->CheckInProgressMessages.pop();
+    return message;
+  }
+  void PushCheckInProgressMessage(std::string message)
+  {
+    this->CheckInProgressMessages.emplace(std::move(message));
+  }
+
+  //! Should `message` command display context.
+  bool GetShowLogContext() const { return this->LogContext; }
+  void SetShowLogContext(bool b) { this->LogContext = b; }
 
   //! Do we want debug output during the cmake run.
   bool GetDebugOutput() { return this->DebugOutput; }
   void SetDebugOutputOn(bool b) { this->DebugOutput = b; }
 
+  //! Do we want debug output from the find commands during the cmake run.
+  bool GetDebugFindOutput() { return this->DebugFindOutput; }
+  void SetDebugFindOutputOn(bool b) { this->DebugFindOutput = b; }
+
   //! Do we want trace output during the cmake run.
-  bool GetTrace() { return this->Trace; }
+  bool GetTrace() const { return this->Trace; }
   void SetTrace(bool b) { this->Trace = b; }
-  bool GetTraceExpand() { return this->TraceExpand; }
+  bool GetTraceExpand() const { return this->TraceExpand; }
   void SetTraceExpand(bool b) { this->TraceExpand = b; }
+  TraceFormat GetTraceFormat() const { return this->TraceFormatVar; }
+  void SetTraceFormat(TraceFormat f) { this->TraceFormatVar = f; }
   void AddTraceSource(std::string const& file)
   {
     this->TraceOnlyThisSources.push_back(file);
@@ -404,6 +451,7 @@
   }
   cmGeneratedFileStream& GetTraceFile() { return this->TraceFile; }
   void SetTraceFile(std::string const& file);
+  void PrintTraceFormatVersion();
 
   bool GetWarnUninitialized() { return this->WarnUninitialized; }
   void SetWarnUninitialized(bool b) { this->WarnUninitialized = b; }
@@ -499,11 +547,14 @@
   }
   cmStateSnapshot GetCurrentSnapshot() const { return this->CurrentSnapshot; }
 
+  bool GetRegenerateDuringBuild() const { return this->RegenerateDuringBuild; }
+
 protected:
   void RunCheckForUnusedVariables();
   int HandleDeleteCacheVariables(const std::string& var);
 
-  using RegisteredGeneratorsVector = std::vector<cmGlobalGeneratorFactory*>;
+  using RegisteredGeneratorsVector =
+    std::vector<std::unique_ptr<cmGlobalGeneratorFactory>>;
   RegisteredGeneratorsVector Generators;
   using RegisteredExtraGeneratorsVector =
     std::vector<cmExternalMakefileProjectGeneratorFactory*>;
@@ -513,7 +564,6 @@
   void AddDefaultGenerators();
   void AddDefaultExtraGenerators();
 
-  cmGlobalGenerator* GlobalGenerator = nullptr;
   std::map<std::string, DiagLevel> DiagLevels;
   std::string GeneratorInstance;
   std::string GeneratorPlatform;
@@ -549,8 +599,10 @@
   ProgressCallbackType ProgressCallback;
   WorkingMode CurrentWorkingMode = NORMAL_MODE;
   bool DebugOutput = false;
+  bool DebugFindOutput = false;
   bool Trace = false;
   bool TraceExpand = false;
+  TraceFormat TraceFormatVar = TRACE_HUMAN;
   cmGeneratedFileStream TraceFile;
   bool WarnUninitialized = false;
   bool WarnUnused = false;
@@ -571,6 +623,7 @@
   FileExtensions FortranFileExtensions;
   bool ClearBuildSystem = false;
   bool DebugTryCompile = false;
+  bool RegenerateDuringBuild = false;
   std::unique_ptr<cmFileTimeCache> FileTimeCache;
   std::string GraphVizFile;
   InstalledFilesMap InstalledFiles;
@@ -587,6 +640,12 @@
   std::vector<std::string> TraceOnlyThisSources;
 
   LogLevel MessageLogLevel = LogLevel::LOG_STATUS;
+  bool LogLevelWasSetViaCLI = false;
+  bool LogContext = false;
+
+  std::stack<std::string> CheckInProgressMessages;
+
+  std::unique_ptr<cmGlobalGenerator> GlobalGenerator;
 
   void UpdateConversionPathTable();
 
@@ -714,4 +773,11 @@
   FOR_EACH_CXX11_FEATURE(F)                                                   \
   FOR_EACH_CXX14_FEATURE(F)
 
+#define FOR_EACH_CUDA_FEATURE(F)                                              \
+  F(cuda_std_03)                                                              \
+  F(cuda_std_11)                                                              \
+  F(cuda_std_14)                                                              \
+  F(cuda_std_17)                                                              \
+  F(cuda_std_20)
+
 #endif
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index 6d3e6ee..494d5d9 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -1,7 +1,16 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
 
-#include "cmAlgorithms.h"
+#include <cassert>
+#include <cctype>
+#include <climits>
+#include <cstring>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <cmext/algorithm>
+
 #include "cmDocumentationEntry.h" // IWYU pragma: keep
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
@@ -24,14 +33,6 @@
 #  include "cmsys/ConsoleBuf.hxx"
 #endif
 
-#include <cassert>
-#include <cctype>
-#include <climits>
-#include <cstring>
-#include <iostream>
-#include <string>
-#include <vector>
-
 namespace {
 #ifndef CMAKE_BOOTSTRAP
 const char* cmDocumentationName[][2] = {
@@ -73,12 +74,15 @@
   { "--log-level=<ERROR|WARNING|NOTICE|STATUS|VERBOSE|DEBUG|TRACE>",
     "Set the verbosity of messages from CMake files. "
     "--loglevel is also accepted for backward compatibility reasons." },
+  { "--log-context", "Prepend log messages with context, if given" },
   { "--debug-trycompile",
     "Do not delete the try_compile build tree. Only "
     "useful on one try_compile at a time." },
   { "--debug-output", "Put cmake in a debug mode." },
+  { "--debug-find", "Put cmake find in a debug mode." },
   { "--trace", "Put cmake in trace mode." },
   { "--trace-expand", "Put cmake in trace mode with variable expansion." },
+  { "--trace-format=<human|json-v1>", "Set the output format of the trace." },
   { "--trace-source=<file>",
     "Trace only this CMake file/module. Multiple options allowed." },
   { "--trace-redirect=<file>",
@@ -99,7 +103,7 @@
   std::vector<std::string> args;
   args.reserve(ac - 1);
   args.emplace_back(av[0]);
-  cmAppend(args, av + 2, av + ac);
+  cm::append(args, av + 2, av + ac);
   return cmcmd::ExecuteCMakeCommand(args);
 }
 
@@ -346,7 +350,7 @@
 #else
   int jobs = cmake::NO_BUILD_PARALLEL_LEVEL;
   std::vector<std::string> targets;
-  std::string config = "Debug";
+  std::string config;
   std::string dir;
   std::vector<std::string> nativeOptions;
   bool cleanFirst = false;
@@ -682,7 +686,6 @@
   ac = args.argc();
   av = args.argv();
 
-  cmSystemTools::EnableMSVCDebugHook();
   cmSystemTools::InitializeLibUV();
   cmSystemTools::FindCMakeResources(av[0]);
   if (ac > 1) {
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index d05e3c8..7eeb97f 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -2,6 +2,12 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmcmd.h"
 
+#include <cmext/algorithm>
+
+#include <fcntl.h>
+
+#include "cm_uv.h"
+
 #include "cmAlgorithms.h"
 #include "cmDuration.h"
 #include "cmGlobalGenerator.h"
@@ -15,22 +21,22 @@
 #include "cmStateSnapshot.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmUVProcessChain.h"
 #include "cmUtils.hxx"
 #include "cmVersion.h"
 #include "cmake.h"
 
 #if !defined(CMAKE_BOOTSTRAP)
 #  include "cmDependsFortran.h" // For -E cmake_copy_f90_mod callback.
+#  include "cmFileTime.h"
 #  include "cmServer.h"
 #  include "cmServerConnection.h"
+
+#  include "bindexplib.h"
 #endif
 
 #if !defined(CMAKE_BOOTSTRAP) && defined(_WIN32)
 #  include "cmsys/ConsoleBuf.hxx"
-
-#  include "cmFileTime.h"
-
-#  include "bindexplib.h"
 #endif
 
 #if !defined(CMAKE_BOOTSTRAP) && defined(_WIN32) && !defined(__CYGWIN__)
@@ -107,10 +113,12 @@
     << "  sha384sum <file>...       - create SHA384 checksum of files\n"
     << "  sha512sum <file>...       - create SHA512 checksum of files\n"
     << "  remove [-f] <file>...     - remove the file(s), use -f to force "
-       "it\n"
-    << "  remove_directory <dir>... - remove directories and their contents\n"
+       "it (deprecated: use rm instead)\n"
+    << "  remove_directory <dir>... - remove directories and their contents (deprecated: use rm instead)\n"
     << "  rename oldname newname    - rename a file or directory "
        "(on one volume)\n"
+    << "  rm [-rRf] <file/dir>...    - remove files or directories, use -f to "
+       "force it, r or R to remove directories and their contents recursively\n"
     << "  server                    - start cmake in server mode\n"
     << "  sleep <number>...         - sleep for given number of seconds\n"
     << "  tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n"
@@ -172,6 +180,24 @@
   return true;
 }
 
+static bool cmRemoveDirectory(const std::string& dir, bool recursive = true)
+{
+  if (cmSystemTools::FileIsSymlink(dir)) {
+    if (!cmSystemTools::RemoveFile(dir)) {
+      std::cerr << "Error removing directory symlink \"" << dir << "\".\n";
+      return false;
+    }
+  } else if (!recursive) {
+    std::cerr << "Error removing directory \"" << dir
+              << "\" without recursive option.\n";
+    return false;
+  } else if (!cmSystemTools::RemoveADirectory(dir)) {
+    std::cerr << "Error removing directory \"" << dir << "\".\n";
+    return false;
+  }
+  return true;
+}
+
 static int HandleIWYU(const std::string& runCmd,
                       const std::string& /* sourceFile */,
                       const std::vector<std::string>& orig_cmd)
@@ -179,7 +205,7 @@
   // Construct the iwyu command line by taking what was given
   // and adding all the arguments we give to the compiler.
   std::vector<std::string> iwyu_cmd = cmExpandedList(runCmd, true);
-  cmAppend(iwyu_cmd, orig_cmd.begin() + 1, orig_cmd.end());
+  cm::append(iwyu_cmd, orig_cmd.begin() + 1, orig_cmd.end());
   // Run the iwyu command line.  Capture its stderr and hide its stdout.
   // Ignore its return code because the tool always returns non-zero.
   std::string stdErr;
@@ -210,7 +236,7 @@
   std::vector<std::string> tidy_cmd = cmExpandedList(runCmd, true);
   tidy_cmd.push_back(sourceFile);
   tidy_cmd.emplace_back("--");
-  cmAppend(tidy_cmd, orig_cmd);
+  cm::append(tidy_cmd, orig_cmd);
 
   // Run the tidy command line.  Capture its stdout and hide its stderr.
   std::string stdOut;
@@ -561,11 +587,11 @@
       return 0;
     }
 
-#if defined(_WIN32) && !defined(CMAKE_BOOTSTRAP)
-    else if (args[1] == "__create_def") {
+#if !defined(CMAKE_BOOTSTRAP)
+    if (args[1] == "__create_def") {
       if (args.size() < 4) {
         std::cerr << "__create_def Usage: -E __create_def outfile.def "
-                     "objlistfile [-nm=nm-path]\n";
+                     "objlistfile [--nm=nm-path]\n";
         return 1;
       }
       cmsys::ifstream fin(args[3].c_str(), std::ios::in | std::ios::binary);
@@ -592,7 +618,7 @@
           return 0;
         }
       }
-      FILE* fout = cmsys::SystemTools::Fopen(args[2].c_str(), "w+");
+      FILE* fout = cmsys::SystemTools::Fopen(args[2], "w+");
       if (!fout) {
         std::cerr << "could not open output .def file: " << args[2].c_str()
                   << "\n";
@@ -706,14 +732,7 @@
       bool return_value = false;
       for (auto const& arg : cmMakeRange(args).advance(2)) {
         if (cmSystemTools::FileIsDirectory(arg)) {
-          if (cmSystemTools::FileIsSymlink(arg)) {
-            if (!cmSystemTools::RemoveFile(arg)) {
-              std::cerr << "Error removing directory symlink \"" << arg
-                        << "\".\n";
-              return_value = true;
-            }
-          } else if (!cmSystemTools::RemoveADirectory(arg)) {
-            std::cerr << "Error removing directory \"" << arg << "\".\n";
+          if (!cmRemoveDirectory(arg)) {
             return_value = true;
           }
         }
@@ -739,6 +758,65 @@
       return 0;
     }
 
+    // Remove directories or files with rm
+    if (args[1] == "rm" && args.size() > 2) {
+      // If an error occurs, we want to continue removing the remaining
+      // files/directories.
+      int return_value = 0;
+      bool force = false;
+      bool recursive = false;
+      bool doing_options = true;
+      bool at_least_one_file = false;
+      for (auto const& arg : cmMakeRange(args).advance(2)) {
+        if (doing_options && cmHasLiteralPrefix(arg, "-")) {
+          if (arg == "--") {
+            doing_options = false;
+          }
+          if (arg.find('f') != std::string::npos) {
+            force = true;
+          }
+          if (arg.find_first_of("rR") != std::string::npos) {
+            recursive = true;
+          }
+          if (arg.find_first_not_of("-frR") != std::string::npos) {
+            cmSystemTools::Error("Unknown -E rm argument: " + arg);
+            return 1;
+          }
+        } else {
+          if (arg.empty()) {
+            continue;
+          }
+          at_least_one_file = true;
+          // Complain if the -f option was not given and
+          // either file does not exist or
+          // file could not be removed and still exists
+          bool file_exists_or_forced_remove = cmSystemTools::FileExists(arg) ||
+            cmSystemTools::FileIsSymlink(arg) || force;
+          if (cmSystemTools::FileIsDirectory(arg)) {
+            if (!cmRemoveDirectory(arg, recursive)) {
+              return_value = 1;
+            }
+          } else if ((!file_exists_or_forced_remove) ||
+                     (!cmSystemTools::RemoveFile(arg) &&
+                      cmSystemTools::FileExists(arg))) {
+            if (!file_exists_or_forced_remove) {
+              cmSystemTools::Error(
+                "File to remove does not exist and force is not set: " + arg);
+            } else {
+              cmSystemTools::Error("File can't be removed and still exist: " +
+                                   arg);
+            }
+            return_value = 1;
+          }
+        }
+      }
+      if (!at_least_one_file) {
+        cmSystemTools::Error("Missing file/directory to remove");
+        return 1;
+      }
+      return return_value;
+    }
+
     // Touch file
     if (args[1] == "touch" && args.size() > 2) {
       for (auto const& arg : cmMakeRange(args).advance(2)) {
@@ -1007,13 +1085,13 @@
       cm.SetHomeDirectory(homeDir);
       cm.SetHomeOutputDirectory(homeOutDir);
       cm.GetCurrentSnapshot().SetDefaultDefinitions();
-      if (cmGlobalGenerator* ggd = cm.CreateGlobalGenerator(gen)) {
-        cm.SetGlobalGenerator(ggd);
+      if (auto ggd = cm.CreateGlobalGenerator(gen)) {
+        cm.SetGlobalGenerator(std::move(ggd));
         cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
         snapshot.GetDirectory().SetCurrentBinary(startOutDir);
         snapshot.GetDirectory().SetCurrentSource(startDir);
-        cmMakefile mf(ggd, snapshot);
-        std::unique_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator(&mf));
+        cmMakefile mf(cm.GetGlobalGenerator(), snapshot);
+        auto lgd = cm.GetGlobalGenerator()->CreateLocalGenerator(&mf);
 
         // Actually scan dependencies.
         return lgd->UpdateDependencies(depInfo, verbose, color) ? 0 : 2;
@@ -1056,6 +1134,10 @@
       return cmcmd::VisualStudioLink(args, 2);
     }
 
+    if (args[1] == "cmake_llvm_rc") {
+      return cmcmd::RunLLVMRC(args);
+    }
+
     // Internal CMake color makefile support.
     if (args[1] == "cmake_echo_color") {
       return cmcmd::ExecuteEchoColor(args);
@@ -1587,6 +1669,108 @@
   return -1;
 }
 
+int cmcmd::RunPreprocessor(const std::vector<std::string>& command,
+                           const std::string& intermediate_file)
+{
+
+  cmUVProcessChainBuilder builder;
+
+  uv_fs_t fs_req;
+  int preprocessedFile =
+    uv_fs_open(nullptr, &fs_req, intermediate_file.c_str(), O_CREAT | O_RDWR,
+               0644, nullptr);
+  uv_fs_req_cleanup(&fs_req);
+
+  builder
+    .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT,
+                       preprocessedFile)
+    .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR)
+    .AddCommand(command);
+  auto process = builder.Start();
+  if (!process.Valid()) {
+    std::cerr << "Failed to start preprocessor.";
+    return 1;
+  }
+  if (!process.Wait()) {
+    std::cerr << "Failed to wait for preprocessor";
+    return 1;
+  }
+  auto status = process.GetStatus();
+  if (!status[0] || status[0]->ExitStatus != 0) {
+    return 1;
+  }
+
+  return 0;
+}
+
+int cmcmd::RunLLVMRC(std::vector<std::string> const& args)
+{
+  // The arguments are
+  //   args[0] == <cmake-executable>
+  //   args[1] == cmake_llvm_rc
+  //   args[2] == intermediate_file
+  //   args[3..n] == preprocess+args
+  //   args[n+1] == --
+  //   args[n+2...] == llvm-rc+args
+  if (args.size() < 3) {
+    std::cerr << "Invalid cmake_llvm_rc arguments";
+    return 1;
+  }
+  const std::string& intermediate_file = args[2];
+  std::vector<std::string> preprocess;
+  std::vector<std::string> resource_compile;
+  std::vector<std::string>* pArgTgt = &preprocess;
+  for (std::string const& arg : cmMakeRange(args).advance(3)) {
+    if (arg == "--") {
+      pArgTgt = &resource_compile;
+    } else {
+      pArgTgt->push_back(arg);
+    }
+  }
+  if (preprocess.empty()) {
+    std::cerr << "Empty preprocessing command";
+    return 1;
+  }
+  if (resource_compile.empty()) {
+    std::cerr << "Empty resource compilation command";
+    return 1;
+  }
+
+  auto result = RunPreprocessor(preprocess, intermediate_file);
+  if (result != 0) {
+
+    cmSystemTools::RemoveFile(intermediate_file);
+    return result;
+  }
+  cmUVProcessChainBuilder builder;
+
+  builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
+    .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR)
+    .AddCommand(resource_compile);
+  auto process = builder.Start();
+  result = 0;
+  if (!process.Valid()) {
+    std::cerr << "Failed to start resource compiler.";
+    result = 1;
+  } else {
+    if (!process.Wait()) {
+      std::cerr << "Failed to wait for resource compiler";
+      result = 1;
+    }
+  }
+
+  cmSystemTools::RemoveFile(intermediate_file);
+  if (result != 0) {
+    return result;
+  }
+  auto status = process.GetStatus();
+  if (!status[0] || status[0]->ExitStatus != 0) {
+    return 1;
+  }
+
+  return 0;
+}
+
 class cmVSLink
 {
   int Type;
@@ -1956,7 +2140,7 @@
   if (this->LinkGeneratesManifest) {
     mtCommand.push_back(this->LinkerManifestFile);
   }
-  cmAppend(mtCommand, this->UserManifests);
+  cm::append(mtCommand, this->UserManifests);
   mtCommand.push_back(out);
   if (notify) {
     // Add an undocumented option that enables a special return
diff --git a/Source/cmcmd.h b/Source/cmcmd.h
index 17f2f9a..5b6c813 100644
--- a/Source/cmcmd.h
+++ b/Source/cmcmd.h
@@ -31,6 +31,9 @@
   static int ExecuteLinkScript(std::vector<std::string> const& args);
   static int WindowsCEEnvironment(const char* version,
                                   const std::string& name);
+  static int RunPreprocessor(const std::vector<std::string>& command,
+                             const std::string& intermediate_file);
+  static int RunLLVMRC(std::vector<std::string> const& args);
   static int VisualStudioLink(std::vector<std::string> const& args, int type);
 };
 
diff --git a/Source/ctest.cxx b/Source/ctest.cxx
index 0d65902..fbdf75a 100644
--- a/Source/ctest.cxx
+++ b/Source/ctest.cxx
@@ -98,9 +98,12 @@
     "Run a specific number of tests by number." },
   { "-U, --union", "Take the Union of -I and -R" },
   { "--rerun-failed", "Run only the tests that failed previously" },
-  { "--repeat-until-fail <n>",
-    "Require each test to run <n> "
-    "times without failing in order to pass" },
+  { "--repeat until-fail:<n>, --repeat-until-fail <n>",
+    "Require each test to run <n> times without failing in order to pass" },
+  { "--repeat until-pass:<n>",
+    "Allow each test to run up to <n> times in order to pass" },
+  { "--repeat after-timeout:<n>",
+    "Allow each test to run up to <n> times if it times out" },
   { "--max-width <width>", "Set the max width for a test name to output" },
   { "--interactive-debug-mode [0|1]", "Set the interactive mode to 0 or 1." },
   { "--resource-spec-file <file>", "Set the resource spec file to use." },
@@ -141,6 +144,8 @@
   { "--http1.0", "Submit using HTTP 1.0." },
   { "--no-compress-output", "Do not compress test output when submitting." },
   { "--print-labels", "Print all available test labels." },
+  { "--no-tests=<[error|ignore]>",
+    "Regard no tests found either as 'error' or 'ignore' it." },
   { nullptr, nullptr }
 };
 
@@ -161,7 +166,6 @@
   argv = encoding_args.argv();
 
   cmSystemTools::DoNotInheritStdPipes();
-  cmSystemTools::EnableMSVCDebugHook();
   cmSystemTools::InitializeLibUV();
   cmSystemTools::FindCMakeResources(argv[0]);
 
diff --git a/Source/kwsys/CTestCustom.cmake.in b/Source/kwsys/CTestCustom.cmake.in
index 760221b..c07f0f3 100644
--- a/Source/kwsys/CTestCustom.cmake.in
+++ b/Source/kwsys/CTestCustom.cmake.in
@@ -12,3 +12,7 @@
 list(APPEND CTEST_CUSTOM_MEMCHECK_IGNORE
   kwsys.testProcess-10
   )
+
+list(APPEND CTEST_CUSTOM_WARNING_EXCEPTION
+  "LICENSE WARNING"
+  )
diff --git a/Source/kwsys/Encoding.hxx.in b/Source/kwsys/Encoding.hxx.in
index b067521..75a2d4d 100644
--- a/Source/kwsys/Encoding.hxx.in
+++ b/Source/kwsys/Encoding.hxx.in
@@ -68,6 +68,8 @@
    * absolute paths with Windows-style backslashes.
    **/
   static std::wstring ToWindowsExtendedPath(std::string const&);
+  static std::wstring ToWindowsExtendedPath(const char* source);
+  static std::wstring ToWindowsExtendedPath(std::wstring const& wsource);
 #  endif
 
 #endif // @KWSYS_NAMESPACE@_STL_HAS_WSTRING
diff --git a/Source/kwsys/EncodingCXX.cxx b/Source/kwsys/EncodingCXX.cxx
index 4593c92..5cad934 100644
--- a/Source/kwsys/EncodingCXX.cxx
+++ b/Source/kwsys/EncodingCXX.cxx
@@ -221,8 +221,18 @@
 // Convert local paths to UNC style paths
 std::wstring Encoding::ToWindowsExtendedPath(std::string const& source)
 {
-  std::wstring wsource = Encoding::ToWide(source);
+  return ToWindowsExtendedPath(ToWide(source));
+}
 
+// Convert local paths to UNC style paths
+std::wstring Encoding::ToWindowsExtendedPath(const char* source)
+{
+  return ToWindowsExtendedPath(ToWide(source));
+}
+
+// Convert local paths to UNC style paths
+std::wstring Encoding::ToWindowsExtendedPath(std::wstring const& wsource)
+{
   // Resolve any relative paths
   DWORD wfull_len;
 
@@ -269,7 +279,7 @@
 
   // If this case has been reached, then the path is invalid.  Leave it
   // unchanged
-  return Encoding::ToWide(source);
+  return wsource;
 }
 #  endif
 
diff --git a/Source/kwsys/FStream.hxx.in b/Source/kwsys/FStream.hxx.in
index d79bbdf..b424488 100644
--- a/Source/kwsys/FStream.hxx.in
+++ b/Source/kwsys/FStream.hxx.in
@@ -87,7 +87,7 @@
 
   bool _open(char const* file_name, std::ios_base::openmode mode)
   {
-    if (is_open() || file_) {
+    if (_is_open() || file_) {
       return false;
     }
 #  if defined(_MSC_VER)
@@ -108,7 +108,7 @@
     return success;
   }
 
-  bool is_open()
+  bool _is_open()
   {
     if (!buf_) {
       return false;
@@ -116,7 +116,7 @@
     return buf_->is_open();
   }
 
-  bool is_open() const
+  bool _is_open() const
   {
     if (!buf_) {
       return false;
@@ -198,9 +198,11 @@
     this->_set_state(this->_open(file_name, mode), this, this);
   }
 
+  bool is_open() { return this->_is_open(); }
+
   void close() { this->_set_state(this->_close(), this, this); }
 
-  using basic_efilebuf<CharType, Traits>::is_open;
+  using basic_efilebuf<CharType, Traits>::_is_open;
 
   internal_buffer_type* rdbuf() const { return this->buf_; }
 
@@ -212,7 +214,7 @@
   : public std::basic_ostream<CharType, Traits>
   , public basic_efilebuf<CharType, Traits>
 {
-  using basic_efilebuf<CharType, Traits>::is_open;
+  using basic_efilebuf<CharType, Traits>::_is_open;
 
 public:
   typedef typename basic_efilebuf<CharType, Traits>::internal_buffer_type
@@ -242,6 +244,8 @@
 
   void close() { this->_set_state(this->_close(), this, this); }
 
+  bool is_open() { return this->_is_open(); }
+
   internal_buffer_type* rdbuf() const { return this->buf_; }
 
   ~basic_ofstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { close(); }
diff --git a/Source/kwsys/RegularExpression.hxx.in b/Source/kwsys/RegularExpression.hxx.in
index df7eb45..d11db88 100644
--- a/Source/kwsys/RegularExpression.hxx.in
+++ b/Source/kwsys/RegularExpression.hxx.in
@@ -66,16 +66,27 @@
   const char* searchstring;
 };
 
+#ifdef _MSC_VER
+#  pragma warning(push)
+#  if _MSC_VER < 1900
+#    pragma warning(disable : 4351) /* new behavior */
+#  endif
+#endif
+
 /**
  * \brief Creates an invalid match object
  */
 inline RegularExpressionMatch::RegularExpressionMatch()
+  : startp{}
+  , endp{}
+  , searchstring{}
 {
-  startp[0] = nullptr;
-  endp[0] = nullptr;
-  searchstring = nullptr;
 }
 
+#ifdef _MSC_VER
+#  pragma warning(pop)
+#endif
+
 /**
  * \brief Returns true if the match pointers are valid
  */
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index ce4d6ef..d27081b 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -2186,12 +2186,15 @@
   // FilesDiffer does not handle file to directory compare
   if (SystemTools::FileIsDirectory(destination)) {
     const std::string new_destination = FileInDir(source, destination);
-    return SystemTools::CopyFileIfDifferent(source, new_destination);
-  }
-  // source and destination are files so do a copy if they
-  // are different
-  if (SystemTools::FilesDiffer(source, destination)) {
-    return SystemTools::CopyFileAlways(source, destination);
+    if (!SystemTools::ComparePath(new_destination, destination)) {
+      return SystemTools::CopyFileIfDifferent(source, new_destination);
+    }
+  } else {
+    // source and destination are files so do a copy if they
+    // are different
+    if (SystemTools::FilesDiffer(source, destination)) {
+      return SystemTools::CopyFileAlways(source, destination);
+    }
   }
   // at this point the files must be the same so return true
   return true;
@@ -2326,14 +2329,8 @@
 static bool CopyFileContentBlockwise(const std::string& source,
                                      const std::string& destination)
 {
-// Open files
-#if defined(_WIN32)
-  kwsys::ifstream fin(
-    Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(source)).c_str(),
-    std::ios::in | std::ios::binary);
-#else
+  // Open files
   kwsys::ifstream fin(source.c_str(), std::ios::in | std::ios::binary);
-#endif
   if (!fin) {
     return false;
   }
@@ -2344,14 +2341,8 @@
   // that do not allow file removal can be modified.
   SystemTools::RemoveFile(destination);
 
-#if defined(_WIN32)
-  kwsys::ofstream fout(
-    Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(destination)).c_str(),
-    std::ios::out | std::ios::trunc | std::ios::binary);
-#else
   kwsys::ofstream fout(destination.c_str(),
                        std::ios::out | std::ios::trunc | std::ios::binary);
-#endif
   if (!fout) {
     return false;
   }
@@ -4678,8 +4669,12 @@
 #  include <stdlib.h>
 namespace KWSYS_NAMESPACE {
 
-static int SystemToolsDebugReport(int, char* message, int*)
+static int SystemToolsDebugReport(int, char* message, int* ret)
 {
+  if (ret) {
+    // Pretend user clicked on Retry button in popup.
+    *ret = 1;
+  }
   fprintf(stderr, "%s", message);
   fflush(stderr);
   return 1; // no further reporting required
diff --git a/Source/kwsys/Terminal.c b/Source/kwsys/Terminal.c
index 4dd2461..4d1b46c 100644
--- a/Source/kwsys/Terminal.c
+++ b/Source/kwsys/Terminal.c
@@ -146,6 +146,7 @@
                                                  "screen-bce",
                                                  "screen-w",
                                                  "screen.linux",
+                                                 "st-256color",
                                                  "tmux",
                                                  "tmux-256color",
                                                  "vt100",
@@ -172,6 +173,14 @@
     }
   }
 
+  /* GNU make 4.1+ may tell us that its output is destined for a TTY. */
+  {
+    const char* termout = getenv("MAKE_TERMOUT");
+    if (termout && *termout != '\0') {
+      return 1;
+    }
+  }
+
   /* If running inside emacs the terminal is not VT100.  Some emacs
      seem to claim the TERM is xterm even though they do not support
      VT100 escapes.  */
diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx
index 1f3a15b..3f6eeb8 100644
--- a/Source/kwsys/testSystemTools.cxx
+++ b/Source/kwsys/testSystemTools.cxx
@@ -1074,6 +1074,15 @@
     }
   }
 
+  if (!kwsys::SystemTools::MakeDirectory("dir_a") ||
+      !kwsys::SystemTools::MakeDirectory("dir_b")) {
+    return false;
+  }
+
+  if (!kwsys::SystemTools::CopyFileIfDifferent("dir_a/", "dir_b")) {
+    ret = false;
+  }
+
   return ret;
 }
 
diff --git a/Templates/MSBuild/FlagTables/v10_Cuda.json b/Templates/MSBuild/FlagTables/v10_Cuda.json
index 1831b8a..b3230ac 100644
--- a/Templates/MSBuild/FlagTables/v10_Cuda.json
+++ b/Templates/MSBuild/FlagTables/v10_Cuda.json
@@ -20,6 +20,26 @@
     ]
   },
   {
+    "name":  "AdditionalCompilerOptions",
+    "switch": "-compiler-options=",
+    "comment": "Host compiler options",
+    "value": "",
+    "flags": [
+      "UserValue",
+      "SpaceAppendable"
+    ]
+  },
+  {
+    "name":  "AdditionalCompilerOptions",
+    "switch": "-compiler-options",
+    "comment": "Host compiler options",
+    "value": "",
+    "flags": [
+      "UserFollowing",
+      "SpaceAppendable"
+    ]
+  },
+  {
     "name":  "CudaRuntime",
     "switch": "cudart=none",
     "comment": "No CUDA runtime library",
diff --git a/Tests/Assembler/CMakeLists.txt b/Tests/Assembler/CMakeLists.txt
index 21b265c..a3c9946 100644
--- a/Tests/Assembler/CMakeLists.txt
+++ b/Tests/Assembler/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 3.8)
 project(Assembler C)
 message("CTEST_FULL_OUTPUT ")
 set(CMAKE_VERBOSE_MAKEFILE 1)
@@ -22,7 +22,11 @@
     set(SRCS main.s)
     add_custom_command(
       OUTPUT main.s
-      COMMAND ${CMAKE_C_COMPILER} ${C_FLAGS} -S ${CMAKE_CURRENT_SOURCE_DIR}/main.c -o main.s
+      COMMAND ${CMAKE_C_COMPILER} ${C_FLAGS}
+        "$<$<CONFIG:Debug>:${CMAKE_C_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL}>"
+        "$<$<NOT:$<CONFIG:Debug>>:${CMAKE_C_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL}>"
+        -S ${CMAKE_CURRENT_SOURCE_DIR}/main.c -o main.s
+      COMMAND_EXPAND_LISTS
       DEPENDS main.c
       VERBATIM
       )
diff --git a/Tests/CFBundleTest/VerifyResult.cmake b/Tests/CFBundleTest/VerifyResult.cmake
index e637bb1..ac14e5d 100644
--- a/Tests/CFBundleTest/VerifyResult.cmake
+++ b/Tests/CFBundleTest/VerifyResult.cmake
@@ -14,7 +14,7 @@
 message(STATUS "dir='${dir}'")
 message(STATUS "gen='${gen}'")
 
-if(gen STREQUAL "Xcode")
+if(gen MATCHES "^(Xcode$|Ninja Multi-Config$)")
   set(expected_filename "${dir}/${CTEST_CONFIGURATION_TYPE}/CFBundleTest.plugin/Contents/MacOS/CFBundleTest")
 else()
   set(expected_filename "${dir}/CFBundleTest.plugin/Contents/MacOS/CFBundleTest")
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/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt
index 840afc1..bb50d76 100644
--- a/Tests/CMakeLib/CMakeLists.txt
+++ b/Tests/CMakeLib/CMakeLists.txt
@@ -11,6 +11,7 @@
   testCTestResourceAllocator.cxx
   testCTestResourceSpec.cxx
   testCTestResourceGroups.cxx
+  testGccDepfileReader.cxx
   testGeneratedFileStream.cxx
   testRST.cxx
   testRange.cxx
@@ -25,6 +26,8 @@
   testUVProcessChain.cxx
   testUVRAII.cxx
   testUVStreambuf.cxx
+  testCMExtMemory.cxx
+  testCMExtAlgorithm.cxx
   )
 
 add_executable(testUVProcessChainHelper testUVProcessChainHelper.cxx)
@@ -33,6 +36,7 @@
 set(testUVProcessChain_ARGS $<TARGET_FILE:testUVProcessChainHelper>)
 set(testUVStreambuf_ARGS $<TARGET_FILE:cmake>)
 set(testCTestResourceSpec_ARGS ${CMAKE_CURRENT_SOURCE_DIR})
+set(testGccDepfileReader_ARGS ${CMAKE_CURRENT_SOURCE_DIR})
 
 if(WIN32)
   list(APPEND CMakeLib_TESTS
diff --git a/Tests/CMakeLib/testCMExtAlgorithm.cxx b/Tests/CMakeLib/testCMExtAlgorithm.cxx
new file mode 100644
index 0000000..b8319c3
--- /dev/null
+++ b/Tests/CMakeLib/testCMExtAlgorithm.cxx
@@ -0,0 +1,118 @@
+#include <iostream>
+#include <memory>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include <cmext/algorithm>
+
+namespace {
+
+int failed = 0;
+
+void testAppend()
+{
+  std::cout << "testAppend()" << std::endl;
+
+  // ----------------------------------------------------
+  // cm::append(Vector, Iterator, Iterator)
+  {
+    std::vector<int> v1{ 1, 2, 3 };
+    std::vector<int> v1_ref{ 1, 2, 3, 4, 5, 6 };
+    std::vector<int> v2{ 4, 5, 6 };
+    std::vector<int> v2_ref{ 4, 5, 6 };
+
+    cm::append(v1, v2.begin(), v2.end());
+
+    if (v1 != v1_ref || v2 != v2_ref) {
+      ++failed;
+    }
+  }
+
+  // ----------------------------------------------------
+  // cm::append(Vector, Range)
+  {
+    std::vector<int> v1{ 1, 2, 3 };
+    std::vector<int> v1_ref{ 1, 2, 3, 4, 5, 6 };
+    std::vector<int> v2{ 4, 5, 6 };
+    std::vector<int> v2_ref{ 4, 5, 6 };
+
+    cm::append(v1, v2);
+
+    if (v1 != v1_ref || v2 != v2_ref) {
+      ++failed;
+    }
+  }
+
+  // ----------------------------------------------------
+  // cm::append(Vector<*>, Vector<unique_ptr>)
+  {
+    std::vector<int*> v1{ new int(1), new int(2), new int(3) };
+    std::vector<int*> v1_ref = v1;
+    std::vector<std::unique_ptr<int>> v2;
+
+    v2.emplace_back(new int(4));
+    v2.emplace_back(new int(5));
+    v2.emplace_back(new int(6));
+
+    cm::append(v1, v2);
+
+    if (v1.size() == 6 && v2.size() == 3) {
+      for (int i = 0; i < 3; i++) {
+        if (v1[i] != v1_ref[i]) {
+          ++failed;
+          break;
+        }
+      }
+      for (int i = 0; i < 3; i++) {
+        if (v1[i + 3] != v2[i].get()) {
+          ++failed;
+          break;
+        }
+      }
+    } else {
+      ++failed;
+    }
+
+    // free memory to please memory sanitizer
+    delete v1[0];
+    delete v1[1];
+    delete v1[2];
+  }
+
+  // ----------------------------------------------------
+  // cm::append(Vector<unique_ptr>, Vector<unique_ptr>)
+  {
+    std::vector<std::unique_ptr<int>> v1;
+    std::vector<std::unique_ptr<int>> v2;
+
+    v1.emplace_back(new int(1));
+    v1.emplace_back(new int(2));
+    v1.emplace_back(new int(3));
+
+    v2.emplace_back(new int(4));
+    v2.emplace_back(new int(5));
+    v2.emplace_back(new int(6));
+
+    cm::append(v1, std::move(v2));
+
+    if (v1.size() == 6 && v2.empty()) {
+      for (int i = 0; i < 6; i++) {
+        if (*v1[i] != i + 1) {
+          ++failed;
+          break;
+        }
+      }
+    } else {
+      ++failed;
+    }
+  }
+}
+}
+
+int testCMExtAlgorithm(int /*unused*/, char* /*unused*/ [])
+{
+  testAppend();
+
+  return failed;
+}
diff --git a/Tests/CMakeLib/testCMExtMemory.cxx b/Tests/CMakeLib/testCMExtMemory.cxx
new file mode 100644
index 0000000..6663c17
--- /dev/null
+++ b/Tests/CMakeLib/testCMExtMemory.cxx
@@ -0,0 +1,65 @@
+#include <iostream>
+#include <memory>
+
+#include <cmext/memory>
+
+namespace {
+class Base
+{
+public:
+  virtual ~Base() = default;
+};
+
+class Derived : public Base
+{
+public:
+  ~Derived() = default;
+
+  void method() {}
+};
+
+template <typename T>
+class Wrapper
+{
+public:
+  Wrapper(T* v)
+    : value(v)
+  {
+  }
+  ~Wrapper() { delete value; }
+
+  T* get() const { return value; }
+
+private:
+  T* value;
+};
+
+bool testReferenceCast()
+{
+  std::cout << "testReferenceCast()" << std::endl;
+
+  std::unique_ptr<Base> u(new Derived);
+  cm::static_reference_cast<Derived>(u).method();
+  cm::dynamic_reference_cast<Derived>(u).method();
+
+  std::shared_ptr<Base> s(new Derived);
+  cm::static_reference_cast<Derived>(s).method();
+  cm::dynamic_reference_cast<Derived>(s).method();
+
+  // can also be used with custom wrappers
+  Wrapper<Base> w(new Derived);
+  cm::static_reference_cast<Derived>(w).method();
+  cm::dynamic_reference_cast<Derived>(w).method();
+
+  return true;
+}
+}
+
+int testCMExtMemory(int /*unused*/, char* /*unused*/ [])
+{
+  if (!testReferenceCast()) {
+    return 1;
+  }
+
+  return 0;
+}
diff --git a/Tests/CMakeLib/testGccDepfileReader.cxx b/Tests/CMakeLib/testGccDepfileReader.cxx
new file mode 100644
index 0000000..924d87b
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader.cxx
@@ -0,0 +1,131 @@
+#include <cstddef>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmGccDepfileReader.h"
+#include "cmGccDepfileReaderTypes.h" // for cmGccDepfileContent, cmGccStyle...
+#include "cmSystemTools.h"
+
+namespace {
+
+cmGccDepfileContent readPlainDepfile(const char* filePath)
+{
+  cmGccDepfileContent result;
+  cmsys::ifstream is(filePath);
+  if (!is.is_open())
+    return result;
+  std::string line;
+
+  cmGccStyleDependency dep;
+  bool readingRules = true;
+  while (cmSystemTools::GetLineFromStream(is, line)) {
+    if (line == "--RULES--") {
+      if (!dep.rules.empty()) {
+        result.push_back(std::move(dep));
+        dep = cmGccStyleDependency();
+      }
+      readingRules = true;
+    } else if (line == "--DEPENDENCIES--") {
+      readingRules = false;
+    } else {
+      std::vector<std::string>& dst = readingRules ? dep.rules : dep.paths;
+      dst.push_back(std::move(line));
+      line = std::string();
+    }
+  }
+
+  if (!dep.rules.empty()) {
+    result.push_back(std::move(dep));
+  }
+
+  return result;
+}
+
+bool compare(const std::vector<std::string>& actual,
+             const std::vector<std::string>& expected, const char* msg)
+{
+  if (actual.size() != expected.size()) {
+    std::cerr << msg << "expected " << expected.size() << " entries."
+              << std::endl
+              << "Actual number of entries: " << actual.size() << std::endl;
+    return false;
+  }
+  for (std::size_t i = 0; i < actual.size(); ++i) {
+    if (actual[i] != expected[i]) {
+      std::cerr << msg << std::endl
+                << "expected: " << expected[i] << std::endl
+                << "actual: " << actual[i] << std::endl;
+      return false;
+    }
+  }
+  return true;
+}
+
+bool compare(const cmGccDepfileContent& actual,
+             const cmGccDepfileContent& expected)
+{
+  if (actual.size() != expected.size()) {
+    std::cerr << "Expected " << expected.size() << " entries." << std::endl
+              << "Actual number of entries: " << actual.size() << std::endl;
+    return false;
+  }
+  for (std::size_t i = 0; i < actual.size(); ++i) {
+    if (!compare(actual[i].rules, expected[i].rules, "Rules differ: ") ||
+        !compare(actual[i].paths, expected[i].paths, "Paths differ: ")) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void dump(const char* label, const cmGccDepfileContent& dfc)
+{
+  std::cerr << label << std::endl;
+  for (const auto& entry : dfc) {
+    auto rit = entry.rules.cbegin();
+    if (rit != entry.rules.cend()) {
+      std::cerr << *rit;
+      for (++rit; rit != entry.rules.cend(); ++rit) {
+        std::cerr << "  " << *rit;
+      }
+      std::cerr << ": " << std::endl;
+    }
+    for (const auto& path : entry.paths) {
+      std::cerr << "    " << path << std::endl;
+    }
+  }
+}
+
+} // anonymous namespace
+
+int testGccDepfileReader(int argc, char* argv[])
+{
+  if (argc < 2) {
+    std::cout << "Invalid arguments.\n";
+    return -1;
+  }
+
+  std::string dataDirPath = argv[1];
+  dataDirPath += "/testGccDepfileReader_data";
+  const int numberOfTestFiles = 3;
+  for (int i = 1; i <= numberOfTestFiles; ++i) {
+    const std::string base = dataDirPath + "/deps" + std::to_string(i);
+    const std::string depfile = base + ".d";
+    const std::string plainDepfile = base + ".txt";
+    std::cout << "Comparing " << base << " with " << plainDepfile << std::endl;
+    const auto actual = cmReadGccDepfile(depfile.c_str());
+    const auto expected = readPlainDepfile(plainDepfile.c_str());
+    if (!compare(actual, expected)) {
+      dump("actual", actual);
+      dump("expected", expected);
+      return 1;
+    }
+  }
+
+  return 0;
+}
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps1.d b/Tests/CMakeLib/testGccDepfileReader_data/deps1.d
new file mode 100644
index 0000000..9e34863
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps1.d
@@ -0,0 +1,20 @@
+main.o: main.cpp /usr/include/stdc-predef.h /usr/include/stdio.h \
+ /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \
+ /usr/include/x86_64-linux-gnu/bits/wordsize.h \
+ /usr/include/x86_64-linux-gnu/bits/long-double.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
+ /usr/lib/gcc/x86_64-linux-gnu/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-linux-gnu/8/include/stdarg.h \
+ /usr/include/x86_64-linux-gnu/bits/types.h \
+ /usr/include/x86_64-linux-gnu/bits/typesizes.h \
+ /usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h \
+ /usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h \
+ /usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h \
+ /usr/include/x86_64-linux-gnu/bits/types/__FILE.h \
+ /usr/include/x86_64-linux-gnu/bits/types/FILE.h \
+ /usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h \
+ /usr/include/x86_64-linux-gnu/bits/types/cookie_io_functions_t.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
+ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps1.txt b/Tests/CMakeLib/testGccDepfileReader_data/deps1.txt
new file mode 100644
index 0000000..fd2679f
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps1.txt
@@ -0,0 +1,26 @@
+--RULES--
+main.o
+--DEPENDENCIES--
+main.cpp
+/usr/include/stdc-predef.h
+/usr/include/stdio.h
+/usr/include/x86_64-linux-gnu/bits/libc-header-start.h
+/usr/include/features.h
+/usr/include/x86_64-linux-gnu/sys/cdefs.h
+/usr/include/x86_64-linux-gnu/bits/wordsize.h
+/usr/include/x86_64-linux-gnu/bits/long-double.h
+/usr/include/x86_64-linux-gnu/gnu/stubs.h
+/usr/include/x86_64-linux-gnu/gnu/stubs-64.h
+/usr/lib/gcc/x86_64-linux-gnu/8/include/stddef.h
+/usr/lib/gcc/x86_64-linux-gnu/8/include/stdarg.h
+/usr/include/x86_64-linux-gnu/bits/types.h
+/usr/include/x86_64-linux-gnu/bits/typesizes.h
+/usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h
+/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h
+/usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h
+/usr/include/x86_64-linux-gnu/bits/types/__FILE.h
+/usr/include/x86_64-linux-gnu/bits/types/FILE.h
+/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h
+/usr/include/x86_64-linux-gnu/bits/types/cookie_io_functions_t.h
+/usr/include/x86_64-linux-gnu/bits/stdio_lim.h
+/usr/include/x86_64-linux-gnu/bits/sys_errlist.h
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps2.d b/Tests/CMakeLib/testGccDepfileReader_data/deps2.d
new file mode 100644
index 0000000..25f0d78
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps2.d
@@ -0,0 +1 @@
+foo.o bar.o: foobar.c
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps2.txt b/Tests/CMakeLib/testGccDepfileReader_data/deps2.txt
new file mode 100644
index 0000000..afaf78e
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps2.txt
@@ -0,0 +1,5 @@
+--RULES--
+foo.o
+bar.o
+--DEPENDENCIES--
+foobar.c
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps3.d b/Tests/CMakeLib/testGccDepfileReader_data/deps3.d
new file mode 100644
index 0000000..d75ceed
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps3.d
@@ -0,0 +1,2 @@
+main.o: main.cpp foo\#bar.h foo\\#bar.h foo\ bar.h \
+ foo\\\ bar.h foo\\\\\ bar.h foo\\\\ foo$$bar.h
diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps3.txt b/Tests/CMakeLib/testGccDepfileReader_data/deps3.txt
new file mode 100644
index 0000000..448f69c
--- /dev/null
+++ b/Tests/CMakeLib/testGccDepfileReader_data/deps3.txt
@@ -0,0 +1,11 @@
+--RULES--
+main.o
+--DEPENDENCIES--
+main.cpp
+foo#bar.h
+foo\#bar.h
+foo bar.h
+foo\ bar.h
+foo\\ bar.h
+foo\\\\
+foo$bar.h
diff --git a/Tests/CMakeLib/testString.cxx b/Tests/CMakeLib/testString.cxx
index d7b3200..1fd3f38 100644
--- a/Tests/CMakeLib/testString.cxx
+++ b/Tests/CMakeLib/testString.cxx
@@ -191,7 +191,7 @@
 {
   std::cout << "testConstructFromView()\n";
   cm::string_view view = cstr;
-  return testFromCStr(view);
+  return testFromCStr(cm::String(view));
 }
 
 static bool testAssignFromView()
@@ -297,7 +297,7 @@
 static bool testConstructFromStaticStringView()
 {
   std::cout << "testConstructFromStaticStringView()\n";
-  return testFromStaticStringView(staticStringView);
+  return testFromStaticStringView(cm::String(staticStringView));
 }
 
 static bool testAssignFromStaticStringView()
@@ -796,7 +796,7 @@
 static bool testMethod_substr_AtEndBorrowed()
 {
   std::cout << "testMethod_substr_AtEndBorrowed()\n";
-  return testMethod_substr_AtEnd("abc"_s);
+  return testMethod_substr_AtEnd(cm::String("abc"_s));
 }
 
 static bool testMethod_substr_AtEndOwned()
@@ -855,7 +855,7 @@
 static bool testMethod_substr_AtStartBorrowed()
 {
   std::cout << "testMethod_substr_AtStartBorrowed()\n";
-  return testMethod_substr_AtStart("abc"_s);
+  return testMethod_substr_AtStart(cm::String("abc"_s));
 }
 
 static bool testMethod_substr_AtStartOwned()
@@ -1146,7 +1146,7 @@
 static bool testStability()
 {
   std::cout << "testStability()\n";
-  cm::String str = "abc"_s;
+  cm::String str("abc"_s);
   ASSERT_TRUE(!str.is_stable());
   ASSERT_TRUE(str.str_if_stable() == nullptr);
   str.stabilize();
diff --git a/Tests/CMakeLib/testUTF8.cxx b/Tests/CMakeLib/testUTF8.cxx
index 986f595..1bf88cf 100644
--- a/Tests/CMakeLib/testUTF8.cxx
+++ b/Tests/CMakeLib/testUTF8.cxx
@@ -9,9 +9,11 @@
 static void test_utf8_char_print(test_utf8_char const c)
 {
   unsigned char const* d = reinterpret_cast<unsigned char const*>(c);
+#ifndef __clang_analyzer__ // somehow thinks arguments are not initialized
   printf("[0x%02X,0x%02X,0x%02X,0x%02X]", static_cast<int>(d[0]),
          static_cast<int>(d[1]), static_cast<int>(d[2]),
          static_cast<int>(d[3]));
+#endif
 }
 
 static void byte_array_print(char const* s)
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 57fa7fc..33c7514 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -211,6 +211,13 @@
   #---------------------------------------------------------------------------
   # Add tests below here.
 
+  if(NOT DEFINED CMake_TEST_Qt5)
+    set(CMake_TEST_Qt5 1)
+  endif()
+  if(CMake_TEST_Qt5)
+    find_package(Qt5Widgets QUIET NO_MODULE)
+  endif()
+
   if(NOT CMake_TEST_EXTERNAL_CMAKE)
     add_subdirectory(CMakeLib)
 
@@ -436,7 +443,9 @@
   ADD_TEST_MACRO(Assembler HelloAsm)
   ADD_TEST_MACRO(SourceGroups SourceGroups)
   ADD_TEST_MACRO(Preprocess Preprocess)
-  set(ExportImport_BUILD_OPTIONS -DCMake_TEST_NESTED_MAKE_PROGRAM:FILEPATH=${CMake_TEST_EXPLICIT_MAKE_PROGRAM})
+  set(ExportImport_BUILD_OPTIONS -DCMake_TEST_NESTED_MAKE_PROGRAM:FILEPATH=${CMake_TEST_EXPLICIT_MAKE_PROGRAM}
+                                 -DCMake_TEST_CUDA:BOOL=${CMake_TEST_CUDA}
+                                 )
   ADD_TEST_MACRO(ExportImport ExportImport)
   ADD_TEST_MACRO(Unset Unset)
   ADD_TEST_MACRO(PolicyScope PolicyScope)
@@ -451,8 +460,12 @@
   ADD_TEST_MACRO(StagingPrefix StagingPrefix)
   ADD_TEST_MACRO(ImportedSameName ImportedSameName)
   ADD_TEST_MACRO(InterfaceLibrary InterfaceLibrary)
-  if(NOT _isMultiConfig)
-    set(ConfigSources_BUILD_OPTIONS -DCMAKE_BUILD_TYPE=$<CONFIGURATION>)
+  if(NOT CMAKE_GENERATOR STREQUAL "Xcode")
+    if(_isMultiConfig)
+      set(ConfigSources_CTEST_OPTIONS --build-config $<CONFIGURATION>)
+    else()
+      set(ConfigSources_BUILD_OPTIONS -DCMAKE_BUILD_TYPE=$<CONFIGURATION>)
+    endif()
     ADD_TEST_MACRO(ConfigSources ConfigSources)
   endif()
   ADD_TEST_MACRO(SourcesProperty SourcesProperty)
@@ -976,6 +989,27 @@
     endif()
   endif()
 
+  # On Windows run the CPackNSISGenerator test
+  # if the nsis is available
+  if(WIN32 AND NSIS_MAKENSIS_EXECUTABLE)
+    add_test(CPackNSISGenerator ${CMAKE_CTEST_COMMAND}
+      -C \${CTEST_CONFIGURATION_TYPE}
+      --build-and-test
+      "${CMake_SOURCE_DIR}/Tests/CPackNSISGenerator"
+      "${CMake_BINARY_DIR}/Tests/CPackNSISGenerator"
+      ${build_generator_args}
+      --build-project CPackNSISGenerator
+      --build-options
+      --test-command ${CMAKE_CMAKE_COMMAND}
+        "-DCPackNSISGenerator_BINARY_DIR:PATH=${CMake_BINARY_DIR}/Tests/CPackNSISGenerator"
+        "-Dconfig=\${CTEST_CONFIGURATION_TYPE}"
+        -P "${CMake_SOURCE_DIR}/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake")
+
+    set_property(TEST CPackNSISGenerator PROPERTY
+      ATTACHED_FILES_ON_FAIL
+      "${CMake_BINARY_DIR}/Tests/CPackNSISGenerator/_CPack_Packages/win32/NSIS/NSISOutput.log")
+  endif()
+
   if(CTEST_TEST_CPACK)
     add_test(CPackUseDefaultVersion ${CMAKE_CTEST_COMMAND}
       --build-and-test
@@ -1128,8 +1162,8 @@
 
       foreach(CPackDEBConfiguration IN LISTS DEB_CONFIGURATIONS_TO_TEST)
         set(CPackRun_CPackDEBConfiguration "-DCPackDEBConfiguration=${CPackDEBConfiguration}")
-        add_test(${DEB_TEST_NAMES}-${CPackDEBConfiguration}
-          ${CMAKE_CTEST_COMMAND} -C \${CTEST_CONFIGURATION_TYPE}
+        add_test(NAME ${DEB_TEST_NAMES}-${CPackDEBConfiguration} COMMAND
+          ${CMAKE_CTEST_COMMAND} -C $<CONFIG>
           --build-and-test
               "${CMake_SOURCE_DIR}/Tests/${DEB_TEST_NAMES}"
               "${CMake_BINARY_DIR}/Tests/${DEB_TEST_NAMES}/build${CPackGen}-${CPackDEBConfiguration}"
@@ -1146,6 +1180,7 @@
               "-D${DEB_TEST_NAMES}_BINARY_DIR:PATH=${CMake_BINARY_DIR}/Tests/${DEB_TEST_NAMES}/build${CPackGen}-${CPackDEBConfiguration}"
               "${CPackRun_CPackGen}"
               "${CPackRun_CPackDEBConfiguration}"
+              "-DCONFIG=$<CONFIG>"
               -P "${CMake_SOURCE_DIR}/Tests/${DEB_TEST_NAMES}/RunCPackVerifyResult-${CPackDEBConfiguration}.cmake")
           list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${DEB_TEST_NAMES}/build${CPackGen}-${CPackDEBConfiguration}")
       endforeach()
@@ -1325,12 +1360,6 @@
     )
   list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/QtAutomocNoQt")
 
-  if(NOT DEFINED CMake_TEST_Qt5)
-    set(CMake_TEST_Qt5 1)
-  endif()
-  if(CMake_TEST_Qt5)
-    find_package(Qt5Widgets QUIET NO_MODULE)
-  endif()
   if(CMake_TEST_Qt5 AND Qt5Widgets_FOUND)
     add_subdirectory(Qt5Autogen)
   endif()
@@ -1401,6 +1430,7 @@
             ICU
             JPEG
             JsonCpp
+            LibArchive
             LibLZMA
             LibRHash
             Libinput
@@ -1440,7 +1470,7 @@
     add_subdirectory(GoogleTest)
   endif()
 
-  if(CMake_TEST_FindPython OR CMake_TEST_FindPython_NumPy)
+  if(CMake_TEST_FindPython OR CMake_TEST_FindPython_NumPy OR CMake_TEST_FindPython_Conda)
     add_subdirectory(FindPython)
   endif()
 
@@ -1586,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
@@ -1597,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)
@@ -1861,7 +1892,7 @@
   ADD_TEST_MACRO(CheckCompilerRelatedVariables CheckCompilerRelatedVariables)
 
   if("${CMAKE_GENERATOR}" MATCHES "Makefile" OR
-     "${CMAKE_GENERATOR}" MATCHES "Ninja")
+     "${CMAKE_GENERATOR}" MATCHES "^Ninja$")
     add_test(MakeClean ${CMAKE_CTEST_COMMAND}
       --build-and-test
       "${CMake_SOURCE_DIR}/Tests/MakeClean"
@@ -3392,17 +3423,6 @@
     set_tests_properties ( KDELibsAlpha1 PROPERTIES TIMEOUT 5400)
   endif()
 
-  # If this is not an in-source build, provide a target to wipe out
-  # all the test build directories.
-  if(NOT EXISTS "${CMake_BINARY_DIR}/CMakeLists.txt")
-    configure_file(${CMake_SOURCE_DIR}/Tests/test_clean.cmake.in
-                   ${CMake_BINARY_DIR}/Tests/test_clean.cmake @ONLY)
-    add_custom_target(test_clean
-      COMMAND ${CMAKE_COMMAND} -P ${CMake_BINARY_DIR}/Tests/test_clean.cmake
-      COMMENT "Removing test build directories."
-      )
-  endif()
-
   # Define a set of "contract" tests, each activated by a cache entry
   # named "CMake_TEST_CONTRACT_<project>".  For each Contract test,
   # the project should provide a directory with a CMakeLists.txt file
@@ -3477,4 +3497,16 @@
   if(NOT CMake_TEST_EXTERNAL_CMAKE)
     add_subdirectory(CMakeTests)
   endif()
+
+  # If this is not an in-source build, provide a target to wipe out
+  # all the test build directories. This must come at the end after
+  # all the above logic has finished adding to TEST_BUILD_DIRS
+  if(NOT EXISTS "${CMake_BINARY_DIR}/CMakeLists.txt")
+    configure_file(${CMake_SOURCE_DIR}/Tests/test_clean.cmake.in
+                   ${CMake_BINARY_DIR}/Tests/test_clean.cmake @ONLY)
+    add_custom_target(test_clean
+      COMMAND ${CMAKE_COMMAND} -P ${CMake_BINARY_DIR}/Tests/test_clean.cmake
+      COMMENT "Removing test build directories."
+      )
+  endif()
 endif()
diff --git a/Tests/CMakeOnly/CMakeLists.txt b/Tests/CMakeOnly/CMakeLists.txt
index 03babd2..361cf5f 100644
--- a/Tests/CMakeOnly/CMakeLists.txt
+++ b/Tests/CMakeOnly/CMakeLists.txt
@@ -31,12 +31,9 @@
 add_CMakeOnly_test(CompilerIdC)
 add_CMakeOnly_test(CompilerIdCXX)
 
-if(CMAKE_OBJC_COMPILER)
+if (APPLE AND CMAKE_C_COMPILER_ID MATCHES "Clang|GNU")
   add_CMakeOnly_test(CompilerIdOBJC)
   add_CMakeOnly_test(CheckOBJCCompilerFlag)
-endif()
-
-if(CMAKE_OBJCXX_COMPILER)
   add_CMakeOnly_test(CompilerIdOBJCXX)
   add_CMakeOnly_test(CheckOBJCXXCompilerFlag)
 endif()
@@ -75,6 +72,12 @@
 
 add_test(CMakeOnly.ProjectIncludeBefore ${CMAKE_CMAKE_COMMAND}
   -DTEST=ProjectIncludeBefore
+  -DCMAKE_ARGS=-DCMAKE_PROJECT_ProjectInclude_INCLUDE_BEFORE=${CMAKE_CURRENT_SOURCE_DIR}/ProjectIncludeBefore/include.cmake
+  -P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake
+  )
+
+add_test(CMakeOnly.ProjectIncludeBeforeAny ${CMAKE_CMAKE_COMMAND}
+  -DTEST=ProjectIncludeBeforeAny
   -DCMAKE_ARGS=-DCMAKE_PROJECT_INCLUDE_BEFORE=${CMAKE_CURRENT_SOURCE_DIR}/ProjectIncludeBefore/include.cmake
   -P ${CMAKE_CURRENT_BINARY_DIR}/Test.cmake
   )
diff --git a/Tests/CMakeOnly/CheckOBJCCompilerFlag/CMakeLists.txt b/Tests/CMakeOnly/CheckOBJCCompilerFlag/CMakeLists.txt
index a9a96ee..a714b73 100644
--- a/Tests/CMakeOnly/CheckOBJCCompilerFlag/CMakeLists.txt
+++ b/Tests/CMakeOnly/CheckOBJCCompilerFlag/CMakeLists.txt
@@ -1,17 +1,7 @@
-cmake_minimum_required(VERSION 2.8.12)
-
-project(CheckOBJCCompilerFlag)
-
+cmake_minimum_required(VERSION 3.16)
+project(CheckOBJCCompilerFlag OBJC)
 include(CheckOBJCCompilerFlag)
-
-if(CMAKE_COMPILER_IS_GNUOBJC)
-  set(COMPILER_FLAG -fobjc-direct-dispatch)
-else()
-  set(COMPILER_FLAG -fobjc-gc)
-endif()
-
-CHECK_OBJC_COMPILER_FLAGS(${COMPILER_FLAG} HAS_COMPILER_FLAG)
-
+check_objc_compiler_flag(-DFOO HAS_COMPILER_FLAG)
 if(NOT HAS_COMPILER_FLAG)
   message(SEND_ERROR "Test fail: HAS_COMPILER_FLAG: ${COMPILER_FLAG}")
-endif
+endif()
diff --git a/Tests/CMakeOnly/CheckOBJCXXCompilerFlag/CMakeLists.txt b/Tests/CMakeOnly/CheckOBJCXXCompilerFlag/CMakeLists.txt
index f83b738..d09f0b9 100644
--- a/Tests/CMakeOnly/CheckOBJCXXCompilerFlag/CMakeLists.txt
+++ b/Tests/CMakeOnly/CheckOBJCXXCompilerFlag/CMakeLists.txt
@@ -1,17 +1,7 @@
-cmake_minimum_required(VERSION 2.8.12)
-
-project(CheckOBJCXXCompilerFlag)
-
+cmake_minimum_required(VERSION 3.16)
+project(CheckOBJCXXCompilerFlag OBJCXX)
 include(CheckOBJCXXCompilerFlag)
-
-if(CMAKE_COMPILER_IS_GNUOBJCXX)
-  set(COMPILER_FLAG -fobjc-direct-dispatch)
-else()
-  set(COMPILER_FLAG -fobjc-gc)
-endif()
-
-CHECK_OBJCXX_COMPILER_FLAGS(${COMPILER_FLAG} HAS_COMPILER_FLAG)
-
+check_objcxx_compiler_flag(-DFOO HAS_COMPILER_FLAG)
 if(NOT HAS_COMPILER_FLAG)
   message(SEND_ERROR "Test fail: HAS_COMPILER_FLAG: ${COMPILER_FLAG}")
 endif()
diff --git a/Tests/CMakeOnly/CheckStructHasMember/CMakeLists.txt b/Tests/CMakeOnly/CheckStructHasMember/CMakeLists.txt
index a584505..859ec41 100644
--- a/Tests/CMakeOnly/CheckStructHasMember/CMakeLists.txt
+++ b/Tests/CMakeOnly/CheckStructHasMember/CMakeLists.txt
@@ -6,7 +6,7 @@
 
 include(CheckStructHasMember)
 
-foreach(_config_type Release RelWithDebInfo MinSizeRel Debug)
+foreach(_config_type Release RelWithDebInfo Debug)
     set(CMAKE_TRY_COMPILE_CONFIGURATION ${_config_type})
     unset(CSHM_RESULT_S1_${_config_type} CACHE)
     unset(CSHM_RESULT_S2_${_config_type} CACHE)
@@ -26,7 +26,7 @@
     endif()
 endforeach()
 
-foreach(_config_type Release RelWithDebInfo MinSizeRel Debug)
+foreach(_config_type Release RelWithDebInfo Debug)
     set(CMAKE_TRY_COMPILE_CONFIGURATION ${_config_type})
     unset(CSHM_RESULT_S1_${_config_type}_C CACHE)
     unset(CSHM_RESULT_S2_${_config_type}_C CACHE)
@@ -46,7 +46,7 @@
     endif()
 endforeach()
 
-foreach(_config_type Release RelWithDebInfo MinSizeRel Debug)
+foreach(_config_type Release RelWithDebInfo Debug)
     set(CMAKE_TRY_COMPILE_CONFIGURATION ${_config_type})
     unset(CSHM_RESULT_S1_${_config_type}_CXX CACHE)
     unset(CSHM_RESULT_S2_${_config_type}_CXX CACHE)
diff --git a/Tests/CMakeOnly/ProjectIncludeBeforeAny/CMakeLists.txt b/Tests/CMakeOnly/ProjectIncludeBeforeAny/CMakeLists.txt
new file mode 100644
index 0000000..5cd9cba
--- /dev/null
+++ b/Tests/CMakeOnly/ProjectIncludeBeforeAny/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(FOO TRUE)
+project(ProjectInclude LANGUAGES NONE)
+if(NOT AUTO_INCLUDE)
+  message(FATAL_ERROR "include file not found")
+endif()
diff --git a/Tests/CMakeOnly/ProjectIncludeBeforeAny/include.cmake b/Tests/CMakeOnly/ProjectIncludeBeforeAny/include.cmake
new file mode 100644
index 0000000..0a4799d
--- /dev/null
+++ b/Tests/CMakeOnly/ProjectIncludeBeforeAny/include.cmake
@@ -0,0 +1,9 @@
+if(NOT FOO)
+  message(FATAL_ERROR "FOO is not set")
+endif()
+
+if(NOT "${PROJECT_NAME}" STREQUAL "")
+  message(FATAL_ERROR "PROJECT_NAME should be empty")
+endif()
+
+set(AUTO_INCLUDE TRUE)
diff --git a/Tests/CMakeOnly/Test.cmake.in b/Tests/CMakeOnly/Test.cmake.in
index 0ae8af1..c531e8b 100644
--- a/Tests/CMakeOnly/Test.cmake.in
+++ b/Tests/CMakeOnly/Test.cmake.in
@@ -7,6 +7,13 @@
   set(maybe_make_program "-DCMAKE_MAKE_PROGRAM=${make_program}")
 endif()
 
+set(_isMultiConfig "@_isMultiConfig@")
+if(_isMultiConfig)
+  set(cfg_opts "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release\\;RelWithDebInfo")
+else()
+  set(cfg_opts)
+endif()
+
 set(source_dir "@CMAKE_CURRENT_SOURCE_DIR@/${TEST_SOURCE}")
 set(binary_dir "@CMAKE_CURRENT_BINARY_DIR@/${TEST}-build")
 file(REMOVE_RECURSE "${binary_dir}")
@@ -16,6 +23,7 @@
   "${source_dir}" -G "@CMAKE_GENERATOR@"
   -A "@CMAKE_GENERATOR_PLATFORM@"
   -T "@CMAKE_GENERATOR_TOOLSET@"
+  ${cfg_opts}
   ${maybe_make_program}
   WORKING_DIRECTORY "${binary_dir}"
   RESULT_VARIABLE result
diff --git a/Tests/CMakeTestMultipleConfigures/RunCMake.cmake b/Tests/CMakeTestMultipleConfigures/RunCMake.cmake
index 9632664..a79bfcb 100644
--- a/Tests/CMakeTestMultipleConfigures/RunCMake.cmake
+++ b/Tests/CMakeTestMultipleConfigures/RunCMake.cmake
@@ -21,11 +21,11 @@
 
 # First setup source and binary trees:
 #
-execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory
+execute_process(COMMAND ${CMAKE_COMMAND} -E rm -rf
   ${dir}/Source
 )
 
-execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory
+execute_process(COMMAND ${CMAKE_COMMAND} -E rm -rf
   ${dir}/Build
 )
 
@@ -69,7 +69,7 @@
 
   # Save this iteration of the Build directory:
   #
-  execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory
+  execute_process(COMMAND ${CMAKE_COMMAND} -E rm -rf
     ${dir}/b${i}
     )
   execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory
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/CMakeLists.txt b/Tests/CPackComponentsDEB/CMakeLists.txt
index bc5b6a9..4363f1b 100644
--- a/Tests/CPackComponentsDEB/CMakeLists.txt
+++ b/Tests/CPackComponentsDEB/CMakeLists.txt
@@ -104,7 +104,7 @@
         COMPONENT applications)
 
 if(EXISTS "./dirtest")
-  execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory ./dirtest)
+  execute_process(COMMAND ${CMAKE_COMMAND} -E rm -rf ./dirtest)
 endif()
 # NOTE: directory left empty on purpose
 execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ./dirtest)
diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult.cmake
index b172da2..3bc8d2a 100644
--- a/Tests/CPackComponentsDEB/RunCPackVerifyResult.cmake
+++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult.cmake
@@ -45,7 +45,7 @@
 
   message("config_args = ${run_cpack_deb_CONFIG_ARGS}")
   message("config_verbose = ${run_cpack_deb_CONFIG_VERBOSE}")
-  execute_process(COMMAND ${CMAKE_CPACK_COMMAND} ${run_cpack_deb_CONFIG_VERBOSE} -G ${CPackGen} ${run_cpack_deb_CONFIG_ARGS}
+  execute_process(COMMAND ${CMAKE_CPACK_COMMAND} ${run_cpack_deb_CONFIG_VERBOSE} -G ${CPackGen} -C "${CONFIG}" ${run_cpack_deb_CONFIG_ARGS}
       RESULT_VARIABLE CPack_result
       OUTPUT_VARIABLE CPack_output
       ERROR_VARIABLE CPack_error
diff --git a/Tests/CPackNSISGenerator/CMakeLists.txt b/Tests/CPackNSISGenerator/CMakeLists.txt
new file mode 100644
index 0000000..b8b2ed6
--- /dev/null
+++ b/Tests/CPackNSISGenerator/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(CPackNSISGenerator)
+
+add_executable(hello main.cpp)
+
+install(TARGETS hello
+  ARCHIVE DESTINATION .
+  RUNTIME DESTINATION .
+  LIBRARY DESTINATION .
+  BUNDLE DESTINATION .)
+
+set(CPACK_NSIS_MUI_HEADERIMAGE "${PROJECT_SOURCE_DIR}\\\\header-image.bmp")
+set(CPACK_PACKAGE_ICON "${PROJECT_SOURCE_DIR}\\\\header-icon.bmp")
+set(CPACK_NSIS_MUI_ICON "${PROJECT_SOURCE_DIR}\\\\install.ico")
+set(CPACK_NSIS_MUI_UNIICON "${PROJECT_SOURCE_DIR}\\\\uninstall.ico")
+set(CPACK_GENERATOR "NSIS")
+set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
+
+include(CPack)
diff --git a/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake b/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
new file mode 100644
index 0000000..01b37c5
--- /dev/null
+++ b/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
@@ -0,0 +1,46 @@
+message(STATUS "=============================================================")
+message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
+message(STATUS "")
+
+if(NOT CPackNSISGenerator_BINARY_DIR)
+  message(FATAL_ERROR "CPackNSISGenerator_BINARY_DIR not set")
+endif()
+
+message(STATUS "CMAKE_COMMAND: ${CMAKE_COMMAND}")
+message(STATUS "CMAKE_CPACK_COMMAND: ${CMAKE_CPACK_COMMAND}")
+message(STATUS "CPackNSISGenerator_BINARY_DIR: ${CPackNSISGenerator_BINARY_DIR}")
+
+if(config)
+  set(_C_config -C ${config})
+endif()
+
+execute_process(COMMAND "${CMAKE_CPACK_COMMAND}"
+                        ${_C_config}
+  RESULT_VARIABLE CPack_result
+  OUTPUT_VARIABLE CPack_output
+  ERROR_VARIABLE CPack_error
+  WORKING_DIRECTORY "${CPackNSISGenerator_BINARY_DIR}")
+
+if(CPack_result)
+  message(FATAL_ERROR "CPack execution went wrong!, CPack_output=${CPack_output}, CPack_error=${CPack_error}")
+else ()
+  message(STATUS "CPack_output=${CPack_output}")
+endif()
+
+set(expected_file_mask "${CPackNSISGenerator_BINARY_DIR}/_CPack_Packages/*/NSIS/*.nsi")
+file(GLOB project_file "${expected_file_mask}")
+
+message(STATUS "project_file='${project_file}'")
+message(STATUS "expected_file_mask='${expected_file_mask}'")
+
+if(NOT project_file)
+  message(FATAL_ERROR "project_file does not exist.")
+endif()
+
+# should match !define MUI_HEADERIMAGE_BITMAP "${PROJECT_SOURCE_DIR}\header-image.bmp"
+file(STRINGS "${project_file}" line REGEX "^!define MUI_HEADERIMAGE_BITMAP")
+string(FIND "${line}" "header-image.bmp" output_index)
+message(STATUS "Found the bitmap at index ${output_index}")
+if("${output_index}" EQUAL "-1")
+  message(FATAL_ERROR "MUI_HEADERIMAGE_BITMAP not found in the project")
+endif()
diff --git a/Tests/CPackNSISGenerator/header-icon.bmp b/Tests/CPackNSISGenerator/header-icon.bmp
new file mode 100644
index 0000000..ef6a656
--- /dev/null
+++ b/Tests/CPackNSISGenerator/header-icon.bmp
Binary files differ
diff --git a/Tests/CPackNSISGenerator/header-image.bmp b/Tests/CPackNSISGenerator/header-image.bmp
new file mode 100644
index 0000000..15b1730
--- /dev/null
+++ b/Tests/CPackNSISGenerator/header-image.bmp
Binary files differ
diff --git a/Tests/CPackNSISGenerator/install.ico b/Tests/CPackNSISGenerator/install.ico
new file mode 100644
index 0000000..3b1e480
--- /dev/null
+++ b/Tests/CPackNSISGenerator/install.ico
Binary files differ
diff --git a/Tests/CPackNSISGenerator/main.cpp b/Tests/CPackNSISGenerator/main.cpp
new file mode 100644
index 0000000..956f345
--- /dev/null
+++ b/Tests/CPackNSISGenerator/main.cpp
@@ -0,0 +1,4 @@
+int main()
+{
+  return 42;
+}
diff --git a/Tests/CPackNSISGenerator/uninstall.ico b/Tests/CPackNSISGenerator/uninstall.ico
new file mode 100644
index 0000000..c4f6316
--- /dev/null
+++ b/Tests/CPackNSISGenerator/uninstall.ico
Binary files differ
diff --git a/Tests/CTestConfig/dashboard.cmake.in b/Tests/CTestConfig/dashboard.cmake.in
index 4bb1262..34824e3 100644
--- a/Tests/CTestConfig/dashboard.cmake.in
+++ b/Tests/CTestConfig/dashboard.cmake.in
@@ -13,6 +13,8 @@
 set(arg "")
 if(NOT _isMultiConfig)
   set(arg "-DCMAKE_BUILD_TYPE:STRING=@cfg@")
+else()
+  set(arg "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release\\;MinSizeRel\\;RelWithDebInfo")
 endif()
 
 message("cmake initial configure")
diff --git a/Tests/CTestConfig/script.cmake.in b/Tests/CTestConfig/script.cmake.in
index 973c7b8..59c585b 100644
--- a/Tests/CTestConfig/script.cmake.in
+++ b/Tests/CTestConfig/script.cmake.in
@@ -6,7 +6,14 @@
 
 ctest_start(Experimental)
 
-ctest_configure(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE rv)
+set(_isMultiConfig "@_isMultiConfig@")
+if(_isMultiConfig)
+  set(cfg_opts "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release\\;MinSizeRel\\;RelWithDebInfo")
+else()
+  set(cfg_opts)
+endif()
+
+ctest_configure(BUILD "${CTEST_BINARY_DIRECTORY}" OPTIONS "${cfg_opts}" RETURN_VALUE rv)
 if(NOT rv STREQUAL 0)
   message(FATAL_ERROR "*** error in ctest_configure ***")
 endif()
diff --git a/Tests/Complex/CMakeLists.txt b/Tests/Complex/CMakeLists.txt
index 2e41754..9fd85be 100644
--- a/Tests/Complex/CMakeLists.txt
+++ b/Tests/Complex/CMakeLists.txt
@@ -324,7 +324,7 @@
       ${file}
       "[${hkey}]" DOC "Registry_Test_Path")
     exec_program(${CMAKE_COMMAND} ARGS "-E delete_regv \"${hkey}\"")
-    exec_program(${CMAKE_COMMAND} ARGS "-E remove \"${dir}/${file}\"")
+    exec_program(${CMAKE_COMMAND} ARGS "-E rm -f \"${dir}/${file}\"")
   endif ()
 endif ()
 
diff --git a/Tests/Complex/Library/CMakeLists.txt b/Tests/Complex/Library/CMakeLists.txt
index 64f6dc8..df874ef 100644
--- a/Tests/Complex/Library/CMakeLists.txt
+++ b/Tests/Complex/Library/CMakeLists.txt
@@ -131,7 +131,7 @@
 
     # Custom target to try preprocessing invocation.
     add_custom_target(test_preprocess ${MAYBE_ALL}
-      COMMAND ${CMAKE_COMMAND} -E remove CMakeFiles/create_file.dir/create_file.i
+      COMMAND ${CMAKE_COMMAND} -E rm -f CMakeFiles/create_file.dir/create_file.i
       COMMAND ${CMAKE_MAKE_PROGRAM} create_file.i
       COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/test_preprocess.cmake
       WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
diff --git a/Tests/ComplexOneConfig/CMakeLists.txt b/Tests/ComplexOneConfig/CMakeLists.txt
index 628cd4e..28b73af 100644
--- a/Tests/ComplexOneConfig/CMakeLists.txt
+++ b/Tests/ComplexOneConfig/CMakeLists.txt
@@ -281,7 +281,7 @@
       ${file}
       "[${hkey}]" DOC "Registry_Test_Path")
     exec_program(${CMAKE_COMMAND} ARGS "-E delete_regv \"${hkey}\"")
-    exec_program(${CMAKE_COMMAND} ARGS "-E remove \"${dir}/${file}\"")
+    exec_program(${CMAKE_COMMAND} ARGS "-E rm -f \"${dir}/${file}\"")
   endif ()
 endif ()
 
diff --git a/Tests/ComplexOneConfig/Library/CMakeLists.txt b/Tests/ComplexOneConfig/Library/CMakeLists.txt
index 64f6dc8..df874ef 100644
--- a/Tests/ComplexOneConfig/Library/CMakeLists.txt
+++ b/Tests/ComplexOneConfig/Library/CMakeLists.txt
@@ -131,7 +131,7 @@
 
     # Custom target to try preprocessing invocation.
     add_custom_target(test_preprocess ${MAYBE_ALL}
-      COMMAND ${CMAKE_COMMAND} -E remove CMakeFiles/create_file.dir/create_file.i
+      COMMAND ${CMAKE_COMMAND} -E rm -f CMakeFiles/create_file.dir/create_file.i
       COMMAND ${CMAKE_MAKE_PROGRAM} create_file.i
       COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/test_preprocess.cmake
       WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
diff --git a/Tests/Contracts/VTK/CMakeLists.txt b/Tests/Contracts/VTK/CMakeLists.txt
index c946499..6ae2732 100644
--- a/Tests/Contracts/VTK/CMakeLists.txt
+++ b/Tests/Contracts/VTK/CMakeLists.txt
@@ -21,7 +21,7 @@
 
 # build & test VTK's release branch
 ExternalProject_Add(${PROJECT_NAME}
-  GIT_REPOSITORY "git://vtk.org/VTK.git"
+  GIT_REPOSITORY "https://gitlab.kitware.com/vtk/vtk.git"
   GIT_TAG "release"
   PREFIX ${base_dir}
   CONFIGURE_COMMAND ""
diff --git a/Tests/Cuda/CMakeLists.txt b/Tests/Cuda/CMakeLists.txt
index 44c6005..58b9b03 100644
--- a/Tests/Cuda/CMakeLists.txt
+++ b/Tests/Cuda/CMakeLists.txt
@@ -1,11 +1,25 @@
 
 ADD_TEST_MACRO(Cuda.Complex CudaComplex)
 ADD_TEST_MACRO(Cuda.ConsumeCompileFeatures CudaConsumeCompileFeatures)
+ADD_TEST_MACRO(Cuda.CXXStandardSetTwice CXXStandardSetTwice)
 ADD_TEST_MACRO(Cuda.ObjectLibrary CudaObjectLibrary)
-ADD_TEST_MACRO(Cuda.MixedStandardLevels MixedStandardLevels)
+ADD_TEST_MACRO(Cuda.MixedStandardLevels1 MixedStandardLevels1)
+ADD_TEST_MACRO(Cuda.MixedStandardLevels2 MixedStandardLevels2)
+ADD_TEST_MACRO(Cuda.MixedStandardLevels3 MixedStandardLevels3)
+ADD_TEST_MACRO(Cuda.MixedStandardLevels4 MixedStandardLevels4)
+ADD_TEST_MACRO(Cuda.MixedStandardLevels5 MixedStandardLevels5)
 ADD_TEST_MACRO(Cuda.NotEnabled CudaNotEnabled)
 ADD_TEST_MACRO(Cuda.SeparableCompCXXOnly SeparableCompCXXOnly)
-ADD_TEST_MACRO(Cuda.ToolkitInclude CudaToolkitInclude)
+ADD_TEST_MACRO(Cuda.Toolkit Toolkit)
+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/CXXStandardSetTwice/CMakeLists.txt b/Tests/Cuda/CXXStandardSetTwice/CMakeLists.txt
new file mode 100644
index 0000000..1941c49
--- /dev/null
+++ b/Tests/Cuda/CXXStandardSetTwice/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.7)
+project(CXXStandardSetTwice CXX CUDA)
+
+string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_30,code=compute_30")
+
+set(CMAKE_CXX_STANDARD 11)
+
+add_executable(CXXStandardSetTwice main.cu)
+target_compile_features(CXXStandardSetTwice PUBLIC cxx_std_11)
+
+if(APPLE)
+  # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+  set_property(TARGET CXXStandardSetTwice PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/MixedStandardLevels/main.cu b/Tests/Cuda/CXXStandardSetTwice/main.cu
similarity index 100%
rename from Tests/Cuda/MixedStandardLevels/main.cu
rename to Tests/Cuda/CXXStandardSetTwice/main.cu
diff --git a/Tests/Cuda/Complex/CMakeLists.txt b/Tests/Cuda/Complex/CMakeLists.txt
index d3d4b7c..08d1e16 100644
--- a/Tests/Cuda/Complex/CMakeLists.txt
+++ b/Tests/Cuda/Complex/CMakeLists.txt
@@ -22,18 +22,11 @@
 set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
 
 add_library(CudaComplexCppBase SHARED dynamic.cpp)
-add_library(CudaComplexSeperableLib STATIC file1.cu file2.cu file3.cu)
-set_target_properties(CudaComplexSeperableLib
-                       PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
-set_target_properties( CudaComplexSeperableLib
-                       PROPERTIES POSITION_INDEPENDENT_CODE ON)
-
 add_library(CudaComplexSharedLib SHARED dynamic.cu)
 target_link_libraries(CudaComplexSharedLib PUBLIC CudaComplexCppBase)
 
+add_library(CudaComplexSeperableLib STATIC file1.cu file2.cu file3.cu)
 add_library(CudaComplexMixedLib SHARED mixed.cpp mixed.cu)
-set_target_properties(CudaComplexMixedLib
-                       PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
 target_link_libraries(CudaComplexMixedLib
                       PUBLIC CudaComplexSharedLib
                       PRIVATE CudaComplexSeperableLib)
@@ -41,7 +34,27 @@
 add_executable(CudaComplex main.cpp)
 target_link_libraries(CudaComplex PUBLIC CudaComplexMixedLib)
 
+
+set_target_properties(CudaComplexMixedLib
+                      CudaComplexSeperableLib
+                      PROPERTIES
+                        POSITION_INDEPENDENT_CODE  ON
+                        CUDA_SEPARABLE_COMPILATION ON
+                      )
+set_target_properties(CudaComplexMixedLib
+                      CudaComplexSharedLib
+                      PROPERTIES
+                        CUDA_RUNTIME_LIBRARY shared
+                      )
+
+
 if(APPLE)
   # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
   set_property(TARGET CudaComplex PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
 endif()
+
+if(UNIX)
+  # Help the shared cuda runtime find libcudart as it is not located
+  # in a default system searched location
+  set_property(TARGET CudaComplexMixedLib PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/Complex/dynamic.cu b/Tests/Cuda/Complex/dynamic.cu
index 9da8853..7f2f2b5 100644
--- a/Tests/Cuda/Complex/dynamic.cu
+++ b/Tests/Cuda/Complex/dynamic.cu
@@ -54,17 +54,20 @@
   return 1;
 }
 
-EXPORT void cuda_dynamic_lib_func()
+EXPORT bool cuda_dynamic_lib_func()
 {
-  DetermineIfValidCudaDevice<<<1, 1>>>();
   cudaError_t err = cudaGetLastError();
   if (err != cudaSuccess) {
-    std::cerr << "DetermineIfValidCudaDevice [SYNC] failed: "
+    std::cerr << "DetermineIfValidCudaDevice [Per Launch] failed: "
               << cudaGetErrorString(err) << std::endl;
+    return false;
   }
+  DetermineIfValidCudaDevice<<<1, 1>>>();
   err = cudaDeviceSynchronize();
   if (err != cudaSuccess) {
-    std::cerr << "DetermineIfValidCudaDevice [ASYNC] failed: "
+    std::cerr << "DetermineIfValidCudaDevice [SYNC] failed: "
               << cudaGetErrorString(cudaGetLastError()) << std::endl;
+    return false;
   }
+  return true;
 }
diff --git a/Tests/Cuda/Complex/main.cpp b/Tests/Cuda/Complex/main.cpp
index 6ca5952..da09b44 100644
--- a/Tests/Cuda/Complex/main.cpp
+++ b/Tests/Cuda/Complex/main.cpp
@@ -22,5 +22,6 @@
 
   int r1 = call_cuda_seperable_code(42);
   int r2 = mixed_launch_kernel(42);
+
   return (r1 == 42 || r2 == 42) ? 1 : 0;
 }
diff --git a/Tests/Cuda/Complex/mixed.cu b/Tests/Cuda/Complex/mixed.cu
index 5b85aec..76119ad 100644
--- a/Tests/Cuda/Complex/mixed.cu
+++ b/Tests/Cuda/Complex/mixed.cu
@@ -15,7 +15,7 @@
 result_type __device__ file1_func(int x);
 result_type_dynamic __device__ file2_func(int x);
 
-IMPORT void __host__ cuda_dynamic_lib_func();
+IMPORT bool __host__ cuda_dynamic_lib_func();
 
 static __global__ void mixed_kernel(result_type* r, int x)
 {
@@ -25,7 +25,9 @@
 
 EXPORT int mixed_launch_kernel(int x)
 {
-  cuda_dynamic_lib_func();
+  if (!cuda_dynamic_lib_func()) {
+    return x;
+  }
 
   result_type* r;
   cudaError_t err = cudaMallocManaged(&r, sizeof(result_type));
diff --git a/Tests/Cuda/IncludePathNoToolkit/CMakeLists.txt b/Tests/Cuda/IncludePathNoToolkit/CMakeLists.txt
new file mode 100644
index 0000000..7be1561
--- /dev/null
+++ b/Tests/Cuda/IncludePathNoToolkit/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.8)
+project (IncludePathNoToolkit CXX CUDA)
+
+#Goal for this example:
+# Validate that between the CXX implicit include directories and the
+# CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES directories we can find
+# the cuda runtime headers
+
+add_executable(IncludePathNoToolkit main.cpp)
+target_include_directories(IncludePathNoToolkit PRIVATE
+                           ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES})
diff --git a/Tests/Cuda/ToolkitInclude/main.cpp b/Tests/Cuda/IncludePathNoToolkit/main.cpp
similarity index 100%
copy from Tests/Cuda/ToolkitInclude/main.cpp
copy to Tests/Cuda/IncludePathNoToolkit/main.cpp
diff --git a/Tests/Cuda/MixedStandardLevels/CMakeLists.txt b/Tests/Cuda/MixedStandardLevels/CMakeLists.txt
deleted file mode 100644
index b399662..0000000
--- a/Tests/Cuda/MixedStandardLevels/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-cmake_minimum_required(VERSION 3.7)
-project(MixedStandardLevels CXX CUDA)
-
-string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_30,code=compute_30")
-
-set(CMAKE_CXX_STANDARD 11)
-
-add_executable(MixedStandardLevels main.cu)
-target_compile_features(MixedStandardLevels PUBLIC cxx_std_11)
-
-if(APPLE)
-  # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
-  set_property(TARGET MixedStandardLevels PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
-endif()
diff --git a/Tests/Cuda/MixedStandardLevels1/CMakeLists.txt b/Tests/Cuda/MixedStandardLevels1/CMakeLists.txt
new file mode 100644
index 0000000..b03e51e
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels1/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.7)
+project(MixedStandardLevels1 CXX CUDA)
+
+string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_30,code=compute_30")
+
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CUDA_STANDARD 11)
+
+add_executable(MixedStandardLevels1 main.cu lib.cpp)
+
+if(APPLE)
+  # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+  set_property(TARGET MixedStandardLevels1 PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/MixedStandardLevels1/lib.cpp b/Tests/Cuda/MixedStandardLevels1/lib.cpp
new file mode 100644
index 0000000..cabbacb
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels1/lib.cpp
@@ -0,0 +1,7 @@
+
+int func(int A, int B)
+{
+  // Verify that we have at least c++14
+  auto mult_func = [](auto a, auto b) { return a * b; };
+  return mult_func(A, B);
+}
diff --git a/Tests/Cuda/MixedStandardLevels1/main.cu b/Tests/Cuda/MixedStandardLevels1/main.cu
new file mode 100644
index 0000000..bc02c6d
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels1/main.cu
@@ -0,0 +1,9 @@
+
+#include <type_traits>
+
+int main(int argc, char** argv)
+{
+  // Verify that we have at least c++11
+  using returnv = std::integral_constant<int, 0>;
+  return returnv::value;
+}
diff --git a/Tests/Cuda/MixedStandardLevels2/CMakeLists.txt b/Tests/Cuda/MixedStandardLevels2/CMakeLists.txt
new file mode 100644
index 0000000..12dd328
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels2/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.7)
+project(MixedStandardLevels2 CXX CUDA)
+
+string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_30,code=compute_30")
+
+set(CMAKE_CXX_STANDARD 17) #this can decay
+
+add_executable(MixedStandardLevels2 main.cu lib.cpp)
+target_compile_features(MixedStandardLevels2 PUBLIC cuda_std_11)
+
+if(APPLE)
+  # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+  set_property(TARGET MixedStandardLevels2 PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/MixedStandardLevels2/lib.cpp b/Tests/Cuda/MixedStandardLevels2/lib.cpp
new file mode 100644
index 0000000..cabbacb
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels2/lib.cpp
@@ -0,0 +1,7 @@
+
+int func(int A, int B)
+{
+  // Verify that we have at least c++14
+  auto mult_func = [](auto a, auto b) { return a * b; };
+  return mult_func(A, B);
+}
diff --git a/Tests/Cuda/MixedStandardLevels2/main.cu b/Tests/Cuda/MixedStandardLevels2/main.cu
new file mode 100644
index 0000000..a97a41e
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels2/main.cu
@@ -0,0 +1,11 @@
+
+#if __cplusplus < 201103L && !defined(_MSC_VER)
+#  error "invalid standard value"
+#endif
+#include <type_traits>
+
+int main(int argc, char** argv)
+{
+  using returnv = std::integral_constant<int, 0>;
+  return returnv::value;
+}
diff --git a/Tests/Cuda/MixedStandardLevels3/CMakeLists.txt b/Tests/Cuda/MixedStandardLevels3/CMakeLists.txt
new file mode 100644
index 0000000..2b611be
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels3/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.7)
+project(MixedStandardLevels3 CXX CUDA)
+
+string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_30,code=compute_30")
+
+add_executable(MixedStandardLevels3 main.cu lib.cpp)
+target_compile_features(MixedStandardLevels3 PUBLIC cuda_std_03 cxx_std_14)
+
+if(APPLE)
+  # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+  set_property(TARGET MixedStandardLevels3 PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/MixedStandardLevels3/lib.cpp b/Tests/Cuda/MixedStandardLevels3/lib.cpp
new file mode 100644
index 0000000..cabbacb
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels3/lib.cpp
@@ -0,0 +1,7 @@
+
+int func(int A, int B)
+{
+  // Verify that we have at least c++14
+  auto mult_func = [](auto a, auto b) { return a * b; };
+  return mult_func(A, B);
+}
diff --git a/Tests/Cuda/MixedStandardLevels3/main.cu b/Tests/Cuda/MixedStandardLevels3/main.cu
new file mode 100644
index 0000000..1c19e8d
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels3/main.cu
@@ -0,0 +1,5 @@
+
+int main(int argc, char** argv)
+{
+  return 0;
+}
diff --git a/Tests/Cuda/MixedStandardLevels4/CMakeLists.txt b/Tests/Cuda/MixedStandardLevels4/CMakeLists.txt
new file mode 100644
index 0000000..faf6869
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels4/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.7)
+project(MixedStandardLevels4 CXX CUDA)
+
+string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_30,code=compute_30")
+
+set(CMAKE_CUDA_STANDARD 03)
+
+add_executable(MixedStandardLevels4 main.cu lib.cpp)
+target_compile_features(MixedStandardLevels4 PUBLIC cxx_std_14)
+
+if(APPLE)
+  # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+  set_property(TARGET MixedStandardLevels4 PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/MixedStandardLevels4/lib.cpp b/Tests/Cuda/MixedStandardLevels4/lib.cpp
new file mode 100644
index 0000000..ef6fc20
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels4/lib.cpp
@@ -0,0 +1,16 @@
+
+
+constexpr int func(int A, int B)
+{
+#if defined(_MSC_VER) && _MSC_VER < 1913
+  // no suppport for extended constexpr
+  return B * A;
+#else
+  // Verify that we have at least c++14
+  if (A < B) {
+    return A + B;
+  } else {
+    return B * A;
+  }
+#endif
+}
diff --git a/Tests/Cuda/MixedStandardLevels4/main.cu b/Tests/Cuda/MixedStandardLevels4/main.cu
new file mode 100644
index 0000000..1c19e8d
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels4/main.cu
@@ -0,0 +1,5 @@
+
+int main(int argc, char** argv)
+{
+  return 0;
+}
diff --git a/Tests/Cuda/MixedStandardLevels5/CMakeLists.txt b/Tests/Cuda/MixedStandardLevels5/CMakeLists.txt
new file mode 100644
index 0000000..7209f60
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels5/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.7)
+project(MixedStandardLevels5 CXX CUDA)
+
+string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_30,code=compute_30")
+
+set(CMAKE_CXX_STANDARD 98)
+
+add_executable(MixedStandardLevels5 main.cu lib.cpp)
+
+if(APPLE)
+  # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+  set_property(TARGET MixedStandardLevels5 PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/Cuda/MixedStandardLevels5/lib.cpp b/Tests/Cuda/MixedStandardLevels5/lib.cpp
new file mode 100644
index 0000000..dd7b31b
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels5/lib.cpp
@@ -0,0 +1,13 @@
+
+#if __cplusplus >= 201103L
+#  error "invalid standard value"
+#endif
+int func(int A, int B)
+{
+  // Verify that we have at least c++14
+  if (A < B) {
+    return A + B;
+  } else {
+    return B * A;
+  }
+}
diff --git a/Tests/Cuda/MixedStandardLevels5/main.cu b/Tests/Cuda/MixedStandardLevels5/main.cu
new file mode 100644
index 0000000..c79afd6
--- /dev/null
+++ b/Tests/Cuda/MixedStandardLevels5/main.cu
@@ -0,0 +1,8 @@
+
+#if __cplusplus >= 201103L
+#  error "invalid standard value"
+#endif
+int main(int argc, char** argv)
+{
+  return 0;
+}
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/Cuda/Toolkit/CMakeLists.txt b/Tests/Cuda/Toolkit/CMakeLists.txt
new file mode 100644
index 0000000..86b4652
--- /dev/null
+++ b/Tests/Cuda/Toolkit/CMakeLists.txt
@@ -0,0 +1,38 @@
+cmake_minimum_required(VERSION 3.15)
+project(Toolkit CXX)
+
+#Goal for this example:
+# Validate that we can use CUDAToolkit to find cuda include paths
+find_package(CUDAToolkit REQUIRED)
+
+message(STATUS "CUDAToolkit_VERSION: ${CUDAToolkit_VERSION}")
+message(STATUS "CUDAToolkit_VERSION_MAJOR: ${CUDAToolkit_VERSION_MAJOR}")
+message(STATUS "CUDAToolkit_VERSION_MINOR: ${CUDAToolkit_VERSION_MINOR}")
+message(STATUS "CUDAToolkit_VERSION_PATCH: ${CUDAToolkit_VERSION_PATCH}")
+message(STATUS "CUDAToolkit_BIN_DIR: ${CUDAToolkit_BIN_DIR}")
+message(STATUS "CUDAToolkit_INCLUDE_DIRS: ${CUDAToolkit_INCLUDE_DIRS}")
+message(STATUS "CUDAToolkit_LIBRARY_DIR: ${CUDAToolkit_LIBRARY_DIR}")
+message(STATUS "CUDAToolkit_NVCC_EXECUTABLE ${CUDAToolkit_NVCC_EXECUTABLE}")
+
+# Verify that all the CUDA:: targets exist even when the CUDA language isn't enabled
+
+foreach (cuda_lib cudart cuda_driver cublas cufft cufftw curand cusolver cusparse nvgraph)
+  if(NOT TARGET CUDA::${cuda_lib})
+    message(FATAL_ERROR "The CUDA::${cuda_lib} target was expected but couldn't be found")
+  endif()
+endforeach()
+
+foreach (cuda_lib nppc nppial nppicc nppidei nppif nppig nppim nppist nppitc npps nppicom nppisu)
+  if(NOT TARGET CUDA::${cuda_lib})
+    message(FATAL_ERROR "The CUDA::${cuda_lib} target was expected but couldn't be found")
+  endif()
+endforeach()
+
+foreach (cuda_lib nvrtc nvToolsExt OpenCL)
+  if(NOT TARGET CUDA::${cuda_lib})
+    message(FATAL_ERROR "The CUDA::${cuda_lib} target was expected but couldn't be found")
+  endif()
+endforeach()
+
+add_executable(Toolkit main.cpp)
+target_link_libraries(Toolkit PRIVATE CUDA::toolkit)
diff --git a/Tests/Cuda/ToolkitInclude/main.cpp b/Tests/Cuda/Toolkit/main.cpp
similarity index 100%
rename from Tests/Cuda/ToolkitInclude/main.cpp
rename to Tests/Cuda/Toolkit/main.cpp
diff --git a/Tests/Cuda/ToolkitInclude/CMakeLists.txt b/Tests/Cuda/ToolkitInclude/CMakeLists.txt
deleted file mode 100644
index f246b54..0000000
--- a/Tests/Cuda/ToolkitInclude/CMakeLists.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-cmake_minimum_required(VERSION 3.8)
-project (ToolkitInclude CXX CUDA)
-
-#Goal for this example:
-# Validate that between the CXX implicit include directories and the
-# CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES directories we can find
-# the cuda runtime headers
-
-add_executable(CudaToolkitInclude main.cpp)
-target_include_directories(CudaToolkitInclude PRIVATE
-                           ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES})
diff --git a/Tests/CudaOnly/CMakeLists.txt b/Tests/CudaOnly/CMakeLists.txt
index f1fd344..cc1ee1a 100644
--- a/Tests/CudaOnly/CMakeLists.txt
+++ b/Tests/CudaOnly/CMakeLists.txt
@@ -5,8 +5,21 @@
 ADD_TEST_MACRO(CudaOnly.GPUDebugFlag CudaOnlyGPUDebugFlag)
 ADD_TEST_MACRO(CudaOnly.ResolveDeviceSymbols CudaOnlyResolveDeviceSymbols)
 ADD_TEST_MACRO(CudaOnly.SeparateCompilation CudaOnlySeparateCompilation)
+ADD_TEST_MACRO(CudaOnly.SharedRuntimePlusToolkit CudaOnlySharedRuntimePlusToolkit)
+ADD_TEST_MACRO(CudaOnly.Standard98 CudaOnlyStandard98)
+ADD_TEST_MACRO(CudaOnly.Toolkit CudaOnlyToolkit)
 ADD_TEST_MACRO(CudaOnly.WithDefs CudaOnlyWithDefs)
 
+# The CUDA only ships the shared version of the toolkit libraries
+# on windows
+if(NOT WIN32)
+  ADD_TEST_MACRO(Cuda.StaticRuntimePlusToolkit StaticRuntimePlusToolkit)
+endif()
+
+if(MSVC)
+  ADD_TEST_MACRO(CudaOnly.PDB CudaOnlyPDB)
+endif()
+
 add_test(NAME CudaOnly.DontResolveDeviceSymbols COMMAND
   ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
   --build-and-test
@@ -18,6 +31,14 @@
   --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
   )
 
-if(MSVC)
-  ADD_TEST_MACRO(CudaOnly.PDB CudaOnlyPDB)
-endif()
+add_test(NAME CudaOnly.RuntimeControls COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMAKE_CURRENT_SOURCE_DIR}/RuntimeControls/"
+  "${CMAKE_CURRENT_BINARY_DIR}/RuntimeControls/"
+  --build-two-config
+    ${build_generator_args}
+  --build-project RuntimeControls
+  --build-options ${build_options}
+  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+  )
diff --git a/Tests/CudaOnly/EnableStandard/CMakeLists.txt b/Tests/CudaOnly/EnableStandard/CMakeLists.txt
index 54e2c14..dfcb8da 100644
--- a/Tests/CudaOnly/EnableStandard/CMakeLists.txt
+++ b/Tests/CudaOnly/EnableStandard/CMakeLists.txt
@@ -11,8 +11,9 @@
 add_executable(CudaOnlyEnableStandard main.cu)
 target_link_libraries(CudaOnlyEnableStandard PRIVATE CUDAStatic11 CUDADynamic11)
 
-set_target_properties(CUDAStatic11 CUDADynamic11 PROPERTIES CUDA_STANDARD 11)
-set_target_properties(CUDAStatic11 CUDADynamic11 PROPERTIES CUDA_STANDARD_REQUIRED TRUE)
+target_compile_features(CUDADynamic11 PRIVATE cuda_std_11)
+set_target_properties(CUDAStatic11 PROPERTIES CUDA_STANDARD 11)
+set_target_properties(CUDAStatic11 PROPERTIES CUDA_STANDARD_REQUIRED TRUE)
 
 #Verify CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES
 foreach(dir ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES})
diff --git a/Tests/CudaOnly/ResolveDeviceSymbols/CMakeLists.txt b/Tests/CudaOnly/ResolveDeviceSymbols/CMakeLists.txt
index 64845c5..57aa0b9 100644
--- a/Tests/CudaOnly/ResolveDeviceSymbols/CMakeLists.txt
+++ b/Tests/CudaOnly/ResolveDeviceSymbols/CMakeLists.txt
@@ -22,11 +22,11 @@
 # 3. Verify that we can't use those device symbols from anything that links
 # to the static library
 string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_30,code=[sm_30] -gencode arch=compute_50,code=\\\"compute_50\\\"")
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CUDA_STANDARD 11)
 
 add_library(CUDAResolveDeviceDepsA STATIC file1.cu)
 add_library(CUDAResolveDeviceDepsB STATIC file2.cu)
+target_compile_features(CUDAResolveDeviceDepsA PUBLIC cuda_std_11)
+target_compile_features(CUDAResolveDeviceDepsB PUBLIC cuda_std_11)
 set_target_properties(CUDAResolveDeviceDepsA CUDAResolveDeviceDepsB
                       PROPERTIES
                       CUDA_SEPARABLE_COMPILATION ON
diff --git a/Tests/CudaOnly/RuntimeControls/CMakeLists.txt b/Tests/CudaOnly/RuntimeControls/CMakeLists.txt
new file mode 100644
index 0000000..8b58fec
--- /dev/null
+++ b/Tests/CudaOnly/RuntimeControls/CMakeLists.txt
@@ -0,0 +1,60 @@
+cmake_minimum_required(VERSION 3.7)
+project (RuntimeControls CUDA)
+
+# Find nm and dumpbin
+if(CMAKE_NM)
+  set(dump_command ${CMAKE_NM})
+  set(dump_args -g)
+else()
+  include(GetPrerequisites)
+  message(STATUS "calling list_prerequisites to find dumpbin")
+  list_prerequisites("${CMAKE_COMMAND}" 0 0 0)
+  if(gp_dumpbin)
+    set(dump_command ${gp_dumpbin})
+    set(dump_args /ARCHIVEMEMBERS)
+  endif()
+endif()
+
+string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_30,code=[compute_30]")
+
+set(CMAKE_CUDA_STANDARD 11)
+set(CMAKE_CUDA_RUNTIME_LIBRARY static)
+
+if(NOT "x${CMAKE_CUDA_SIMULATE_ID}" STREQUAL "xMSVC")
+  add_library(UsesNoCudaRT SHARED file1.cu)
+  set_target_properties(UsesNoCudaRT PROPERTIES CUDA_RUNTIME_LIBRARY none)
+endif()
+
+add_library(UsesStaticCudaRT SHARED file2.cu)
+
+add_executable(CudaOnlyRuntimeControls main.cu)
+set_target_properties(CudaOnlyRuntimeControls PROPERTIES CUDA_RUNTIME_LIBRARY shared)
+
+target_link_libraries(CudaOnlyRuntimeControls PRIVATE $<TARGET_NAME_IF_EXISTS:UsesNoCudaRT> UsesStaticCudaRT)
+
+
+if(dump_command)
+  if(TARGET UsesNoCudaRT)
+    add_custom_command(TARGET UsesNoCudaRT POST_BUILD
+    COMMAND ${CMAKE_COMMAND}
+    -DDUMP_COMMAND=${dump_command}
+    -DDUMP_ARGS=${dump_args}
+    -DTEST_LIBRARY_PATH=$<TARGET_FILE:UsesNoCudaRT>
+    -P ${CMAKE_CURRENT_SOURCE_DIR}/no_runtime.cmake
+    )
+  endif()
+  add_custom_command(TARGET UsesStaticCudaRT POST_BUILD
+    COMMAND ${CMAKE_COMMAND}
+    -DDUMP_COMMAND=${dump_command}
+    -DDUMP_ARGS=${dump_args}
+    -DTEST_LIBRARY_PATH=$<TARGET_FILE:UsesStaticCudaRT>
+    -P ${CMAKE_CURRENT_SOURCE_DIR}/uses_static_runtime.cmake
+  )
+  string(REPLACE ";" "|" dirs "${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES}")
+  add_custom_command(TARGET CudaOnlyRuntimeControls POST_BUILD
+    COMMAND ${CMAKE_COMMAND}
+    -DEXEC_PATH=$<TARGET_FILE:CudaOnlyRuntimeControls>
+    -DEXTRA_LIB_DIRS="${dirs}"
+    -P ${CMAKE_CURRENT_SOURCE_DIR}/verify_runtime.cmake
+  )
+endif()
diff --git a/Tests/CudaOnly/RuntimeControls/file1.cu b/Tests/CudaOnly/RuntimeControls/file1.cu
new file mode 100644
index 0000000..28beb5e
--- /dev/null
+++ b/Tests/CudaOnly/RuntimeControls/file1.cu
@@ -0,0 +1,18 @@
+
+#ifdef _WIN32
+#  define EXPORT __declspec(dllexport)
+#else
+#  define EXPORT
+#endif
+
+void __global__ file1_kernel(int x, int& r)
+{
+  r = -x;
+}
+
+EXPORT int file1_launch_kernel(int x)
+{
+  int r = 0;
+  file1_kernel<<<1, 1>>>(x, r);
+  return r;
+}
diff --git a/Tests/CudaOnly/RuntimeControls/file2.cu b/Tests/CudaOnly/RuntimeControls/file2.cu
new file mode 100644
index 0000000..ff68a70
--- /dev/null
+++ b/Tests/CudaOnly/RuntimeControls/file2.cu
@@ -0,0 +1,18 @@
+
+#ifdef _WIN32
+#  define EXPORT __declspec(dllexport)
+#else
+#  define EXPORT
+#endif
+
+void __global__ file2_kernel(int x, int& r)
+{
+  r = -x;
+}
+
+EXPORT int file2_launch_kernel(int x)
+{
+  int r = 0;
+  file2_kernel<<<1, 1>>>(x, r);
+  return r;
+}
diff --git a/Tests/CudaOnly/RuntimeControls/main.cu b/Tests/CudaOnly/RuntimeControls/main.cu
new file mode 100644
index 0000000..0be22af
--- /dev/null
+++ b/Tests/CudaOnly/RuntimeControls/main.cu
@@ -0,0 +1,81 @@
+
+#include <iostream>
+
+#include "cuda.h"
+
+#ifdef _WIN32
+#  define IMPORT __declspec(dllimport)
+#else
+#  define IMPORT
+#endif
+
+#ifndef _WIN32
+IMPORT int file1_launch_kernel(int x);
+#endif
+
+IMPORT int file2_launch_kernel(int x);
+
+int choose_cuda_device()
+{
+  int nDevices = 0;
+  cudaError_t err = cudaGetDeviceCount(&nDevices);
+  if (err != cudaSuccess) {
+    std::cerr << "Failed to retrieve the number of CUDA enabled devices"
+              << std::endl;
+    return 1;
+  }
+  for (int i = 0; i < nDevices; ++i) {
+    cudaDeviceProp prop;
+    cudaError_t err = cudaGetDeviceProperties(&prop, i);
+    if (err != cudaSuccess) {
+      std::cerr << "Could not retrieve properties from CUDA device " << i
+                << std::endl;
+      return 1;
+    }
+    std::cout << "prop.major: " << prop.major << std::endl;
+    if (prop.major >= 3) {
+      err = cudaSetDevice(i);
+      if (err != cudaSuccess) {
+        std::cout << "Could not select CUDA device " << i << std::endl;
+      } else {
+        return 0;
+      }
+    }
+  }
+
+  std::cout << "Could not find a CUDA enabled card supporting compute >=3.0"
+            << std::endl;
+
+  return 1;
+}
+
+int main(int argc, char** argv)
+{
+  int ret = choose_cuda_device();
+  if (ret) {
+    return 0;
+  }
+
+  cudaError_t err;
+#ifndef _WIN32
+  file1_launch_kernel(1);
+  err = cudaGetLastError();
+  if (err != cudaSuccess) {
+    std::cerr << "file1_launch_kernel: kernel launch should have passed.\n "
+                 "Error message: "
+              << cudaGetErrorString(err) << std::endl;
+    return 1;
+  }
+#endif
+
+  file2_launch_kernel(1);
+  err = cudaGetLastError();
+  if (err != cudaSuccess) {
+    std::cerr << "file2_launch_kernel: kernel launch should have passed.\n "
+                 "Error message: "
+              << cudaGetErrorString(err) << std::endl;
+    return 1;
+  }
+
+  return 0;
+}
diff --git a/Tests/CudaOnly/RuntimeControls/no_runtime.cmake b/Tests/CudaOnly/RuntimeControls/no_runtime.cmake
new file mode 100644
index 0000000..55f28cc
--- /dev/null
+++ b/Tests/CudaOnly/RuntimeControls/no_runtime.cmake
@@ -0,0 +1,14 @@
+execute_process(COMMAND ${DUMP_COMMAND} ${DUMP_ARGS} ${TEST_LIBRARY_PATH}
+  RESULT_VARIABLE RESULT
+  OUTPUT_VARIABLE OUTPUT
+  ERROR_VARIABLE ERROR
+)
+
+if(NOT "${RESULT}" STREQUAL "0")
+  message(FATAL_ERROR "${DUMP_COMMAND} failed [${RESULT}] [${OUTPUT}] [${ERROR}]")
+endif()
+
+if(NOT "${OUTPUT}" MATCHES "(__cuda)")
+  message(FATAL_ERROR
+  "not missing cuda device symbols, static runtime linking was used.")
+endif()
diff --git a/Tests/CudaOnly/RuntimeControls/uses_static_runtime.cmake b/Tests/CudaOnly/RuntimeControls/uses_static_runtime.cmake
new file mode 100644
index 0000000..b372fea
--- /dev/null
+++ b/Tests/CudaOnly/RuntimeControls/uses_static_runtime.cmake
@@ -0,0 +1,14 @@
+execute_process(COMMAND ${DUMP_COMMAND} ${DUMP_ARGS} ${TEST_LIBRARY_PATH}
+  RESULT_VARIABLE RESULT
+  OUTPUT_VARIABLE OUTPUT
+  ERROR_VARIABLE ERROR
+)
+
+if(NOT "${RESULT}" STREQUAL "0")
+  message(FATAL_ERROR "${DUMP_COMMAND} failed [${RESULT}] [${OUTPUT}] [${ERROR}]")
+endif()
+
+if("${OUTPUT}" MATCHES "__cuda")
+  message(FATAL_ERROR
+    "missing cuda device symbols, static runtime linking was not used.")
+endif()
diff --git a/Tests/CudaOnly/RuntimeControls/verify_runtime.cmake b/Tests/CudaOnly/RuntimeControls/verify_runtime.cmake
new file mode 100644
index 0000000..b313dac
--- /dev/null
+++ b/Tests/CudaOnly/RuntimeControls/verify_runtime.cmake
@@ -0,0 +1,16 @@
+
+string(REPLACE "|" ";" dirs "${EXTRA_LIB_DIRS}")
+file(GET_RUNTIME_DEPENDENCIES
+  RESOLVED_DEPENDENCIES_VAR resolved_libs
+  UNRESOLVED_DEPENDENCIES_VAR unresolved_libs
+  DIRECTORIES ${dirs}
+  EXECUTABLES ${EXEC_PATH}
+  )
+
+list(FILTER resolved_libs INCLUDE REGEX ".*cudart.*")
+list(LENGTH resolved_libs has_cudart)
+
+if(has_cudart EQUAL 0)
+  message(FATAL_ERROR
+    "missing cudart shared library from runtime dependency output.")
+endif()
diff --git a/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt b/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt
index 1e574d6..c1bd64a 100644
--- a/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt
+++ b/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt
@@ -11,11 +11,10 @@
 #all containing cuda separable compilation code links properly
 string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_30,code=\\\"compute_30,sm_30,sm_35\\\"")
 string(APPEND CMAKE_CUDA_FLAGS " --generate-code=arch=compute_50,code=[compute_50,sm_50,sm_52]")
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CUDA_STANDARD 11)
 
 set(CMAKE_CUDA_SEPARABLE_COMPILATION ON)
 add_library(CUDASeparateLibA STATIC file1.cu file2.cu file3.cu)
+target_compile_features(CUDASeparateLibA PRIVATE cuda_std_11)
 get_property(sep_comp TARGET CUDASeparateLibA PROPERTY CUDA_SEPARABLE_COMPILATION)
 if(NOT sep_comp)
   message(FATAL_ERROR "CUDA_SEPARABLE_COMPILATION not initialized")
@@ -36,11 +35,14 @@
 #cause a segv when trying to run the executable
 #
 add_library(CUDASeparateLibB STATIC file4.cu file5.cu)
+target_compile_features(CUDASeparateLibB PRIVATE cuda_std_11)
 target_link_libraries(CUDASeparateLibB PRIVATE CUDASeparateLibA)
 
 add_executable(CudaOnlySeparateCompilation main.cu)
 target_link_libraries(CudaOnlySeparateCompilation
                       PRIVATE CUDASeparateLibB)
+set_target_properties(CudaOnlySeparateCompilation PROPERTIES CUDA_STANDARD 11)
+set_target_properties(CudaOnlySeparateCompilation PROPERTIES CUDA_STANDARD_REQUIRED TRUE)
 
 set_target_properties(CUDASeparateLibA
                       CUDASeparateLibB
diff --git a/Tests/CudaOnly/SharedRuntimePlusToolkit/CMakeLists.txt b/Tests/CudaOnly/SharedRuntimePlusToolkit/CMakeLists.txt
new file mode 100644
index 0000000..03fba22
--- /dev/null
+++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/CMakeLists.txt
@@ -0,0 +1,42 @@
+cmake_minimum_required(VERSION 3.15)
+project(SharedRuntimePlusToolkit CUDA)
+
+#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.cu nppif.cu)
+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.cu)
+target_link_libraries(SharedToolkit PRIVATE Common PUBLIC CUDA::curand CUDA::nppif)
+set_target_properties(SharedToolkit PROPERTIES CUDA_RUNTIME_LIBRARY none)
+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.cu)
+  target_link_libraries(StaticToolkit PRIVATE Common CUDA::curand_static CUDA::nppif_static)
+  set_target_properties(StaticToolkit PROPERTIES CUDA_RUNTIME_LIBRARY Shared)
+
+  #static runtime with mixed toolkit libraries
+  add_library(MixedToolkit SHARED mixed.cu)
+  target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand_static CUDA::nppif)
+  set_target_properties(MixedToolkit PROPERTIES CUDA_RUNTIME_LIBRARY Shared)
+endif()
+
+add_executable(CudaOnlySharedRuntimePlusToolkit main.cu)
+target_link_libraries(CudaOnlySharedRuntimePlusToolkit PRIVATE SharedToolkit
+                      $<TARGET_NAME_IF_EXISTS:StaticToolkit>
+                      $<TARGET_NAME_IF_EXISTS:MixedToolkit>)
+
+if(UNIX)
+  # Help the shared cuda runtime find libcudart as it is not located
+  # in a default system searched location
+  set_property(TARGET CudaOnlySharedRuntimePlusToolkit PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/CudaOnly/SharedRuntimePlusToolkit/curand.cu b/Tests/CudaOnly/SharedRuntimePlusToolkit/curand.cu
new file mode 100644
index 0000000..fdd7b53
--- /dev/null
+++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/curand.cu
@@ -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/CudaOnly/SharedRuntimePlusToolkit/main.cu b/Tests/CudaOnly/SharedRuntimePlusToolkit/main.cu
new file mode 100644
index 0000000..2a4da22
--- /dev/null
+++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/main.cu
@@ -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/CudaOnly/SharedRuntimePlusToolkit/mixed.cu b/Tests/CudaOnly/SharedRuntimePlusToolkit/mixed.cu
new file mode 100644
index 0000000..6de6886
--- /dev/null
+++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/mixed.cu
@@ -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/CudaOnly/SharedRuntimePlusToolkit/nppif.cu b/Tests/CudaOnly/SharedRuntimePlusToolkit/nppif.cu
new file mode 100644
index 0000000..ac5341c
--- /dev/null
+++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/nppif.cu
@@ -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/CudaOnly/SharedRuntimePlusToolkit/shared.cu b/Tests/CudaOnly/SharedRuntimePlusToolkit/shared.cu
new file mode 100644
index 0000000..f3c3dbc
--- /dev/null
+++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/shared.cu
@@ -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/CudaOnly/SharedRuntimePlusToolkit/static.cu b/Tests/CudaOnly/SharedRuntimePlusToolkit/static.cu
new file mode 100644
index 0000000..6932fa3
--- /dev/null
+++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/static.cu
@@ -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/CudaOnly/Standard98/CMakeLists.txt b/Tests/CudaOnly/Standard98/CMakeLists.txt
new file mode 100644
index 0000000..ef9a685
--- /dev/null
+++ b/Tests/CudaOnly/Standard98/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.7)
+project(CudaOnlyStandard98 CUDA)
+
+string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_30,code=compute_30")
+
+# Support setting CUDA Standard to 98 which internally gets transformed to
+# CUDA03
+set(CMAKE_CUDA_STANDARD 98)
+
+add_executable(CudaOnlyStandard98 main.cu)
+
+if(APPLE)
+  # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
+  set_property(TARGET CudaOnlyStandard98 PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+endif()
diff --git a/Tests/CudaOnly/Standard98/main.cu b/Tests/CudaOnly/Standard98/main.cu
new file mode 100644
index 0000000..c79afd6
--- /dev/null
+++ b/Tests/CudaOnly/Standard98/main.cu
@@ -0,0 +1,8 @@
+
+#if __cplusplus >= 201103L
+#  error "invalid standard value"
+#endif
+int main(int argc, char** argv)
+{
+  return 0;
+}
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/CMakeLists.txt b/Tests/CudaOnly/StaticRuntimePlusToolkit/CMakeLists.txt
new file mode 100644
index 0000000..97ac229
--- /dev/null
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/CMakeLists.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.15)
+project(StaticRuntimePlusToolkit CUDA)
+
+#Goal for this example:
+# Validate that with cuda we can use some components of the CUDA toolkit, and
+# specify the cuda runtime
+find_package(CUDAToolkit REQUIRED)
+
+add_library(Common OBJECT curand.cu nppif.cu)
+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.cu)
+target_link_libraries(SharedToolkit PRIVATE Common CUDA::curand CUDA::nppif )
+set_target_properties(SharedToolkit PROPERTIES CUDA_RUNTIME_LIBRARY none)
+target_link_libraries(SharedToolkit PUBLIC CUDA::cudart_static)
+
+#static runtime with static toolkit libraries
+add_library(StaticToolkit SHARED static.cu)
+target_link_libraries(StaticToolkit PRIVATE Common CUDA::curand_static CUDA::nppif_static)
+
+#static runtime with mixed toolkit libraries
+add_library(MixedToolkit SHARED mixed.cu)
+target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand CUDA::nppif_static)
+set_target_properties(MixedToolkit PROPERTIES CUDA_RUNTIME_LIBRARY Static)
+
+add_executable(CudaOnlyStaticRuntimePlusToolkit main.cu)
+target_link_libraries(CudaOnlyStaticRuntimePlusToolkit PRIVATE SharedToolkit StaticToolkit MixedToolkit)
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/curand.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/curand.cu
new file mode 100644
index 0000000..95872f0
--- /dev/null
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/curand.cu
@@ -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/CudaOnly/StaticRuntimePlusToolkit/main.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/main.cu
new file mode 100644
index 0000000..5a09f8e
--- /dev/null
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/main.cu
@@ -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/CudaOnly/StaticRuntimePlusToolkit/mixed.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/mixed.cu
new file mode 100644
index 0000000..a05140d
--- /dev/null
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/mixed.cu
@@ -0,0 +1,8 @@
+
+int curand_main();
+int nppif_main();
+
+int mixed_version()
+{
+  return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/nppif.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/nppif.cu
new file mode 100644
index 0000000..2871090
--- /dev/null
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/nppif.cu
@@ -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/CudaOnly/StaticRuntimePlusToolkit/shared.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/shared.cu
new file mode 100644
index 0000000..9967b66
--- /dev/null
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/shared.cu
@@ -0,0 +1,8 @@
+
+int curand_main();
+int nppif_main();
+
+int shared_version()
+{
+  return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/static.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/static.cu
new file mode 100644
index 0000000..ca7eb4c
--- /dev/null
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/static.cu
@@ -0,0 +1,8 @@
+
+int curand_main();
+int nppif_main();
+
+int static_version()
+{
+  return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/CudaOnly/Toolkit/CMakeLists.txt b/Tests/CudaOnly/Toolkit/CMakeLists.txt
new file mode 100644
index 0000000..0d5d574
--- /dev/null
+++ b/Tests/CudaOnly/Toolkit/CMakeLists.txt
@@ -0,0 +1,44 @@
+cmake_minimum_required(VERSION 3.15)
+project(CudaOnlyToolkit CUDA)
+find_package(CUDAToolkit REQUIRED)
+
+message(STATUS "CUDAToolkit_VERSION: ${CUDAToolkit_VERSION}")
+message(STATUS "CUDAToolkit_VERSION_MAJOR: ${CUDAToolkit_VERSION_MAJOR}")
+message(STATUS "CUDAToolkit_VERSION_MINOR: ${CUDAToolkit_VERSION_MINOR}")
+message(STATUS "CUDAToolkit_VERSION_PATCH: ${CUDAToolkit_VERSION_PATCH}")
+message(STATUS "CUDAToolkit_BIN_DIR: ${CUDAToolkit_BIN_DIR}")
+message(STATUS "CUDAToolkit_INCLUDE_DIRS: ${CUDAToolkit_INCLUDE_DIRS}")
+message(STATUS "CUDAToolkit_LIBRARY_DIR: ${CUDAToolkit_LIBRARY_DIR}")
+message(STATUS "CUDAToolkit_NVCC_EXECUTABLE ${CUDAToolkit_NVCC_EXECUTABLE}")
+
+# Verify that all the CUDA:: targets and variables exist
+foreach (cuda_lib cudart cuda_driver cublas cufft cufftw curand cusolver cusparse nvgraph)
+  if(NOT CUDA_${cuda_lib}_LIBRARY)
+    message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found")
+  endif()
+  if(NOT TARGET CUDA::${cuda_lib})
+    message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
+  endif()
+endforeach()
+
+foreach (cuda_lib nppc nppial nppicc nppidei nppif nppig nppim nppist nppitc npps nppicom nppisu)
+  if(NOT CUDA_${cuda_lib}_LIBRARY)
+    message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found")
+  endif()
+  if(NOT TARGET CUDA::${cuda_lib})
+    message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
+  endif()
+endforeach()
+
+foreach (cuda_lib nvrtc nvToolsExt OpenCL)
+  if(NOT CUDA_${cuda_lib}_LIBRARY)
+    message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found")
+  endif()
+
+  if(NOT TARGET CUDA::${cuda_lib})
+    message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
+  endif()
+endforeach()
+
+add_executable(CudaOnlyToolkit main.cu)
+target_link_libraries(CudaOnlyToolkit PRIVATE CUDA::toolkit)
diff --git a/Tests/CudaOnly/Toolkit/main.cu b/Tests/CudaOnly/Toolkit/main.cu
new file mode 100644
index 0000000..0f3ccdc
--- /dev/null
+++ b/Tests/CudaOnly/Toolkit/main.cu
@@ -0,0 +1,8 @@
+// Only thing we care about is that these headers are found
+#include <cuda.h>
+#include <cuda_runtime_api.h>
+
+int main(int argc, char** argv)
+{
+  return 0;
+}
diff --git a/Tests/CudaOnly/WithDefs/CMakeLists.txt b/Tests/CudaOnly/WithDefs/CMakeLists.txt
index 00fd7d2..ba9bf04 100644
--- a/Tests/CudaOnly/WithDefs/CMakeLists.txt
+++ b/Tests/CudaOnly/WithDefs/CMakeLists.txt
@@ -28,7 +28,7 @@
   PRIVATE
     -DFLAG_COMPILE_LANG_$<COMPILE_LANGUAGE>
     -DFLAG_LANG_IS_CUDA=$<COMPILE_LANGUAGE:CUDA>
-    -Xcompiler=-DHOST_DEFINE
+    --compiler-options=-DHOST_DEFINE
     $<$<CONFIG:DEBUG>:$<BUILD_INTERFACE:${debug_compile_flags}>>
   )
 
diff --git a/Tests/CustComDepend/CMakeLists.txt b/Tests/CustComDepend/CMakeLists.txt
index 46276b2..777cdcc 100644
--- a/Tests/CustComDepend/CMakeLists.txt
+++ b/Tests/CustComDepend/CMakeLists.txt
@@ -6,9 +6,9 @@
 add_executable(foo foo.cxx)
 add_custom_command(
   OUTPUT ${CustComDepend_BINARY_DIR}/bar.c
-  COMMAND ${CustComDepend_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/foo
+  COMMAND $<TARGET_FILE:foo>
   ${CustComDepend_BINARY_DIR}/bar.c
-  DEPENDS ${CustComDepend_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/foo
+  DEPENDS $<TARGET_FILE:foo>
 )
 
 add_library(bar SHARED ${CustComDepend_BINARY_DIR}/bar.c)
diff --git a/Tests/CustomCommand/CMakeLists.txt b/Tests/CustomCommand/CMakeLists.txt
index e9a9f52..53d56bf 100644
--- a/Tests/CustomCommand/CMakeLists.txt
+++ b/Tests/CustomCommand/CMakeLists.txt
@@ -70,7 +70,7 @@
   COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/doc1temp.h
                                    ${PROJECT_BINARY_DIR}/doc1.h
   COMMAND ${CMAKE_COMMAND} -E echo " Removing doc1temp.h."
-  COMMAND ${CMAKE_COMMAND} -E remove -f ${PROJECT_BINARY_DIR}/doc1temp.h
+  COMMAND ${CMAKE_COMMAND} -E rm -f ${PROJECT_BINARY_DIR}/doc1temp.h
   )
 
 # Add custom command to generate foo.h.
@@ -412,7 +412,7 @@
 add_dependencies(do_check_command_line check_command_line)
 
 add_custom_target(pre_check_command_line
-  COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_CURRENT_BINARY_DIR}/check_mark.txt
+  COMMAND ${CMAKE_COMMAND} -E rm -f ${CMAKE_CURRENT_BINARY_DIR}/check_mark.txt
   )
 add_dependencies(do_check_command_line pre_check_command_line)
 
@@ -534,3 +534,43 @@
 set_property(SOURCE "${gen_file}" PROPERTY SYMBOLIC ON)
 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(
+  OUTPUT ${depends_path}
+  COMMAND ${CMAKE_COMMAND} -E touch ${depends_path}
+)
+
+add_custom_command(
+  OUTPUT "depends_on_path.txt"
+  COMMAND ${CMAKE_COMMAND} -E touch "depends_on_path.txt"
+  DEPENDS ${depends_path}
+)
+
+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")
+
+add_library(mac_fw SHARED mac_fw.c)
+set_target_properties(mac_fw PROPERTIES
+  FRAMEWORK 1
+  LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib
+  )
+add_custom_command(OUTPUT mac_fw.txt COMMAND ${CMAKE_COMMAND} -E touch mac_fw.txt DEPENDS mac_fw)
+add_custom_target(drive_mac_fw ALL DEPENDS mac_fw.txt)
diff --git a/Tests/CustomCommand/mac_fw.c b/Tests/CustomCommand/mac_fw.c
new file mode 100644
index 0000000..cb35b44
--- /dev/null
+++ b/Tests/CustomCommand/mac_fw.c
@@ -0,0 +1,4 @@
+int mac_fw(void)
+{
+  return 0;
+}
diff --git a/Tests/EnforceConfig.cmake.in b/Tests/EnforceConfig.cmake.in
index b7587aa..7781ded 100644
--- a/Tests/EnforceConfig.cmake.in
+++ b/Tests/EnforceConfig.cmake.in
@@ -33,5 +33,6 @@
 unset(ENV{CMAKE_GENERATOR_INSTANCE})
 unset(ENV{CMAKE_GENERATOR_PLATFORM})
 unset(ENV{CMAKE_GENERATOR_TOOLSET})
+unset(ENV{CMAKE_EXPORT_COMPILE_COMMANDS})
 
 @TEST_HOME_ENV_CODE@
diff --git a/Tests/ExportImport/CMakeLists.txt b/Tests/ExportImport/CMakeLists.txt
index dc621eb..d88eb11 100644
--- a/Tests/ExportImport/CMakeLists.txt
+++ b/Tests/ExportImport/CMakeLists.txt
@@ -7,7 +7,7 @@
 # Wipe out the install tree to make sure the exporter works.
 add_custom_command(
   OUTPUT ${ExportImport_BINARY_DIR}/CleanupProject
-  COMMAND ${CMAKE_COMMAND} -E remove_directory ${ExportImport_BINARY_DIR}/Root
+  COMMAND ${CMAKE_COMMAND} -E rm -rf ${ExportImport_BINARY_DIR}/Root
   )
 add_custom_target(CleanupTarget ALL DEPENDS ${ExportImport_BINARY_DIR}/CleanupProject)
 set_property(
diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt
index 9d8a248..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)
@@ -240,6 +241,10 @@
 )
 include(GenerateExportHeader)
 
+# Test deprecation of imported library
+add_library(testLibDeprecation STATIC testLib1.c)
+set_property(TARGET testLibDeprecation PROPERTY DEPRECATION "Deprecated version. Please use latest version")
+
 add_subdirectory(renamed)
 
 add_library(testSharedLibRequired SHARED testSharedLibRequired.cpp)
@@ -515,6 +520,7 @@
   testExe2lib testLib4lib testLib4libdbg testLib4libopt
   testLib6 testLib7 testLib8
   testLib9
+  testLibDeprecation
   testLibCycleA testLibCycleB
   testLibNoSONAME
   cmp0022NEW cmp0022OLD
@@ -585,6 +591,7 @@
 export(TARGETS testExe2 testLib4 testLib5 testLib6 testLib7 testExe3 testExe4 testExe2lib
   testLib8
   testLib9 testLib9ObjPub testLib9ObjPriv testLib9ObjIface
+  testLibDeprecation
   testLib4lib testLib4libdbg testLib4libopt
   testLibCycleA testLibCycleB
   testLibNoSONAME
@@ -646,6 +653,18 @@
   export(TARGETS testLinkDepends NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake)
 endif()
 
+#------------------------------------------------------------------------------
+# test export of CUDA language
+if(CMake_TEST_CUDA)
+  enable_language(CUDA)
+  add_library(cudaInterfaceLib INTERFACE)
+  target_compile_features(cudaInterfaceLib INTERFACE $<BUILD_INTERFACE:cuda_std_11> $<INSTALL_INTERFACE:cuda_std_14>)
+
+  install(TARGETS cudaInterfaceLib
+    EXPORT RequiredExp DESTINATION lib)
+  export(TARGETS cudaInterfaceLib NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake)
+endif()
+
 # Test the presence of targets named the same as languages.
 # IMPORTED_LINK_INTERFACE_LANGUAGES entries should not be targets.
 add_library(C INTERFACE)
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/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt
index b5df961..3cb3833 100644
--- a/Tests/ExportImport/Import/A/CMakeLists.txt
+++ b/Tests/ExportImport/Import/A/CMakeLists.txt
@@ -51,6 +51,12 @@
 checkForProperty(exp_testLib4 "EXPORTED_PROPERTY2"  "EXPORTING_TESTLIB4_1")
 checkForProperty(bld_testLib4 "EXPORTED_PROPERTY3"  "EXPORTING_TESTLIB4_2")
 checkForProperty(exp_testLib4 "EXPORTED_PROPERTY3"  "EXPORTING_TESTLIB4_2")
+checkForProperty(bld_testLibDeprecation "DEPRECATION"  "Deprecated version. Please use latest version")
+checkForProperty(exp_testLibDeprecation "DEPRECATION"  "Deprecated version. Please use latest version")
+
+# Try linking to a deprecated library
+target_link_libraries(imp_testExe1 exp_testLibDeprecation)
+
 
 # Try linking to a library imported from the install tree.
 target_link_libraries(imp_testExe1
@@ -499,3 +505,10 @@
   checkForProperty(bld_testLinkDepends "INTERFACE_LINK_DEPENDS" "BUILD_LINK_DEPENDS")
   checkForProperty(Req::testLinkDepends "INTERFACE_LINK_DEPENDS" "${CMAKE_INSTALL_PREFIX}/INSTALL_LINK_DEPENDS")
 endif()
+
+#------------------------------------------------------------------------------
+# test import of CUDA language level
+if(CMake_TEST_CUDA)
+  checkForProperty(bld_cudaInterfaceLib "INTERFACE_COMPILE_FEATURES" "cuda_std_11")
+  checkForProperty(Req::cudaInterfaceLib "INTERFACE_COMPILE_FEATURES" "cuda_std_14")
+endif()
diff --git a/Tests/ExportImport/InitialCache.cmake.in b/Tests/ExportImport/InitialCache.cmake.in
index f600d90..44cd179 100644
--- a/Tests/ExportImport/InitialCache.cmake.in
+++ b/Tests/ExportImport/InitialCache.cmake.in
@@ -14,3 +14,4 @@
 set(CMAKE_INSTALL_PREFIX "@ExportImport_BINARY_DIR@/Root" CACHE STRING "Installation Prefix")
 set(CMAKE_SKIP_RPATH ON CACHE BOOL "No RPATH")
 set(CMAKE_GNUtoMS "@ExportImport_GNUtoMS@" CACHE BOOL "CMAKE_GNUtoMS")
+set(CMake_TEST_CUDA "@CMake_TEST_CUDA@" CACHE BOOL "CMake_TEST_CUDA")
diff --git a/Tests/ExternalProject/CMakeLists.txt b/Tests/ExternalProject/CMakeLists.txt
index 093391e..450e7e5 100644
--- a/Tests/ExternalProject/CMakeLists.txt
+++ b/Tests/ExternalProject/CMakeLists.txt
@@ -380,7 +380,9 @@
     set(proj TutorialStep1-GIT-config)
     ExternalProject_Add(${proj}
       GIT_REPOSITORY "${local_git_repo}"
-      GIT_CONFIG core.eol=lf core.autocrlf=input
+      GIT_CONFIG core.eol=lf
+                 core.autocrlf=input
+                 "http.extraheader=AUTHORIZATION: bearer --unsupportedOption"
       CMAKE_GENERATOR "${CMAKE_GENERATOR}"
       CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
       INSTALL_COMMAND ""
@@ -482,6 +484,66 @@
   )
   set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
 
+  # Unzip/untar the git repository in our source folder so that other
+  # projects below may use it to test git args of ExternalProject_Add
+  #
+  set(proj SetupLocalGITRepositoryWithRecursiveSubmodules)
+  ExternalProject_Add(${proj}
+          SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/LocalRepositories/GIT-with-recursive-submodules
+          URL ${CMAKE_CURRENT_SOURCE_DIR}/gitrepo-sub-rec.tgz
+          BUILD_COMMAND ""
+          CONFIGURE_COMMAND "${GIT_EXECUTABLE}" --version
+          INSTALL_COMMAND ""
+          )
+  set_property(TARGET ${proj}
+          PROPERTY FOLDER "SetupRepos/Local/Deeply/Nested/For/Testing")
+
+  set(local_git_repo "../../LocalRepositories/GIT-with-recursive-submodules")
+
+  set(proj TS1-GIT-RECURSIVE_SUBMODULES-default)
+  ExternalProject_Add(${proj}
+          GIT_REPOSITORY "${local_git_repo}"
+          CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+          CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+                     -DWITH_RECURSIVE:BOOL=ON
+          BUILD_COMMAND  ""
+          INSTALL_COMMAND ""
+          DEPENDS "SetupLocalGITRepository"
+                  "SetupLocalGITRepositoryWithSubmodules"
+                  "SetupLocalGITRepositoryWithRecursiveSubmodules"
+          )
+  set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
+  set(proj TS1-GIT-RECURSIVE_SUBMODULES-exclusive)
+  ExternalProject_Add(${proj}
+          GIT_REPOSITORY "${local_git_repo}"
+          GIT_SUBMODULES_RECURSE TRUE
+          CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+          CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+                     -DWITH_RECURSIVE:BOOL=ON
+          BUILD_COMMAND  ""
+          INSTALL_COMMAND ""
+          DEPENDS "SetupLocalGITRepository"
+                  "SetupLocalGITRepositoryWithSubmodules"
+                  "SetupLocalGITRepositoryWithRecursiveSubmodules"
+          )
+  set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
+  set(proj TS1-GIT-RECURSIVE_SUBMODULES-off)
+  ExternalProject_Add(${proj}
+          GIT_REPOSITORY "${local_git_repo}"
+          GIT_SUBMODULES_RECURSE FALSE
+          CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+          CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+                     -DWITH_RECURSIVE:BOOL=OFF
+          BUILD_COMMAND  ""
+          INSTALL_COMMAND ""
+          DEPENDS "SetupLocalGITRepository"
+                  "SetupLocalGITRepositoryWithSubmodules"
+                  "SetupLocalGITRepositoryWithRecursiveSubmodules"
+          )
+  set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
 endif()
 
 set(do_hg_tests 0)
@@ -601,11 +663,19 @@
   add_test(TutorialStep1-GIT-bytag
     "${binary_base}/TutorialStep1-GIT-bytag/Tutorial" 99)
 
+  add_test(TutorialStep1-GIT-bytag-withsubmodules
+    "${binary_base}/TutorialStep1-GIT-bytag-withsubmodules/Tutorial" 99)
+
   add_test(TutorialStep1-GIT-shallow-master
     "${binary_base}/TutorialStep1-GIT-shallow-master/Tutorial" 98)
 
   add_test(TutorialStep1-GIT-master
     "${binary_base}/TutorialStep1-GIT-master/Tutorial" 98)
+
+  if(NOT git_version VERSION_LESS 1.7.7)
+    add_test(TutorialStep1-GIT-config
+      "${binary_base}/TutorialStep1-GIT-config/Tutorial" 98)
+  endif()
 endif()
 
 
diff --git a/Tests/ExternalProject/gitrepo-sub-rec.tgz b/Tests/ExternalProject/gitrepo-sub-rec.tgz
new file mode 100644
index 0000000..b0f3f18
--- /dev/null
+++ b/Tests/ExternalProject/gitrepo-sub-rec.tgz
Binary files differ
diff --git a/Tests/FindGTest/Test/CMakeLists.txt b/Tests/FindGTest/Test/CMakeLists.txt
index b65b9d2..6537238 100644
--- a/Tests/FindGTest/Test/CMakeLists.txt
+++ b/Tests/FindGTest/Test/CMakeLists.txt
@@ -8,6 +8,10 @@
 target_link_libraries(test_gtest_tgt GTest::Main)
 add_test(NAME test_gtest_tgt COMMAND test_gtest_tgt)
 
+add_executable(test_gtest_tgt_upstream main.cxx)
+target_link_libraries(test_gtest_tgt_upstream GTest::gtest_main)
+add_test(NAME test_gtest_tgt_upstream COMMAND test_gtest_tgt_upstream)
+
 add_executable(test_gtest_var main.cxx)
 target_include_directories(test_gtest_var PRIVATE ${GTEST_INCLUDE_DIRS})
 target_link_libraries(test_gtest_var PRIVATE ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
diff --git a/Tests/FindLibArchive/CMakeLists.txt b/Tests/FindLibArchive/CMakeLists.txt
new file mode 100644
index 0000000..f532ef2
--- /dev/null
+++ b/Tests/FindLibArchive/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindLibArchive.Test COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/FindLibArchive/Test"
+  "${CMake_BINARY_DIR}/Tests/FindLibArchive/Test"
+  ${build_generator_args}
+  --build-project TestFindLibArchive
+  --build-options ${build_options}
+  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+  )
diff --git a/Tests/FindLibArchive/Test/CMakeLists.txt b/Tests/FindLibArchive/Test/CMakeLists.txt
new file mode 100644
index 0000000..35843bb
--- /dev/null
+++ b/Tests/FindLibArchive/Test/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.12)
+project(TestFindLibArchive C)
+include(CTest)
+
+find_package(LibArchive REQUIRED)
+
+add_executable(test_libarchive_tgt main.c)
+target_link_libraries(test_libarchive_tgt LibArchive::LibArchive)
+add_test(NAME test_libarchive_tgt COMMAND test_libarchive_tgt)
+
+add_executable(test_libarchive_var main.c)
+target_include_directories(test_libarchive_var PRIVATE ${LibArchive_INCLUDE_DIRS})
+target_link_libraries(test_libarchive_var PRIVATE ${LibArchive_LIBRARIES})
+add_test(NAME test_libarchive_var COMMAND test_libarchive_var)
diff --git a/Tests/FindLibArchive/Test/main.c b/Tests/FindLibArchive/Test/main.c
new file mode 100644
index 0000000..03e7ece
--- /dev/null
+++ b/Tests/FindLibArchive/Test/main.c
@@ -0,0 +1,7 @@
+#include <archive.h>
+
+int main(void)
+{
+  archive_read_free(archive_read_new());
+  return 0;
+}
diff --git a/Tests/FindLibXml2/Test/CMakeLists.txt b/Tests/FindLibXml2/Test/CMakeLists.txt
index df5d8c3..041cc13 100644
--- a/Tests/FindLibXml2/Test/CMakeLists.txt
+++ b/Tests/FindLibXml2/Test/CMakeLists.txt
@@ -14,3 +14,7 @@
 target_include_directories(test_var PRIVATE ${LIBXML2_INCLUDE_DIRS})
 target_link_libraries(test_var PRIVATE ${LIBXML2_LIBRARIES})
 add_test(NAME test_var COMMAND test_var)
+
+add_test(NAME xmllint_tgt COMMAND LibXml2::xmllint --version)
+
+add_test(NAME xmllint_var COMMAND ${LIBXML2_XMLLINT_EXECUTABLE} --version)
diff --git a/Tests/FindPackageModeMakefileTest/CMakeLists.txt b/Tests/FindPackageModeMakefileTest/CMakeLists.txt
index 23832da..8a87a8c 100644
--- a/Tests/FindPackageModeMakefileTest/CMakeLists.txt
+++ b/Tests/FindPackageModeMakefileTest/CMakeLists.txt
@@ -19,6 +19,14 @@
     # configure a FindFoo.cmake so it knows where the library can be found
     configure_file(FindFoo.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FindFoo.cmake @ONLY)
 
+    # Need the -isysroot flag on recentish macOS after command line tools
+    # no longer provide headers in /usr/include
+    if(APPLE AND CMAKE_OSX_SYSROOT)
+      set(__EXTRA_OSX_SYSROOT_FLAGS "-isysroot ${CMAKE_OSX_SYSROOT}")
+    else()
+      set(__EXTRA_OSX_SYSROOT_FLAGS "")
+    endif()
+
     # now set up the test:
     file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/cmakeExecutable.mk"
       CONTENT "CMAKE = \"$<TARGET_FILE:cmake>\"\n"
diff --git a/Tests/FindPackageModeMakefileTest/Makefile.in b/Tests/FindPackageModeMakefileTest/Makefile.in
index 8e7ff72..5ef67d0 100644
--- a/Tests/FindPackageModeMakefileTest/Makefile.in
+++ b/Tests/FindPackageModeMakefileTest/Makefile.in
@@ -5,6 +5,7 @@
 CMAKE_CXX_COMPILER = "@CMAKE_CXX_COMPILER@"
 CMAKE_CXX_COMPILER_ID = "@CMAKE_CXX_COMPILER_ID@"
 CMAKE_CXX_FLAGS = @CMAKE_CXX_FLAGS@
+__EXTRA_OSX_SYSROOT_FLAGS = @__EXTRA_OSX_SYSROOT_FLAGS@
 
 CMAKE_FOO = $(CMAKE) --find-package -DCMAKE_MODULE_PATH=$(CMAKE_CURRENT_BINARY_DIR) -DNAME=Foo -DLANGUAGE=CXX -DCOMPILER_ID=$(CMAKE_CXX_COMPILER_ID)
 
@@ -15,7 +16,7 @@
 main.o: clean main.cpp
 	@$(CMAKE_FOO) -DMODE=COMPILE >$(tmp)
 	@foo="`cat $(tmp)`"; \
-	 printf '"%s" %s %s -c main.cpp\n' $(CMAKE_CXX_COMPILER) "$(CMAKE_CXX_FLAGS)" "$$foo" >$(tmp)
+	 printf '"%s" %s %s %s -c main.cpp\n' $(CMAKE_CXX_COMPILER) "$(CMAKE_CXX_FLAGS)" "$(__EXTRA_OSX_SYSROOT_FLAGS)" "$$foo" >$(tmp)
 	@cat $(tmp)
 	@sh $(tmp)
 	@rm -f $(tmp)
diff --git a/Tests/FindPython/CMakeLists.txt b/Tests/FindPython/CMakeLists.txt
index 868cfe0..01fa6c3 100644
--- a/Tests/FindPython/CMakeLists.txt
+++ b/Tests/FindPython/CMakeLists.txt
@@ -67,14 +67,64 @@
   set_tests_properties(FindPython.Python3Fail PROPERTIES
     PASS_REGULAR_EXPRESSION "Could NOT find Python3 \\(missing: foobar\\)")
 
-  add_test(NAME FindPython.Python COMMAND
+  add_test(NAME FindPython.Python.LOCATION COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
     "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
-    "${CMake_BINARY_DIR}/Tests/FindPython/Python"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python.LOCATION"
     ${build_generator_args}
     --build-project TestPython
-    --build-options ${build_options}
+    --build-options ${build_options} -DPython_FIND_STRATEGY=LOCATION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+  add_test(NAME FindPython.Python.VERSION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python.VERSION"
+    ${build_generator_args}
+    --build-project TestPython
+    --build-options ${build_options} -DPython_FIND_STRATEGY=VERSION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+  add_test(NAME FindPython.Python.V2.LOCATION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.LOCATION"
+    ${build_generator_args}
+    --build-project TestPython
+    --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=LOCATION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+  add_test(NAME FindPython.Python.V2.VERSION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.VERSION"
+    ${build_generator_args}
+    --build-project TestPython
+    --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=VERSION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+  add_test(NAME FindPython.Python.V3.LOCATION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python.V3.LOCATION"
+    ${build_generator_args}
+    --build-project TestPython
+    --build-options ${build_options} -DPython_REQUESTED_VERSION=3 -DPython_FIND_STRATEGY=LOCATION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+  add_test(NAME FindPython.Python.V3.VERSION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python.V3.VERSION"
+    ${build_generator_args}
+    --build-project TestPython
+    --build-options ${build_options} -DPython_REQUESTED_VERSION=3 -DPython_FIND_STRATEGY=VERSION
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
 
@@ -134,6 +184,48 @@
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
 
+  add_test(NAME FindPython.CustomFailureMessage COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/CustomFailureMessage"
+    "${CMake_BINARY_DIR}/Tests/FindPython/CustomFailureMessage"
+    ${build_generator_args}
+    --build-project TestCustomFailureMessage
+    --build-options ${build_options} "-Dbuild_generator_args=${build_generator_args}"
+    "-DCMake_SOURCE_DIR=${CMake_SOURCE_DIR}"
+    "-DCMake_BINARY_DIR=${CMake_BINARY_DIR}"
+    "-DCMake_TEST_FindPython_NumPy=${CMake_TEST_FindPython_NumPy}"
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+
+  if (CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin")
+    add_test(NAME FindPython.Interpreter.SOABI COMMAND
+      ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+      --build-and-test
+      "${CMake_SOURCE_DIR}/Tests/FindPython/SOABI"
+      "${CMake_BINARY_DIR}/Tests/FindPython/SOABI.Interpreter"
+      ${build_generator_args}
+      --build-project TestSOABI
+      --build-options ${build_options} "-Dbuild_generator_args=${build_generator_args}"
+      "-DCMake_SOURCE_DIR=${CMake_SOURCE_DIR}"
+      "-DCMake_BINARY_DIR=${CMake_BINARY_DIR}"
+      "-DCMake_TEST_FindPython_COMPONENT=Interpreter"
+      --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+      )
+    add_test(NAME FindPython.Development.SOABI COMMAND
+      ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+      --build-and-test
+      "${CMake_SOURCE_DIR}/Tests/FindPython/SOABI"
+      "${CMake_BINARY_DIR}/Tests/FindPython/SOABI.Development"
+      ${build_generator_args}
+      --build-project TestSOABI
+      --build-options ${build_options} "-Dbuild_generator_args=${build_generator_args}"
+      "-DCMake_SOURCE_DIR=${CMake_SOURCE_DIR}"
+      "-DCMake_BINARY_DIR=${CMake_BINARY_DIR}"
+      "-DCMake_TEST_FindPython_COMPONENT=Development"
+      --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+      )
+  endif()
 endif()
 
 if(CMake_TEST_FindPython_NumPy)
@@ -158,3 +250,16 @@
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
   )
  endif()
+
+ if(CMake_TEST_FindPython_Conda)
+  add_test(NAME FindPython.VirtualEnvConda COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/VirtualEnvConda"
+    "${CMake_BINARY_DIR}/Tests/FindPython/VirtualEnvConda"
+    ${build_generator_args}
+    --build-project TestVirtualEnvConda
+    --build-options ${build_options}
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+ endif()
diff --git a/Tests/FindPython/CustomFailureMessage/CMakeLists.txt b/Tests/FindPython/CustomFailureMessage/CMakeLists.txt
new file mode 100644
index 0000000..a0d8eb2
--- /dev/null
+++ b/Tests/FindPython/CustomFailureMessage/CMakeLists.txt
@@ -0,0 +1,79 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestCustomFailureMessage LANGUAGES NONE)
+
+include(CTest)
+
+add_test(NAME FindPython.CustomFailureMessage.Interpreter COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/FindPython/CustomFailureMessage/Check"
+  "${CMake_BINARY_DIR}/Tests/FindPython/CustomFailureMessage/Interpreter"
+  ${build_generator_args}
+  --build-project TestCustomFailureMessage.Check
+  --build-options "-DCHECK_COMPONENTS=Interpreter"
+                  "-DPython3_EXECUTABLE=/not/found/interpreter"
+  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+  )
+set_tests_properties(FindPython.CustomFailureMessage.Interpreter PROPERTIES
+  PASS_REGULAR_EXPRESSION "Reason given by package:.+Interpreter: Cannot run the interpreter")
+
+add_test(NAME FindPython.CustomFailureMessage.Library COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/FindPython/CustomFailureMessage/Check"
+  "${CMake_BINARY_DIR}/Tests/FindPython/CustomFailureMessage/Library"
+  ${build_generator_args}
+  --build-project TestCustomFailureMessage.Check
+  --build-options "-DCHECK_COMPONENTS=Development"
+                  "-DPython3_LIBRARY=/not/found/library"
+  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+  )
+set_tests_properties(FindPython.CustomFailureMessage.Library PROPERTIES
+  PASS_REGULAR_EXPRESSION "Reason given by package:.+Development: Cannot find the library")
+
+add_test(NAME FindPython.CustomFailureMessage.Include COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/FindPython/CustomFailureMessage/Check"
+  "${CMake_BINARY_DIR}/Tests/FindPython/CustomFailureMessage/Include"
+  ${build_generator_args}
+  --build-project TestCustomFailureMessage.Check
+  --build-options "-DCHECK_COMPONENTS=Development"
+                  "-DPython3_INCLUDE_DIR=/not/found/include"
+  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+  )
+set_tests_properties(FindPython.CustomFailureMessage.Include PROPERTIES
+  PASS_REGULAR_EXPRESSION "Reason given by package:.+Development: Cannot find the directory")
+
+add_test(NAME FindPython.CustomFailureMessage.Multiple COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/FindPython/CustomFailureMessage/Check"
+  "${CMake_BINARY_DIR}/Tests/FindPython/CustomFailureMessage/Multiple"
+  ${build_generator_args}
+  --build-project TestCustomFailureMessage.Check
+  --build-options "-DCHECK_COMPONENTS=Interpreter;Development"
+                  "-DPython3_EXECUTABLE=/not/found/interpreter"
+                  "-DPython3_LIBRARY=/not/found/library"
+  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+  )
+set_tests_properties(FindPython.CustomFailureMessage.Multiple PROPERTIES
+  PASS_REGULAR_EXPRESSION "Reason given by package:.+Interpreter: Cannot run the interpreter.+Development: Cannot find the library")
+
+
+if (CMake_TEST_FindPython_NumPy)
+  add_test(NAME FindPython.CustomFailureMessage.NumPy COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/CustomFailureMessage/Check"
+    "${CMake_BINARY_DIR}/Tests/FindPython/CustomFailureMessage/NumPy"
+    ${build_generator_args}
+    --build-project TestCustomFailureMessage.Check
+    --build-options "-DCHECK_COMPONENTS=Interpreter;Development;NumPy"
+                    "-DPython3_NumPy_INCLUDE_DIR=/not/found/numpy/include"
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+  set_tests_properties(FindPython.CustomFailureMessage.NumPy PROPERTIES
+    PASS_REGULAR_EXPRESSION "Reason given by package:.+NumPy: Cannot find the directory")
+endif()
diff --git a/Tests/FindPython/CustomFailureMessage/Check/CMakeLists.txt b/Tests/FindPython/CustomFailureMessage/Check/CMakeLists.txt
new file mode 100644
index 0000000..fed963e
--- /dev/null
+++ b/Tests/FindPython/CustomFailureMessage/Check/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestCustomFailureMessage.Check LANGUAGES C)
+
+find_package (Python3 REQUIRED COMPONENTS ${CHECK_COMPONENTS})
diff --git a/Tests/FindPython/Python/CMakeLists.txt b/Tests/FindPython/Python/CMakeLists.txt
index 62c805e..3ee38e3 100644
--- a/Tests/FindPython/Python/CMakeLists.txt
+++ b/Tests/FindPython/Python/CMakeLists.txt
@@ -4,9 +4,9 @@
 
 include(CTest)
 
-find_package(Python 3 REQUIRED COMPONENTS Interpreter Development)
+find_package(Python ${Python_REQUESTED_VERSION} REQUIRED COMPONENTS Interpreter Development)
 if (NOT Python_FOUND)
-  message (FATAL_ERROR "Fail to found Python 3")
+  message (FATAL_ERROR "Fail to found Python ${Python_REQUESTED_VERSION}")
 endif()
 
 if(NOT TARGET Python::Interpreter)
@@ -20,13 +20,15 @@
   message(SEND_ERROR "Python::Module not found")
 endif()
 
-Python_add_library (spam3 MODULE ../spam.c)
-target_compile_definitions (spam3 PRIVATE PYTHON3)
+if (Python_REQUESTED_VERSION)
+  Python_add_library (spam${Python_REQUESTED_VERSION} MODULE ../spam.c)
+  target_compile_definitions (spam${Python_REQUESTED_VERSION} PRIVATE PYTHON${Python_REQUESTED_VERSION})
 
-add_test (NAME python_spam3
-          COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:spam3>"
-          "${Python_EXECUTABLE}" -c "import spam3; spam3.system(\"cd\")")
-
-add_test(NAME findpython_script
-         COMMAND "${CMAKE_COMMAND}" -DPYTHON_PACKAGE_NAME=Python
-         -P "${CMAKE_CURRENT_LIST_DIR}/../FindPythonScript.cmake")
+  add_test (NAME python_spam${Python_REQUESTED_VERSION}
+            COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:spam${Python_REQUESTED_VERSION}>"
+            "${Python_EXECUTABLE}" -c "import spam${Python_REQUESTED_VERSION}; spam${Python_REQUESTED_VERSION}.system(\"cd\")")
+else()
+  add_test(NAME findpython_script
+           COMMAND "${CMAKE_COMMAND}" -DPYTHON_PACKAGE_NAME=Python
+           -P "${CMAKE_CURRENT_LIST_DIR}/../FindPythonScript.cmake")
+endif()
diff --git a/Tests/FindPython/SOABI/CMakeLists.txt b/Tests/FindPython/SOABI/CMakeLists.txt
new file mode 100644
index 0000000..4a6aea3
--- /dev/null
+++ b/Tests/FindPython/SOABI/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestSOABI C)
+
+find_package(Python3 COMPONENTS ${CMake_TEST_FindPython_COMPONENT})
+if (NOT Python3_FOUND)
+  message (FATAL_ERROR "Fail to found Python 3")
+endif()
+
+if(NOT DEFINED Python3_SOABI)
+  message(FATAL_ERROR "Python3_SOABI for ${CMake_TEST_FindPython_COMPONENT} not found")
+endif()
+
+if (Python3_Development_FOUND AND Python3_SOABI)
+  Python3_add_library (spam3 MODULE WITH_SOABI ../spam.c)
+  target_compile_definitions (spam3 PRIVATE PYTHON3)
+
+  get_property (suffix TARGET spam3 PROPERTY SUFFIX)
+  if (NOT suffix MATCHES "^.${Python3_SOABI}")
+    message(FATAL_ERROR "Module suffix do not include Python3_SOABI")
+  endif()
+endif()
diff --git a/Tests/FindPython/VirtualEnv/CMakeLists.txt b/Tests/FindPython/VirtualEnv/CMakeLists.txt
index 64ba201..045a3f2 100644
--- a/Tests/FindPython/VirtualEnv/CMakeLists.txt
+++ b/Tests/FindPython/VirtualEnv/CMakeLists.txt
@@ -10,6 +10,7 @@
 endif()
 
 set (Python3_VIRTUAL_ENV "${CMAKE_CURRENT_BINARY_DIR}/py3venv")
+file (REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/py3venv")
 
 execute_process (COMMAND "${Python3_EXECUTABLE}" -m venv "${Python3_VIRTUAL_ENV}"
                  RESULT_VARIABLE result
@@ -21,22 +22,26 @@
 
 add_test(NAME FindPython3.VirtualEnvDefault
          COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+                                           --unset=CONDA_PREFIX
                                            "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
                  "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
                  -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvDefault.cmake")
 
 add_test(NAME FindPython3.VirtualEnvOnly
          COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+                                           --unset=CONDA_PREFIX
                                            "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
                  "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
                  -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
 add_test(NAME FindPython3.UnsetVirtualEnvOnly
          COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
                                            --unset=VIRTUAL_ENV
+                                           --unset=CONDA_PREFIX
                  "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
 
 add_test(NAME FindPython3.VirtualEnvStandard
          COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+                                           --unset=CONDA_PREFIX
                                            "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
                  "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
                  -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvStandard.cmake")
diff --git a/Tests/FindPython/VirtualEnvConda/CMakeLists.txt b/Tests/FindPython/VirtualEnvConda/CMakeLists.txt
new file mode 100644
index 0000000..565095a
--- /dev/null
+++ b/Tests/FindPython/VirtualEnvConda/CMakeLists.txt
@@ -0,0 +1,46 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestVirtualEnvConda LANGUAGES NONE)
+
+include(CTest)
+
+find_program(CONDA_EXECUTABLE conda)
+if (CONDA_EXECUTABLE EQUAL NOTFOUND)
+  message (FATAL_ERROR "Fail to found Conda")
+endif()
+
+set (Python3_VIRTUAL_ENV "${CMAKE_CURRENT_BINARY_DIR}/condaenv")
+
+execute_process (COMMAND "${CONDA_EXECUTABLE}" create --no-default-packages --prefix "${Python3_VIRTUAL_ENV}" --yes python=3
+                 RESULT_VARIABLE result
+                 OUTPUT_VARIABLE outputs
+                 ERROR_VARIABLE outputs)
+if (result)
+  message (FATAL_ERROR "Fail to create virtual environment: ${outputs}")
+endif()
+
+add_test(NAME FindPython3.VirtualEnvDefaultConda
+         COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+                                           --unset=VIRTUAL_ENV
+                                           "CONDA_PREFIX=${Python3_VIRTUAL_ENV}"
+                 "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+                 -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvDefault.cmake")
+
+add_test(NAME FindPython3.VirtualEnvOnlyConda
+         COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+                                           --unset=VIRTUAL_ENV
+                                           "CONDA_PREFIX=${Python3_VIRTUAL_ENV}"
+                 "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+                 -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
+add_test(NAME FindPython3.UnsetVirtualEnvOnlyConda
+         COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+                                           --unset=CONDA_PREFIX
+                                           --unset=VIRTUAL_ENV
+                 "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
+
+add_test(NAME FindPython3.VirtualEnvStandardConda
+         COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+                                           --unset=VIRTUAL_ENV
+                                           "CONDA_PREFIX=${Python3_VIRTUAL_ENV}"
+                 "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+                 -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvStandard.cmake")
diff --git a/Tests/FindPython/VirtualEnvConda/VirtualEnvDefault.cmake b/Tests/FindPython/VirtualEnvConda/VirtualEnvDefault.cmake
new file mode 100644
index 0000000..020ecac
--- /dev/null
+++ b/Tests/FindPython/VirtualEnvConda/VirtualEnvDefault.cmake
@@ -0,0 +1,6 @@
+
+find_package (Python3 REQUIRED)
+
+if (NOT Python3_EXECUTABLE MATCHES "^${PYTHON3_VIRTUAL_ENV}/.+")
+  message (FATAL_ERROR "Fail to use virtual environment")
+endif()
diff --git a/Tests/FindPython/VirtualEnvConda/VirtualEnvOnly.cmake b/Tests/FindPython/VirtualEnvConda/VirtualEnvOnly.cmake
new file mode 100644
index 0000000..29a4924
--- /dev/null
+++ b/Tests/FindPython/VirtualEnvConda/VirtualEnvOnly.cmake
@@ -0,0 +1,16 @@
+
+#
+# Virtual environment is defined for python3
+# Trying to find a python2 using only virtual environment
+# It is expecting to fail if a virtual environment is active and to success otherwise.
+#
+set (Python2_FIND_VIRTUALENV ONLY)
+find_package (Python2 QUIET)
+
+if (PYTHON3_VIRTUAL_ENV AND Python2_FOUND)
+  message (FATAL_ERROR "Python2 unexpectedly found.")
+endif()
+
+if (NOT PYTHON3_VIRTUAL_ENV AND NOT Python2_FOUND)
+  message (FATAL_ERROR "Fail to find Python2.")
+endif()
diff --git a/Tests/FindPython/VirtualEnvConda/VirtualEnvStandard.cmake b/Tests/FindPython/VirtualEnvConda/VirtualEnvStandard.cmake
new file mode 100644
index 0000000..89f27d8
--- /dev/null
+++ b/Tests/FindPython/VirtualEnvConda/VirtualEnvStandard.cmake
@@ -0,0 +1,7 @@
+
+set (Python3_FIND_VIRTUALENV STANDARD)
+find_package (Python3 REQUIRED)
+
+if (Python3_EXECUTABLE MATCHES "^${PYTHON3_VIRTUAL_ENV}/.+")
+  message (FATAL_ERROR "Python3 virtual env unexpectedly found.")
+endif()
diff --git a/Tests/FortranModules/Executable/CMakeLists.txt b/Tests/FortranModules/Executable/CMakeLists.txt
index de08d86..f31a3e6 100644
--- a/Tests/FortranModules/Executable/CMakeLists.txt
+++ b/Tests/FortranModules/Executable/CMakeLists.txt
@@ -1,6 +1,6 @@
 include_directories(${Library_MODDIR})
 include_directories(${External_BINARY_DIR})
-link_directories(${External_BINARY_DIR})
+link_directories(${External_BINARY_DIR}/${CMAKE_CFG_INTDIR})
 
 add_executable(subdir_exe2 main.f90)
 target_link_libraries(subdir_exe2 subdir_mods subdir_mods2)
diff --git a/Tests/FortranOnly/CMakeLists.txt b/Tests/FortranOnly/CMakeLists.txt
index de887fa..d945375 100644
--- a/Tests/FortranOnly/CMakeLists.txt
+++ b/Tests/FortranOnly/CMakeLists.txt
@@ -103,11 +103,11 @@
 
     # Custom target to try preprocessing invocation.
     add_custom_target(test_preprocess ${MAYBE_ALL}
-      COMMAND ${CMAKE_COMMAND} -E remove CMakeFiles/preprocess.dir/preprocess.F.i
+      COMMAND ${CMAKE_COMMAND} -E rm -f CMakeFiles/preprocess.dir/preprocess.F.i
       COMMAND ${CMAKE_MAKE_PROGRAM} preprocess.i
       COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/test_preprocess.cmake
       # Remove bogus file some compilers leave behind.
-      COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_CURRENT_SOURCE_DIR}/preprocess.s
+      COMMAND ${CMAKE_COMMAND} -E rm -f ${CMAKE_CURRENT_SOURCE_DIR}/preprocess.s
       WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
       )
   endif()
diff --git a/Tests/IncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/CMakeLists.txt
index 761c405..fa3309f 100644
--- a/Tests/IncludeDirectories/CMakeLists.txt
+++ b/Tests/IncludeDirectories/CMakeLists.txt
@@ -94,6 +94,6 @@
   message(SEND_ERROR "Empty include_directories entry was not ignored.")
 endif()
 
-if(NOT CMAKE_GENERATOR STREQUAL Xcode AND NOT CMAKE_GENERATOR STREQUAL Ninja)
+if(NOT CMAKE_GENERATOR STREQUAL "Xcode" AND NOT CMAKE_GENERATOR MATCHES "Ninja")
   add_subdirectory(CMP0021)
 endif()
diff --git a/Tests/InterfaceLibrary/CMakeLists.txt b/Tests/InterfaceLibrary/CMakeLists.txt
index 954c02d..311ca2a 100644
--- a/Tests/InterfaceLibrary/CMakeLists.txt
+++ b/Tests/InterfaceLibrary/CMakeLists.txt
@@ -3,6 +3,12 @@
 
 project(InterfaceLibrary)
 
+set(cfg_dir)
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+  set(cfg_dir /$<CONFIG>)
+endif()
+
 add_library(iface_nodepends INTERFACE)
 target_compile_definitions(iface_nodepends INTERFACE IFACE_DEFINE)
 
@@ -32,7 +38,7 @@
 set_property(TARGET item_iface PROPERTY IMPORTED_LIBNAME item_real)
 add_dependencies(item_iface item_real)
 get_property(item_iface_dependencies TARGET item_iface PROPERTY MANUALLY_ADDED_DEPENDENCIES)
-link_directories(${CMAKE_CURRENT_BINARY_DIR})
+link_directories(${CMAKE_CURRENT_BINARY_DIR}${cfg_dir})
 
 add_executable(InterfaceLibrary definetestexe.cpp)
 target_link_libraries(InterfaceLibrary
diff --git a/Tests/JavaExportImport/CMakeLists.txt b/Tests/JavaExportImport/CMakeLists.txt
index c70704a..7a2d020 100644
--- a/Tests/JavaExportImport/CMakeLists.txt
+++ b/Tests/JavaExportImport/CMakeLists.txt
@@ -9,7 +9,7 @@
 # Wipe out the install tree to make sure the exporter works.
 add_custom_command(
   OUTPUT ${JavaExportImport_BINARY_DIR}/CleanupProject
-  COMMAND ${CMAKE_COMMAND} -E remove_directory ${JavaExportImport_BINARY_DIR}/Root
+  COMMAND ${CMAKE_COMMAND} -E rm -rf ${JavaExportImport_BINARY_DIR}/Root
   )
 add_custom_target(CleanupTarget ALL DEPENDS ${JavaExportImport_BINARY_DIR}/CleanupProject)
 set_property(
diff --git a/Tests/LinkDirectory/CMakeLists.txt b/Tests/LinkDirectory/CMakeLists.txt
index c60de84..c7a2700 100644
--- a/Tests/LinkDirectory/CMakeLists.txt
+++ b/Tests/LinkDirectory/CMakeLists.txt
@@ -33,7 +33,7 @@
 # directly because it does not know the full paths to the libraries.
 # (The purpose of this test is to check that link_directories works.)
 ExternalProject_Add_Step(ExternalTarget cleanup
-  COMMAND ${CMAKE_COMMAND} -E remove_directory ${LinkDirectory_BINARY_DIR}/bin
+  COMMAND ${CMAKE_COMMAND} -E rm -rf ${LinkDirectory_BINARY_DIR}/bin
   DEPENDEES download
   DEPENDERS configure
   DEPENDS mylibA mylibB
diff --git a/Tests/LinkDirectory/External/CMakeLists.txt b/Tests/LinkDirectory/External/CMakeLists.txt
index d2a1f9f..c877913 100644
--- a/Tests/LinkDirectory/External/CMakeLists.txt
+++ b/Tests/LinkDirectory/External/CMakeLists.txt
@@ -2,13 +2,19 @@
 project(LinkDirectoryExternal C)
 
 
+set(cfg_dir)
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+  set(cfg_dir /$<CONFIG>)
+endif()
+
 add_executable(myexe2 myexe.c)
 set_property(TARGET myexe2 PROPERTY OUTPUT_NAME LinkDirectory2)
-target_link_directories(myexe2 PRIVATE lib "${CMAKE_CURRENT_SOURCE_DIR}/../lib")
+target_link_directories(myexe2 PRIVATE lib${cfg_dir} "${CMAKE_CURRENT_SOURCE_DIR}/../lib${cfg_dir}")
 target_link_libraries(myexe2 PRIVATE mylibA mylibB)
 
 add_library (mylibs INTERFACE)
-target_link_directories(mylibs INTERFACE lib "${CMAKE_CURRENT_SOURCE_DIR}/../lib")
+target_link_directories(mylibs INTERFACE lib${cfg_dir} "${CMAKE_CURRENT_SOURCE_DIR}/../lib${cfg_dir}")
 target_link_libraries(mylibs INTERFACE mylibA mylibB)
 add_executable(myexe3 myexe.c)
 set_property(TARGET myexe3 PROPERTY OUTPUT_NAME LinkDirectory3)
@@ -17,11 +23,11 @@
 
 # Test CMP0015 OLD behavior: -L../lib
 cmake_policy(SET CMP0015 OLD)
-link_directories(../lib)
+link_directories(../lib${cfg_dir})
 
 # Test CMP0015 NEW behavior: -L${CMAKE_CURRENT_SOURCE_DIR}/lib
 cmake_policy(SET CMP0015 NEW)
-link_directories(lib)
+link_directories(lib${cfg_dir})
 
 add_executable(myexe myexe.c)
 set_property(TARGET myexe PROPERTY OUTPUT_NAME LinkDirectory)
diff --git a/Tests/MacRuntimePath/CMakeLists.txt b/Tests/MacRuntimePath/CMakeLists.txt
index a3c6fd9..9f1bf1a 100644
--- a/Tests/MacRuntimePath/CMakeLists.txt
+++ b/Tests/MacRuntimePath/CMakeLists.txt
@@ -7,7 +7,7 @@
 # Wipe out the install tree to make sure the exporter works.
 add_custom_command(
   OUTPUT ${MacRuntimePath_BINARY_DIR}/CleanupProject
-  COMMAND ${CMAKE_COMMAND} -E remove_directory ${MacRuntimePath_BINARY_DIR}/Root
+  COMMAND ${CMAKE_COMMAND} -E rm -rf ${MacRuntimePath_BINARY_DIR}/Root
   )
 add_custom_target(CleanupTarget ALL DEPENDS ${MacRuntimePath_BINARY_DIR}/CleanupProject)
 set_property(
diff --git a/Tests/OutDir/CMakeLists.txt b/Tests/OutDir/CMakeLists.txt
index 823ab08..8afe036 100644
--- a/Tests/OutDir/CMakeLists.txt
+++ b/Tests/OutDir/CMakeLists.txt
@@ -20,7 +20,7 @@
 foreach(config ${configs})
   foreach(type archive runtime library)
     string(TOUPPER "${type}" TYPE)
-    set(CMAKE_${TYPE}_OUTPUT_DIRECTORY_${config} "${top}/${type}")
+    set(CMAKE_${TYPE}_OUTPUT_DIRECTORY_${config} "${top}/${type}/$<CONFIG>")
     file(REMOVE_RECURSE "${top}/${type}")
   endforeach()
 endforeach()
@@ -29,7 +29,7 @@
 
 add_custom_command(
   OUTPUT OutDir.h
-  COMMAND ${CMAKE_COMMAND} -Dtop=${top} -P ${OutDir_SOURCE_DIR}/OutDir.cmake
+  COMMAND ${CMAKE_COMMAND} -Dtop=${top} -Dcfg_dir=$<CONFIG> -P ${OutDir_SOURCE_DIR}/OutDir.cmake
   DEPENDS COnly ${OutDir_SOURCE_DIR}/OutDir.cmake
   )
 include_directories(${top})
diff --git a/Tests/OutDir/OutDir.cmake b/Tests/OutDir/OutDir.cmake
index a1f13e7..2a003b8 100644
--- a/Tests/OutDir/OutDir.cmake
+++ b/Tests/OutDir/OutDir.cmake
@@ -3,17 +3,17 @@
 
 find_library(TESTC1_LIB
   NAMES testc1 testc1_test_debug_postfix
-  PATHS ${top}/archive
+  PATHS ${top}/archive/${cfg_dir}
   NO_DEFAULT_PATH)
 
 find_library(TESTC2_LIB
   NAMES testc2 testc2_test_debug_postfix
-  PATHS ${top}/archive ${top}/library
+  PATHS ${top}/archive/${cfg_dir} ${top}/library/${cfg_dir}
   NO_DEFAULT_PATH)
 
 find_program(CONLY_EXE
   NAMES COnly
-  PATHS ${top}/runtime
+  PATHS ${top}/runtime/${cfg_dir}
   NO_DEFAULT_PATH)
 
 file(RELATIVE_PATH TESTC1_LIB_FILE "${top}" "${TESTC1_LIB}")
diff --git a/Tests/Qt4Autogen/CMakeLists.txt b/Tests/Qt4Autogen/CMakeLists.txt
index 68b885b..e7f1ae3 100644
--- a/Tests/Qt4Autogen/CMakeLists.txt
+++ b/Tests/Qt4Autogen/CMakeLists.txt
@@ -7,3 +7,5 @@
 
 # Common tests
 include("../QtAutogen/Tests.cmake")
+
+set(TEST_BUILD_DIRS "${TEST_BUILD_DIRS}" PARENT_SCOPE)
diff --git a/Tests/Qt5Autogen/CMakeLists.txt b/Tests/Qt5Autogen/CMakeLists.txt
index 49d33cc..df4927a 100644
--- a/Tests/Qt5Autogen/CMakeLists.txt
+++ b/Tests/Qt5Autogen/CMakeLists.txt
@@ -4,3 +4,5 @@
 
 # Common tests
 include("../QtAutogen/Tests.cmake")
+
+set(TEST_BUILD_DIRS "${TEST_BUILD_DIRS}" PARENT_SCOPE)
diff --git a/Tests/QtAutogen/MocCMP0100/CMakeLists.txt b/Tests/QtAutogen/MocCMP0100/CMakeLists.txt
new file mode 100644
index 0000000..559cffe
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0100/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.10)
+project(MocCMP0100)
+include("../AutogenCoreTest.cmake")
+
+set(CMAKE_AUTOMOC ON)
+set(CSD ${CMAKE_CURRENT_SOURCE_DIR})
+
+add_subdirectory(OLD)
+add_subdirectory(NEW)
diff --git a/Tests/QtAutogen/MocCMP0100/NEW/CMakeLists.txt b/Tests/QtAutogen/MocCMP0100/NEW/CMakeLists.txt
new file mode 100644
index 0000000..654b31e
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0100/NEW/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.16)
+cmake_policy(SET CMP0100 NEW)
+
+add_executable(mocCMP0100New
+  ${CSD}/main.cpp
+  ${CSD}/Obj.hh # Manually include Obj.hh
+  ${CSD}/Obj.cpp
+  ${CSD}/Obj2.cpp # Let AUTOMOC detect Obj2.hh
+)
+target_link_libraries(mocCMP0100New ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/MocCMP0100/OLD/CMakeLists.txt b/Tests/QtAutogen/MocCMP0100/OLD/CMakeLists.txt
new file mode 100644
index 0000000..2be0535
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0100/OLD/CMakeLists.txt
@@ -0,0 +1,31 @@
+cmake_minimum_required(VERSION 3.16)
+cmake_policy(SET CMP0100 OLD)
+
+# Generate moc files externally.
+# If AUTOMOC generates the header moc files as well
+# (it should not in OLD behavior), the test will fail with a
+# multiple definition error when linking the executable.
+qtx_wrap_cpp(mocCMP0100OldMoc ${CSD}/Obj.hh ${CSD}/Obj2.hh)
+qtx_generate_moc(${CBD}/Obj.cpp ${CMAKE_CURRENT_BINARY_DIR}/Obj.moc)
+qtx_generate_moc(${CBD}/Obj2.cpp ${CMAKE_CURRENT_BINARY_DIR}/Obj2.moc)
+
+# Make sure AUTOGEN file skipping is disabled
+set_source_files_properties(
+  ${CSD}/Obj.hh
+  ${CBD}/Obj.cpp
+  ${CSD}/Obj2.hh
+  ${CBD}/Obj2.cpp
+  PROPERTIES
+  SKIP_AUTOGEN OFF
+  SKIP_AUTOMOC OFF
+)
+
+add_executable(mocCMP0100Old
+  ${CSD}/main.cpp
+  ${CSD}/Obj.hh # Manually include Obj.hh
+  ${CSD}/Obj.cpp
+  ${CSD}/Obj2.cpp # Let AUTOMOC detect Obj2.hh
+  ${mocCMP0100OldMoc}
+)
+target_link_libraries(mocCMP0100Old ${QT_LIBRARIES})
+target_include_directories(mocCMP0100Old PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
diff --git a/Tests/QtAutogen/MocCMP0100/Obj.cpp b/Tests/QtAutogen/MocCMP0100/Obj.cpp
new file mode 100644
index 0000000..bb6d0a0
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0100/Obj.cpp
@@ -0,0 +1,31 @@
+#include "Obj.hh"
+
+#include <QObject>
+
+class ObjPrivate : public QObject
+{
+  Q_OBJECT
+public:
+  ObjPrivate();
+  ~ObjPrivate();
+};
+
+ObjPrivate::ObjPrivate()
+{
+}
+
+ObjPrivate::~ObjPrivate()
+{
+}
+
+Obj::Obj()
+  : d(new ObjPrivate)
+{
+}
+
+Obj::~Obj()
+{
+  delete d;
+}
+
+#include "Obj.moc"
diff --git a/Tests/QtAutogen/MocCMP0100/Obj.hh b/Tests/QtAutogen/MocCMP0100/Obj.hh
new file mode 100644
index 0000000..940bfc2
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0100/Obj.hh
@@ -0,0 +1,20 @@
+#ifndef OBJ_HH
+#define OBJ_HH
+
+#include <QObject>
+
+// Qt enabled private class
+class ObjPrivate;
+// Qt enabled class
+class Obj : public QObject
+{
+  Q_OBJECT
+public:
+  Obj();
+  ~Obj();
+
+private:
+  ObjPrivate* const d;
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocCMP0100/Obj2.cpp b/Tests/QtAutogen/MocCMP0100/Obj2.cpp
new file mode 100644
index 0000000..8a359ad
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0100/Obj2.cpp
@@ -0,0 +1,31 @@
+#include "Obj2.hh"
+
+#include <QObject>
+
+class Obj2Private : public QObject
+{
+  Q_OBJECT
+public:
+  Obj2Private();
+  ~Obj2Private();
+};
+
+Obj2Private::Obj2Private()
+{
+}
+
+Obj2Private::~Obj2Private()
+{
+}
+
+Obj2::Obj2()
+  : d(new Obj2Private)
+{
+}
+
+Obj2::~Obj2()
+{
+  delete d;
+}
+
+#include "Obj2.moc"
diff --git a/Tests/QtAutogen/MocCMP0100/Obj2.hh b/Tests/QtAutogen/MocCMP0100/Obj2.hh
new file mode 100644
index 0000000..1c74cdd
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0100/Obj2.hh
@@ -0,0 +1,20 @@
+#ifndef OBJ2_HH
+#define OBJ2_HH
+
+#include <QObject>
+
+// Qt enabled private class
+class Obj2Private;
+// Qt enabled class
+class Obj2 : public QObject
+{
+  Q_OBJECT
+public:
+  Obj2();
+  ~Obj2();
+
+private:
+  Obj2Private* const d;
+};
+
+#endif
diff --git a/Tests/QtAutogen/MocCMP0100/main.cpp b/Tests/QtAutogen/MocCMP0100/main.cpp
new file mode 100644
index 0000000..17061da
--- /dev/null
+++ b/Tests/QtAutogen/MocCMP0100/main.cpp
@@ -0,0 +1,9 @@
+#include "Obj.hh"
+#include "Obj2.hh"
+
+int main(int argv, char** args)
+{
+  Obj obj;
+  Obj2 obj2;
+  return 0;
+}
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA.hpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA.hpp
index e1fdf0b..198ae98 100644
--- a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA.hpp
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleA.hpp
@@ -10,7 +10,7 @@
   Q_OBJECT
   // Json file in source local directory
   Q_PLUGIN_METADATA(IID "org.styles.A" FILE "StyleA.json")
-  A_CUSTOM_MACRO(SomeArg, "StyleA_Custom.json", AnotherArg)
+  A_CUSTOM_MACRO(org.styles.A, "StyleA_Custom.json", AnotherArg)
 public:
   QStyle* create(const QString& key);
 };
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleB.hpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleB.hpp
index 7550d0c..8ce8d77 100644
--- a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleB.hpp
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleB.hpp
@@ -10,7 +10,7 @@
   Q_OBJECT
   // Json file in source local subdirectory
   Q_PLUGIN_METADATA(IID "org.styles.B" FILE "jsonIn/StyleB.json")
-  A_CUSTOM_MACRO(SomeArg, "jsonIn/StyleB_Custom.json", AnotherArg)
+  A_CUSTOM_MACRO(org.styles.B, "jsonIn/StyleB_Custom.json", AnotherArg)
 public:
   QStyle* create(const QString& key);
 };
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleC.hpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleC.hpp
index ec71bec..53171e3 100644
--- a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleC.hpp
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleC.hpp
@@ -10,7 +10,7 @@
   Q_OBJECT
   // Json file in global root directory
   Q_PLUGIN_METADATA(IID "org.styles.C" FILE "StyleC.json")
-  A_CUSTOM_MACRO(SomeArg, "StyleC_Custom.json", AnotherArg)
+  A_CUSTOM_MACRO(org.styles.C, "StyleC_Custom.json", AnotherArg)
 public:
   QStyle* create(const QString& key);
 };
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleD.hpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleD.hpp
index 3c093b9..29674f9 100644
--- a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleD.hpp
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleD.hpp
@@ -10,7 +10,7 @@
   Q_OBJECT
   // Json file in global sub director
   Q_PLUGIN_METADATA(IID "org.styles.D" FILE "sub/StyleD.json")
-  A_CUSTOM_MACRO(SomeArg, "sub/StyleD_Custom.json", AnotherArg)
+  A_CUSTOM_MACRO(org.styles.D, "sub/StyleD_Custom.json", AnotherArg)
 public:
   QStyle* create(const QString& key);
 };
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleEInclude.hpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleEInclude.hpp
index 5f10fb4..7318220 100644
--- a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleEInclude.hpp
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/StyleEInclude.hpp
@@ -10,7 +10,7 @@
   Q_OBJECT
   // Json files in global root directory
   Q_PLUGIN_METADATA(IID "org.styles.E" FILE "StyleE.json")
-  A_CUSTOM_MACRO(SomeArg, "StyleE_Custom.json", AnotherArg)
+  A_CUSTOM_MACRO(org.styles.E, "StyleE_Custom.json", AnotherArg)
 public:
   QStyle* create(const QString& key);
 };
diff --git a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/UtilityMacros.hpp b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/UtilityMacros.hpp
index 53a4284..2f558a8 100644
--- a/Tests/QtAutogen/RerunMocPlugin/MocPlugin/UtilityMacros.hpp
+++ b/Tests/QtAutogen/RerunMocPlugin/MocPlugin/UtilityMacros.hpp
@@ -1,7 +1,7 @@
 #ifndef UTILITYMACROS_HPP
 #define UTILITYMACROS_HPP
 
-// Empty test macro definition
-#define A_CUSTOM_MACRO(name, jsonFile, pluginRegistrations)
+#define A_CUSTOM_MACRO(url, jsonFile, pluginRegistrations)                    \
+  Q_PLUGIN_METADATA(IID #url FILE jsonFile)
 
 #endif
diff --git a/Tests/QtAutogen/SameName/CMakeLists.txt b/Tests/QtAutogen/SameName/CMakeLists.txt
index cd29a2a..4ce8dbd 100644
--- a/Tests/QtAutogen/SameName/CMakeLists.txt
+++ b/Tests/QtAutogen/SameName/CMakeLists.txt
@@ -1,7 +1,10 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.16.0)
 project(SameName)
 include("../AutogenGuiTest.cmake")
 
+# Process .hh headers in AUTOMOC
+cmake_policy(SET CMP0100 NEW)
+
 # Test AUTOMOC and AUTORCC on source files with the same name
 # but in different subdirectories
 
@@ -18,6 +21,7 @@
   ccc/data.qrc
   item.cpp
   object.h
+  object.hh
   object.h++
   object.hpp
   object.hxx
diff --git a/Tests/QtAutogen/SameName/main.cpp b/Tests/QtAutogen/SameName/main.cpp
index 19a6f6d..725f4cd 100644
--- a/Tests/QtAutogen/SameName/main.cpp
+++ b/Tests/QtAutogen/SameName/main.cpp
@@ -6,6 +6,7 @@
 #include "item.hpp"
 #include "object.h"
 #include "object.h++"
+#include "object.hh"
 #include "object.hpp"
 #include "object.hxx"
 #include "object_upper_ext.H"
@@ -21,6 +22,7 @@
   ::ccc::Item ccc_item;
   // Object instances
   ::Object_h obj_h;
+  ::Object_hh obj_hh;
   ::Object_hplpl obj_hplpl;
   ::Object_hpp obj_hpp;
   ::Object_hxx obj_hxx;
diff --git a/Tests/QtAutogen/SameName/object.hh b/Tests/QtAutogen/SameName/object.hh
new file mode 100644
index 0000000..3e16f83
--- /dev/null
+++ b/Tests/QtAutogen/SameName/object.hh
@@ -0,0 +1,13 @@
+#ifndef OBJECT_HH
+#define OBJECT_HH
+
+#include <QObject>
+
+class Object_hh : public QObject
+{
+  Q_OBJECT
+  Q_SLOT
+  void go(){};
+};
+
+#endif
diff --git a/Tests/QtAutogen/Tests.cmake b/Tests/QtAutogen/Tests.cmake
index 2b001d4..a19a9ae 100644
--- a/Tests/QtAutogen/Tests.cmake
+++ b/Tests/QtAutogen/Tests.cmake
@@ -32,6 +32,7 @@
 
 if(QT_TEST_ALLOW_QT_MACROS)
   ADD_AUTOGEN_TEST(MocCMP0071)
+  ADD_AUTOGEN_TEST(MocCMP0100)
   ADD_AUTOGEN_TEST(MocInclude)
   ADD_AUTOGEN_TEST(MocIncludeSymlink)
   ADD_AUTOGEN_TEST(MocSkipSource)
diff --git a/Tests/RunCMake/AutoExportDll/AIXExportExplicit-build-result.txt b/Tests/RunCMake/AutoExportDll/AIXExportExplicit-build-result.txt
new file mode 100644
index 0000000..d197c91
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/AIXExportExplicit-build-result.txt
@@ -0,0 +1 @@
+[^0]
diff --git a/Tests/RunCMake/AutoExportDll/AIXExportExplicit-build-stdout.txt b/Tests/RunCMake/AutoExportDll/AIXExportExplicit-build-stdout.txt
new file mode 100644
index 0000000..760ba3c
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/AIXExportExplicit-build-stdout.txt
@@ -0,0 +1 @@
+ERROR: Undefined symbol: .AIXNotExported
diff --git a/Tests/RunCMake/AutoExportDll/AIXExportExplicit.cmake b/Tests/RunCMake/AutoExportDll/AIXExportExplicit.cmake
new file mode 100644
index 0000000..d23b172
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/AIXExportExplicit.cmake
@@ -0,0 +1,7 @@
+enable_language(C)
+
+set(CMAKE_AIX_EXPORT_ALL_SYMBOLS OFF)
+add_library(AIXExportExplicitLib SHARED AIXExportExplicitLib.c)
+add_executable(AIXExportExplicitMain AIXExportExplicitMain.c)
+target_link_options(AIXExportExplicitLib PRIVATE LINKER:-bE:${CMAKE_CURRENT_SOURCE_DIR}/AIXExportExplicitLib.exp)
+target_link_libraries(AIXExportExplicitMain PRIVATE AIXExportExplicitLib)
diff --git a/Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.c b/Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.c
new file mode 100644
index 0000000..58fd5ac
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.c
@@ -0,0 +1,8 @@
+int AIXNotExported(void)
+{
+  return 0;
+}
+int AIXExportedSymbol(void)
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.exp b/Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.exp
new file mode 100644
index 0000000..9eb7bf8
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.exp
@@ -0,0 +1 @@
+AIXExportedSymbol
diff --git a/Tests/RunCMake/AutoExportDll/AIXExportExplicitMain.c b/Tests/RunCMake/AutoExportDll/AIXExportExplicitMain.c
new file mode 100644
index 0000000..ad9c8ec
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/AIXExportExplicitMain.c
@@ -0,0 +1,7 @@
+extern int AIXNotExported(void);
+extern int AIXExportedSymbol(void);
+
+int main(void)
+{
+  return AIXNotExported() + AIXExportedSymbol();
+}
diff --git a/Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake b/Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake
index 6c9be4b..75130f2 100644
--- a/Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake
+++ b/Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake
@@ -55,3 +55,14 @@
     message(SEND_ERROR "\"${EXPORTS_DEF}\" has been updated.")
   endif()
 endif()
+
+function(run_AIXExportExplicit)
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/AIXExpotExplicit-build")
+  run_cmake(AIXExportExplicit)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake_TEST_OUTPUT_MERGE TRUE)
+  run_cmake_command(AIXExportExplicit-build ${CMAKE_COMMAND} --build . --config Debug)
+endfunction()
+if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
+  run_AIXExportExplicit()
+endif()
diff --git a/Tests/RunCMake/CMP0037/RunCMakeTest.cmake b/Tests/RunCMake/CMP0037/RunCMakeTest.cmake
index 98274f0..5952279 100644
--- a/Tests/RunCMake/CMP0037/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMP0037/RunCMakeTest.cmake
@@ -1,5 +1,24 @@
 include(RunCMake)
 
+if(RunCMake_GENERATOR MATCHES "^Ninja")
+  # Detect ninja version so we know what tests can be supported.
+  execute_process(
+    COMMAND "${RunCMake_MAKE_PROGRAM}" --version
+    OUTPUT_VARIABLE ninja_out
+    ERROR_VARIABLE ninja_out
+    RESULT_VARIABLE ninja_res
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+    )
+  if(ninja_res EQUAL 0 AND "x${ninja_out}" MATCHES "^x[0-9]+\\.[0-9]+")
+    set(ninja_version "${ninja_out}")
+    message(STATUS "ninja version: ${ninja_version}")
+  else()
+    message(FATAL_ERROR "'ninja --version' reported:\n${ninja_out}")
+  endif()
+else()
+  set(ninja_version "")
+endif()
+
 run_cmake(CMP0037-OLD-space)
 run_cmake(CMP0037-NEW-space)
 run_cmake(CMP0037-WARN-space)
@@ -9,8 +28,10 @@
   run_cmake(CMP0037-WARN-colon)
 endif()
 
-run_cmake(CMP0037-WARN-reserved)
-run_cmake(CMP0037-OLD-reserved)
+if(NOT ninja_version VERSION_GREATER_EQUAL 1.10)
+  run_cmake(CMP0037-WARN-reserved)
+  run_cmake(CMP0037-OLD-reserved)
+endif()
 run_cmake(CMP0037-NEW-reserved)
 
 run_cmake(NEW-cond)
diff --git a/Tests/RunCMake/CMP0068/CMP0068-OLD-stderr.txt b/Tests/RunCMake/CMP0068/CMP0068-OLD-stderr.txt
new file mode 100644
index 0000000..a736129
--- /dev/null
+++ b/Tests/RunCMake/CMP0068/CMP0068-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0068-OLD.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0068 will be removed from a future version
+  of CMake.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0069/CMP0069-OLD-stderr.txt b/Tests/RunCMake/CMP0069/CMP0069-OLD-stderr.txt
new file mode 100644
index 0000000..f51a6f4
--- /dev/null
+++ b/Tests/RunCMake/CMP0069/CMP0069-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0069-OLD.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0069 will be removed from a future version
+  of CMake.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/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 581a39e..e9f8bca 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
@@ -125,7 +126,7 @@
 if(CMAKE_GENERATOR MATCHES "Make")
   add_RunCMake_test(Make -DMAKE_IS_GNU=${MAKE_IS_GNU})
 endif()
-if(CMAKE_GENERATOR STREQUAL "Ninja")
+if(CMAKE_GENERATOR MATCHES "Ninja")
   set(Ninja_ARGS
     -DCMAKE_C_OUTPUT_EXTENSION=${CMAKE_C_OUTPUT_EXTENSION}
     -DCMAKE_SHARED_LIBRARY_PREFIX=${CMAKE_SHARED_LIBRARY_PREFIX}
@@ -134,6 +135,16 @@
     list(APPEND Ninja_ARGS -DTEST_Fortran=1)
   endif()
   add_RunCMake_test(Ninja)
+  set(NinjaMultiConfig_ARGS
+    -DCYGWIN=${CYGWIN}
+    )
+  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)
 
@@ -189,6 +200,7 @@
 add_RunCMake_test(GetPrerequisites)
 add_RunCMake_test(GNUInstallDirs -DSYSTEM_NAME=${CMAKE_SYSTEM_NAME})
 add_RunCMake_test(GoogleTest) # Note: does not actually depend on Google Test
+add_RunCMake_test(Graphviz)
 add_RunCMake_test(TargetPropertyGeneratorExpressions)
 add_RunCMake_test(Languages)
 add_RunCMake_test(LinkStatic)
@@ -209,6 +221,7 @@
 add_RunCMake_test(Swift -DCMAKE_Swift_COMPILER=${CMAKE_Swift_COMPILER})
 add_RunCMake_test(TargetObjects)
 add_RunCMake_test(TargetSources)
+add_RunCMake_test(TargetProperties)
 add_RunCMake_test(ToolchainFile)
 add_RunCMake_test(find_dependency)
 add_RunCMake_test(CompileDefinitions)
@@ -271,6 +284,7 @@
 add_RunCMake_test(find_path)
 add_RunCMake_test(find_program -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME})
 add_RunCMake_test(foreach)
+add_RunCMake_test(function)
 add_RunCMake_test(get_filename_component)
 add_RunCMake_test(get_property)
 add_RunCMake_test(if)
@@ -278,6 +292,7 @@
 add_RunCMake_test(include_directories)
 add_RunCMake_test(include_guard)
 add_RunCMake_test(list)
+add_RunCMake_test(load_cache)
 add_RunCMake_test(math)
 add_RunCMake_test(message)
 add_RunCMake_test(option)
@@ -289,6 +304,10 @@
 add_RunCMake_test(string)
 add_RunCMake_test(test_include_dirs)
 add_RunCMake_test(BundleUtilities)
+if(APPLE)
+  add_RunCMake_test(INSTALL_NAME_DIR)
+  add_RunCMake_test(MacOSVersions)
+endif()
 
 function(add_RunCMake_test_try_compile)
   if(CMAKE_VERSION VERSION_LESS 3.9.20170907 AND "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
@@ -335,6 +354,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
@@ -436,12 +456,12 @@
 
 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)
 add_RunCMake_test(CheckIPOSupported)
-add_RunCMake_test(CommandLine -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME})
+add_RunCMake_test(CommandLine -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} -DCYGWIN=${CYGWIN} -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE})
 add_RunCMake_test(CommandLineTar)
 
 if(CMAKE_PLATFORM_NO_VERSIONED_SONAME OR (NOT CMAKE_SHARED_LIBRARY_SONAME_FLAG AND NOT CMAKE_SHARED_LIBRARY_SONAME_C_FLAG))
@@ -454,7 +474,9 @@
   -DCMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN=${CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN}
   -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
   -DCMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG=${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG}
-  -DCMAKE_EXECUTABLE_FORMAT=${CMAKE_EXECUTABLE_FORMAT})
+  -DCMAKE_EXECUTABLE_FORMAT=${CMAKE_EXECUTABLE_FORMAT}
+  -DCMake_INSTALL_NAME_TOOL_BUG=${CMake_INSTALL_NAME_TOOL_BUG}
+  )
 
 add_RunCMake_test(CPackCommandLine)
 add_RunCMake_test(CPackConfig)
@@ -554,6 +576,7 @@
   DEB.MD5SUMS
   DEB.DEB_PACKAGE_VERSION_BACK_COMPATIBILITY
   DEB.DEB_DESCRIPTION
+  DEB.PROJECT_META
 
   RPM.CUSTOM_BINARY_SPEC_FILE
   RPM.CUSTOM_NAMES
@@ -574,6 +597,7 @@
   RPM.SUGGESTS
   RPM.SYMLINKS
   RPM.USER_FILELIST
+  RPM.PROJECT_META
 
   7Z
   TBZ2
@@ -584,10 +608,16 @@
   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
-add_RunCMake_test(AutoExportDll -DCMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID})
+add_RunCMake_test(AutoExportDll
+  -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
+  -DCMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}
+  )
 
 add_RunCMake_test(AndroidMK)
 
diff --git a/Tests/RunCMake/CPack/CPackTestHelpers.cmake b/Tests/RunCMake/CPack/CPackTestHelpers.cmake
index f65cb9d..24f54c6 100644
--- a/Tests/RunCMake/CPack/CPackTestHelpers.cmake
+++ b/Tests/RunCMake/CPack/CPackTestHelpers.cmake
@@ -75,7 +75,7 @@
     if(package_target)
       set(cpack_command_ ${CMAKE_COMMAND} --build "${RunCMake_TEST_BINARY_DIR}" --target package)
     else()
-      set(cpack_command_ ${CMAKE_CPACK_COMMAND} ${pack_params_})
+      set(cpack_command_ ${CMAKE_CPACK_COMMAND} ${pack_params_} -C Debug)
     endif()
 
     # execute cpack
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 c2382b0..3be1fd0 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")
@@ -43,3 +43,4 @@
   false
   "MONOLITHIC;COMPONENT"
 )
+run_cpack_test(PROJECT_META "RPM.PROJECT_META;DEB.PROJECT_META" 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/EXTERNAL/expected-json-1.0.txt b/Tests/RunCMake/CPack/tests/EXTERNAL/expected-json-1.0.txt
index 18bf617..ca25b1e 100644
--- a/Tests/RunCMake/CPack/tests/EXTERNAL/expected-json-1.0.txt
+++ b/Tests/RunCMake/CPack/tests/EXTERNAL/expected-json-1.0.txt
@@ -1,5 +1,6 @@
 ^\{
-  "componentGroups" :[ ]
+  ("buildConfig" : "Debug",
+)?  "componentGroups" :[ ]
   \{
     "f12" :[ ]
     \{
diff --git a/Tests/RunCMake/CPack/tests/PROJECT_META/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/PROJECT_META/ExpectedFiles.cmake
new file mode 100644
index 0000000..448ed2b
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PROJECT_META/ExpectedFiles.cmake
@@ -0,0 +1,9 @@
+if(GENERATOR_TYPE STREQUAL DEB)
+  set(EXPECTED_FILE_1 "project_meta-1.2.3*.deb")
+elseif(GENERATOR_TYPE STREQUAL RPM)
+  set(EXPECTED_FILE_1 "project_meta-1.2.3*.rpm")
+else()
+  message(FATAL_ERROR "Unexpected CPack generator")
+endif()
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
diff --git a/Tests/RunCMake/CPack/tests/PROJECT_META/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/PROJECT_META/VerifyResult.cmake
new file mode 100644
index 0000000..b3accb5
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PROJECT_META/VerifyResult.cmake
@@ -0,0 +1,30 @@
+function(checkPackageURL FILE TAG EXPECTED_URL)
+  getPackageInfo("${FILE}" "_file_info")
+  string(REPLACE "\n" ";" _file_info "${_file_info}")
+
+  set(_seen_url FALSE)
+  foreach(_line IN LISTS _file_info)
+    if(_line MATCHES "${TAG}: (.*)")
+      set(_seen_url TRUE)
+      if(NOT CMAKE_MATCH_1 STREQUAL EXPECTED_URL)
+        message(FATAL_ERROR "Unexpected `Homepage` URL: `${CMAKE_MATCH_1}` != `${EXPECTED_URL}`")
+      endif()
+      break()
+    endif()
+  endforeach()
+  if(NOT _seen_url)
+    message(FATAL_ERROR "The packge `${FILE}` do not have URL as expected")
+  endif()
+endfunction()
+
+if(GENERATOR_TYPE STREQUAL DEB)
+  set(_tag " Homepage") # NOTE The leading space
+elseif(GENERATOR_TYPE STREQUAL RPM)
+  set(_tag "URL.*")
+else()
+  message(FATAL_ERROR "Unexpected CPack generator")
+endif()
+
+checkPackageURL("${FOUND_FILE_1}" "${_tag}" "https://meta.test.info")
+
+# kate: indent-width 2;
diff --git a/Tests/RunCMake/CPack/tests/PROJECT_META/test.cmake b/Tests/RunCMake/CPack/tests/PROJECT_META/test.cmake
new file mode 100644
index 0000000..9c5266a
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/PROJECT_META/test.cmake
@@ -0,0 +1,11 @@
+project(
+  MetaInfoTest
+  VERSION 1.2.3
+  DESCRIPTION "This is going to be a summary"
+  HOMEPAGE_URL "https://meta.test.info"
+)
+install(FILES CMakeLists.txt DESTINATION foo COMPONENT test)
+
+if(PACKAGING_TYPE STREQUAL "COMPONENT")
+  set(CPACK_COMPONENTS_ALL test)
+endif()
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/CTestCommandLine/CMakeLists.txt.in b/Tests/RunCMake/CTestCommandLine/CMakeLists.txt.in
new file mode 100644
index 0000000..5437800
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/CMakeLists.txt.in
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.1)
+project(CTestCommandLine@CASE_NAME@ NONE)
+include(CTest)
+add_test(NAME RunCMakeVersion COMMAND "${CMAKE_COMMAND}" --version)
diff --git a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
index 6b23162..9b9ae65 100644
--- a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
@@ -1,9 +1,33 @@
 include(RunCMake)
+include(RunCTest)
+
 set(RunCMake_TEST_TIMEOUT 60)
 
 unset(ENV{CTEST_PARALLEL_LEVEL})
 unset(ENV{CTEST_OUTPUT_ON_FAILURE})
 
+run_cmake_command(repeat-opt-bad1
+  ${CMAKE_CTEST_COMMAND} --repeat until-pass
+  )
+run_cmake_command(repeat-opt-bad2
+  ${CMAKE_CTEST_COMMAND} --repeat until-pass:foo
+  )
+run_cmake_command(repeat-opt-bad3
+  ${CMAKE_CTEST_COMMAND} --repeat until-fail:2 --repeat-until-fail 2
+  )
+run_cmake_command(repeat-opt-bad4
+  ${CMAKE_CTEST_COMMAND} --repeat-until-fail 2 --repeat until-fail:2
+  )
+run_cmake_command(repeat-opt-until-pass
+  ${CMAKE_CTEST_COMMAND} --repeat until-pass:2
+  )
+run_cmake_command(repeat-opt-until-fail
+  ${CMAKE_CTEST_COMMAND} --repeat until-fail:2
+  )
+run_cmake_command(repeat-opt-after-timeout
+  ${CMAKE_CTEST_COMMAND} --repeat after-timeout:2
+  )
+
 run_cmake_command(repeat-until-fail-bad1
   ${CMAKE_CTEST_COMMAND} --repeat-until-fail
   )
@@ -14,19 +38,39 @@
   ${CMAKE_CTEST_COMMAND} --repeat-until-fail 2
   )
 
+function(run_repeat_until_pass_tests)
+  # Use a single build tree for a few tests without cleaning.
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/repeat-until-pass-build)
+  run_cmake(repeat-until-pass-cmake)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(repeat-until-pass-ctest
+    ${CMAKE_CTEST_COMMAND} -C Debug --repeat until-pass:3
+    )
+endfunction()
+run_repeat_until_pass_tests()
+
+function(run_repeat_after_timeout_tests)
+  # Use a single build tree for a few tests without cleaning.
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/repeat-after-timeout-build)
+  run_cmake(repeat-after-timeout-cmake)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(repeat-after-timeout-ctest
+    ${CMAKE_CTEST_COMMAND} -C Debug --repeat after-timeout:3
+    )
+endfunction()
+run_repeat_after_timeout_tests()
+
 function(run_repeat_until_fail_tests)
   # Use a single build tree for a few tests without cleaning.
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/repeat-until-fail-build)
-  set(RunCMake_TEST_NO_CLEAN 1)
-  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
-  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
-
   run_cmake(repeat-until-fail-cmake)
+  set(RunCMake_TEST_NO_CLEAN 1)
   run_cmake_command(repeat-until-fail-ctest
-    ${CMAKE_CTEST_COMMAND} -C Debug --repeat-until-fail 3
+    ${CMAKE_CTEST_COMMAND} -C Debug ${ARGN}
     )
 endfunction()
-run_repeat_until_fail_tests()
+run_repeat_until_fail_tests(--repeat-until-fail 3)
+run_repeat_until_fail_tests(--repeat until-fail:3)
 
 function(run_BadCTestTestfile)
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/BadCTestTestfile)
@@ -269,3 +313,35 @@
   run_cmake_command(show-only_json-v1 ${CMAKE_CTEST_COMMAND} --show-only=json-v1)
 endfunction()
 run_ShowOnly()
+
+function(run_NoTests)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/NoTests)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+  file(WRITE "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake" "")
+  run_cmake_command(no-tests_ignore ${CMAKE_CTEST_COMMAND} --no-tests=ignore)
+  run_cmake_command(no-tests_error ${CMAKE_CTEST_COMMAND} --no-tests=error)
+  run_cmake_command(no-tests_bad ${CMAKE_CTEST_COMMAND} --no-tests=bad)
+  run_cmake_command(no-tests_legacy ${CMAKE_CTEST_COMMAND})
+  file(WRITE "${RunCMake_TEST_BINARY_DIR}/NoTestsScript.cmake" "
+    set(CTEST_COMMAND \"${CMAKE_CTEST_COMMAND}\")
+    set(CTEST_SOURCE_DIRECTORY \"${RunCMake_SOURCE_DIR}\")
+    set(CTEST_BINARY_DIRECTORY \"${RunCMake_TEST_BINARY_DIR}\")
+    ctest_start(Experimental)
+    ctest_test()
+")
+  run_cmake_command(
+    no-tests-script_ignore ${CMAKE_CTEST_COMMAND} --no-tests=ignore
+    -S "${RunCMake_TEST_BINARY_DIR}/NoTestsScript.cmake")
+  run_cmake_command(
+    no-tests-script_error ${CMAKE_CTEST_COMMAND} --no-tests=error
+    -S "${RunCMake_TEST_BINARY_DIR}/NoTestsScript.cmake")
+  run_cmake_command(
+    no-tests-script_legacy ${CMAKE_CTEST_COMMAND}
+    -S "${RunCMake_TEST_BINARY_DIR}/NoTestsScript.cmake")
+endfunction()
+run_NoTests()
+
+# Check the configuration type variable is passed
+run_ctest(check-configuration-type)
diff --git a/Tests/RunCMake/CTestCommandLine/check-configuration-type-stderr.txt b/Tests/RunCMake/CTestCommandLine/check-configuration-type-stderr.txt
new file mode 100644
index 0000000..b2c1a45
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/check-configuration-type-stderr.txt
@@ -0,0 +1,2 @@
+Command line CTEST_CONFIGURATION_TYPE=Debug
+set CTEST_CONFIGURATION_TYPE=Release
diff --git a/Tests/RunCMake/CTestCommandLine/no-tests-script_error-result.txt b/Tests/RunCMake/CTestCommandLine/no-tests-script_error-result.txt
new file mode 100644
index 0000000..b57e2de
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/no-tests-script_error-result.txt
@@ -0,0 +1 @@
+(-1|255)
diff --git a/Tests/RunCMake/CTestCommandLine/no-tests-script_error-stderr.txt b/Tests/RunCMake/CTestCommandLine/no-tests-script_error-stderr.txt
new file mode 100644
index 0000000..a7c4b11
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/no-tests-script_error-stderr.txt
@@ -0,0 +1 @@
+^No tests were found!!!$
diff --git a/Tests/RunCMake/CTestCommandLine/no-tests-script_legacy-result.txt b/Tests/RunCMake/CTestCommandLine/no-tests-script_legacy-result.txt
new file mode 100644
index 0000000..b57e2de
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/no-tests-script_legacy-result.txt
@@ -0,0 +1 @@
+(-1|255)
diff --git a/Tests/RunCMake/CTestCommandLine/no-tests-script_legacy-stderr.txt b/Tests/RunCMake/CTestCommandLine/no-tests-script_legacy-stderr.txt
new file mode 100644
index 0000000..a7c4b11
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/no-tests-script_legacy-stderr.txt
@@ -0,0 +1 @@
+^No tests were found!!!$
diff --git a/Tests/RunCMake/CTestCommandLine/no-tests_bad-result.txt b/Tests/RunCMake/CTestCommandLine/no-tests_bad-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/no-tests_bad-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestCommandLine/no-tests_bad-stderr.txt b/Tests/RunCMake/CTestCommandLine/no-tests_bad-stderr.txt
new file mode 100644
index 0000000..1703539
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/no-tests_bad-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: '--no-tests=' given unknown value 'bad'$
diff --git a/Tests/RunCMake/CTestCommandLine/no-tests_error-result.txt b/Tests/RunCMake/CTestCommandLine/no-tests_error-result.txt
new file mode 100644
index 0000000..45a4fb7
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/no-tests_error-result.txt
@@ -0,0 +1 @@
+8
diff --git a/Tests/RunCMake/CTestCommandLine/no-tests_error-stderr.txt b/Tests/RunCMake/CTestCommandLine/no-tests_error-stderr.txt
new file mode 100644
index 0000000..eafba1c
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/no-tests_error-stderr.txt
@@ -0,0 +1 @@
+No tests were found!!!
diff --git a/Tests/RunCMake/CTestCommandLine/no-tests_legacy-stderr.txt b/Tests/RunCMake/CTestCommandLine/no-tests_legacy-stderr.txt
new file mode 100644
index 0000000..a7c4b11
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/no-tests_legacy-stderr.txt
@@ -0,0 +1 @@
+^No tests were found!!!$
diff --git a/Tests/RunCMake/CTestCommandLine/repeat-after-timeout-cmake.cmake b/Tests/RunCMake/CTestCommandLine/repeat-after-timeout-cmake.cmake
new file mode 100644
index 0000000..873c0bd
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/repeat-after-timeout-cmake.cmake
@@ -0,0 +1,15 @@
+enable_testing()
+
+set(TEST_OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/test_output.txt")
+add_test(NAME initialization
+  COMMAND ${CMAKE_COMMAND}
+  "-DTEST_OUTPUT_FILE=${TEST_OUTPUT_FILE}"
+  -P "${CMAKE_CURRENT_SOURCE_DIR}/init.cmake")
+add_test(NAME test1
+  COMMAND ${CMAKE_COMMAND}
+  "-DTEST_OUTPUT_FILE=${TEST_OUTPUT_FILE}"
+  -P "${CMAKE_CURRENT_SOURCE_DIR}/test1-timeout.cmake")
+set_tests_properties(test1 PROPERTIES DEPENDS "initialization" TIMEOUT 5)
+
+add_test(hello ${CMAKE_COMMAND} -E echo hello)
+add_test(goodbye ${CMAKE_COMMAND} -E echo goodbye)
diff --git a/Tests/RunCMake/CTestCommandLine/repeat-after-timeout-ctest-stdout.txt b/Tests/RunCMake/CTestCommandLine/repeat-after-timeout-ctest-stdout.txt
new file mode 100644
index 0000000..d0a5487
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/repeat-after-timeout-ctest-stdout.txt
@@ -0,0 +1,15 @@
+^Test project .*/Tests/RunCMake/CTestCommandLine/repeat-after-timeout-build
+    Start 1: initialization
+1/4 Test #1: initialization ...................   Passed +[0-9.]+ sec
+    Start 2: test1
+2/4 Test #2: test1 ............................\*\*\*Timeout +[0-9.]+ sec
+    Start 2: test1
+    Test #2: test1 ............................   Passed +[0-9.]+ sec
+    Start 3: hello
+3/4 Test #3: hello ............................   Passed +[0-9.]+ sec
+    Start 4: goodbye
+4/4 Test #4: goodbye ..........................   Passed +[0-9.]+ sec
+
+100% tests passed, 0 tests failed out of 4
+
+Total Test time \(real\) = +[0-9.]+ sec$
diff --git a/Tests/RunCMake/CTestCommandLine/repeat-opt-after-timeout-stderr.txt b/Tests/RunCMake/CTestCommandLine/repeat-opt-after-timeout-stderr.txt
new file mode 100644
index 0000000..a7c4b11
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/repeat-opt-after-timeout-stderr.txt
@@ -0,0 +1 @@
+^No tests were found!!!$
diff --git a/Tests/RunCMake/CTestCommandLine/repeat-opt-bad1-result.txt b/Tests/RunCMake/CTestCommandLine/repeat-opt-bad1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/repeat-opt-bad1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestCommandLine/repeat-opt-bad1-stderr.txt b/Tests/RunCMake/CTestCommandLine/repeat-opt-bad1-stderr.txt
new file mode 100644
index 0000000..f6f3241
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/repeat-opt-bad1-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: '--repeat' given invalid value 'until-pass'$
diff --git a/Tests/RunCMake/CTestCommandLine/repeat-opt-bad2-result.txt b/Tests/RunCMake/CTestCommandLine/repeat-opt-bad2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/repeat-opt-bad2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestCommandLine/repeat-opt-bad2-stderr.txt b/Tests/RunCMake/CTestCommandLine/repeat-opt-bad2-stderr.txt
new file mode 100644
index 0000000..2f9f32a
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/repeat-opt-bad2-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: '--repeat' given invalid value 'until-pass:foo'$
diff --git a/Tests/RunCMake/CTestCommandLine/repeat-opt-bad3-result.txt b/Tests/RunCMake/CTestCommandLine/repeat-opt-bad3-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/repeat-opt-bad3-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestCommandLine/repeat-opt-bad3-stderr.txt b/Tests/RunCMake/CTestCommandLine/repeat-opt-bad3-stderr.txt
new file mode 100644
index 0000000..de4e11b
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/repeat-opt-bad3-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: At most one '--repeat' option may be used\.$
diff --git a/Tests/RunCMake/CTestCommandLine/repeat-opt-bad4-result.txt b/Tests/RunCMake/CTestCommandLine/repeat-opt-bad4-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/repeat-opt-bad4-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CTestCommandLine/repeat-opt-bad4-stderr.txt b/Tests/RunCMake/CTestCommandLine/repeat-opt-bad4-stderr.txt
new file mode 100644
index 0000000..de4e11b
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/repeat-opt-bad4-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: At most one '--repeat' option may be used\.$
diff --git a/Tests/RunCMake/CTestCommandLine/repeat-opt-until-fail-stderr.txt b/Tests/RunCMake/CTestCommandLine/repeat-opt-until-fail-stderr.txt
new file mode 100644
index 0000000..a7c4b11
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/repeat-opt-until-fail-stderr.txt
@@ -0,0 +1 @@
+^No tests were found!!!$
diff --git a/Tests/RunCMake/CTestCommandLine/repeat-opt-until-pass-stderr.txt b/Tests/RunCMake/CTestCommandLine/repeat-opt-until-pass-stderr.txt
new file mode 100644
index 0000000..a7c4b11
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/repeat-opt-until-pass-stderr.txt
@@ -0,0 +1 @@
+^No tests were found!!!$
diff --git a/Tests/RunCMake/CTestCommandLine/repeat-until-pass-cmake.cmake b/Tests/RunCMake/CTestCommandLine/repeat-until-pass-cmake.cmake
new file mode 100644
index 0000000..d109551
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/repeat-until-pass-cmake.cmake
@@ -0,0 +1,15 @@
+enable_testing()
+
+set(TEST_OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/test_output.txt")
+add_test(NAME initialization
+  COMMAND ${CMAKE_COMMAND}
+  "-DTEST_OUTPUT_FILE=${TEST_OUTPUT_FILE}"
+  -P "${CMAKE_CURRENT_SOURCE_DIR}/init.cmake")
+add_test(NAME test1
+  COMMAND ${CMAKE_COMMAND}
+  "-DTEST_OUTPUT_FILE=${TEST_OUTPUT_FILE}"
+  -P "${CMAKE_CURRENT_SOURCE_DIR}/test1-pass.cmake")
+set_tests_properties(test1 PROPERTIES DEPENDS "initialization")
+
+add_test(hello ${CMAKE_COMMAND} -E echo hello)
+add_test(goodbye ${CMAKE_COMMAND} -E echo goodbye)
diff --git a/Tests/RunCMake/CTestCommandLine/repeat-until-pass-ctest-stdout.txt b/Tests/RunCMake/CTestCommandLine/repeat-until-pass-ctest-stdout.txt
new file mode 100644
index 0000000..3745dc2
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/repeat-until-pass-ctest-stdout.txt
@@ -0,0 +1,15 @@
+^Test project .*/Tests/RunCMake/CTestCommandLine/repeat-until-pass-build
+    Start 1: initialization
+1/4 Test #1: initialization ...................   Passed +[0-9.]+ sec
+    Start 2: test1
+2/4 Test #2: test1 ............................\*\*\*Failed +[0-9.]+ sec
+    Start 2: test1
+    Test #2: test1 ............................   Passed +[0-9.]+ sec
+    Start 3: hello
+3/4 Test #3: hello ............................   Passed +[0-9.]+ sec
+    Start 4: goodbye
+4/4 Test #4: goodbye ..........................   Passed +[0-9.]+ sec
+
+100% tests passed, 0 tests failed out of 4
+
+Total Test time \(real\) = +[0-9.]+ sec$
diff --git a/Tests/RunCMake/CTestCommandLine/test.cmake.in b/Tests/RunCMake/CTestCommandLine/test.cmake.in
new file mode 100644
index 0000000..b82968a
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/test.cmake.in
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 3.1)
+
+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_NIGHTLY_START_TIME            "01:00:00 UTC")
+set(CTEST_COMMAND                       "@CMAKE_CTEST_COMMAND@")
+
+if("@CASE_NAME@" MATCHES "^check-configuration-type")
+  message("Command line CTEST_CONFIGURATION_TYPE=" ${CTEST_CONFIGURATION_TYPE})
+  set(CTEST_CONFIGURATION_TYPE "Release")
+  message("set CTEST_CONFIGURATION_TYPE=" ${CTEST_CONFIGURATION_TYPE})
+
+  ctest_start(Experimental)
+endif()
diff --git a/Tests/RunCMake/CTestCommandLine/test1-pass.cmake b/Tests/RunCMake/CTestCommandLine/test1-pass.cmake
new file mode 100644
index 0000000..dda8dea
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/test1-pass.cmake
@@ -0,0 +1,13 @@
+# This is run by test test1 in repeat-until-pass-cmake.cmake with cmake -P.
+# It reads the file TEST_OUTPUT_FILE and increments the number
+# found in the file by 1.  Unless the number is 2, then the
+# code sends out a cmake error causing the test to pass only on
+# the second time it is run.
+message("TEST_OUTPUT_FILE = ${TEST_OUTPUT_FILE}")
+file(READ "${TEST_OUTPUT_FILE}" COUNT)
+message("COUNT= ${COUNT}")
+math(EXPR COUNT "${COUNT} + 1")
+file(WRITE "${TEST_OUTPUT_FILE}" "${COUNT}")
+if(NOT COUNT EQUAL 2)
+  message(FATAL_ERROR "this test passes only on the 2nd run")
+endif()
diff --git a/Tests/RunCMake/CTestCommandLine/test1-timeout.cmake b/Tests/RunCMake/CTestCommandLine/test1-timeout.cmake
new file mode 100644
index 0000000..fbf2ccc
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/test1-timeout.cmake
@@ -0,0 +1,14 @@
+# This is run by test test1 in repeat-after-timeout-cmake.cmake with cmake -P.
+# It reads the file TEST_OUTPUT_FILE and increments the number
+# found in the file by 1.  Unless the number is 2, then the
+# code sends out a cmake error causing the test to not timeout only on
+# the second time it is run.
+message("TEST_OUTPUT_FILE = ${TEST_OUTPUT_FILE}")
+file(READ "${TEST_OUTPUT_FILE}" COUNT)
+message("COUNT= ${COUNT}")
+math(EXPR COUNT "${COUNT} + 1")
+file(WRITE "${TEST_OUTPUT_FILE}" "${COUNT}")
+if(NOT COUNT EQUAL 2)
+  message("this test times out except on the 2nd run")
+  execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 10)
+endif()
diff --git a/Tests/RunCMake/CTestResourceAllocation/ResourceCommon.cmake b/Tests/RunCMake/CTestResourceAllocation/ResourceCommon.cmake
index 7d63299..ef79dce 100644
--- a/Tests/RunCMake/CTestResourceAllocation/ResourceCommon.cmake
+++ b/Tests/RunCMake/CTestResourceAllocation/ResourceCommon.cmake
@@ -1,6 +1,6 @@
 function(setup_resource_tests)
   if(CTEST_RESOURCE_ALLOC_ENABLED)
-    add_test(NAME ResourceSetup COMMAND "${CMAKE_COMMAND}" -E remove -f "${CMAKE_BINARY_DIR}/ctresalloc.log")
+    add_test(NAME ResourceSetup COMMAND "${CMAKE_COMMAND}" -E rm -f "${CMAKE_BINARY_DIR}/ctresalloc.log")
   endif()
 endfunction()
 
diff --git a/Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-stderr.txt b/Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-stderr.txt
index 41df5af..91d7ef9 100644
--- a/Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-stderr.txt
+++ b/Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res-stderr.txt
@@ -1,4 +1,14 @@
-^Insufficient resources
+^Insufficient resources for test Test1:
+
+  Test requested resources of type 'fluxcapacitors' in the following amounts:
+    200 slots
+  but only the following units were available:
+    'outatime': 121 slots
+
+Resource spec file:
+
+  [^
+]*/Tests/RunCMake/CTestResourceAllocation/resspec.json
 CMake Error at [^
 ]*/Tests/RunCMake/CTestResourceAllocation/notenough1-ctest-s-res/test\.cmake:[0-9]+ \(message\):
   Tests did not pass$
diff --git a/Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-stderr.txt b/Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-stderr.txt
index 6c2f554..5c75a3d 100644
--- a/Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-stderr.txt
+++ b/Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res-stderr.txt
@@ -1,4 +1,11 @@
-^Insufficient resources
+^Insufficient resources for test Test1:
+
+  Test requested resources of type 'terminators' which does not exist
+
+Resource spec file:
+
+  [^
+]*/Tests/RunCMake/CTestResourceAllocation/resspec.json
 CMake Error at [^
 ]*/Tests/RunCMake/CTestResourceAllocation/notenough2-ctest-s-res/test\.cmake:[0-9]+ \(message\):
   Tests did not pass$
diff --git a/Tests/RunCMake/CTestResourceAllocation/notenough3-ctest-s-res-stderr.txt b/Tests/RunCMake/CTestResourceAllocation/notenough3-ctest-s-res-stderr.txt
index 82dfdef..4902a19 100644
--- a/Tests/RunCMake/CTestResourceAllocation/notenough3-ctest-s-res-stderr.txt
+++ b/Tests/RunCMake/CTestResourceAllocation/notenough3-ctest-s-res-stderr.txt
@@ -1,4 +1,21 @@
-^Insufficient resources
+^Insufficient resources for test Test1:
+
+  Test requested resources of type 'widgets' in the following amounts:
+    12 slots
+  but only the following units were available:
+    '0': 4 slots
+    '1': 2 slots
+    '2': 4 slots
+    '3': 8 slots
+    '4': 1 slot
+    '5': 1 slot
+    '6': 1 slot
+    '7': 1 slot
+
+Resource spec file:
+
+  [^
+]*/Tests/RunCMake/CTestResourceAllocation/resspec.json
 CMake Error at [^
 ]*/Tests/RunCMake/CTestResourceAllocation/notenough3-ctest-s-res/test\.cmake:[0-9]+ \(message\):
   Tests did not pass$
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/CheckIPOSupported/cmp0069-is-old-stderr.txt b/Tests/RunCMake/CheckIPOSupported/cmp0069-is-old-stderr.txt
index f183594..1baa63a 100644
--- a/Tests/RunCMake/CheckIPOSupported/cmp0069-is-old-stderr.txt
+++ b/Tests/RunCMake/CheckIPOSupported/cmp0069-is-old-stderr.txt
@@ -1,4 +1,15 @@
-^CMake Error at .*/Modules/CheckIPOSupported\.cmake:[0-9]+ \(message\):
+^CMake Deprecation Warning at cmp0069-is-old.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0069 will be removed from a future version
+  of CMake.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
++
+CMake Error at .*/Modules/CheckIPOSupported\.cmake:[0-9]+ \(message\):
   Policy CMP0069 set to OLD
 Call Stack \(most recent call first\):
   cmp0069-is-old\.cmake:[0-9]+ \(check_ipo_supported\)
diff --git a/Tests/RunCMake/CommandLine/E_rm_bad_argument-result.txt b/Tests/RunCMake/CommandLine/E_rm_bad_argument-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_bad_argument-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_rm_bad_argument-stderr.txt b/Tests/RunCMake/CommandLine/E_rm_bad_argument-stderr.txt
new file mode 100644
index 0000000..62b963a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_bad_argument-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: Unknown -E rm argument: -rd$
diff --git a/Tests/RunCMake/CommandLine/E_rm_directory_link_existing-check.cmake b/Tests/RunCMake/CommandLine/E_rm_directory_link_existing-check.cmake
new file mode 100644
index 0000000..b1a29a2
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_directory_link_existing-check.cmake
@@ -0,0 +1,3 @@
+if(NOT EXISTS ${out}/dir/existing.txt)
+  set(RunCMake_TEST_FAILED "${out}/dir/existing.txt should exist (we only removed the link to dir folder)")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_rm_directory_link_existing-result.txt b/Tests/RunCMake/CommandLine/E_rm_directory_link_existing-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_directory_link_existing-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_rm_empty_file_specified-stderr.txt b/Tests/RunCMake/CommandLine/E_rm_empty_file_specified-stderr.txt
new file mode 100644
index 0000000..1ac7dba
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_empty_file_specified-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: Missing file/directory to remove$
diff --git a/Tests/RunCMake/CommandLine/E_rm_empty_file_specified.cmake b/Tests/RunCMake/CommandLine/E_rm_empty_file_specified.cmake
new file mode 100644
index 0000000..6cd4edd
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_empty_file_specified.cmake
@@ -0,0 +1,8 @@
+execute_process(
+  COMMAND ${CMAKE_COMMAND} -E rm ""
+  RESULT_VARIABLE actual_result
+  )
+
+if(NOT "${actual_result}" EQUAL "1")
+  message(SEND_ERROR "cmake -E rm \"\" should have returned 1, got ${actual_result}")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_rm_file_force_existing-check.cmake b/Tests/RunCMake/CommandLine/E_rm_file_force_existing-check.cmake
new file mode 100644
index 0000000..e28b160
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_file_force_existing-check.cmake
@@ -0,0 +1,3 @@
+if(EXISTS ${out}/existing.txt)
+  set(RunCMake_TEST_FAILED "${out}/existing.txt not removed")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_rm_file_force_existing-result.txt b/Tests/RunCMake/CommandLine/E_rm_file_force_existing-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_file_force_existing-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_rm_file_force_non_existing-result.txt b/Tests/RunCMake/CommandLine/E_rm_file_force_non_existing-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_file_force_non_existing-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_rm_file_link_existing-check.cmake b/Tests/RunCMake/CommandLine/E_rm_file_link_existing-check.cmake
new file mode 100644
index 0000000..a0a9b20
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_file_link_existing-check.cmake
@@ -0,0 +1,3 @@
+if(NOT EXISTS ${out}/existing.txt)
+  set(RunCMake_TEST_FAILED "${out}/existing.txt should exist (we only removed the link)")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_rm_file_link_existing-result.txt b/Tests/RunCMake/CommandLine/E_rm_file_link_existing-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_file_link_existing-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_rm_file_link_non_existing-result.txt b/Tests/RunCMake/CommandLine/E_rm_file_link_non_existing-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_file_link_non_existing-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_rm_file_non_force_existing-check.cmake b/Tests/RunCMake/CommandLine/E_rm_file_non_force_existing-check.cmake
new file mode 100644
index 0000000..e28b160
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_file_non_force_existing-check.cmake
@@ -0,0 +1,3 @@
+if(EXISTS ${out}/existing.txt)
+  set(RunCMake_TEST_FAILED "${out}/existing.txt not removed")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_rm_file_non_force_existing-result.txt b/Tests/RunCMake/CommandLine/E_rm_file_non_force_existing-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_file_non_force_existing-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_rm_file_non_force_non_existing-result.txt b/Tests/RunCMake/CommandLine/E_rm_file_non_force_non_existing-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_file_non_force_non_existing-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_rm_file_non_force_non_existing-stderr.txt b/Tests/RunCMake/CommandLine/E_rm_file_non_force_non_existing-stderr.txt
new file mode 100644
index 0000000..05df88a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_file_non_force_non_existing-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: File to remove does not exist and force is not set: .*/rm_tests/not_existing.txt
diff --git a/Tests/RunCMake/CommandLine/E_rm_file_recursive_existing-check.cmake b/Tests/RunCMake/CommandLine/E_rm_file_recursive_existing-check.cmake
new file mode 100644
index 0000000..e28b160
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_file_recursive_existing-check.cmake
@@ -0,0 +1,3 @@
+if(EXISTS ${out}/existing.txt)
+  set(RunCMake_TEST_FAILED "${out}/existing.txt not removed")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_rm_file_recursive_existing-result.txt b/Tests/RunCMake/CommandLine/E_rm_file_recursive_existing-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_file_recursive_existing-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_rm_file_recursive_non_existing-result.txt b/Tests/RunCMake/CommandLine/E_rm_file_recursive_non_existing-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_file_recursive_non_existing-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_rm_file_recursive_non_existing-stderr.txt b/Tests/RunCMake/CommandLine/E_rm_file_recursive_non_existing-stderr.txt
new file mode 100644
index 0000000..05df88a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_file_recursive_non_existing-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: File to remove does not exist and force is not set: .*/rm_tests/not_existing.txt
diff --git a/Tests/RunCMake/CommandLine/E_rm_force_recursive_directory_with_files-check.cmake b/Tests/RunCMake/CommandLine/E_rm_force_recursive_directory_with_files-check.cmake
new file mode 100644
index 0000000..1a976cb
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_force_recursive_directory_with_files-check.cmake
@@ -0,0 +1,3 @@
+if(EXISTS ${out})
+  set(RunCMake_TEST_FAILED "${out} not removed")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_rm_force_recursive_directory_with_files-result.txt b/Tests/RunCMake/CommandLine/E_rm_force_recursive_directory_with_files-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_force_recursive_directory_with_files-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_rm_force_recursive_non_existing_file-result.txt b/Tests/RunCMake/CommandLine/E_rm_force_recursive_non_existing_file-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_force_recursive_non_existing_file-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_rm_no_file_specified-result.txt b/Tests/RunCMake/CommandLine/E_rm_no_file_specified-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_no_file_specified-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_rm_no_file_specified-stderr.txt b/Tests/RunCMake/CommandLine/E_rm_no_file_specified-stderr.txt
new file mode 100644
index 0000000..1ac7dba
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_no_file_specified-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: Missing file/directory to remove$
diff --git a/Tests/RunCMake/CommandLine/E_rm_non_recursive_directory-two-directories-check.cmake b/Tests/RunCMake/CommandLine/E_rm_non_recursive_directory-two-directories-check.cmake
new file mode 100644
index 0000000..609271e
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_non_recursive_directory-two-directories-check.cmake
@@ -0,0 +1,3 @@
+if(NOT EXISTS ${out}/d1 OR NOT EXISTS ${out}/d2)
+  set(RunCMake_TEST_FAILED "${out}/d1 or ${out}/d2 is removed but should not")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_rm_non_recursive_directory-two-directories-result.txt b/Tests/RunCMake/CommandLine/E_rm_non_recursive_directory-two-directories-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_non_recursive_directory-two-directories-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_rm_non_recursive_directory-two-directories-stderr.txt b/Tests/RunCMake/CommandLine/E_rm_non_recursive_directory-two-directories-stderr.txt
new file mode 100644
index 0000000..33ea2e3
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_non_recursive_directory-two-directories-stderr.txt
@@ -0,0 +1,2 @@
+^Error removing directory ".*/rm_tests/d1" without recursive option\.
+Error removing directory ".*/rm_tests/d2" without recursive option\.$
diff --git a/Tests/RunCMake/CommandLine/E_rm_recursive_directory-two-directories-check.cmake b/Tests/RunCMake/CommandLine/E_rm_recursive_directory-two-directories-check.cmake
new file mode 100644
index 0000000..5282da7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_recursive_directory-two-directories-check.cmake
@@ -0,0 +1,3 @@
+if(EXISTS ${out}/d1 OR EXISTS ${out}/d2)
+  set(RunCMake_TEST_FAILED "${out}/d1 or ${out}/d2 should be removed")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_rm_recursive_directory-two-directories-result.txt b/Tests/RunCMake/CommandLine/E_rm_recursive_directory-two-directories-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_recursive_directory-two-directories-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_rm_recursive_directory_link_existing-check.cmake b/Tests/RunCMake/CommandLine/E_rm_recursive_directory_link_existing-check.cmake
new file mode 100644
index 0000000..b1a29a2
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_recursive_directory_link_existing-check.cmake
@@ -0,0 +1,3 @@
+if(NOT EXISTS ${out}/dir/existing.txt)
+  set(RunCMake_TEST_FAILED "${out}/dir/existing.txt should exist (we only removed the link to dir folder)")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_rm_recursive_directory_link_existing-result.txt b/Tests/RunCMake/CommandLine/E_rm_recursive_directory_link_existing-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_recursive_directory_link_existing-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_rm_recursive_file_link_existing-check.cmake b/Tests/RunCMake/CommandLine/E_rm_recursive_file_link_existing-check.cmake
new file mode 100644
index 0000000..a0a9b20
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_recursive_file_link_existing-check.cmake
@@ -0,0 +1,3 @@
+if(NOT EXISTS ${out}/existing.txt)
+  set(RunCMake_TEST_FAILED "${out}/existing.txt should exist (we only removed the link)")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_rm_recursive_file_link_existing-result.txt b/Tests/RunCMake/CommandLine/E_rm_recursive_file_link_existing-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_recursive_file_link_existing-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_rm_recursive_file_link_non_existing-result.txt b/Tests/RunCMake/CommandLine/E_rm_recursive_file_link_non_existing-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_rm_recursive_file_link_non_existing-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index b608d33..087ef21 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -254,6 +254,24 @@
 endfunction()
 run_EnvironmentGenerator()
 
+function(run_EnvironmentExportCompileCommands)
+  set(RunCMake_TEST_SOURCE_DIR ${RunCMake_SOURCE_DIR}/env-export-compile-commands)
+
+  run_cmake(env-export-compile-commands-unset)
+
+  set(ENV{CMAKE_EXPORT_COMPILE_COMMANDS} ON)
+  run_cmake(env-export-compile-commands-set)
+
+  set(RunCMake_TEST_OPTIONS -DCMAKE_EXPORT_COMPILE_COMMANDS=OFF)
+  run_cmake(env-export-compile-commands-override)
+
+  unset(ENV{CMAKE_EXPORT_COMPILE_COMMANDS})
+endfunction(run_EnvironmentExportCompileCommands)
+
+if(RunCMake_GENERATOR MATCHES "Unix Makefiles" OR RunCMake_GENERATOR MATCHES "Ninja")
+  run_EnvironmentExportCompileCommands()
+endif()
+
 if(RunCMake_GENERATOR STREQUAL "Ninja")
   # Use a single build tree for a few tests without cleaning.
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Build-build)
@@ -370,6 +388,76 @@
 unset(out)
 unset(outfile)
 
+set(out ${RunCMake_BINARY_DIR}/rm_tests)
+file(REMOVE_RECURSE "${out}")
+file(MAKE_DIRECTORY ${out})
+file(TOUCH ${out}/existing.txt)
+run_cmake_command(E_rm_file_force_existing
+  ${CMAKE_COMMAND} -E rm -f ${out}/existing.txt)
+file(TOUCH ${out}/existing.txt)
+run_cmake_command(E_rm_file_non_force_existing
+  ${CMAKE_COMMAND} -E rm ${out}/existing.txt)
+run_cmake_command(E_rm_file_force_non_existing
+  ${CMAKE_COMMAND} -E rm -f ${out}/not_existing.txt)
+run_cmake_command(E_rm_file_non_force_non_existing
+  ${CMAKE_COMMAND} -E rm ${out}/not_existing.txt)
+
+file(TOUCH ${out}/existing.txt)
+run_cmake_command(E_rm_file_recursive_existing
+  ${CMAKE_COMMAND} -E rm -r ${out}/existing.txt)
+run_cmake_command(E_rm_file_recursive_non_existing
+  ${CMAKE_COMMAND} -E rm -r ${out}/not_existing.txt)
+
+file(MAKE_DIRECTORY ${out}/d1 ${out}/d2)
+run_cmake_command(E_rm_non_recursive_directory-two-directories
+  ${CMAKE_COMMAND} -E rm ${out}/d1 ${out}/d2)
+
+run_cmake_command(E_rm_recursive_directory-two-directories
+  ${CMAKE_COMMAND} -E rm -R ${out}/d1 ${out}/d2)
+
+run_cmake_command(E_rm_no_file_specified
+  ${CMAKE_COMMAND} -E rm -rf)
+
+run_cmake_command(E_rm_empty_file_specified
+  ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/E_rm_empty_file_specified.cmake)
+
+run_cmake_command(E_rm_bad_argument
+  ${CMAKE_COMMAND} -E rm -rd ${out}/d1 ${out}/d2)
+
+file(MAKE_DIRECTORY ${out}/d1 ${out}/d2)
+file(WRITE ${out}/test.txt "")
+run_cmake_command(E_rm_force_recursive_directory_with_files
+  ${CMAKE_COMMAND} -E rm -rf ${out}/)
+
+run_cmake_command(E_rm_force_recursive_non_existing_file
+  ${CMAKE_COMMAND} -E rm -Rf ${out}/test.txt)
+
+if(NOT WIN32 AND NOT CYGWIN)
+  file(MAKE_DIRECTORY ${out})
+  file(TOUCH ${out}/existing.txt)
+  file(MAKE_DIRECTORY ${out}/dir)
+  file(TOUCH ${out}/dir/existing.txt) # add a file in the folder
+  file(CREATE_LINK ${out}/dir ${out}/link_dir SYMBOLIC)
+  file(CREATE_LINK ${out}/existing.txt ${out}/existing_file_link.txt SYMBOLIC)
+  file(CREATE_LINK ${out}/non_existing.txt ${out}/non_existing_file_link.txt SYMBOLIC)
+  run_cmake_command(E_rm_file_link_existing
+    ${CMAKE_COMMAND} -E rm ${out}/existing_file_link.txt)
+  run_cmake_command(E_rm_directory_link_existing
+    ${CMAKE_COMMAND} -E rm ${out}/link_dir)
+  run_cmake_command(E_rm_file_link_non_existing
+    ${CMAKE_COMMAND} -E rm ${out}/non_existing_file_link.txt)
+
+  file(CREATE_LINK ${out}/dir ${out}/link_dir SYMBOLIC)
+  file(CREATE_LINK ${out}/existing.txt ${out}/existing_file_link.txt SYMBOLIC)
+  file(CREATE_LINK ${out}/non_existing.txt ${out}/non_existing_file_link.txt SYMBOLIC)
+  run_cmake_command(E_rm_recursive_file_link_existing
+    ${CMAKE_COMMAND} -E rm -R ${out}/existing_file_link.txt)
+  run_cmake_command(E_rm_recursive_directory_link_existing
+    ${CMAKE_COMMAND} -E rm -r ${out}/link_dir)
+  run_cmake_command(E_rm_recursive_file_link_non_existing
+    ${CMAKE_COMMAND} -E rm -r ${out}/non_existing_file_link.txt)
+endif()
+unset(out)
 
 run_cmake_command(E_env-no-command0 ${CMAKE_COMMAND} -E env)
 run_cmake_command(E_env-no-command1 ${CMAKE_COMMAND} -E env TEST_ENV=1)
@@ -519,6 +607,14 @@
 run_cmake(trace-redirect-nofile)
 unset(RunCMake_TEST_OPTIONS)
 
+set(RunCMake_TEST_OPTIONS --trace        --trace-format=json-v1 --trace-redirect=${RunCMake_BINARY_DIR}/json-v1.trace)
+run_cmake(trace-json-v1)
+unset(RunCMake_TEST_OPTIONS)
+
+set(RunCMake_TEST_OPTIONS --trace-expand --trace-format=json-v1 --trace-redirect=${RunCMake_BINARY_DIR}/json-v1-expand.trace)
+run_cmake(trace-json-v1-expand)
+unset(RunCMake_TEST_OPTIONS)
+
 set(RunCMake_TEST_OPTIONS -Wno-deprecated --warn-uninitialized)
 run_cmake(warn-uninitialized)
 unset(RunCMake_TEST_OPTIONS)
@@ -571,3 +667,33 @@
   run_cmake_command(closed_stderr sh -c "\"${CMAKE_COMMAND}\" --version 2>&-")
   run_cmake_command(closed_stdall sh -c "\"${CMAKE_COMMAND}\" --version <&- >&- 2>&-")
 endif()
+
+function(run_llvm_rc)
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/llvm_rc-build")
+  set(RunCMake_TEST_NO_CLEAN 1)
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+  run_cmake_command(llvm_rc_no_args ${CMAKE_COMMAND} -E cmake_llvm_rc)
+  run_cmake_command(llvm_rc_no_-- ${CMAKE_COMMAND} -E cmake_llvm_rc test.tmp ${CMAKE_COMMAND} -E echo "This is a test")
+  run_cmake_command(llvm_rc_empty_preprocessor ${CMAKE_COMMAND} -E cmake_llvm_rc test.tmp -- ${CMAKE_COMMAND} -E echo "This is a test")
+  run_cmake_command(llvm_rc_failing_first_command ${CMAKE_COMMAND} -E cmake_llvm_rc test.tmp ${CMAKE_COMMAND} -E false -- ${CMAKE_COMMAND} -E echo "This is a test")
+  run_cmake_command(llvm_rc_failing_second_command ${CMAKE_COMMAND} -E cmake_llvm_rc test.tmp ${CMAKE_COMMAND} -E echo "This is a test" -- ${CMAKE_COMMAND} -E false )
+  if(EXISTS ${RunCMake_TEST_BINARY_DIR}/test.tmp)
+      message(SEND_ERROR "${test} - FAILED:\n"
+        "test.tmp was not deleted")
+  endif()
+  run_cmake_command(llvm_rc_full_run ${CMAKE_COMMAND} -E cmake_llvm_rc test.tmp ${CMAKE_COMMAND} -E echo "This is a test" -- ${CMAKE_COMMAND} -E copy test.tmp llvmrc.result )
+  if(EXISTS ${RunCMake_TEST_BINARY_DIR}/test.tmp)
+      message(SEND_ERROR "${test} - FAILED:\n"
+        "test.tmp was not deleted")
+  endif()
+  file(READ ${RunCMake_TEST_BINARY_DIR}/llvmrc.result LLVMRC_RESULT)
+  if(NOT "${LLVMRC_RESULT}" STREQUAL "This is a test\n")
+    message(SEND_ERROR "${test} - FAILED:\n"
+        "llvmrc.result was not created")
+  endif()
+  #  file(REMOVE ${RunCMake_TEST_BINARY_DIR}/llvmrc.result)
+  unset(LLVMRC_RESULT)
+endfunction()
+run_llvm_rc()
diff --git a/Tests/RunCMake/CommandLine/env-export-compile-commands-override-check.cmake b/Tests/RunCMake/CommandLine/env-export-compile-commands-override-check.cmake
new file mode 100644
index 0000000..032a1ae
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/env-export-compile-commands-override-check.cmake
@@ -0,0 +1,3 @@
+if(EXISTS "${RunCMake_TEST_BINARY_DIR}/compile_commands.json")
+  set(RunCMake_TEST_FAILED "compile_commands.json generated with CMAKE_EXPORT_COMPILE_COMMANDS overridden")
+endif()
diff --git a/Tests/RunCMake/CommandLine/env-export-compile-commands-set-check.cmake b/Tests/RunCMake/CommandLine/env-export-compile-commands-set-check.cmake
new file mode 100644
index 0000000..a749a55
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/env-export-compile-commands-set-check.cmake
@@ -0,0 +1,3 @@
+if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/compile_commands.json")
+  set(RunCMake_TEST_FAILED "compile_commands.json not generated with CMAKE_EXPORT_COMPILE_COMMANDS set")
+endif()
diff --git a/Tests/RunCMake/CommandLine/env-export-compile-commands-unset-check.cmake b/Tests/RunCMake/CommandLine/env-export-compile-commands-unset-check.cmake
new file mode 100644
index 0000000..c5878f0
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/env-export-compile-commands-unset-check.cmake
@@ -0,0 +1,3 @@
+if(EXISTS "${RunCMake_TEST_BINARY_DIR}/compile_commands.json")
+  set(RunCMake_TEST_FAILED "compile_commands.json generated with CMAKE_EXPORT_COMPILE_COMMANDS unset")
+endif()
diff --git a/Tests/RunCMake/CommandLine/env-export-compile-commands/CMakeLists.txt b/Tests/RunCMake/CommandLine/env-export-compile-commands/CMakeLists.txt
new file mode 100644
index 0000000..aa6fbfd
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/env-export-compile-commands/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.14)
+project(env-export-compile-commands C)
+
+# Add target with a source file to make sure compile_commands.json gets
+# generated.
+file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/main.c)
+add_executable(env-export-compile-commands ${CMAKE_CURRENT_BINARY_DIR}/main.c)
diff --git a/Tests/RunCMake/CommandLine/llvm_rc_empty_preprocessor-result.txt b/Tests/RunCMake/CommandLine/llvm_rc_empty_preprocessor-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/llvm_rc_empty_preprocessor-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/llvm_rc_empty_preprocessor-stderr.txt b/Tests/RunCMake/CommandLine/llvm_rc_empty_preprocessor-stderr.txt
new file mode 100644
index 0000000..cb69366
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/llvm_rc_empty_preprocessor-stderr.txt
@@ -0,0 +1 @@
+Empty preprocessing command
diff --git a/Tests/RunCMake/CommandLine/llvm_rc_failing_first_command-result.txt b/Tests/RunCMake/CommandLine/llvm_rc_failing_first_command-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/llvm_rc_failing_first_command-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/llvm_rc_failing_second_command-result.txt b/Tests/RunCMake/CommandLine/llvm_rc_failing_second_command-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/llvm_rc_failing_second_command-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/llvm_rc_no_---result.txt b/Tests/RunCMake/CommandLine/llvm_rc_no_---result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/llvm_rc_no_---result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/llvm_rc_no_---stderr.txt b/Tests/RunCMake/CommandLine/llvm_rc_no_---stderr.txt
new file mode 100644
index 0000000..9c140b7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/llvm_rc_no_---stderr.txt
@@ -0,0 +1 @@
+Empty resource compilation command
diff --git a/Tests/RunCMake/CommandLine/llvm_rc_no_args-result.txt b/Tests/RunCMake/CommandLine/llvm_rc_no_args-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/llvm_rc_no_args-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/llvm_rc_no_args-stderr.txt b/Tests/RunCMake/CommandLine/llvm_rc_no_args-stderr.txt
new file mode 100644
index 0000000..d66b547
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/llvm_rc_no_args-stderr.txt
@@ -0,0 +1 @@
+Invalid cmake_llvm_rc arguments
diff --git a/Tests/RunCMake/CommandLine/trace-json-v1-check.cmake b/Tests/RunCMake/CommandLine/trace-json-v1-check.cmake
new file mode 100644
index 0000000..66af039
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/trace-json-v1-check.cmake
@@ -0,0 +1,11 @@
+if(PYTHON_EXECUTABLE)
+  execute_process(
+    COMMAND ${PYTHON_EXECUTABLE} "${RunCMake_SOURCE_DIR}/trace-json-v1-check.py" "${RunCMake_BINARY_DIR}/json-v1.trace"
+    RESULT_VARIABLE result
+    OUTPUT_VARIABLE output
+    ERROR_VARIABLE output
+    )
+  if(NOT result EQUAL 0)
+    set(RunCMake_TEST_FAILED "JSON trace validation failed:\n${output}")
+  endif()
+endif()
diff --git a/Tests/RunCMake/CommandLine/trace-json-v1-check.py b/Tests/RunCMake/CommandLine/trace-json-v1-check.py
new file mode 100755
index 0000000..e617b76
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/trace-json-v1-check.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python3
+
+import json
+import os
+import sys
+
+if sys.version_info[0] >= 3:
+    unicode = str
+
+trace_file = None
+expand = False
+
+for i in sys.argv[1:]:
+    if trace_file is None and not i.startswith('-'):
+        trace_file = i
+        continue
+
+    if i in ['-e', '--expand']:
+        expand = True
+
+assert trace_file is not None
+assert os.path.exists(trace_file)
+
+if expand:
+    msg_args = ['STATUS', 'fff', 'fff;sss;  SPACES !!!  ', ' 42  space in string!', '  SPACES !!!  ']
+else:
+    msg_args = ['STATUS', 'fff', '${ASDF}', ' ${FOO} ${BAR}', '  SPACES !!!  ']
+
+required_traces = [
+    {
+        'args': ['STATUS', 'JSON-V1 str', 'spaces'],
+        'cmd': 'message',
+    },
+    {
+        'args': ['ASDF', 'fff', 'sss', '  SPACES !!!  '],
+        'cmd': 'set',
+    },
+    {
+        'args': ['FOO', '42'],
+        'cmd': 'set',
+    },
+    {
+        'args': ['BAR', ' space in string!'],
+        'cmd': 'set',
+    },
+    {
+        'args': msg_args,
+        'cmd': 'message',
+        'frame': 3 if expand else 2
+    },
+]
+
+with open(trace_file, 'r') as fp:
+    # Check for version (must be the first document)
+    vers = json.loads(fp.readline())
+    assert sorted(vers.keys()) == ['version']
+    assert sorted(vers['version'].keys()) == ['major', 'minor']
+    assert vers['version']['major'] == 1
+    assert vers['version']['minor'] == 0
+
+    for i in fp.readlines():
+        line = json.loads(i)
+        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:
+            # Compare the subset of required keys with line
+            if {k: line[k] for k in j} == j:
+                required_traces.remove(j)
+
+assert not required_traces
diff --git a/Tests/RunCMake/CommandLine/trace-json-v1-expand-check.cmake b/Tests/RunCMake/CommandLine/trace-json-v1-expand-check.cmake
new file mode 100644
index 0000000..7916d2e
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/trace-json-v1-expand-check.cmake
@@ -0,0 +1,11 @@
+if(PYTHON_EXECUTABLE)
+  execute_process(
+    COMMAND ${PYTHON_EXECUTABLE} "${RunCMake_SOURCE_DIR}/trace-json-v1-check.py" --expand "${RunCMake_BINARY_DIR}/json-v1-expand.trace"
+    RESULT_VARIABLE result
+    OUTPUT_VARIABLE output
+    ERROR_VARIABLE output
+    )
+  if(NOT result EQUAL 0)
+    set(RunCMake_TEST_FAILED "JSON trace validation failed:\n${output}")
+  endif()
+endif()
diff --git a/Tests/RunCMake/CommandLine/trace-json-v1-expand.cmake b/Tests/RunCMake/CommandLine/trace-json-v1-expand.cmake
new file mode 100644
index 0000000..5c190e6
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/trace-json-v1-expand.cmake
@@ -0,0 +1 @@
+include(trace-json-v1.cmake)
diff --git a/Tests/RunCMake/CommandLine/trace-json-v1.cmake b/Tests/RunCMake/CommandLine/trace-json-v1.cmake
new file mode 100644
index 0000000..ed0a0f9
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/trace-json-v1.cmake
@@ -0,0 +1,5 @@
+message(STATUS "JSON-V1 str" "spaces")
+set(ASDF fff sss "  SPACES !!!  ")
+set(FOO 42)
+set(BAR " space in string!")
+message(STATUS fff ${ASDF} " ${FOO} ${BAR}" "  SPACES !!!  ")
diff --git a/Tests/RunCMake/CompilerLauncher/C-common.cmake b/Tests/RunCMake/CompilerLauncher/C-common.cmake
new file mode 100644
index 0000000..96b004b
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/C-common.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+set(CMAKE_VERBOSE_MAKEFILE TRUE)
+add_executable(main main.c)
diff --git a/Tests/RunCMake/CompilerLauncher/C-env-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/C-env-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/C-env-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/CompilerLauncher/C-env-launch-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/C-env-launch-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/C-env-launch-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/CompilerLauncher/C-env.cmake b/Tests/RunCMake/CompilerLauncher/C-env.cmake
new file mode 100644
index 0000000..09b5167
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/C-env.cmake
@@ -0,0 +1 @@
+include(C-common.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/C-launch-env.cmake b/Tests/RunCMake/CompilerLauncher/C-launch-env.cmake
new file mode 100644
index 0000000..68abcb5
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/C-launch-env.cmake
@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(C-env.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/C.cmake b/Tests/RunCMake/CompilerLauncher/C.cmake
index 67bf7c4..481e74d 100644
--- a/Tests/RunCMake/CompilerLauncher/C.cmake
+++ b/Tests/RunCMake/CompilerLauncher/C.cmake
@@ -1,4 +1,2 @@
-enable_language(C)
 set(CMAKE_C_COMPILER_LAUNCHER "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
-set(CMAKE_VERBOSE_MAKEFILE TRUE)
-add_executable(main main.c)
+include(C-common.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/CUDA-common.cmake b/Tests/RunCMake/CompilerLauncher/CUDA-common.cmake
new file mode 100644
index 0000000..6f7fc86
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/CUDA-common.cmake
@@ -0,0 +1,3 @@
+enable_language(CUDA)
+set(CMAKE_VERBOSE_MAKEFILE TRUE)
+add_executable(main main.cu)
diff --git a/Tests/RunCMake/CompilerLauncher/CUDA-env-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/CUDA-env-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/CUDA-env-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/CompilerLauncher/CUDA-env-launch-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/CUDA-env-launch-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/CUDA-env-launch-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/CompilerLauncher/CUDA-env.cmake b/Tests/RunCMake/CompilerLauncher/CUDA-env.cmake
new file mode 100644
index 0000000..cefbe9e
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/CUDA-env.cmake
@@ -0,0 +1 @@
+include(CUDA-common.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/CUDA-launch-env.cmake b/Tests/RunCMake/CompilerLauncher/CUDA-launch-env.cmake
new file mode 100644
index 0000000..d0d777a
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/CUDA-launch-env.cmake
@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(CUDA-env.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/CUDA.cmake b/Tests/RunCMake/CompilerLauncher/CUDA.cmake
index fe5560b..7f1652b 100644
--- a/Tests/RunCMake/CompilerLauncher/CUDA.cmake
+++ b/Tests/RunCMake/CompilerLauncher/CUDA.cmake
@@ -1,4 +1,2 @@
-enable_language(CUDA)
 set(CMAKE_CUDA_COMPILER_LAUNCHER "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
-set(CMAKE_VERBOSE_MAKEFILE TRUE)
-add_executable(main main.cu)
+include(CUDA-common.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/CXX-common.cmake b/Tests/RunCMake/CompilerLauncher/CXX-common.cmake
new file mode 100644
index 0000000..3d2ee00
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/CXX-common.cmake
@@ -0,0 +1,3 @@
+enable_language(CXX)
+set(CMAKE_VERBOSE_MAKEFILE TRUE)
+add_executable(main main.cxx)
diff --git a/Tests/RunCMake/CompilerLauncher/CXX-env-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/CXX-env-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/CXX-env-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/CompilerLauncher/CXX-env-launch-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/CXX-env-launch-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/CXX-env-launch-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/CompilerLauncher/CXX-env.cmake b/Tests/RunCMake/CompilerLauncher/CXX-env.cmake
new file mode 100644
index 0000000..db36956
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/CXX-env.cmake
@@ -0,0 +1 @@
+include(CXX-common.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/CXX-launch-env.cmake b/Tests/RunCMake/CompilerLauncher/CXX-launch-env.cmake
new file mode 100644
index 0000000..a65cc89
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/CXX-launch-env.cmake
@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(CXX-env.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/CXX.cmake b/Tests/RunCMake/CompilerLauncher/CXX.cmake
index cdd3478..1f9a12b 100644
--- a/Tests/RunCMake/CompilerLauncher/CXX.cmake
+++ b/Tests/RunCMake/CompilerLauncher/CXX.cmake
@@ -1,4 +1,2 @@
-enable_language(CXX)
 set(CMAKE_CXX_COMPILER_LAUNCHER "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
-set(CMAKE_VERBOSE_MAKEFILE TRUE)
-add_executable(main main.cxx)
+include(CXX-common.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/Fortran-common.cmake b/Tests/RunCMake/CompilerLauncher/Fortran-common.cmake
new file mode 100644
index 0000000..e33c2ca
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/Fortran-common.cmake
@@ -0,0 +1,3 @@
+enable_language(Fortran)
+set(CMAKE_VERBOSE_MAKEFILE TRUE)
+add_executable(main main.F)
diff --git a/Tests/RunCMake/CompilerLauncher/Fortran-env-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/Fortran-env-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/Fortran-env-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/CompilerLauncher/Fortran-env-launch-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/Fortran-env-launch-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/Fortran-env-launch-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/CompilerLauncher/Fortran-env.cmake b/Tests/RunCMake/CompilerLauncher/Fortran-env.cmake
new file mode 100644
index 0000000..3dc27c3
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/Fortran-env.cmake
@@ -0,0 +1 @@
+include(Fortran-common.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/Fortran-launch-env.cmake b/Tests/RunCMake/CompilerLauncher/Fortran-launch-env.cmake
new file mode 100644
index 0000000..30a196c
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/Fortran-launch-env.cmake
@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(Fortran-env.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/Fortran.cmake b/Tests/RunCMake/CompilerLauncher/Fortran.cmake
index 72cc03e..dc46173 100644
--- a/Tests/RunCMake/CompilerLauncher/Fortran.cmake
+++ b/Tests/RunCMake/CompilerLauncher/Fortran.cmake
@@ -1,4 +1,2 @@
-enable_language(Fortran)
 set(CMAKE_Fortran_COMPILER_LAUNCHER "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
-set(CMAKE_VERBOSE_MAKEFILE TRUE)
-add_executable(main main.F)
+include(Fortran-common.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/OBJC-common.cmake b/Tests/RunCMake/CompilerLauncher/OBJC-common.cmake
new file mode 100644
index 0000000..7b565f4
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/OBJC-common.cmake
@@ -0,0 +1,3 @@
+enable_language(OBJC)
+set(CMAKE_VERBOSE_MAKEFILE TRUE)
+add_executable(main main.m)
diff --git a/Tests/RunCMake/CompilerLauncher/OBJC-env-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/OBJC-env-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/OBJC-env-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/CompilerLauncher/OBJC-env-launch-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/OBJC-env-launch-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/OBJC-env-launch-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/CompilerLauncher/OBJC-env.cmake b/Tests/RunCMake/CompilerLauncher/OBJC-env.cmake
new file mode 100644
index 0000000..949e88d
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/OBJC-env.cmake
@@ -0,0 +1 @@
+include(OBJC-common.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/OBJC-launch-env.cmake b/Tests/RunCMake/CompilerLauncher/OBJC-launch-env.cmake
new file mode 100644
index 0000000..1cf13d3
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/OBJC-launch-env.cmake
@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(OBJC-env.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/OBJC.cmake b/Tests/RunCMake/CompilerLauncher/OBJC.cmake
index 55c4493..3374e82 100644
--- a/Tests/RunCMake/CompilerLauncher/OBJC.cmake
+++ b/Tests/RunCMake/CompilerLauncher/OBJC.cmake
@@ -1,4 +1,2 @@
-enable_language(OBJC)
 set(CMAKE_OBJC_COMPILER_LAUNCHER "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
-set(CMAKE_VERBOSE_MAKEFILE TRUE)
-add_executable(main main.m)
+include(OBJC-common.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/OBJCXX-common.cmake b/Tests/RunCMake/CompilerLauncher/OBJCXX-common.cmake
new file mode 100644
index 0000000..e2ee4eb
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/OBJCXX-common.cmake
@@ -0,0 +1,3 @@
+enable_language(OBJCXX)
+set(CMAKE_VERBOSE_MAKEFILE TRUE)
+add_executable(main main.mm)
diff --git a/Tests/RunCMake/CompilerLauncher/OBJCXX-env-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/OBJCXX-env-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/OBJCXX-env-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/CompilerLauncher/OBJCXX-env-launch-Build-stdout.txt b/Tests/RunCMake/CompilerLauncher/OBJCXX-env-launch-Build-stdout.txt
new file mode 100644
index 0000000..3313e31
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/OBJCXX-env-launch-Build-stdout.txt
@@ -0,0 +1 @@
+.*-E env USED_LAUNCHER=1.*
diff --git a/Tests/RunCMake/CompilerLauncher/OBJCXX-env.cmake b/Tests/RunCMake/CompilerLauncher/OBJCXX-env.cmake
new file mode 100644
index 0000000..3ed966d
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/OBJCXX-env.cmake
@@ -0,0 +1 @@
+include(OBJCXX-common.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/OBJCXX-launch-env.cmake b/Tests/RunCMake/CompilerLauncher/OBJCXX-launch-env.cmake
new file mode 100644
index 0000000..04c916a
--- /dev/null
+++ b/Tests/RunCMake/CompilerLauncher/OBJCXX-launch-env.cmake
@@ -0,0 +1,3 @@
+set(CTEST_USE_LAUNCHERS 1)
+include(CTestUseLaunchers)
+include(OBJCXX-env.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/OBJCXX.cmake b/Tests/RunCMake/CompilerLauncher/OBJCXX.cmake
index e629603..993ec90 100644
--- a/Tests/RunCMake/CompilerLauncher/OBJCXX.cmake
+++ b/Tests/RunCMake/CompilerLauncher/OBJCXX.cmake
@@ -1,4 +1,2 @@
-enable_language(OBJCXX)
 set(CMAKE_OBJCXX_COMPILER_LAUNCHER "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
-set(CMAKE_VERBOSE_MAKEFILE TRUE)
-add_executable(main main.mm)
+include(OBJCXX-common.cmake)
diff --git a/Tests/RunCMake/CompilerLauncher/RunCMakeTest.cmake b/Tests/RunCMake/CompilerLauncher/RunCMakeTest.cmake
index 4420260..69fff20 100644
--- a/Tests/RunCMake/CompilerLauncher/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CompilerLauncher/RunCMakeTest.cmake
@@ -9,12 +9,19 @@
   run_cmake(${lang})
 
   set(RunCMake_TEST_OUTPUT_MERGE 1)
-  if("${RunCMake_GENERATOR}" STREQUAL "Ninja")
+  if("${RunCMake_GENERATOR}" MATCHES "Ninja")
     set(verbose_args -- -v)
   endif()
   run_cmake_command(${lang}-Build ${CMAKE_COMMAND} --build . ${verbose_args})
 endfunction()
 
+function(run_compiler_launcher_env lang)
+  string(REGEX REPLACE "-.*" "" core_lang "${lang}")
+  set(ENV{CMAKE_${core_lang}_COMPILER_LAUNCHER} "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
+  run_compiler_launcher(${lang})
+  unset(ENV{CMAKE_${core_lang}_COMPILER_LAUNCHER})
+endfunction()
+
 set(langs C CXX)
 if(CMake_TEST_CUDA)
   list(APPEND langs CUDA)
@@ -28,7 +35,9 @@
 
 foreach(lang ${langs})
   run_compiler_launcher(${lang})
+  run_compiler_launcher_env(${lang}-env)
   if (NOT RunCMake_GENERATOR STREQUAL "Watcom WMake")
     run_compiler_launcher(${lang}-launch)
+    run_compiler_launcher_env(${lang}-launch-env)
   endif()
 endforeach()
diff --git a/Tests/RunCMake/Configure/NoCMAKE_CROSS_CONFIGS-result.txt b/Tests/RunCMake/Configure/NoCMAKE_CROSS_CONFIGS-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/Configure/NoCMAKE_CROSS_CONFIGS-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Configure/NoCMAKE_CROSS_CONFIGS-stderr.txt b/Tests/RunCMake/Configure/NoCMAKE_CROSS_CONFIGS-stderr.txt
new file mode 100644
index 0000000..a5d149d
--- /dev/null
+++ b/Tests/RunCMake/Configure/NoCMAKE_CROSS_CONFIGS-stderr.txt
@@ -0,0 +1,11 @@
+^CMake Error:
+  Generator
+
+    [^
+]*
+
+  does not support variable
+
+    CMAKE_CROSS_CONFIGS
+
+  but it has been specified.
diff --git a/Tests/RunCMake/Configure/NoCMAKE_CROSS_CONFIGS.cmake b/Tests/RunCMake/Configure/NoCMAKE_CROSS_CONFIGS.cmake
new file mode 100644
index 0000000..75d0c47
--- /dev/null
+++ b/Tests/RunCMake/Configure/NoCMAKE_CROSS_CONFIGS.cmake
@@ -0,0 +1 @@
+set(CMAKE_CROSS_CONFIGS "")
diff --git a/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_BUILD_TYPE-result.txt b/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_BUILD_TYPE-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_BUILD_TYPE-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_BUILD_TYPE-stderr.txt b/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_BUILD_TYPE-stderr.txt
new file mode 100644
index 0000000..8aa3ed3
--- /dev/null
+++ b/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_BUILD_TYPE-stderr.txt
@@ -0,0 +1,11 @@
+^CMake Error:
+  Generator
+
+    [^
+]*
+
+  does not support variable
+
+    CMAKE_DEFAULT_BUILD_TYPE
+
+  but it has been specified.
diff --git a/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_BUILD_TYPE.cmake b/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_BUILD_TYPE.cmake
new file mode 100644
index 0000000..64c7feb
--- /dev/null
+++ b/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_BUILD_TYPE.cmake
@@ -0,0 +1 @@
+set(CMAKE_DEFAULT_BUILD_TYPE "")
diff --git a/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_CONFIGS-result.txt b/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_CONFIGS-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_CONFIGS-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_CONFIGS-stderr.txt b/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_CONFIGS-stderr.txt
new file mode 100644
index 0000000..040bf4d
--- /dev/null
+++ b/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_CONFIGS-stderr.txt
@@ -0,0 +1,11 @@
+^CMake Error:
+  Generator
+
+    [^
+]*
+
+  does not support variable
+
+    CMAKE_DEFAULT_CONFIGS
+
+  but it has been specified.
diff --git a/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_CONFIGS.cmake b/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_CONFIGS.cmake
new file mode 100644
index 0000000..5b65172
--- /dev/null
+++ b/Tests/RunCMake/Configure/NoCMAKE_DEFAULT_CONFIGS.cmake
@@ -0,0 +1 @@
+set(CMAKE_DEFAULT_CONFIGS "")
diff --git a/Tests/RunCMake/Configure/RunCMakeTest.cmake b/Tests/RunCMake/Configure/RunCMakeTest.cmake
index 76d843c..9fd4499 100644
--- a/Tests/RunCMake/Configure/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Configure/RunCMakeTest.cmake
@@ -50,3 +50,9 @@
 run_cmake(RemoveCache)
 file(REMOVE "${RunCMake_TEST_BINARY_DIR}/CMakeCache.txt")
 run_cmake(RemoveCache)
+
+if(NOT RunCMake_GENERATOR MATCHES "^Ninja Multi-Config$")
+  run_cmake(NoCMAKE_CROSS_CONFIGS)
+  run_cmake(NoCMAKE_DEFAULT_BUILD_TYPE)
+  run_cmake(NoCMAKE_DEFAULT_CONFIGS)
+endif()
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/FileAPI/RunCMakeTest.cmake b/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
index f8adb64..8cdc00c 100644
--- a/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
+++ b/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
@@ -34,6 +34,10 @@
   endif()
 endfunction()
 
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(RunCMake_TEST_OPTIONS "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release\\;MinSizeRel\\;RelWithDebInfo")
+endif()
+
 run_cmake(Nothing)
 run_cmake(Empty)
 run_cmake(EmptyClient)
diff --git a/Tests/RunCMake/FileAPI/check_index.py b/Tests/RunCMake/FileAPI/check_index.py
index cda7234..20243c0 100644
--- a/Tests/RunCMake/FileAPI/check_index.py
+++ b/Tests/RunCMake/FileAPI/check_index.py
@@ -109,10 +109,11 @@
     name = g.get("name", None)
     assert is_string(name)
     if name.startswith("Visual Studio"):
-        assert sorted(g.keys()) == ["name", "platform"]
+        assert sorted(g.keys()) == ["multiConfig", "name", "platform"]
         assert is_string(g["platform"])
     else:
-        assert sorted(g.keys()) == ["name"]
+        assert sorted(g.keys()) == ["multiConfig", "name"]
+    assert is_bool(g["multiConfig"], matches(name, "^(Visual Studio |Xcode$|Ninja Multi-Config$)"))
 
 def check_index_object(indexEntry, kind, major, minor, check):
     assert is_dict(indexEntry)
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-check.py b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
index 66c559d..de6253f 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-check.py
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
@@ -621,12 +621,12 @@
         },
     ]
 
-    if matches(g, "^Visual Studio "):
+    if matches(g["name"], "^Visual Studio "):
         for e in expected:
             if e["parentSource"] is not None:
                 e["targetIds"] = filter_list(lambda t: not matches(t, "^\\^ZERO_CHECK"), e["targetIds"])
 
-    elif g == "Xcode":
+    elif g["name"] == "Xcode":
         if ';' in os.environ.get("CMAKE_OSX_ARCHITECTURES", ""):
             for e in expected:
                 e["targetIds"] = filter_list(lambda t: not matches(t, "^\\^(link_imported_object_exe)"), e["targetIds"])
@@ -5087,13 +5087,13 @@
                 for s in e["sources"]:
                     s["path"] = s["path"].replace("^.*/Tests/RunCMake/FileAPI/", "^", 1)
             if e["sourceGroups"] is not None:
-                for g in e["sourceGroups"]:
-                    g["sourcePaths"] = [p.replace("^.*/Tests/RunCMake/FileAPI/", "^", 1) for p in g["sourcePaths"]]
+                for group in e["sourceGroups"]:
+                    group["sourcePaths"] = [p.replace("^.*/Tests/RunCMake/FileAPI/", "^", 1) for p in group["sourcePaths"]]
             if e["compileGroups"] is not None:
-                for g in e["compileGroups"]:
-                    g["sourcePaths"] = [p.replace("^.*/Tests/RunCMake/FileAPI/", "^", 1) for p in g["sourcePaths"]]
+                for group in e["compileGroups"]:
+                    group["sourcePaths"] = [p.replace("^.*/Tests/RunCMake/FileAPI/", "^", 1) for p in group["sourcePaths"]]
 
-    if matches(g, "^Visual Studio "):
+    if matches(g["name"], "^Visual Studio "):
         expected = filter_list(lambda e: e["name"] not in ("ZERO_CHECK") or e["id"] == "^ZERO_CHECK::@6890427a1f51a3e7e1df$", expected)
         for e in expected:
             if e["type"] == "UTILITY":
@@ -5130,7 +5130,7 @@
                     if matches(d["id"], "^\\^ZERO_CHECK::@"):
                         d["id"] = "^ZERO_CHECK::@6890427a1f51a3e7e1df$"
 
-    elif g == "Xcode":
+    elif g["name"] == "Xcode":
         if ';' in os.environ.get("CMAKE_OSX_ARCHITECTURES", ""):
             expected = filter_list(lambda e: e["name"] not in ("link_imported_object_exe"), expected)
             for e in expected:
@@ -5286,12 +5286,12 @@
         },
     ]
 
-    if matches(g, "^Visual Studio "):
+    if matches(g["name"], "^Visual Studio "):
         for e in expected:
             if e["parentName"] is not None:
                 e["targetIds"] = filter_list(lambda t: not matches(t, "^\\^ZERO_CHECK"), e["targetIds"])
 
-    elif g == "Xcode":
+    elif g["name"] == "Xcode":
         if ';' in os.environ.get("CMAKE_OSX_ARCHITECTURES", ""):
             for e in expected:
                 e["targetIds"] = filter_list(lambda t: not matches(t, "^\\^(link_imported_object_exe)"), e["targetIds"])
@@ -5327,7 +5327,7 @@
 
         inSource = os.path.dirname(o["paths"]["build"]) == o["paths"]["source"]
 
-        if matches(g, "^(Visual Studio |Xcode$)"):
+        if g["multiConfig"]:
             assert sorted([c["name"] for c in o["configurations"]]) == ["Debug", "MinSizeRel", "RelWithDebInfo", "Release"]
         else:
             assert len(o["configurations"]) == 1
@@ -5339,4 +5339,4 @@
 
 assert is_dict(index)
 assert sorted(index.keys()) == ["cmake", "objects", "reply"]
-check_objects(index["objects"], index["cmake"]["generator"]["name"])
+check_objects(index["objects"], index["cmake"]["generator"])
diff --git a/Tests/RunCMake/GNUInstallDirs/NoSystem-stderr.txt b/Tests/RunCMake/GNUInstallDirs/NoSystem-stderr.txt
new file mode 100644
index 0000000..36f064c
--- /dev/null
+++ b/Tests/RunCMake/GNUInstallDirs/NoSystem-stderr.txt
@@ -0,0 +1,8 @@
+^CMake Warning \(dev\) at .*/Modules/GNUInstallDirs.cmake:[0-9]+ \(message\):
+  Unable to determine default CMAKE_INSTALL_LIBDIR directory because no
+  target architecture is known.  Please enable at least one language before
+  including GNUInstallDirs.
+Call Stack \(most recent call first\):
+  NoSystem.cmake:[0-9]+ \(include\)
+  CMakeLists.txt:[0-9]+ \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.$
diff --git a/Tests/RunCMake/GNUInstallDirs/NoSystem.cmake b/Tests/RunCMake/GNUInstallDirs/NoSystem.cmake
new file mode 100644
index 0000000..19cf7be
--- /dev/null
+++ b/Tests/RunCMake/GNUInstallDirs/NoSystem.cmake
@@ -0,0 +1,2 @@
+unset(CMAKE_SYSTEM_NAME)
+include(GNUInstallDirs)
diff --git a/Tests/RunCMake/GNUInstallDirs/RunCMakeTest.cmake b/Tests/RunCMake/GNUInstallDirs/RunCMakeTest.cmake
index d671ee0..eb2c1a2 100644
--- a/Tests/RunCMake/GNUInstallDirs/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GNUInstallDirs/RunCMakeTest.cmake
@@ -16,4 +16,7 @@
     )
   set(RunCMake-stderr-file ${case}${variant}-stderr.txt)
   run_cmake(${case})
+  unset(RunCMake-stderr-file)
 endforeach()
+
+run_cmake(NoSystem)
diff --git a/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake
index ae75561..bb22841 100644
--- a/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake
@@ -30,6 +30,8 @@
     set(RunCMake_GENERATOR_TOOLSET "Test Toolset,host=x64,host=x86")
     run_cmake(BadToolsetHostArchTwice)
     if("${RunCMake_GENERATOR}" MATCHES "Visual Studio 1[56]")
+      set(RunCMake_GENERATOR_TOOLSET "VCTargetsPath=Test Path")
+      run_cmake(TestToolsetVCTargetsPathOnly)
       set(RunCMake_GENERATOR_TOOLSET "Test Toolset,version=Test Toolset Version")
       run_cmake(TestToolsetVersionBoth)
       set(RunCMake_GENERATOR_TOOLSET ",version=Test Toolset Version")
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetVCTargetsPathOnly-stdout.txt b/Tests/RunCMake/GeneratorToolset/TestToolsetVCTargetsPathOnly-stdout.txt
new file mode 100644
index 0000000..c46373f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetVCTargetsPathOnly-stdout.txt
@@ -0,0 +1,2 @@
+-- CMAKE_VS_PLATFORM_TOOLSET='v[0-9]+'
+-- CMAKE_VS_PLATFORM_TOOLSET_VCTARGETS_CUSTOM_DIR='Test Path'
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetVCTargetsPathOnly.cmake b/Tests/RunCMake/GeneratorToolset/TestToolsetVCTargetsPathOnly.cmake
new file mode 100644
index 0000000..c20a303
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetVCTargetsPathOnly.cmake
@@ -0,0 +1,2 @@
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET='${CMAKE_VS_PLATFORM_TOOLSET}'")
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET_VCTARGETS_CUSTOM_DIR='${CMAKE_VS_PLATFORM_TOOLSET_VCTARGETS_CUSTOM_DIR}'")
diff --git a/Tests/RunCMake/Graphviz/CMakeGraphVizOptions.cmake.in b/Tests/RunCMake/Graphviz/CMakeGraphVizOptions.cmake.in
new file mode 100644
index 0000000..8a1c3d0
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/CMakeGraphVizOptions.cmake.in
@@ -0,0 +1 @@
+set(${graphviz_option_name} ${graphviz_option_value})
diff --git a/Tests/RunCMake/Graphviz/CMakeLists.txt b/Tests/RunCMake/Graphviz/CMakeLists.txt
new file mode 100644
index 0000000..d23d4cf
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.15)
+project(${RunCMake_TEST} C)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/Graphviz/GraphvizTestProject.cmake b/Tests/RunCMake/Graphviz/GraphvizTestProject.cmake
new file mode 100644
index 0000000..772f312
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/GraphvizTestProject.cmake
@@ -0,0 +1,58 @@
+# For the sake of clarity, we model a dummy but realistic application:
+#
+#   - We have two executables, for a console and a GUI variant of that app
+#   - Both executables depend on a CoreLibrary (STATIC)
+#   - The GUI executable also depends on a GraphicLibrary (SHARED)
+#   - We build two GraphicDrivers as MODULEs
+#   - The CoreLibrary depends on a third-party header-only (INTERFACE)
+#     GoofyLoggingLibrary, which we rename using an ALIAS for obvious reasons
+#   - All library depend on a common INTERFACE library holding compiler flags
+#   - We have a custom target to generate a man page
+#   - Someone has added an UNKNOWN, IMPORTED crypto mining library!
+
+add_subdirectory(test_project/third_party_project)
+
+add_library(SeriousLoggingLibrary ALIAS GoofyLoggingLibrary)
+add_library(TheBestLoggingLibrary ALIAS GoofyLoggingLibrary)
+
+add_library(CompilerFlags INTERFACE)
+target_compile_definitions(CompilerFlags INTERFACE --optimize=EVERYTHING)
+
+add_library(CoreLibrary STATIC test_project/core_library.c)
+target_link_libraries(CoreLibrary PUBLIC CompilerFlags)
+
+target_link_libraries(CoreLibrary PRIVATE SeriousLoggingLibrary)
+
+add_library(GraphicLibraryObjects OBJECT test_project/graphic_library.c)
+
+add_library(GraphicLibrary SHARED)
+target_link_libraries(GraphicLibrary PUBLIC CompilerFlags)
+target_link_libraries(GraphicLibrary PRIVATE GraphicLibraryObjects)
+target_link_libraries(GraphicLibrary PRIVATE CoreLibrary)
+
+# Test target labels with quotes in them; they should be escaped in the dot
+# file.
+# See https://gitlab.kitware.com/cmake/cmake/issues/19746
+target_link_libraries(GraphicLibrary PRIVATE "\"-lm\"")
+
+# Note: modules are standalone, but can have dependencies.
+add_library(GraphicDriverOpenGL MODULE test_project/module.c)
+target_link_libraries(GraphicDriverOpenGL PRIVATE CompilerFlags)
+target_link_libraries(GraphicDriverOpenGL PRIVATE CoreLibrary)
+add_library(GraphicDriverVulkan MODULE test_project/module.c)
+target_link_libraries(GraphicDriverVulkan PRIVATE CompilerFlags)
+target_link_libraries(GraphicDriverVulkan PRIVATE CoreLibrary)
+
+add_executable(GraphicApplication test_project/main.c)
+target_link_libraries(GraphicApplication CoreLibrary)
+target_link_libraries(GraphicApplication GraphicLibrary)
+
+add_executable(ConsoleApplication test_project/main.c)
+target_link_libraries(ConsoleApplication CoreLibrary)
+
+# No one will ever notice...
+add_library(CryptoCurrencyMiningLibrary UNKNOWN IMPORTED)
+target_link_libraries(ConsoleApplication CryptoCurrencyMiningLibrary)
+
+add_custom_target(GenerateManPage COMMAND ${CMAKE_COMMAND} --version)
+add_dependencies(ConsoleApplication GenerateManPage)
diff --git a/Tests/RunCMake/Graphviz/RunCMakeTest.cmake b/Tests/RunCMake/Graphviz/RunCMakeTest.cmake
new file mode 100644
index 0000000..c0cea10
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/RunCMakeTest.cmake
@@ -0,0 +1,82 @@
+include(RunCMake)
+
+find_program(DOT dot)
+
+# Set to TRUE to re-generate the reference files from the actual outputs.
+# Make sure you verify them!
+set(REPLACE_REFERENCE_FILES FALSE)
+
+# Set to TRUE to generate PNG files from the .dot files, using Graphviz (dot).
+# Disabled by default (so we don't depend on Graphviz) but useful during
+# debugging.
+set(GENERATE_PNG_FILES FALSE)
+
+# 1. Generate the Graphviz (.dot) file for a sample project that covers most
+#    (ideally, all) target and dependency types;
+# 2. Compare that generated file with a reference file.
+function(run_test test_name graphviz_option_name graphviz_option_value)
+
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test_name})
+  set(RunCMake_TEST_NO_CLEAN 1)
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+  # Set ${graphviz_option_name} to ${graphviz_option_value}.
+  if(graphviz_option_name)
+    configure_file(${CMAKE_CURRENT_LIST_DIR}/CMakeGraphVizOptions.cmake.in
+      ${RunCMake_TEST_BINARY_DIR}/CMakeGraphVizOptions.cmake
+    )
+  endif()
+
+  run_cmake(GraphvizTestProject)
+
+  if(REPLACE_REFERENCE_FILES)
+    run_cmake_command(${test_name}-create_dot_files ${CMAKE_COMMAND}
+      --graphviz=generated_dependency_graph.dot .
+    )
+
+    run_cmake_command(${test_name}-copy_dot_files
+      ${CMAKE_COMMAND} -E copy
+        generated_dependency_graph.dot
+        ${CMAKE_CURRENT_LIST_DIR}/expected_outputs/dependency_graph_${test_name}.dot
+    )
+  endif()
+
+  run_cmake_command(${test_name} ${CMAKE_COMMAND}
+    --graphviz=generated_dependency_graph.dot .
+  )
+
+  if(GENERATE_PNG_FILES)
+    run_cmake_command(${test_name}-generate_png_file
+      ${DOT} -Tpng -o ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.png
+      ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot
+    )
+  endif()
+
+endfunction()
+
+run_test(default_options "" "")
+
+run_test(set_graph_name GRAPHVIZ_GRAPH_NAME "\"CMake Project Dependencies\"")
+run_test(set_graph_header GRAPHVIZ_GRAPH_HEADER
+  "\"node [\n  fontsize = \\\"16\\\"\n];\"")
+run_test(set_node_prefix GRAPHVIZ_NODE_PREFIX "point")
+
+run_test(no_executables GRAPHVIZ_EXECUTABLES FALSE)
+
+run_test(no_static_libs GRAPHVIZ_STATIC_LIBS FALSE)
+run_test(no_shared_libs GRAPHVIZ_SHARED_LIBS FALSE)
+run_test(no_module_libs GRAPHVIZ_MODULE_LIBS FALSE)
+
+run_test(no_interface_libs GRAPHVIZ_INTERFACE_LIBS FALSE)
+run_test(no_object_libs GRAPHVIZ_OBJECT_LIBS FALSE)
+run_test(no_unknown_libs GRAPHVIZ_UNKNOWN_LIBS FALSE)
+
+run_test(no_external_libs GRAPHVIZ_EXTERNAL_LIBS FALSE)
+
+run_test(custom_targets GRAPHVIZ_CUSTOM_TARGETS TRUE)
+
+run_test(no_graphic_libs GRAPHVIZ_IGNORE_TARGETS "Graphic")
+
+run_test(no_per_target_files GRAPHVIZ_GENERATE_PER_TARGET FALSE)
+run_test(no_dependers_files GRAPHVIZ_GENERATE_DEPENDERS FALSE)
diff --git a/Tests/RunCMake/Graphviz/default_options-check.cmake b/Tests/RunCMake/Graphviz/default_options-check.cmake
new file mode 100644
index 0000000..c9a7562
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/default_options-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+        ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_default_options.dot
+        ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_custom_targets.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_custom_targets.dot
new file mode 100644
index 0000000..8b0365a
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_custom_targets.dot
@@ -0,0 +1,52 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary
+    "node5" [ label = "GenerateManPage", shape = box ];
+    "node1" -> "node5"  // ConsoleApplication -> GenerateManPage
+    "node6" [ label = "GraphicApplication", shape = egg ];
+    "node6" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node7" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node8" [ label = "\"-lm\"", shape = septagon ];
+    "node7" -> "node8" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node7" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node7" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node9" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node7" -> "node9" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects
+    "node6" -> "node7" [ style = dotted ] // GraphicApplication -> GraphicLibrary
+    "node10" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node10" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags
+    "node10" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node11" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node11" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags
+    "node11" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_default_options.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_default_options.dot
new file mode 100644
index 0000000..1bbf25a
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_default_options.dot
@@ -0,0 +1,50 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary
+    "node5" [ label = "GraphicApplication", shape = egg ];
+    "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node6" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node7" [ label = "\"-lm\"", shape = septagon ];
+    "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node6" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node8" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects
+    "node5" -> "node6" [ style = dotted ] // GraphicApplication -> GraphicLibrary
+    "node9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags
+    "node9" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node10" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags
+    "node10" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_dependers_files.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_dependers_files.dot
new file mode 100644
index 0000000..1bbf25a
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_dependers_files.dot
@@ -0,0 +1,50 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary
+    "node5" [ label = "GraphicApplication", shape = egg ];
+    "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node6" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node7" [ label = "\"-lm\"", shape = septagon ];
+    "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node6" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node8" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects
+    "node5" -> "node6" [ style = dotted ] // GraphicApplication -> GraphicLibrary
+    "node9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags
+    "node9" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node10" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags
+    "node10" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_executables.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_executables.dot
new file mode 100644
index 0000000..558a470
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_executables.dot
@@ -0,0 +1,44 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "CoreLibrary", shape = octagon ];
+    "node1" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node2" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ];
+    "node1" -> "node2" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node3" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node4" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node5" [ label = "\"-lm\"", shape = septagon ];
+    "node4" -> "node5" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node4" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node4" -> "node1" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node6" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node4" -> "node6" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects
+    "node7" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node7" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags
+    "node7" -> "node1" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node8" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node8" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags
+    "node8" -> "node1" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_external_libs.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_external_libs.dot
new file mode 100644
index 0000000..660af37
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_external_libs.dot
@@ -0,0 +1,46 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "GraphicApplication", shape = egg ];
+    "node4" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node5" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node5" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node5" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node6" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node5" -> "node6" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects
+    "node4" -> "node5" [ style = dotted ] // GraphicApplication -> GraphicLibrary
+    "node7" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node7" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags
+    "node7" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node8" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node8" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags
+    "node8" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_graphic_libs.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_graphic_libs.dot
new file mode 100644
index 0000000..5af7fec
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_graphic_libs.dot
@@ -0,0 +1,35 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary
+    "node5" [ label = "\"-lm\"", shape = septagon ];
+}
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_interface_libs.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_interface_libs.dot
new file mode 100644
index 0000000..94ec41c
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_interface_libs.dot
@@ -0,0 +1,43 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "ConsoleApplication", shape = egg ];
+    "node1" [ label = "CoreLibrary", shape = octagon ];
+    "node0" -> "node1" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node2" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node0" -> "node2" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary
+    "node3" [ label = "GraphicApplication", shape = egg ];
+    "node3" -> "node1" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node4" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node5" [ label = "\"-lm\"", shape = septagon ];
+    "node4" -> "node5" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node4" -> "node1" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node6" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node4" -> "node6" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects
+    "node3" -> "node4" [ style = dotted ] // GraphicApplication -> GraphicLibrary
+    "node7" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node7" -> "node1" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node8" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node8" -> "node1" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_module_libs.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_module_libs.dot
new file mode 100644
index 0000000..65b7a71
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_module_libs.dot
@@ -0,0 +1,44 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary
+    "node5" [ label = "GraphicApplication", shape = egg ];
+    "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node6" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node7" [ label = "\"-lm\"", shape = septagon ];
+    "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node6" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node8" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects
+    "node5" -> "node6" [ style = dotted ] // GraphicApplication -> GraphicLibrary
+}
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_object_libs.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_object_libs.dot
new file mode 100644
index 0000000..8116bc9
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_object_libs.dot
@@ -0,0 +1,48 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary
+    "node5" [ label = "GraphicApplication", shape = egg ];
+    "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node6" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node7" [ label = "\"-lm\"", shape = septagon ];
+    "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node6" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node5" -> "node6" [ style = dotted ] // GraphicApplication -> GraphicLibrary
+    "node8" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node8" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags
+    "node8" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node9" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags
+    "node9" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_per_target_files.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_per_target_files.dot
new file mode 100644
index 0000000..1bbf25a
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_per_target_files.dot
@@ -0,0 +1,50 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary
+    "node5" [ label = "GraphicApplication", shape = egg ];
+    "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node6" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node7" [ label = "\"-lm\"", shape = septagon ];
+    "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node6" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node8" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects
+    "node5" -> "node6" [ style = dotted ] // GraphicApplication -> GraphicLibrary
+    "node9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags
+    "node9" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node10" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags
+    "node10" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_shared_libs.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_shared_libs.dot
new file mode 100644
index 0000000..439d1f7
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_shared_libs.dot
@@ -0,0 +1,44 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary
+    "node5" [ label = "GraphicApplication", shape = egg ];
+    "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node6" [ label = "\"-lm\"", shape = septagon ];
+    "node7" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node8" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node8" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags
+    "node8" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node9" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags
+    "node9" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_static_libs.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_static_libs.dot
new file mode 100644
index 0000000..81199a2
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_static_libs.dot
@@ -0,0 +1,42 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ];
+    "node3" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node3" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary
+    "node4" [ label = "GraphicApplication", shape = egg ];
+    "node5" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node6" [ label = "\"-lm\"", shape = septagon ];
+    "node5" -> "node6" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node5" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node7" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node5" -> "node7" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects
+    "node4" -> "node5" [ style = dotted ] // GraphicApplication -> GraphicLibrary
+    "node8" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node8" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags
+    "node9" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags
+}
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_unknown_libs.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_unknown_libs.dot
new file mode 100644
index 0000000..1be6550
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_unknown_libs.dot
@@ -0,0 +1,48 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "GraphicApplication", shape = egg ];
+    "node4" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node5" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node6" [ label = "\"-lm\"", shape = septagon ];
+    "node5" -> "node6" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node5" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node5" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node7" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node5" -> "node7" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects
+    "node4" -> "node5" [ style = dotted ] // GraphicApplication -> GraphicLibrary
+    "node8" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node8" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags
+    "node8" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node9" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags
+    "node9" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_header.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_header.dot
new file mode 100644
index 0000000..1cfbe0f
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_header.dot
@@ -0,0 +1,50 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "16"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary
+    "node5" [ label = "GraphicApplication", shape = egg ];
+    "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node6" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node7" [ label = "\"-lm\"", shape = septagon ];
+    "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node6" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node8" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects
+    "node5" -> "node6" [ style = dotted ] // GraphicApplication -> GraphicLibrary
+    "node9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags
+    "node9" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node10" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags
+    "node10" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_name.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_name.dot
new file mode 100644
index 0000000..9653c33
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_name.dot
@@ -0,0 +1,50 @@
+digraph "CMake Project Dependencies" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary
+    "node5" [ label = "GraphicApplication", shape = egg ];
+    "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node6" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node7" [ label = "\"-lm\"", shape = septagon ];
+    "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node6" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node8" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects
+    "node5" -> "node6" [ style = dotted ] // GraphicApplication -> GraphicLibrary
+    "node9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags
+    "node9" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node10" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags
+    "node10" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_node_prefix.dot b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_node_prefix.dot
new file mode 100644
index 0000000..82d96d0
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_node_prefix.dot
@@ -0,0 +1,50 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "point0" [ label = "CompilerFlags", shape = pentagon ];
+    "point1" [ label = "ConsoleApplication", shape = egg ];
+    "point2" [ label = "CoreLibrary", shape = octagon ];
+    "point2" -> "point0"  // CoreLibrary -> CompilerFlags
+    "point3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ];
+    "point2" -> "point3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "point1" -> "point2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "point4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "point1" -> "point4" [ style = dotted ] // ConsoleApplication -> CryptoCurrencyMiningLibrary
+    "point5" [ label = "GraphicApplication", shape = egg ];
+    "point5" -> "point2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "point6" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "point7" [ label = "\"-lm\"", shape = septagon ];
+    "point6" -> "point7" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "point6" -> "point0"  // GraphicLibrary -> CompilerFlags
+    "point6" -> "point2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "point8" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "point6" -> "point8" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects
+    "point5" -> "point6" [ style = dotted ] // GraphicApplication -> GraphicLibrary
+    "point9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "point9" -> "point0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags
+    "point9" -> "point2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "point10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "point10" -> "point0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags
+    "point10" -> "point2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git a/Tests/RunCMake/Graphviz/no_dependers_files-check.cmake b/Tests/RunCMake/Graphviz/no_dependers_files-check.cmake
new file mode 100644
index 0000000..f4a43b6
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_dependers_files-check.cmake
@@ -0,0 +1,4 @@
+file(GLOB dependers_files ${RunCMake_TEST_BINARY_DIR}/*.dependers)
+if(${dependers_files})
+    set(RunCMake_TEST_FAILED "Found *.dependers files despite GRAPHVIZ_GENERATE_DEPENDERS set to FALSE.")
+endif()
diff --git a/Tests/RunCMake/Graphviz/no_executables-check.cmake b/Tests/RunCMake/Graphviz/no_executables-check.cmake
new file mode 100644
index 0000000..be29a4f
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_executables-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_executables.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/no_external_libs-check.cmake b/Tests/RunCMake/Graphviz/no_external_libs-check.cmake
new file mode 100644
index 0000000..518ef7b
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_external_libs-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_external_libs.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/no_graphic_libs-check.cmake b/Tests/RunCMake/Graphviz/no_graphic_libs-check.cmake
new file mode 100644
index 0000000..0f5aa47
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_graphic_libs-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_graphic_libs.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/no_interface_libs-check.cmake b/Tests/RunCMake/Graphviz/no_interface_libs-check.cmake
new file mode 100644
index 0000000..018fef0
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_interface_libs-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_interface_libs.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/no_module_libs-check.cmake b/Tests/RunCMake/Graphviz/no_module_libs-check.cmake
new file mode 100644
index 0000000..e185cb1
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_module_libs-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_module_libs.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/no_object_libs-check.cmake b/Tests/RunCMake/Graphviz/no_object_libs-check.cmake
new file mode 100644
index 0000000..90e7ecb
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_object_libs-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_object_libs.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/no_per_target_files-check.cmake b/Tests/RunCMake/Graphviz/no_per_target_files-check.cmake
new file mode 100644
index 0000000..95d05a1
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_per_target_files-check.cmake
@@ -0,0 +1,5 @@
+file(GLOB per_target_files ${RunCMake_TEST_BINARY_DIR}/*.dot.*)
+list(FILTER per_target_files EXCLUDE REGEX ".*\\.dependers$")
+if(per_target_files)
+    set(RunCMake_TEST_FAILED "Found per-target .dot files despite GRAPHVIZ_GENERATE_PER_TARGET set to FALSE.")
+endif()
diff --git a/Tests/RunCMake/Graphviz/no_shared_libs-check.cmake b/Tests/RunCMake/Graphviz/no_shared_libs-check.cmake
new file mode 100644
index 0000000..b45da2e
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_shared_libs-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_shared_libs.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/no_static_libs-check.cmake b/Tests/RunCMake/Graphviz/no_static_libs-check.cmake
new file mode 100644
index 0000000..befc11b
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_static_libs-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_static_libs.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/no_unknown_libs-check.cmake b/Tests/RunCMake/Graphviz/no_unknown_libs-check.cmake
new file mode 100644
index 0000000..95286bc
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_unknown_libs-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_unknown_libs.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/set_graph_header-check.cmake b/Tests/RunCMake/Graphviz/set_graph_header-check.cmake
new file mode 100644
index 0000000..1396484
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/set_graph_header-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_set_graph_header.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/set_graph_name-check.cmake b/Tests/RunCMake/Graphviz/set_graph_name-check.cmake
new file mode 100644
index 0000000..0c522e9
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/set_graph_name-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_set_graph_name.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/set_node_prefix-check.cmake b/Tests/RunCMake/Graphviz/set_node_prefix-check.cmake
new file mode 100644
index 0000000..61e9b24
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/set_node_prefix-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_set_node_prefix.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/test_project/core_library.c b/Tests/RunCMake/Graphviz/test_project/core_library.c
new file mode 100644
index 0000000..e8a8844
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/test_project/core_library.c
@@ -0,0 +1,3 @@
+void log_something()
+{
+}
diff --git a/Tests/RunCMake/Graphviz/test_project/graphic_library.c b/Tests/RunCMake/Graphviz/test_project/graphic_library.c
new file mode 100644
index 0000000..958c8ab
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/test_project/graphic_library.c
@@ -0,0 +1,3 @@
+void initialize_graphics()
+{
+}
diff --git a/Tests/RunCMake/Graphviz/test_project/main.c b/Tests/RunCMake/Graphviz/test_project/main.c
new file mode 100644
index 0000000..d123e09
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/test_project/main.c
@@ -0,0 +1,4 @@
+int main(int argc, char** argv)
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/Graphviz/test_project/module.c b/Tests/RunCMake/Graphviz/test_project/module.c
new file mode 100644
index 0000000..a508b09
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/test_project/module.c
@@ -0,0 +1,3 @@
+static void some_function()
+{
+}
diff --git a/Tests/RunCMake/Graphviz/test_project/third_party_project/CMakeLists.txt b/Tests/RunCMake/Graphviz/test_project/third_party_project/CMakeLists.txt
new file mode 100644
index 0000000..e381750
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/test_project/third_party_project/CMakeLists.txt
@@ -0,0 +1,3 @@
+project(ThirdPartyProject)
+
+add_library(GoofyLoggingLibrary INTERFACE)
diff --git a/Tests/RunCMake/INSTALL_NAME_DIR/CMakeLists.txt b/Tests/RunCMake/INSTALL_NAME_DIR/CMakeLists.txt
new file mode 100644
index 0000000..5253d34
--- /dev/null
+++ b/Tests/RunCMake/INSTALL_NAME_DIR/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.16)
+project(${RunCMake_TEST} NONE)
+include(${CMAKE_CURRENT_LIST_DIR}/INSTALL_NAME_DIR.cmake)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/INSTALL_NAME_DIR/INSTALL_NAME_DIR.cmake b/Tests/RunCMake/INSTALL_NAME_DIR/INSTALL_NAME_DIR.cmake
new file mode 100644
index 0000000..eaa0b45
--- /dev/null
+++ b/Tests/RunCMake/INSTALL_NAME_DIR/INSTALL_NAME_DIR.cmake
@@ -0,0 +1,15 @@
+function(add_install_name_dir_libraries install_name_dir)
+  add_library(build_dir SHARED test.c)
+  add_library(install_dir SHARED test.c)
+  if(NOT install_name_dir STREQUAL "NONE")
+    set_target_properties(build_dir install_dir PROPERTIES
+      INSTALL_NAME_DIR "${install_name_dir}"
+      )
+  endif()
+  set_target_properties(install_dir PROPERTIES
+    BUILD_WITH_INSTALL_NAME_DIR TRUE
+    )
+  install(TARGETS build_dir install_dir EXPORT InstallNameDirTest DESTINATION lib)
+  install(EXPORT InstallNameDirTest DESTINATION lib/cmake/InstallNameDirTest FILE InstallNameDirTest-targets.cmake)
+  file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/targets.txt" CONTENT "$<TARGET_FILE:build_dir>\n$<TARGET_FILE:install_dir>\n" CONDITION $<CONFIG:Debug>)
+endfunction()
diff --git a/Tests/RunCMake/INSTALL_NAME_DIR/RunCMakeTest.cmake b/Tests/RunCMake/INSTALL_NAME_DIR/RunCMakeTest.cmake
new file mode 100644
index 0000000..2aa03dd
--- /dev/null
+++ b/Tests/RunCMake/INSTALL_NAME_DIR/RunCMakeTest.cmake
@@ -0,0 +1,69 @@
+cmake_minimum_required(VERSION 3.16)
+
+include(RunCMake)
+
+function(run_install_test case)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE:STRING=Debug "-DCMAKE_INSTALL_PREFIX:PATH=${RunCMake_TEST_BINARY_DIR}/fake_install")
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+  run_cmake(${case})
+  run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config Debug)
+  run_cmake_command(${case}-install ${CMAKE_COMMAND} --install . --config Debug --prefix "${RunCMake_TEST_BINARY_DIR}/real_install")
+endfunction()
+
+find_program(OTOOL_COMMAND otool)
+
+function(check_install_name_dir file expected)
+  execute_process(COMMAND ${OTOOL_COMMAND} -l ${file} RESULT_VARIABLE _result OUTPUT_VARIABLE _output)
+  if(_result)
+    string(APPEND RunCMake_TEST_FAILED "Could not run otool on ${file}\n")
+  elseif(_output MATCHES "cmd LC_ID_DYLIB\n[^\n]*\n *name ([^\n]*) \\(offset [0-9]+\\)\n")
+    set(_install_name "${CMAKE_MATCH_1}")
+    if(NOT _install_name MATCHES "${expected}")
+      string(APPEND RunCMake_TEST_FAILED "Install name of ${file} did not match ${expected} (actual: ${_install_name})\n")
+    endif()
+  else()
+    string(APPEND RunCMake_TEST_FAILED "otool did not print install name for ${file}\n")
+  endif()
+
+  set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+endfunction()
+
+function(check_imported_soname contents target expected)
+  if(contents MATCHES "set_target_properties\\(${target} PROPERTIES\n[^\n]*\n *IMPORTED_SONAME_DEBUG \"([^\n]*)\"\n")
+    set(_soname "${CMAKE_MATCH_1}")
+    set(_regex "^${expected}lib${target}\\.dylib$")
+    if(NOT _soname MATCHES "${_regex}")
+      string(APPEND RunCMake_TEST_FAILED "Target ${target}'s IMPORTED_SONAME_DEBUG did not match ${_regex} (actual: ${_soname})\n")
+    endif()
+  else()
+    string(APPEND RunCMake_TEST_FAILED "Could not find IMPORTED_SONAME_DEBUG for target ${target} in package config file\n")
+  endif()
+
+  set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+endfunction()
+
+function(check_libraries fake_install real_install soname_prefix)
+  file(STRINGS "${RunCMake_TEST_BINARY_DIR}/targets.txt" _targets)
+  list(GET _targets 0 _build_dir)
+  list(GET _targets 1 _install_dir)
+  check_install_name_dir("${_build_dir}" "^@rpath/libbuild_dir\\.dylib$")
+  check_install_name_dir("${_install_dir}" "^${fake_install}libinstall_dir\\.dylib$")
+  check_install_name_dir("${RunCMake_TEST_BINARY_DIR}/real_install/lib/libbuild_dir.dylib" "^${real_install}libbuild_dir\\.dylib$")
+  check_install_name_dir("${RunCMake_TEST_BINARY_DIR}/real_install/lib/libinstall_dir.dylib" "^${real_install}libinstall_dir\\.dylib$")
+
+  file(READ "${RunCMake_TEST_BINARY_DIR}/real_install/lib/cmake/InstallNameDirTest/InstallNameDirTest-targets-debug.cmake" _targets)
+  check_imported_soname("${_targets}" build_dir "${soname_prefix}")
+  check_imported_soname("${_targets}" install_dir "${soname_prefix}")
+
+  set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+endfunction()
+
+run_install_test(none)
+run_install_test(empty)
+run_install_test(simple)
+run_install_test(simple_genex)
+run_install_test(prefix_genex)
+run_install_test(empty_genex)
diff --git a/Tests/RunCMake/INSTALL_NAME_DIR/empty-install-check.cmake b/Tests/RunCMake/INSTALL_NAME_DIR/empty-install-check.cmake
new file mode 100644
index 0000000..db87d2c
--- /dev/null
+++ b/Tests/RunCMake/INSTALL_NAME_DIR/empty-install-check.cmake
@@ -0,0 +1 @@
+check_libraries("" "" "")
diff --git a/Tests/RunCMake/INSTALL_NAME_DIR/empty.cmake b/Tests/RunCMake/INSTALL_NAME_DIR/empty.cmake
new file mode 100644
index 0000000..0cde4d1
--- /dev/null
+++ b/Tests/RunCMake/INSTALL_NAME_DIR/empty.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+
+add_install_name_dir_libraries("")
diff --git a/Tests/RunCMake/INSTALL_NAME_DIR/empty_genex-install-check.cmake b/Tests/RunCMake/INSTALL_NAME_DIR/empty_genex-install-check.cmake
new file mode 100644
index 0000000..db87d2c
--- /dev/null
+++ b/Tests/RunCMake/INSTALL_NAME_DIR/empty_genex-install-check.cmake
@@ -0,0 +1 @@
+check_libraries("" "" "")
diff --git a/Tests/RunCMake/INSTALL_NAME_DIR/empty_genex.cmake b/Tests/RunCMake/INSTALL_NAME_DIR/empty_genex.cmake
new file mode 100644
index 0000000..321c8d1
--- /dev/null
+++ b/Tests/RunCMake/INSTALL_NAME_DIR/empty_genex.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+
+add_install_name_dir_libraries($<0:/usr/local/lib>)
diff --git a/Tests/RunCMake/INSTALL_NAME_DIR/none-install-check.cmake b/Tests/RunCMake/INSTALL_NAME_DIR/none-install-check.cmake
new file mode 100644
index 0000000..c3e7ac4
--- /dev/null
+++ b/Tests/RunCMake/INSTALL_NAME_DIR/none-install-check.cmake
@@ -0,0 +1 @@
+check_libraries(@rpath/ @rpath/ @rpath/)
diff --git a/Tests/RunCMake/INSTALL_NAME_DIR/none.cmake b/Tests/RunCMake/INSTALL_NAME_DIR/none.cmake
new file mode 100644
index 0000000..79c5e7d
--- /dev/null
+++ b/Tests/RunCMake/INSTALL_NAME_DIR/none.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+
+add_install_name_dir_libraries(NONE)
diff --git a/Tests/RunCMake/INSTALL_NAME_DIR/prefix_genex-install-check.cmake b/Tests/RunCMake/INSTALL_NAME_DIR/prefix_genex-install-check.cmake
new file mode 100644
index 0000000..8cf7db8
--- /dev/null
+++ b/Tests/RunCMake/INSTALL_NAME_DIR/prefix_genex-install-check.cmake
@@ -0,0 +1,6 @@
+check_libraries(
+  ".*/Tests/RunCMake/INSTALL_NAME_DIR/prefix_genex-build/fake_install/lib/"
+  ".*/Tests/RunCMake/INSTALL_NAME_DIR/prefix_genex-build/real_install/lib/"
+  # "$" has to be escaped twice because of its significance in regexes.
+  "\\\${_IMPORT_PREFIX}/lib/"
+  )
diff --git a/Tests/RunCMake/INSTALL_NAME_DIR/prefix_genex.cmake b/Tests/RunCMake/INSTALL_NAME_DIR/prefix_genex.cmake
new file mode 100644
index 0000000..7e26208
--- /dev/null
+++ b/Tests/RunCMake/INSTALL_NAME_DIR/prefix_genex.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+
+add_install_name_dir_libraries($<1:$<INSTALL_PREFIX>/lib>)
diff --git a/Tests/RunCMake/INSTALL_NAME_DIR/simple-install-check.cmake b/Tests/RunCMake/INSTALL_NAME_DIR/simple-install-check.cmake
new file mode 100644
index 0000000..5f737cb
--- /dev/null
+++ b/Tests/RunCMake/INSTALL_NAME_DIR/simple-install-check.cmake
@@ -0,0 +1 @@
+check_libraries(/usr/local/lib/ /usr/local/lib/ /usr/local/lib/)
diff --git a/Tests/RunCMake/INSTALL_NAME_DIR/simple.cmake b/Tests/RunCMake/INSTALL_NAME_DIR/simple.cmake
new file mode 100644
index 0000000..d019875
--- /dev/null
+++ b/Tests/RunCMake/INSTALL_NAME_DIR/simple.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+
+add_install_name_dir_libraries(/usr/local/lib)
diff --git a/Tests/RunCMake/INSTALL_NAME_DIR/simple_genex-install-check.cmake b/Tests/RunCMake/INSTALL_NAME_DIR/simple_genex-install-check.cmake
new file mode 100644
index 0000000..5f737cb
--- /dev/null
+++ b/Tests/RunCMake/INSTALL_NAME_DIR/simple_genex-install-check.cmake
@@ -0,0 +1 @@
+check_libraries(/usr/local/lib/ /usr/local/lib/ /usr/local/lib/)
diff --git a/Tests/RunCMake/INSTALL_NAME_DIR/simple_genex.cmake b/Tests/RunCMake/INSTALL_NAME_DIR/simple_genex.cmake
new file mode 100644
index 0000000..1e729e8
--- /dev/null
+++ b/Tests/RunCMake/INSTALL_NAME_DIR/simple_genex.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+
+add_install_name_dir_libraries($<1:/usr/local/lib>)
diff --git a/Tests/RunCMake/INSTALL_NAME_DIR/test.c b/Tests/RunCMake/INSTALL_NAME_DIR/test.c
new file mode 100644
index 0000000..c2db61c
--- /dev/null
+++ b/Tests/RunCMake/INSTALL_NAME_DIR/test.c
@@ -0,0 +1,3 @@
+void test(void)
+{
+}
diff --git a/Tests/RunCMake/MacOSVersions/CMakeLists.txt b/Tests/RunCMake/MacOSVersions/CMakeLists.txt
new file mode 100644
index 0000000..2632ffa
--- /dev/null
+++ b/Tests/RunCMake/MacOSVersions/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.16)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/MacOSVersions/MacOSVersions-build-check.cmake b/Tests/RunCMake/MacOSVersions/MacOSVersions-build-check.cmake
new file mode 100644
index 0000000..c4faa8b
--- /dev/null
+++ b/Tests/RunCMake/MacOSVersions/MacOSVersions-build-check.cmake
@@ -0,0 +1,27 @@
+set(cfg_dir)
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(cfg_dir /Debug)
+endif()
+
+set(lib "${RunCMake_TEST_BINARY_DIR}${cfg_dir}/libfoo.1.0.dylib")
+if(NOT EXISTS "${lib}")
+  set(RunCMake_TEST_FAILED "Library file is missing:\n  ${lib}")
+  return()
+endif()
+
+execute_process(COMMAND otool -l "${lib}" OUTPUT_VARIABLE out ERROR_VARIABLE err RESULT_VARIABLE res)
+if(NOT res EQUAL 0)
+  string(REPLACE "\n" "\n  " err "  ${err}")
+  set(RunCMake_TEST_FAILED "Running 'otool -l' on file:\n  ${lib}\nfailed:\n${err}")
+  return()
+endif()
+
+foreach(ver
+    [[current version 3\.2\.1]]
+    [[compatibility version 2\.1\.0]]
+    )
+  if(NOT "${out}" MATCHES "( |\n)${ver}( |\n)")
+    set(RunCMake_TEST_FAILED "Library file:\n  ${lib}\ndoes not contain '${ver}'")
+    return()
+  endif()
+endforeach()
diff --git a/Tests/RunCMake/MacOSVersions/MacOSVersions.cmake b/Tests/RunCMake/MacOSVersions/MacOSVersions.cmake
new file mode 100644
index 0000000..fc51bd8
--- /dev/null
+++ b/Tests/RunCMake/MacOSVersions/MacOSVersions.cmake
@@ -0,0 +1,9 @@
+enable_language(C)
+
+add_library(foo SHARED foo.c)
+set_target_properties(foo PROPERTIES
+  VERSION 1.0
+  SOVERSION 1
+  MACHO_COMPATIBILITY_VERSION 2.1.0
+  MACHO_CURRENT_VERSION 3.2.1
+  )
diff --git a/Tests/RunCMake/MacOSVersions/RunCMakeTest.cmake b/Tests/RunCMake/MacOSVersions/RunCMakeTest.cmake
new file mode 100644
index 0000000..eb7ca48
--- /dev/null
+++ b/Tests/RunCMake/MacOSVersions/RunCMakeTest.cmake
@@ -0,0 +1,11 @@
+include(RunCMake)
+
+function(run_MacOSVersions)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/MacOSVersions-build)
+  run_cmake(MacOSVersions)
+
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(MacOSVersions-build ${CMAKE_COMMAND} --build . --config Debug)
+endfunction()
+
+run_MacOSVersions()
diff --git a/Tests/RunCMake/MacOSVersions/foo.c b/Tests/RunCMake/MacOSVersions/foo.c
new file mode 100644
index 0000000..c83d856
--- /dev/null
+++ b/Tests/RunCMake/MacOSVersions/foo.c
@@ -0,0 +1,4 @@
+int foo(void)
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/Make/RunCMakeTest.cmake b/Tests/RunCMake/Make/RunCMakeTest.cmake
index 82db6b7..6b2721c 100644
--- a/Tests/RunCMake/Make/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Make/RunCMakeTest.cmake
@@ -26,10 +26,13 @@
   endif()
   run_cmake_command(VerboseBuild-build ${CMAKE_COMMAND} --build . -v --clean-first)
   unset(RunCMake-stdout-file)
+  set(_backup_lang "$ENV{LANG}")
   if(MAKE_IS_GNU)
     set(RunCMake-stdout-file VerboseBuild-nowork-gnu-stdout.txt)
+    set(ENV{LANG} "C")
   endif()
   run_cmake_command(VerboseBuild-nowork ${CMAKE_COMMAND} --build . --verbose)
+  set(ENV{LANG} "${_backup_lang}")
 endfunction()
 run_VerboseBuild()
 
diff --git a/Tests/RunCMake/MaxRecursionDepth/variable_watch-default-script-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/variable_watch-default-script-stderr.txt
index 4dddc96..07deee2 100644
--- a/Tests/RunCMake/MaxRecursionDepth/variable_watch-default-script-stderr.txt
+++ b/Tests/RunCMake/MaxRecursionDepth/variable_watch-default-script-stderr.txt
@@ -1,6 +1,6 @@
 [0-9]+
-CMake Error at .*/variable_watch\.cmake:9999 \(update_x\):
+CMake Error at .*/variable_watch\.cmake:[0-9]+ \(update_x\):
   Maximum recursion depth of [0-9]+ exceeded
 Call Stack \(most recent call first\):
   .*/variable_watch\.cmake:5 \(set\)
-  .*/variable_watch\.cmake:9999 \(update_x\)
+  .*/variable_watch\.cmake:[0-9]+ \(update_x\)
diff --git a/Tests/RunCMake/MaxRecursionDepth/variable_watch-default-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/variable_watch-default-stderr.txt
index a8b4756..b2395b3 100644
--- a/Tests/RunCMake/MaxRecursionDepth/variable_watch-default-stderr.txt
+++ b/Tests/RunCMake/MaxRecursionDepth/variable_watch-default-stderr.txt
@@ -1,6 +1,6 @@
 [0-9]+
-CMake Error at variable_watch\.cmake:9999 \(update_x\):
+CMake Error at variable_watch\.cmake:[0-9]+ \(update_x\):
   Maximum recursion depth of [0-9]+ exceeded
 Call Stack \(most recent call first\):
   variable_watch\.cmake:5 \(set\)
-  variable_watch\.cmake:9999 \(update_x\)
+  variable_watch\.cmake:[0-9]+ \(update_x\)
diff --git a/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-var-script-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-var-script-stderr.txt
index 4dddc96..07deee2 100644
--- a/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-var-script-stderr.txt
+++ b/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-var-script-stderr.txt
@@ -1,6 +1,6 @@
 [0-9]+
-CMake Error at .*/variable_watch\.cmake:9999 \(update_x\):
+CMake Error at .*/variable_watch\.cmake:[0-9]+ \(update_x\):
   Maximum recursion depth of [0-9]+ exceeded
 Call Stack \(most recent call first\):
   .*/variable_watch\.cmake:5 \(set\)
-  .*/variable_watch\.cmake:9999 \(update_x\)
+  .*/variable_watch\.cmake:[0-9]+ \(update_x\)
diff --git a/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-var-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-var-stderr.txt
index a8b4756..b2395b3 100644
--- a/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-var-stderr.txt
+++ b/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-var-stderr.txt
@@ -1,6 +1,6 @@
 [0-9]+
-CMake Error at variable_watch\.cmake:9999 \(update_x\):
+CMake Error at variable_watch\.cmake:[0-9]+ \(update_x\):
   Maximum recursion depth of [0-9]+ exceeded
 Call Stack \(most recent call first\):
   variable_watch\.cmake:5 \(set\)
-  variable_watch\.cmake:9999 \(update_x\)
+  variable_watch\.cmake:[0-9]+ \(update_x\)
diff --git a/Tests/RunCMake/MaxRecursionDepth/variable_watch-var-script-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/variable_watch-var-script-stderr.txt
index 00b2b3c..52fedd3 100644
--- a/Tests/RunCMake/MaxRecursionDepth/variable_watch-var-script-stderr.txt
+++ b/Tests/RunCMake/MaxRecursionDepth/variable_watch-var-script-stderr.txt
@@ -2,17 +2,17 @@
 6
 8
 10
-CMake Error at .*/variable_watch\.cmake:9999 \(update_x\):
+CMake Error at .*/variable_watch\.cmake:[0-9]+ \(update_x\):
   Maximum recursion depth of 10 exceeded
 Call Stack \(most recent call first\):
   .*/variable_watch\.cmake:5 \(set\)
-  .*/variable_watch\.cmake:9999 \(update_x\)
+  .*/variable_watch\.cmake:[0-9]+ \(update_x\)
   .*/variable_watch\.cmake:5 \(set\)
-  .*/variable_watch\.cmake:9999 \(update_x\)
+  .*/variable_watch\.cmake:[0-9]+ \(update_x\)
   .*/variable_watch\.cmake:5 \(set\)
-  .*/variable_watch\.cmake:9999 \(update_x\)
+  .*/variable_watch\.cmake:[0-9]+ \(update_x\)
   .*/variable_watch\.cmake:5 \(set\)
-  .*/variable_watch\.cmake:9999 \(update_x\)
+  .*/variable_watch\.cmake:[0-9]+ \(update_x\)
   .*/variable_watch\.cmake:9 \(set\)
   .*/CMakeLists\.txt:5 \(include\)
 
diff --git a/Tests/RunCMake/MaxRecursionDepth/variable_watch-var-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/variable_watch-var-stderr.txt
index 8f27bf1..1427f1d 100644
--- a/Tests/RunCMake/MaxRecursionDepth/variable_watch-var-stderr.txt
+++ b/Tests/RunCMake/MaxRecursionDepth/variable_watch-var-stderr.txt
@@ -2,17 +2,17 @@
 6
 8
 10
-CMake Error at variable_watch\.cmake:9999 \(update_x\):
+CMake Error at variable_watch\.cmake:[0-9]+ \(update_x\):
   Maximum recursion depth of 10 exceeded
 Call Stack \(most recent call first\):
   variable_watch\.cmake:5 \(set\)
-  variable_watch\.cmake:9999 \(update_x\)
+  variable_watch\.cmake:[0-9]+ \(update_x\)
   variable_watch\.cmake:5 \(set\)
-  variable_watch\.cmake:9999 \(update_x\)
+  variable_watch\.cmake:[0-9]+ \(update_x\)
   variable_watch\.cmake:5 \(set\)
-  variable_watch\.cmake:9999 \(update_x\)
+  variable_watch\.cmake:[0-9]+ \(update_x\)
   variable_watch\.cmake:5 \(set\)
-  variable_watch\.cmake:9999 \(update_x\)
+  variable_watch\.cmake:[0-9]+ \(update_x\)
   variable_watch\.cmake:9 \(set\)
   CMakeLists\.txt:5 \(include\)
 
diff --git a/Tests/RunCMake/Ninja/CustomCommandJobPool.cmake b/Tests/RunCMake/Ninja/CustomCommandJobPool.cmake
index 1e36e65..a96802a 100644
--- a/Tests/RunCMake/Ninja/CustomCommandJobPool.cmake
+++ b/Tests/RunCMake/Ninja/CustomCommandJobPool.cmake
@@ -1,3 +1,4 @@
+set_property(GLOBAL PROPERTY JOB_POOLS custom_command_pool=2 custom_target_pool=2)
 add_custom_command(
   OUTPUT hello.copy.c
   COMMAND "${CMAKE_COMMAND}" -E copy
diff --git a/Tests/RunCMake/Ninja/RunCMakeTest.cmake b/Tests/RunCMake/Ninja/RunCMakeTest.cmake
index 808a872..a00d830 100644
--- a/Tests/RunCMake/Ninja/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Ninja/RunCMakeTest.cmake
@@ -1,5 +1,8 @@
 include(RunCMake)
 
+set(RunCMake_GENERATOR "Ninja")
+set(RunCMake_GENERATOR_IS_MULTI_CONFIG 0)
+
 # Detect ninja version so we know what tests can be supported.
 execute_process(
   COMMAND "${RunCMake_MAKE_PROGRAM}" --version
diff --git a/Tests/RunCMake/NinjaMultiConfig/AdditionalCleanFiles-all-clean-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/AdditionalCleanFiles-all-clean-ninja-check.cmake
new file mode 100644
index 0000000..012dc2f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/AdditionalCleanFiles-all-clean-ninja-check.cmake
@@ -0,0 +1,4 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    # Intentionally empty
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/AdditionalCleanFiles-check.cmake b/Tests/RunCMake/NinjaMultiConfig/AdditionalCleanFiles-check.cmake
new file mode 100644
index 0000000..77412f1
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/AdditionalCleanFiles-check.cmake
@@ -0,0 +1,8 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${RunCMake_TEST_BINARY_DIR}/global.txt
+    ${RunCMake_TEST_BINARY_DIR}/Debug.txt
+    ${RunCMake_TEST_BINARY_DIR}/Release.txt
+    ${RunCMake_TEST_BINARY_DIR}/MinSizeRel.txt
+    ${RunCMake_TEST_BINARY_DIR}/RelWithDebInfo.txt
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/AdditionalCleanFiles-release-clean-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/AdditionalCleanFiles-release-clean-build-check.cmake
new file mode 100644
index 0000000..f211223
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/AdditionalCleanFiles-release-clean-build-check.cmake
@@ -0,0 +1,6 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${RunCMake_TEST_BINARY_DIR}/Debug.txt
+    ${RunCMake_TEST_BINARY_DIR}/MinSizeRel.txt
+    ${RunCMake_TEST_BINARY_DIR}/RelWithDebInfo.txt
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/AdditionalCleanFiles.cmake b/Tests/RunCMake/NinjaMultiConfig/AdditionalCleanFiles.cmake
new file mode 100644
index 0000000..983a494
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/AdditionalCleanFiles.cmake
@@ -0,0 +1,3 @@
+file(GENERATE OUTPUT $<CONFIG>.txt CONTENT "$<CONFIG>\n")
+file(TOUCH ${CMAKE_BINARY_DIR}/global.txt)
+set_directory_properties(PROPERTIES ADDITIONAL_CLEAN_FILES "$<CONFIG>.txt;global.txt")
diff --git a/Tests/RunCMake/NinjaMultiConfig/AutoMocExecutable.cmake b/Tests/RunCMake/NinjaMultiConfig/AutoMocExecutable.cmake
new file mode 100644
index 0000000..950e18e
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/AutoMocExecutable.cmake
@@ -0,0 +1,10 @@
+enable_language(C)
+
+add_executable(badmoc badmoc.c)
+target_compile_definitions(badmoc PRIVATE "CONFIG=\"$<CONFIG>\"")
+
+add_executable(exe main.c)
+set_target_properties(exe PROPERTIES
+  AUTOMOC ON
+  AUTOMOC_EXECUTABLE $<TARGET_FILE:badmoc>
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/CMakeLists.txt b/Tests/RunCMake/NinjaMultiConfig/CMakeLists.txt
new file mode 100644
index 0000000..2632ffa
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.16)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/NinjaMultiConfig/Clean-release-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Clean-release-build-check.cmake
new file mode 100644
index 0000000..cfe6984
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Clean-release-build-check.cmake
@@ -0,0 +1,16 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${TARGET_FILE_mylib_Release}
+    ${TARGET_LINKER_FILE_mylib_Release}
+    ${TARGET_SONAME_FILE_mylib_Release}
+    ${TARGET_OBJECT_FILES_mylib_Release}
+
+    ${TARGET_OBJECT_FILES_myobj_Release}
+
+    ${TARGET_FILE_exeall_Release}
+    ${TARGET_EXE_FILE_exeall_Release}
+    ${TARGET_OBJECT_FILES_exeall_Release}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_exenotall_Release}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/Clean-release-clean-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Clean-release-clean-build-check.cmake
new file mode 100644
index 0000000..06b3fb6
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Clean-release-clean-build-check.cmake
@@ -0,0 +1,7 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_exeall_Release}
+    ${TARGET_OBJECT_FILES_exenotall_Release}
+    ${TARGET_OBJECT_FILES_mylib_Release}
+    ${TARGET_OBJECT_FILES_myobj_Release}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/Clean-release-notall-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Clean-release-notall-ninja-check.cmake
new file mode 100644
index 0000000..42d6a78
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Clean-release-notall-ninja-check.cmake
@@ -0,0 +1,16 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${TARGET_FILE_mylib_Release}
+    ${TARGET_LINKER_FILE_mylib_Release}
+    ${TARGET_SONAME_FILE_mylib_Release}
+    ${TARGET_OBJECT_FILES_mylib_Release}
+
+    ${TARGET_OBJECT_FILES_myobj_Release}
+
+    ${TARGET_FILE_exeall_Release}
+    ${TARGET_EXE_FILE_exeall_Release}
+    ${TARGET_OBJECT_FILES_exeall_Release}
+
+    ${TARGET_FILE_exenotall_Release}
+    ${TARGET_OBJECT_FILES_exenotall_Release}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/Clean.cmake b/Tests/RunCMake/NinjaMultiConfig/Clean.cmake
new file mode 100644
index 0000000..2258d2b
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Clean.cmake
@@ -0,0 +1,17 @@
+enable_language(C)
+
+add_executable(exeall main.c)
+set_target_properties(exeall PROPERTIES VERSION 1.0.0)
+add_executable(exenotall main.c)
+set_target_properties(exenotall PROPERTIES EXCLUDE_FROM_ALL TRUE)
+
+add_library(mylib SHARED simplelib.c)
+set_target_properties(mylib PROPERTIES
+  VERSION 1.0.0
+  SOVERSION 1
+  )
+
+add_library(myobj OBJECT simplelib.c)
+
+include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake)
+generate_output_files(exeall exenotall mylib myobj)
diff --git a/Tests/RunCMake/NinjaMultiConfig/Common.cmake b/Tests/RunCMake/NinjaMultiConfig/Common.cmake
new file mode 100644
index 0000000..6c0d82a
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Common.cmake
@@ -0,0 +1,62 @@
+function(generate_output_files)
+  set(content)
+  foreach(tgt IN LISTS ARGN)
+    get_property(type TARGET ${tgt} PROPERTY TYPE)
+
+    if(NOT type STREQUAL "OBJECT_LIBRARY")
+      set(file " [==[$<TARGET_FILE:${tgt}>]==]")
+      set(filename " [==[$<TARGET_FILE_NAME:${tgt}>]==]")
+    else()
+      set(file)
+      set(filename)
+    endif()
+    string(APPEND content "set(TARGET_FILE_${tgt}_$<CONFIG>${file})\n")
+    string(APPEND content "set(TARGET_FILE_NAME_${tgt}_$<CONFIG>${filename})\n")
+
+    if(type MATCHES "^(STATIC|MODULE|SHARED)_LIBRARY$")
+      set(linker_file " [==[$<TARGET_LINKER_FILE:${tgt}>]==]")
+      set(linker_filename " [==[$<TARGET_LINKER_FILE_NAME:${tgt}>]==]")
+    else()
+      set(linker_file)
+      set(linker_filename)
+    endif()
+    string(APPEND content "set(TARGET_LINKER_FILE_${tgt}_$<CONFIG>${linker_file})\n")
+    string(APPEND content "set(TARGET_LINKER_FILE_NAME_${tgt}_$<CONFIG>${linker_filename})\n")
+
+    if(NOT WIN32 AND NOT CYGWIN AND type MATCHES "^(SHARED_LIBRARY)$")
+      set(soname_file " [==[$<TARGET_SONAME_FILE:${tgt}>]==]")
+      set(soname_filename " [==[$<TARGET_SONAME_FILE_NAME:${tgt}>]==]")
+    else()
+      set(soname_file)
+      set(soname_filename)
+    endif()
+    string(APPEND content "set(TARGET_SONAME_FILE_${tgt}_$<CONFIG>${soname_file})\n")
+    string(APPEND content "set(TARGET_SONAME_FILE_NAME_${tgt}_$<CONFIG>${soname_filename})\n")
+
+    if(type MATCHES "^(EXECUTABLE)$")
+      set(exe_file " [==[$<TARGET_FILE_DIR:${tgt}>/$<TARGET_FILE_PREFIX:${tgt}>$<TARGET_FILE_BASE_NAME:${tgt}>$<TARGET_FILE_SUFFIX:${tgt}>]==]")
+      set(exe_filename " [==[$<TARGET_FILE_PREFIX:${tgt}>$<TARGET_FILE_BASE_NAME:${tgt}>$<TARGET_FILE_SUFFIX:${tgt}>]==]")
+
+      if(WIN32)
+        set(exe_lib_file " [==[$<TARGET_FILE_DIR:${tgt}>/$<TARGET_FILE_PREFIX:${tgt}>$<TARGET_FILE_BASE_NAME:${tgt}>.lib]==]")
+        string(APPEND content "set(TARGET_EXE_LIB_FILE_${tgt}_$<CONFIG>${exe_lib_file})\n")
+      endif()
+    else()
+      set(exe_file)
+      set(exe_filename)
+    endif()
+    string(APPEND content "set(TARGET_EXE_FILE_${tgt}_$<CONFIG>${exe_file})\n")
+    string(APPEND content "set(TARGET_EXE_FILE_NAME_${tgt}_$<CONFIG>${exe_filename})\n")
+
+    string(APPEND content "set(TARGET_OBJECT_FILES_${tgt}_$<CONFIG> [==[$<TARGET_OBJECTS:${tgt}>]==])\n")
+  endforeach()
+
+  file(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/target_files_$<CONFIG>.cmake" CONTENT "${content}")
+
+  set(content)
+  foreach(config IN LISTS CMAKE_CONFIGURATION_TYPES)
+    string(APPEND content "include(\${CMAKE_CURRENT_LIST_DIR}/target_files_${config}.cmake)\n")
+  endforeach()
+
+  file(WRITE "${CMAKE_BINARY_DIR}/target_files.cmake" "${content}")
+endfunction()
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..39db5ff
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CudaSimple-debug-target-build-check.cmake
@@ -0,0 +1,28 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simplecudaexe_Debug}
+    ${TARGET_EXE_LIB_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/CustomCommandDepfile-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile-check.cmake
new file mode 100644
index 0000000..c595b10
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile-check.cmake
@@ -0,0 +1,5 @@
+set(log "${RunCMake_BINARY_DIR}/CustomCommandDepfile-build/CMakeFiles/impl-Debug.ninja")
+file(READ "${log}" build_file)
+if(NOT "${build_file}" MATCHES "depfile = test\\.d")
+  set(RunCMake_TEST_FAILED "Log file:\n ${log}\ndoes not have expected line: depfile = test.d")
+endif()
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile.cmake
new file mode 100644
index 0000000..1a42670
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile.cmake
@@ -0,0 +1,9 @@
+add_custom_command(
+  OUTPUT main.copy.c
+  COMMAND "${CMAKE_COMMAND}" -E copy
+          "${CMAKE_CURRENT_SOURCE_DIR}/main.c"
+          main.copy.c
+  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+  DEPFILE "test.d"
+  )
+add_custom_target(copy ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/main.copy.c")
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-build-check.cmake
new file mode 100644
index 0000000..2abdb43
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-build-check.cmake
@@ -0,0 +1,38 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${CONFIG_FILES}
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_generator_Debug}
+    ${TARGET_OBJECT_FILES_generator_Debug}
+
+    ${TARGET_FILE_generated_Debug}
+    ${TARGET_OBJECT_FILES_generated_Debug}
+
+    ${TARGET_FILE_generatorlib_Debug}
+    ${TARGET_LINKER_FILE_generatorlib_Debug}
+    ${TARGET_OBJECT_FILES_generatorlib_Debug}
+
+    ${TARGET_OBJECT_FILES_generatorobj_Debug}
+
+    ${TARGET_OBJECT_FILES_emptyobj_Debug}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_generator_Release}
+    ${TARGET_OBJECT_FILES_generated_Release}
+    ${TARGET_OBJECT_FILES_generatorlib_Release}
+    ${TARGET_OBJECT_FILES_generatorobj_Release}
+    ${TARGET_OBJECT_FILES_emptyobj_Release}
+
+    ${TARGET_OBJECT_FILES_generator_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generated_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generatorlib_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generatorobj_MinSizeRel}
+    ${TARGET_OBJECT_FILES_emptyobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_generator_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generated_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generatorlib_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generatorobj_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_emptyobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-clean-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-clean-ninja-check.cmake
new file mode 100644
index 0000000..aff42c3
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-clean-ninja-check.cmake
@@ -0,0 +1,37 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${CONFIG_FILES}
+
+    ${TARGET_FILE_generator_Release}
+    ${TARGET_OBJECT_FILES_generator_Release}
+
+    ${TARGET_FILE_generated_Release}
+    ${TARGET_OBJECT_FILES_generated_Release}
+
+    ${TARGET_FILE_generatorlib_Release}
+    ${TARGET_LINKER_FILE_generatorlib_Release}
+    ${TARGET_OBJECT_FILES_generatorlib_Release}
+
+    ${TARGET_OBJECT_FILES_generatorobj_Release}
+
+    ${TARGET_OBJECT_FILES_emptyobj_Release}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_generator_Debug}
+    ${TARGET_OBJECT_FILES_generated_Debug}
+    ${TARGET_OBJECT_FILES_generatorlib_Debug}
+    ${TARGET_OBJECT_FILES_generatorobj_Debug}
+    ${TARGET_OBJECT_FILES_emptyobj_Debug}
+
+    ${TARGET_OBJECT_FILES_generator_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generated_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generatorlib_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generatorobj_MinSizeRel}
+    ${TARGET_OBJECT_FILES_emptyobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_generator_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generated_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generatorlib_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generatorobj_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_emptyobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-generated-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-generated-stdout.txt
new file mode 100644
index 0000000..765d486
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-generated-stdout.txt
@@ -0,0 +1,12 @@
+^Generator genex config definition: Debug
+Generator genex config include dir: Debug
+Generator library genex config definition: Debug
+Generator library genex config include dir: Debug
+Generator object genex config definition: Debug
+Generator object genex config include dir: Debug
+Generated genex config definition: Debug
+Generated genex config include dir: Debug
+Generated library genex config definition: Debug
+Generated library genex config include dir: Debug
+Generated object genex config definition: Debug
+Generated object genex config include dir: Debug$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-in-release-graph-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-in-release-graph-build-check.cmake
new file mode 100644
index 0000000..167f5b9
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-in-release-graph-build-check.cmake
@@ -0,0 +1,43 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${CONFIG_FILES}
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_generated_Debug}
+    ${TARGET_OBJECT_FILES_generated_Debug}
+
+    ${TARGET_FILE_generatorlib_Debug}
+    ${TARGET_LINKER_FILE_generatorlib_Debug}
+    ${TARGET_OBJECT_FILES_generatorlib_Debug}
+
+    ${TARGET_OBJECT_FILES_generatorobj_Debug}
+
+    ${TARGET_OBJECT_FILES_emptyobj_Debug}
+
+    ${TARGET_FILE_generator_Release}
+    ${TARGET_OBJECT_FILES_generator_Release}
+
+    ${TARGET_FILE_generatorlib_Release}
+    ${TARGET_LINKER_FILE_generatorlib_Release}
+    ${TARGET_OBJECT_FILES_generatorlib_Release}
+
+    ${TARGET_OBJECT_FILES_generatorobj_Release}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_generator_Debug}
+
+    ${TARGET_OBJECT_FILES_generated_Release}
+    ${TARGET_OBJECT_FILES_emptyobj_Release}
+
+    ${TARGET_OBJECT_FILES_generator_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generated_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generatorlib_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generatorobj_MinSizeRel}
+    ${TARGET_OBJECT_FILES_emptyobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_generator_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generated_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generatorlib_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generatorobj_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_emptyobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-in-release-graph-clean-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-in-release-graph-clean-ninja-check.cmake
new file mode 100644
index 0000000..1e4cbe1
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-in-release-graph-clean-ninja-check.cmake
@@ -0,0 +1,35 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${CONFIG_FILES}
+
+    ${TARGET_FILE_generator_Release}
+    ${TARGET_OBJECT_FILES_generator_Release}
+
+    ${TARGET_FILE_generatorlib_Release}
+    ${TARGET_LINKER_FILE_generatorlib_Release}
+    ${TARGET_OBJECT_FILES_generatorlib_Release}
+
+    ${TARGET_OBJECT_FILES_generatorobj_Release}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_generator_Debug}
+    ${TARGET_OBJECT_FILES_generated_Debug}
+    ${TARGET_OBJECT_FILES_generatorlib_Debug}
+    ${TARGET_OBJECT_FILES_generatorobj_Debug}
+    ${TARGET_OBJECT_FILES_emptyobj_Debug}
+
+    ${TARGET_OBJECT_FILES_generated_Release}
+    ${TARGET_OBJECT_FILES_emptyobj_Release}
+
+    ${TARGET_OBJECT_FILES_generator_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generated_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generatorlib_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generatorobj_MinSizeRel}
+    ${TARGET_OBJECT_FILES_emptyobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_generator_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generated_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generatorlib_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generatorobj_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_emptyobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-in-release-graph-generated-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-in-release-graph-generated-stdout.txt
new file mode 100644
index 0000000..1c9abef
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-debug-in-release-graph-generated-stdout.txt
@@ -0,0 +1,12 @@
+^Generator genex config definition: Release
+Generator genex config include dir: Release
+Generator library genex config definition: Release
+Generator library genex config include dir: Release
+Generator object genex config definition: Release
+Generator object genex config include dir: Release
+Generated genex config definition: Debug
+Generated genex config include dir: Debug
+Generated library genex config definition: Debug
+Generated library genex config include dir: Debug
+Generated object genex config definition: Debug
+Generated object genex config include dir: Debug$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-clean-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-clean-build-check.cmake
new file mode 100644
index 0000000..8ba6d68
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-clean-build-check.cmake
@@ -0,0 +1,29 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${CONFIG_FILES}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_generator_Debug}
+    ${TARGET_OBJECT_FILES_generated_Debug}
+    ${TARGET_OBJECT_FILES_generatorlib_Debug}
+    ${TARGET_OBJECT_FILES_generatorobj_Debug}
+    ${TARGET_OBJECT_FILES_emptyobj_Debug}
+
+    ${TARGET_OBJECT_FILES_generator_Release}
+    ${TARGET_OBJECT_FILES_generated_Release}
+    ${TARGET_OBJECT_FILES_generatorlib_Release}
+    ${TARGET_OBJECT_FILES_generatorobj_Release}
+    ${TARGET_OBJECT_FILES_emptyobj_Release}
+
+    ${TARGET_OBJECT_FILES_generator_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generated_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generatorlib_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generatorobj_MinSizeRel}
+    ${TARGET_OBJECT_FILES_emptyobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_generator_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generated_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generatorlib_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generatorobj_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_emptyobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-generated-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-generated-stdout.txt
new file mode 100644
index 0000000..576ec51
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-generated-stdout.txt
@@ -0,0 +1,12 @@
+^Generator genex config definition: Release
+Generator genex config include dir: Release
+Generator library genex config definition: Release
+Generator library genex config include dir: Release
+Generator object genex config definition: Release
+Generator object genex config include dir: Release
+Generated genex config definition: Release
+Generated genex config include dir: Release
+Generated library genex config definition: Release
+Generated library genex config include dir: Release
+Generated object genex config definition: Release
+Generated object genex config include dir: Release$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-in-debug-graph-generated-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-in-debug-graph-generated-stdout.txt
new file mode 100644
index 0000000..25392af
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-in-debug-graph-generated-stdout.txt
@@ -0,0 +1,12 @@
+^Generator genex config definition: Debug
+Generator genex config include dir: Debug
+Generator library genex config definition: Debug
+Generator library genex config include dir: Debug
+Generator object genex config definition: Debug
+Generator object genex config include dir: Debug
+Generated genex config definition: Release
+Generated genex config include dir: Release
+Generated library genex config definition: Release
+Generated library genex config include dir: Release
+Generated object genex config definition: Release
+Generated object genex config include dir: Release$
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-in-debug-graph-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-in-debug-graph-ninja-check.cmake
new file mode 100644
index 0000000..faf392e
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-in-debug-graph-ninja-check.cmake
@@ -0,0 +1,44 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${CONFIG_FILES}
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_generator_Debug}
+    ${TARGET_OBJECT_FILES_generator_Debug}
+
+    ${TARGET_FILE_generatorlib_Debug}
+    ${TARGET_LINKER_FILE_generatorlib_Debug}
+    ${TARGET_OBJECT_FILES_generatorlib_Debug}
+
+    ${TARGET_OBJECT_FILES_generatorobj_Debug}
+
+    ${TARGET_FILE_generator_Release}
+    ${TARGET_OBJECT_FILES_generator_Release}
+
+    ${TARGET_FILE_generated_Release}
+    ${TARGET_OBJECT_FILES_generated_Release}
+
+    ${TARGET_FILE_generatorlib_Release}
+    ${TARGET_LINKER_FILE_generatorlib_Release}
+    ${TARGET_OBJECT_FILES_generatorlib_Release}
+
+    ${TARGET_OBJECT_FILES_generatorobj_Release}
+
+    ${TARGET_OBJECT_FILES_emptyobj_Release}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_generated_Debug}
+    ${TARGET_OBJECT_FILES_emptyobj_Debug}
+
+    ${TARGET_OBJECT_FILES_generator_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generated_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generatorlib_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generatorobj_MinSizeRel}
+    ${TARGET_OBJECT_FILES_emptyobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_generator_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generated_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generatorlib_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generatorobj_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_emptyobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-ninja-check.cmake
new file mode 100644
index 0000000..b51a6a7
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator-release-ninja-check.cmake
@@ -0,0 +1,46 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${CONFIG_FILES}
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_generator_Debug}
+    ${TARGET_OBJECT_FILES_generator_Debug}
+
+    ${TARGET_FILE_generated_Debug}
+    ${TARGET_OBJECT_FILES_generated_Debug}
+
+    ${TARGET_FILE_generatorlib_Debug}
+    ${TARGET_LINKER_FILE_generatorlib_Debug}
+    ${TARGET_OBJECT_FILES_generatorlib_Debug}
+
+    ${TARGET_OBJECT_FILES_generatorobj_Debug}
+
+    ${TARGET_OBJECT_FILES_emptyobj_Debug}
+
+    ${TARGET_FILE_generator_Release}
+    ${TARGET_OBJECT_FILES_generator_Release}
+
+    ${TARGET_FILE_generated_Release}
+    ${TARGET_OBJECT_FILES_generated_Release}
+
+    ${TARGET_FILE_generatorlib_Release}
+    ${TARGET_LINKER_FILE_generatorlib_Release}
+    ${TARGET_OBJECT_FILES_generatorlib_Release}
+
+    ${TARGET_OBJECT_FILES_generatorobj_Release}
+
+    ${TARGET_OBJECT_FILES_emptyobj_Release}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_generator_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generated_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generatorlib_MinSizeRel}
+    ${TARGET_OBJECT_FILES_generatorobj_MinSizeRel}
+    ${TARGET_OBJECT_FILES_emptyobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_generator_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generated_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generatorlib_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_generatorobj_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_emptyobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator.cmake
new file mode 100644
index 0000000..f4aca5e
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandGenerator.cmake
@@ -0,0 +1,56 @@
+enable_language(C)
+
+add_library(generatorlib STATIC generatorlib.c)
+add_library(generatorobj OBJECT generatorobj.c)
+add_library(emptyobj OBJECT empty.c)
+add_library(emptyobj2 OBJECT empty.c)
+
+add_executable(generator generator.c $<TARGET_OBJECTS:generatorobj>)
+target_link_libraries(generator PRIVATE generatorlib)
+
+add_custom_command(OUTPUT generated.c COMMAND generator generated.c)
+add_executable(generated ${CMAKE_BINARY_DIR}/generated.c $<TARGET_OBJECTS:generatorobj> $<TARGET_OBJECTS:emptyobj>)
+target_link_libraries(generated PRIVATE generatorlib)
+
+file(GENERATE OUTPUT include/genex/$<CONFIG>/genex_config.h CONTENT
+"#ifndef GENEX_CONFIG_H
+#define GENEX_CONFIG_H
+
+#define GENEX_CONFIG_INCLUDE_DIR \"$<CONFIG>\"
+
+#endif /* GENEX_CONFIG_H */
+")
+file(GENERATE OUTPUT include/intdir/$<CONFIG>/intdir_config.h CONTENT
+"#ifndef INTDIR_CONFIG_H
+#define INTDIR_CONFIG_H
+
+#define INTDIR_CONFIG_INCLUDE_DIR \"$<CONFIG>\"
+
+#endif /* INTDIR_CONFIG_H */
+")
+
+foreach(g generatorlib generatorobj generator generated)
+  target_compile_definitions(${g} PRIVATE
+    "GENEX_CONFIG_DEFINITION=\"$<CONFIG>\""
+  # FIXME Get this working
+  #  "INTDIR_CONFIG_DEFINITION=\"${CMAKE_CFG_INTDIR}\""
+    )
+  target_include_directories(${g} PRIVATE
+    "${CMAKE_BINARY_DIR}/include/genex/$<CONFIG>"
+  # FIXME Get this working
+  #  "${CMAKE_BINARY_DIR}/include/intdir/${CMAKE_CFG_INTDIR}"
+    )
+endforeach()
+
+include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake)
+generate_output_files(generatorlib generatorobj emptyobj generator generated)
+
+file(APPEND "${CMAKE_BINARY_DIR}/target_files.cmake" "set(GENERATED_FILES [==[${CMAKE_BINARY_DIR}/generated.c]==])\n")
+set(genfiles)
+foreach(cfg Debug Release MinSizeRel RelWithDebInfo)
+  list(APPEND genfiles
+    ${CMAKE_BINARY_DIR}/include/genex/${cfg}/genex_config.h
+    ${CMAKE_BINARY_DIR}/include/intdir/${cfg}/intdir_config.h
+    )
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/target_files.cmake" "set(CONFIG_FILES [==[${genfiles}]==])\n")
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-debug-command-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-debug-command-ninja-check.cmake
new file mode 100644
index 0000000..f5c4020
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-debug-command-ninja-check.cmake
@@ -0,0 +1,6 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${TARGET_DEPENDS_SubdirCommand}
+    ${TARGET_DEPENDS_TopCommand}
+  )
+check_file_contents("${TARGET_DEPENDS_TopCommand}" "^Genex config: Debug\nINTDIR config: Debug\n$")
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-debug-in-release-graph-postbuild-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-debug-in-release-graph-postbuild-build-check.cmake
new file mode 100644
index 0000000..05861b2
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-debug-in-release-graph-postbuild-build-check.cmake
@@ -0,0 +1,8 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${TARGET_DEPENDS_SubdirCommand}
+    ${TARGET_DEPENDS_TopCommand}
+    ${TARGET_BYPRODUCTS_SubdirTarget}
+    ${TARGET_BYPRODUCTS_TopTarget}
+    ${TARGET_FILE_SubdirPostBuild_Debug}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-debug-target-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-debug-target-build-check.cmake
new file mode 100644
index 0000000..52895b2
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-debug-target-build-check.cmake
@@ -0,0 +1,8 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${TARGET_DEPENDS_SubdirCommand}
+    ${TARGET_DEPENDS_TopCommand}
+    ${TARGET_BYPRODUCTS_SubdirTarget}
+    ${TARGET_BYPRODUCTS_TopTarget}
+  )
+check_file_contents("${TARGET_BYPRODUCTS_TopTarget}" "^Genex config: Debug\nINTDIR config: Debug\n$")
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-debug-targetpostbuild-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-debug-targetpostbuild-build-check.cmake
new file mode 100644
index 0000000..80439ea
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-debug-targetpostbuild-build-check.cmake
@@ -0,0 +1,12 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${TARGET_DEPENDS_SubdirCommand}
+    ${TARGET_DEPENDS_TopCommand}
+    ${TARGET_BYPRODUCTS_SubdirTarget}
+    ${TARGET_BYPRODUCTS_TopTarget}
+    ${TARGET_FILE_SubdirPostBuild_Debug}
+    ${TARGET_FILE_SubdirPostBuild_Release}
+    ${TARGET_BYPRODUCTS_SubdirPostBuild}
+    ${TARGET_BYPRODUCTS_TopTargetPostBuild}
+  )
+check_file_contents("${TARGET_BYPRODUCTS_TopTargetPostBuild}" "^Genex config: Debug\nINTDIR config: Debug\n$")
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-minsizerel-command-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-minsizerel-command-ninja-check.cmake
new file mode 100644
index 0000000..2813f02
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-minsizerel-command-ninja-check.cmake
@@ -0,0 +1,5 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${TARGET_DEPENDS_SubdirCommand}
+  )
+check_file_contents("${TARGET_DEPENDS_SubdirCommand}" "^Genex config: MinSizeRel\nINTDIR config: MinSizeRel\n$")
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-command-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-command-build-check.cmake
new file mode 100644
index 0000000..2da9735
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-command-build-check.cmake
@@ -0,0 +1,5 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${TARGET_DEPENDS_SubdirCommand}
+  )
+check_file_contents("${TARGET_DEPENDS_SubdirCommand}" "^Genex config: Release\nINTDIR config: Release\n$")
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-postbuild-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-postbuild-ninja-check.cmake
new file mode 100644
index 0000000..0916b90
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-postbuild-ninja-check.cmake
@@ -0,0 +1,11 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${TARGET_DEPENDS_SubdirCommand}
+    ${TARGET_DEPENDS_TopCommand}
+    ${TARGET_BYPRODUCTS_SubdirTarget}
+    ${TARGET_BYPRODUCTS_TopTarget}
+    ${TARGET_FILE_SubdirPostBuild_Debug}
+    ${TARGET_FILE_SubdirPostBuild_Release}
+    ${TARGET_BYPRODUCTS_SubdirPostBuild}
+  )
+check_file_contents("${TARGET_BYPRODUCTS_SubdirPostBuild}" "^Genex config: Release\nINTDIR config: Release\n$")
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-target-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-target-ninja-check.cmake
new file mode 100644
index 0000000..87e78b4
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-target-ninja-check.cmake
@@ -0,0 +1,7 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${TARGET_DEPENDS_SubdirCommand}
+    ${TARGET_DEPENDS_TopCommand}
+    ${TARGET_BYPRODUCTS_SubdirTarget}
+  )
+check_file_contents("${TARGET_BYPRODUCTS_SubdirTarget}" "^Genex config: Release\nINTDIR config: Release\n$")
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-targetpostbuild-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-targetpostbuild-ninja-check.cmake
new file mode 100644
index 0000000..f67d5be
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets-release-targetpostbuild-ninja-check.cmake
@@ -0,0 +1,13 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${TARGET_DEPENDS_SubdirCommand}
+    ${TARGET_DEPENDS_TopCommand}
+    ${TARGET_BYPRODUCTS_SubdirTarget}
+    ${TARGET_BYPRODUCTS_TopTarget}
+    ${TARGET_FILE_SubdirPostBuild_Debug}
+    ${TARGET_FILE_SubdirPostBuild_Release}
+    ${TARGET_BYPRODUCTS_SubdirPostBuild}
+    ${TARGET_BYPRODUCTS_TopTargetPostBuild}
+    ${TARGET_BYPRODUCTS_SubdirTargetPostBuild}
+  )
+check_file_contents("${TARGET_BYPRODUCTS_SubdirTargetPostBuild}" "^Genex config: Release\nINTDIR config: Release\n$")
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets.cmake
new file mode 100644
index 0000000..b2b24e8
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets.cmake
@@ -0,0 +1,39 @@
+enable_language(C)
+
+file(REMOVE "${CMAKE_BINARY_DIR}/target_files_custom.cmake")
+
+function(get_write_file_command var filename)
+  set(${var} ${CMAKE_COMMAND} -DOUTPUT_FILE=${filename} -DGENEX_CONFIG=$<CONFIG> -DINTDIR_CONFIG=${CMAKE_CFG_INTDIR} -P ${CMAKE_SOURCE_DIR}/WriteFile.cmake PARENT_SCOPE)
+endfunction()
+
+function(create_targets prefix)
+  get_write_file_command(cmd ${prefix}Command.txt)
+  add_custom_command(OUTPUT ${prefix}Command.txt COMMAND ${cmd})
+  add_custom_target(${prefix}Command DEPENDS ${prefix}Command.txt)
+
+  get_write_file_command(cmd ${prefix}Target.txt)
+  add_custom_target(${prefix}Target COMMAND ${cmd} BYPRODUCTS ${prefix}Target.txt)
+
+  get_write_file_command(cmd ${prefix}PostBuild.txt)
+  add_executable(${prefix}PostBuild ${CMAKE_SOURCE_DIR}/main.c)
+  add_custom_command(TARGET ${prefix}PostBuild COMMAND ${cmd} BYPRODUCTS ${prefix}PostBuild.txt)
+
+  get_write_file_command(cmd ${prefix}TargetPostBuild.txt)
+  add_custom_target(${prefix}TargetPostBuild)
+  add_custom_command(TARGET ${prefix}TargetPostBuild COMMAND ${cmd} BYPRODUCTS ${prefix}TargetPostBuild.txt)
+
+  file(APPEND "${CMAKE_BINARY_DIR}/target_files_custom.cmake"
+"set(TARGET_DEPENDS_${prefix}Command [==[${CMAKE_CURRENT_BINARY_DIR}/${prefix}Command.txt]==])
+set(TARGET_BYPRODUCTS_${prefix}Target [==[${CMAKE_CURRENT_BINARY_DIR}/${prefix}Target.txt]==])
+set(TARGET_BYPRODUCTS_${prefix}PostBuild [==[${CMAKE_CURRENT_BINARY_DIR}/${prefix}PostBuild.txt]==])
+set(TARGET_BYPRODUCTS_${prefix}TargetPostBuild [==[${CMAKE_CURRENT_BINARY_DIR}/${prefix}TargetPostBuild.txt]==])
+")
+endfunction()
+
+add_subdirectory(CustomCommandsAndTargetsSubdir)
+
+create_targets(Top)
+
+include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake)
+generate_output_files(TopPostBuild SubdirPostBuild)
+file(APPEND "${CMAKE_BINARY_DIR}/target_files.cmake" "include(\${CMAKE_CURRENT_LIST_DIR}/target_files_custom.cmake)\n")
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargetsSubdir/CMakeLists.txt b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargetsSubdir/CMakeLists.txt
new file mode 100644
index 0000000..894e3ed
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargetsSubdir/CMakeLists.txt
@@ -0,0 +1 @@
+create_targets(Subdir)
diff --git a/Tests/RunCMake/NinjaMultiConfig/DefaultBuildFileConfig.cmake b/Tests/RunCMake/NinjaMultiConfig/DefaultBuildFileConfig.cmake
new file mode 100644
index 0000000..bb7b160
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/DefaultBuildFileConfig.cmake
@@ -0,0 +1 @@
+# Intentionally empty
diff --git a/Tests/RunCMake/NinjaMultiConfig/Framework.cmake b/Tests/RunCMake/NinjaMultiConfig/Framework.cmake
new file mode 100644
index 0000000..b4c35f6
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Framework.cmake
@@ -0,0 +1,22 @@
+enable_language(C)
+
+set(header "${CMAKE_CURRENT_BINARY_DIR}/header.h")
+file(GENERATE
+  OUTPUT "${header}"
+  CONTENT "/* foo */"
+  CONDITION "$<CONFIG:Release>"
+  )
+add_library(framework SHARED "${header}" empty.c)
+
+set_property(TARGET framework PROPERTY FRAMEWORK ON)
+set_property(TARGET framework APPEND PROPERTY PUBLIC_HEADER ${header})
+
+set_target_properties(framework PROPERTIES
+  LIBRARY_OUTPUT_DIRECTORY "lib"
+  LIBRARY_OUTPUT_DIRECTORY_DEBUG "lib"
+  LIBRARY_OUTPUT_DIRECTORY_RELEASE "lib"
+  DEBUG_POSTFIX "_debug"
+  )
+
+include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake)
+generate_output_files(framework)
diff --git a/Tests/RunCMake/NinjaMultiConfig/FrameworkDependencyAutogen.cmake b/Tests/RunCMake/NinjaMultiConfig/FrameworkDependencyAutogen.cmake
new file mode 100644
index 0000000..75e21b9
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/FrameworkDependencyAutogen.cmake
@@ -0,0 +1,20 @@
+enable_language(C)
+
+set(CMAKE_LINK_DEPENDS_NO_SHARED ON)
+
+set(QT_VERSION_MAJOR 6)
+set(fake_moc_path "${CMAKE_CURRENT_BINARY_DIR}/fake_moc")
+file(WRITE "${fake_moc_path}" "")
+
+add_library(test1 SHARED simplelib.c)
+add_library(test2 SHARED empty.c)
+target_link_libraries(test2 test1)
+
+set_target_properties(test1 test2 PROPERTIES
+  FRAMEWORK ON
+  AUTOMOC ON
+  AUTOMOC_EXECUTABLE "${fake_moc_path}"
+  )
+
+include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake)
+generate_output_files(test1 test2)
diff --git a/Tests/RunCMake/NinjaMultiConfig/Install-debug-in-release-graph-install-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Install-debug-in-release-graph-install-ninja-check.cmake
new file mode 100644
index 0000000..bc15a25
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Install-debug-in-release-graph-install-ninja-check.cmake
@@ -0,0 +1,31 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${TARGET_FILE_exe_Debug}
+    ${TARGET_OBJECT_FILES_exe_Debug}
+
+    ${TARGET_FILE_mylib_Release}
+    ${TARGET_LINKER_FILE_mylib_Debug}
+    ${TARGET_OBJECT_FILES_mylib_Debug}
+
+    ${RunCMake_TEST_BINARY_DIR}/install/bin/Debug/${TARGET_FILE_NAME_exe_Debug}
+    ${RunCMake_TEST_BINARY_DIR}/install/lib/Debug/${TARGET_FILE_NAME_mylib_Debug}
+    ${RunCMake_TEST_BINARY_DIR}/install/lib/Debug/${TARGET_LINKER_FILE_NAME_mylib_Debug}
+
+    ${TARGET_FILE_exe_Release}
+    ${TARGET_OBJECT_FILES_exe_Release}
+
+    ${TARGET_FILE_mylib_Release}
+    ${TARGET_LINKER_FILE_mylib_Release}
+    ${TARGET_OBJECT_FILES_mylib_Release}
+
+    ${RunCMake_TEST_BINARY_DIR}/install/bin/Release/${TARGET_FILE_NAME_exe_Release}
+    ${RunCMake_TEST_BINARY_DIR}/install/lib/Release/${TARGET_FILE_NAME_mylib_Release}
+    ${RunCMake_TEST_BINARY_DIR}/install/lib/Release/${TARGET_LINKER_FILE_NAME_mylib_Release}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_exe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_mylib_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_exe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_mylib_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/Install-release-install-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Install-release-install-build-check.cmake
new file mode 100644
index 0000000..3280c89
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Install-release-install-build-check.cmake
@@ -0,0 +1,23 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${TARGET_FILE_exe_Release}
+    ${TARGET_OBJECT_FILES_exe_Release}
+
+    ${TARGET_FILE_mylib_Release}
+    ${TARGET_LINKER_FILE_mylib_Release}
+    ${TARGET_OBJECT_FILES_mylib_Release}
+
+    ${RunCMake_TEST_BINARY_DIR}/install/bin/Release/${TARGET_FILE_NAME_exe_Release}
+    ${RunCMake_TEST_BINARY_DIR}/install/lib/Release/${TARGET_FILE_NAME_mylib_Release}
+    ${RunCMake_TEST_BINARY_DIR}/install/lib/Release/${TARGET_LINKER_FILE_NAME_mylib_Release}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_exe_Debug}
+    ${TARGET_OBJECT_FILES_mylib_Debug}
+
+    ${TARGET_OBJECT_FILES_exe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_mylib_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_exe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_mylib_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/Install.cmake b/Tests/RunCMake/NinjaMultiConfig/Install.cmake
new file mode 100644
index 0000000..e26e3e0
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Install.cmake
@@ -0,0 +1,10 @@
+enable_language(C)
+
+add_executable(exe main.c)
+add_library(mylib STATIC simplelib.c)
+
+install(TARGETS exe DESTINATION bin/$<CONFIG>)
+install(TARGETS mylib DESTINATION lib/$<CONFIG>)
+
+include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake)
+generate_output_files(exe mylib)
diff --git a/Tests/RunCMake/NinjaMultiConfig/InvalidCrossConfigs-result.txt b/Tests/RunCMake/NinjaMultiConfig/InvalidCrossConfigs-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/InvalidCrossConfigs-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/NinjaMultiConfig/InvalidCrossConfigs-stderr.txt b/Tests/RunCMake/NinjaMultiConfig/InvalidCrossConfigs-stderr.txt
new file mode 100644
index 0000000..76c5ecf
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/InvalidCrossConfigs-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error:
+  CMAKE_CROSS_CONFIGS is not a subset of CMAKE_CONFIGURATION_TYPES
+
+
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/NinjaMultiConfig/InvalidCrossConfigs.cmake b/Tests/RunCMake/NinjaMultiConfig/InvalidCrossConfigs.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/InvalidCrossConfigs.cmake
diff --git a/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultBuildFileConfig-result.txt b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultBuildFileConfig-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultBuildFileConfig-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultBuildFileConfig-stderr.txt b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultBuildFileConfig-stderr.txt
new file mode 100644
index 0000000..5aa9038
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultBuildFileConfig-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Error:
+  The configuration specified by CMAKE_DEFAULT_BUILD_TYPE \(RelWithDebInfo\) is
+  not present in CMAKE_CONFIGURATION_TYPES
+
+
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultBuildFileConfig.cmake b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultBuildFileConfig.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultBuildFileConfig.cmake
diff --git a/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsCross-result.txt b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsCross-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsCross-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsCross-stderr.txt b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsCross-stderr.txt
new file mode 100644
index 0000000..6c2df86
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsCross-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error:
+  CMAKE_DEFAULT_CONFIGS is not a subset of CMAKE_CROSS_CONFIGS
+
+
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsCross.cmake b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsCross.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsCross.cmake
diff --git a/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsNoCross-result.txt b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsNoCross-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsNoCross-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsNoCross-stderr.txt b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsNoCross-stderr.txt
new file mode 100644
index 0000000..5d090a0
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsNoCross-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Error:
+  CMAKE_DEFAULT_CONFIGS cannot be used without CMAKE_DEFAULT_BUILD_TYPE or
+  CMAKE_CROSS_CONFIGS
+
+
+CMake Generate step failed\.  Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsNoCross.cmake b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsNoCross.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/InvalidDefaultConfigsNoCross.cmake
diff --git a/Tests/RunCMake/NinjaMultiConfig/NoUnusedVariables.cmake b/Tests/RunCMake/NinjaMultiConfig/NoUnusedVariables.cmake
new file mode 100644
index 0000000..bb7b160
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/NoUnusedVariables.cmake
@@ -0,0 +1 @@
+# Intentionally empty
diff --git a/Tests/RunCMake/NinjaMultiConfig/PostfixAndLocation-debug-in-release-graph-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/PostfixAndLocation-debug-in-release-graph-build-check.cmake
new file mode 100644
index 0000000..3657b5b
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/PostfixAndLocation-debug-in-release-graph-build-check.cmake
@@ -0,0 +1,7 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${TARGET_FILE_mylib_Release}
+    ${TARGET_LINKER_FILE_mylib_Release}
+    ${TARGET_FILE_mylib_Debug}
+    ${TARGET_LINKER_FILE_mylib_Debug}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/PostfixAndLocation-release-in-release-graph-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/PostfixAndLocation-release-in-release-graph-build-check.cmake
new file mode 100644
index 0000000..3345ee8
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/PostfixAndLocation-release-in-release-graph-build-check.cmake
@@ -0,0 +1,5 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${TARGET_FILE_mylib_Release}
+    ${TARGET_LINKER_FILE_mylib_Release}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/PostfixAndLocation.cmake b/Tests/RunCMake/NinjaMultiConfig/PostfixAndLocation.cmake
new file mode 100644
index 0000000..abef3c8
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/PostfixAndLocation.cmake
@@ -0,0 +1,18 @@
+enable_language(C)
+
+set(CMAKE_DEBUG_POSTFIX "_debug")
+
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}/lib)
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR}/lib)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}/bin)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR}/bin)
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}/lib)
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR}/lib)
+
+add_library(mylib SHARED simplelib.c)
+
+include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake)
+generate_output_files(mylib)
diff --git a/Tests/RunCMake/NinjaMultiConfig/Qt5-debug-in-release-graph-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Qt5-debug-in-release-graph-build-check.cmake
new file mode 100644
index 0000000..2d8df13
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Qt5-debug-in-release-graph-build-check.cmake
@@ -0,0 +1,7 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${AUTOGEN_FILES}
+
+    ${TARGET_FILE_exe_Debug}
+    ${TARGET_OBJECT_FILES_exe_Debug}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/Qt5.cmake b/Tests/RunCMake/NinjaMultiConfig/Qt5.cmake
new file mode 100644
index 0000000..3a1c7f5
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Qt5.cmake
@@ -0,0 +1,30 @@
+enable_language(CXX)
+
+find_package(Qt5Core REQUIRED)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTOMOC_COMPILER_PREDEFINES OFF)
+
+add_executable(exe qt5.cxx)
+target_link_libraries(exe PRIVATE Qt5::Core)
+
+include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake)
+generate_output_files(exe)
+
+set(moc_writes_depfiles 0)
+if(Qt5Core_VERSION VERSION_GREATER_EQUAL "5.15.0")
+  set(moc_writes_depfiles 1)
+endif()
+
+set(autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/mocs_compilation.cpp")
+if(moc_writes_depfiles)
+  list(APPEND autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/deps")
+  list(APPEND autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/timestamp")
+endif()
+foreach(c IN LISTS CMAKE_CONFIGURATION_TYPES)
+  list(APPEND autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/include_${c}/moc_qt5.cpp")
+  if(moc_writes_depfiles)
+    list(APPEND autogen_files "${CMAKE_BINARY_DIR}/exe_autogen/include_${c}/moc_qt5.cpp.d")
+  endif()
+endforeach()
+file(APPEND "${CMAKE_BINARY_DIR}/target_files.cmake" "set(AUTOGEN_FILES [==[${autogen_files}]==])\n")
diff --git a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
new file mode 100644
index 0000000..6472f46
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
@@ -0,0 +1,303 @@
+cmake_minimum_required(VERSION 3.16)
+
+include(RunCMake)
+
+set(RunCMake_GENERATOR "Ninja Multi-Config")
+set(RunCMake_GENERATOR_IS_MULTI_CONFIG 1)
+
+function(check_files dir)
+  cmake_parse_arguments(_check_files "" "" "INCLUDE;EXCLUDE" ${ARGN})
+
+  set(expected ${_check_files_INCLUDE})
+  list(FILTER expected EXCLUDE REGEX "^$")
+  list(REMOVE_DUPLICATES expected)
+  list(SORT expected)
+
+  file(GLOB_RECURSE actual "${dir}/*")
+  list(FILTER actual EXCLUDE REGEX "/CMakeFiles/|\\.ninja$|/CMakeCache\\.txt$|/target_files[^/]*\\.cmake$|/\\.ninja_[^/]*$|/cmake_install\\.cmake$|\\.ilk$|\\.manifest$|\\.pdb$|\\.exp$|/install_manifest\\.txt$")
+  foreach(f IN LISTS _check_files_INCLUDE _check_files_EXCLUDE)
+    if(EXISTS ${f})
+      list(APPEND actual ${f})
+    endif()
+  endforeach()
+  list(REMOVE_DUPLICATES actual)
+  list(SORT actual)
+
+  if(NOT "${expected}" STREQUAL "${actual}")
+    string(REPLACE ";" "\n  " expected_formatted "${expected}")
+    string(REPLACE ";" "\n  " actual_formatted "${actual}")
+    string(APPEND RunCMake_TEST_FAILED "Actual files did not match expected\nExpected:\n  ${expected_formatted}\nActual:\n  ${actual_formatted}\n")
+  endif()
+
+  set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+endfunction()
+
+function(check_file_contents filename expected)
+  if(NOT EXISTS "${filename}")
+    string(APPEND RunCMake_TEST_FAILED "File ${filename} does not exist\n")
+  else()
+    file(READ "${filename}" actual)
+    if(NOT actual MATCHES "${expected}")
+      string(REPLACE "\n" "\n  " expected_formatted "${expected}")
+      string(REPLACE "\n" "\n  " actual_formatted "${actual}")
+      string(APPEND RunCMake_TEST_FAILED "Contents of ${filename} do not match expected\nExpected:\n  ${expected_formatted}\nActual:\n  ${actual_formatted}\n")
+    endif()
+  endif()
+
+  set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+endfunction()
+
+function(run_cmake_configure case)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+  run_cmake(${case})
+endfunction()
+
+function(run_cmake_build case suffix config)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(tgts)
+  foreach(tgt IN LISTS ARGN)
+    list(APPEND tgts --target ${tgt})
+  endforeach()
+  if(config)
+    set(config_arg --config ${config})
+  else()
+    set(config_arg)
+  endif()
+  run_cmake_command(${case}-${suffix}-build "${CMAKE_COMMAND}" --build . ${config_arg} ${tgts})
+endfunction()
+
+function(run_ninja case suffix file)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(${case}-${suffix}-ninja "${RunCMake_MAKE_PROGRAM}" -f "${file}" ${ARGN})
+endfunction()
+
+###############################################################################
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Simple-build)
+# IMPORTANT: Setting RelWithDebInfo as the first item in CMAKE_CONFIGURATION_TYPES
+# generates a build.ninja file with that configuration
+set(RunCMake_TEST_OPTIONS "-DCMAKE_CONFIGURATION_TYPES=RelWithDebInfo\\;Debug\\;Release\\;MinSizeRel;-DCMAKE_CROSS_CONFIGS=all")
+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)
+get_filename_component(simpleshared_Release "${TARGET_FILE_simpleshared_Release}" NAME)
+run_cmake_build(Simple release-filename Release ${simpleshared_Release})
+file(RELATIVE_PATH simpleexe_Release "${RunCMake_TEST_BINARY_DIR}" "${TARGET_FILE_simpleexe_Release}")
+run_ninja(Simple release-file build-Release.ninja ${simpleexe_Release})
+run_cmake_build(Simple all-configs Release simplestatic:all)
+run_ninja(Simple default-build-file build.ninja simpleexe)
+run_cmake_build(Simple all-clean Release clean:all)
+run_cmake_build(Simple debug-subdir Debug SimpleSubdir/all)
+run_ninja(Simple release-in-minsizerel-graph-subdir build-MinSizeRel.ninja SimpleSubdir/all:Release)
+run_cmake_build(Simple all-subdir Release SimpleSubdir/all:all)
+run_ninja(Simple minsizerel-top build-MinSizeRel.ninja all)
+run_cmake_build(Simple debug-in-release-graph-top Release all:Debug)
+run_ninja(Simple all-clean-again build-Debug.ninja clean:all)
+run_ninja(Simple all-top build-RelWithDebInfo.ninja all:all)
+# Leave enough time for the timestamp to change on second-resolution systems
+execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 1)
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/empty.cmake")
+run_ninja(Simple reconfigure-config build-Release.ninja simpleexe)
+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_CONFIGURATION_TYPES=Debug\\;Release\\;MinSizeRel\\;RelWithDebInfo;-DCMAKE_DEFAULT_BUILD_TYPE=Release;-DCMAKE_DEFAULT_CONFIGS=all;-DCMAKE_CROSS_CONFIGS=all")
+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}/SimpleDefaultBuildAliasList-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_DEFAULT_BUILD_TYPE=Release;-DCMAKE_DEFAULT_CONFIGS=Debug\\;Release;-DCMAKE_CROSS_CONFIGS=all")
+run_cmake_configure(SimpleDefaultBuildAliasList)
+unset(RunCMake_TEST_OPTIONS)
+include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
+run_ninja(SimpleDefaultBuildAliasList target-configs build.ninja simpleexe)
+# IMPORTANT: This tests cmake --build . with no config using build.ninja
+run_cmake_build(SimpleDefaultBuildAliasList all-configs "" all)
+run_ninja(SimpleDefaultBuildAliasList all-relwithdebinfo build.ninja all:RelWithDebInfo)
+run_ninja(SimpleDefaultBuildAliasList clean-configs build.ninja clean)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SimpleDefaultBuildAliasListCross-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_DEFAULT_BUILD_TYPE=RelWithDebInfo;-DCMAKE_DEFAULT_CONFIGS=all;-DCMAKE_CROSS_CONFIGS=Debug\\;Release")
+run_cmake_configure(SimpleDefaultBuildAliasListCross)
+unset(RunCMake_TEST_OPTIONS)
+include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
+run_ninja(SimpleDefaultBuildAliasListCross target-configs build.ninja simpleexe)
+
+unset(RunCMake_TEST_BINARY_DIR)
+
+set(RunCMake_TEST_OPTIONS "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release;-DCMAKE_CROSS_CONFIGS=Debug\\;Release\\;RelWithDebInfo")
+run_cmake(InvalidCrossConfigs)
+unset(RunCMake_TEST_OPTIONS)
+
+set(RunCMake_TEST_OPTIONS "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release;-DCMAKE_DEFAULT_BUILD_TYPE=RelWithDebInfo")
+run_cmake(InvalidDefaultBuildFileConfig)
+unset(RunCMake_TEST_OPTIONS)
+
+set(RunCMake_TEST_OPTIONS "-DCMAKE_CROSS_CONFIGS=Debug\\;Release;-DCMAKE_DEFAULT_BUILD_TYPE=Release;-DCMAKE_DEFAULT_CONFIGS=Debug\\;Release\\;RelWithDebInfo")
+run_cmake(InvalidDefaultConfigsCross)
+unset(RunCMake_TEST_OPTIONS)
+
+set(RunCMake_TEST_OPTIONS "-DCMAKE_DEFAULT_BUILD_TYPE=Release;-DCMAKE_DEFAULT_CONFIGS=all")
+run_cmake(InvalidDefaultConfigsNoCross)
+unset(RunCMake_TEST_OPTIONS)
+
+set(RunCMake_TEST_OPTIONS "-DCMAKE_DEFAULT_BUILD_TYPE=Release")
+run_cmake(DefaultBuildFileConfig)
+unset(RunCMake_TEST_OPTIONS)
+
+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_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}/Framework-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_CROSS_CONFIGS=all")
+run_cmake_configure(Framework)
+unset(RunCMake_TEST_OPTIONS)
+include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
+run_cmake_build(Framework framework Debug all)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/FrameworkDependencyAutogen-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_CROSS_CONFIGS=all")
+run_cmake_configure(FrameworkDependencyAutogen)
+unset(RunCMake_TEST_OPTIONS)
+include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
+run_cmake_build(FrameworkDependencyAutogen framework Release test2:Debug)
+
+set(RunCMake_TEST_NO_CLEAN 1)
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CustomCommandGenerator-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release\\;MinSizeRel\\;RelWithDebInfo;-DCMAKE_CROSS_CONFIGS=all")
+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}")
+run_ninja(CustomCommandGenerator release build-Release.ninja generated)
+run_cmake_command(CustomCommandGenerator-release-generated "${TARGET_FILE_generated_Release}")
+run_ninja(CustomCommandGenerator debug-clean build-Debug.ninja clean)
+run_cmake_build(CustomCommandGenerator release-clean Release clean)
+run_cmake_build(CustomCommandGenerator debug-in-release-graph Release generated:Debug)
+run_cmake_command(CustomCommandGenerator-debug-in-release-graph-generated "${TARGET_FILE_generated_Debug}")
+run_ninja(CustomCommandGenerator debug-in-release-graph-clean build-Debug.ninja clean:Debug)
+run_ninja(CustomCommandGenerator release-in-debug-graph build-Debug.ninja generated:Release)
+run_cmake_command(CustomCommandGenerator-release-in-debug-graph-generated "${TARGET_FILE_generated_Release}")
+unset(RunCMake_TEST_NO_CLEAN)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CustomCommandsAndTargets-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_CROSS_CONFIGS=all")
+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
+#run_ninja(CustomCommandsAndTargets minsizerel-command build-MinSizeRel.ninja CustomCommandsAndTargetsSubdir/SubdirCommand)
+run_ninja(CustomCommandsAndTargets debug-command build-Debug.ninja TopCommand)
+run_ninja(CustomCommandsAndTargets release-target build-Release.ninja SubdirTarget)
+run_cmake_build(CustomCommandsAndTargets debug-target Debug TopTarget)
+run_cmake_build(CustomCommandsAndTargets debug-in-release-graph-postbuild Release SubdirPostBuild:Debug)
+run_ninja(CustomCommandsAndTargets release-postbuild build-Release.ninja SubdirPostBuild)
+run_cmake_build(CustomCommandsAndTargets debug-targetpostbuild Debug TopTargetPostBuild)
+run_ninja(CustomCommandsAndTargets release-targetpostbuild build-Release.ninja SubdirTargetPostBuild)
+
+unset(RunCMake_TEST_BINARY_DIR)
+
+run_cmake(CustomCommandDepfile)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/PostfixAndLocation-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release;-DCMAKE_CROSS_CONFIGS=all")
+run_cmake_configure(PostfixAndLocation)
+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)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Clean-build)
+run_cmake_configure(Clean)
+include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
+run_cmake_build(Clean release Release)
+run_ninja(Clean release-notall build-Release.ninja exenotall)
+run_cmake_build(Clean release-clean Release clean)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/AdditionalCleanFiles-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release\\;MinSizeRel\\;RelWithDebInfo;-DCMAKE_CROSS_CONFIGS=all")
+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;-DCMAKE_CROSS_CONFIGS=all")
+run_cmake_configure(Install)
+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)
+
+# FIXME Get this working
+#set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/AutoMocExecutable-build)
+#run_cmake_configure(AutoMocExecutable)
+#run_cmake_build(AutoMocExecutable debug-in-release-graph Release exe)
+
+# Need to test this manually because run_cmake() adds --no-warn-unused-cli
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/NoUnusedVariables-build)
+run_cmake_command(NoUnusedVariables ${CMAKE_COMMAND} ${CMAKE_CURRENT_LIST_DIR}
+  -G "Ninja Multi-Config"
+  "-DRunCMake_TEST=NoUnusedVariables"
+  "-DCMAKE_CROSS_CONFIGS=all"
+  "-DCMAKE_DEFAULT_BUILD_TYPE=Debug"
+  "-DCMAKE_DEFAULT_CONFIGS=all"
+  )
+
+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_CROSS_CONFIGS=all")
+  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-all-clean-again-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-all-clean-again-ninja-check.cmake
new file mode 100644
index 0000000..0f919df
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-all-clean-again-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/Simple-all-clean-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-all-clean-build-check.cmake
new file mode 100644
index 0000000..0f919df
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-all-clean-build-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/Simple-all-configs-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-all-configs-build-check.cmake
new file mode 100644
index 0000000..170a0e8
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-all-configs-build-check.cmake
@@ -0,0 +1,47 @@
+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_simplestatic_MinSizeRel}
+    ${TARGET_LINKER_FILE_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+
+    ${TARGET_FILE_simplestatic_RelWithDebInfo}
+    ${TARGET_LINKER_FILE_simplestatic_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/Simple-all-subdir-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-all-subdir-build-check.cmake
new file mode 100644
index 0000000..de4505c
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-all-subdir-build-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/Simple-all-top-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-all-top-ninja-check.cmake
new file mode 100644
index 0000000..c171e3d
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-all-top-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/Simple-debug-in-release-graph-top-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-debug-in-release-graph-top-build-check.cmake
new file mode 100644
index 0000000..fe980fe
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-debug-in-release-graph-top-build-check.cmake
@@ -0,0 +1,53 @@
+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_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_OBJECT_FILES_simpleobj_RelWithDebInfo}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/Simple-debug-subdir-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-debug-subdir-build-check.cmake
new file mode 100644
index 0000000..6bb7773
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-debug-subdir-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/Simple-debug-target-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-debug-target-build-check.cmake
new file mode 100644
index 0000000..6bb7773
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-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/Simple-debug-target-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-debug-target-ninja-check.cmake
new file mode 100644
index 0000000..f9c1e92
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-debug-target-ninja-check.cmake
@@ -0,0 +1,33 @@
+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}
+
+  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/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/Simple-default-build-file-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-default-build-file-ninja-check.cmake
new file mode 100644
index 0000000..dae1f4d
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-default-build-file-ninja-check.cmake
@@ -0,0 +1,51 @@
+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_simplestatic_MinSizeRel}
+    ${TARGET_LINKER_FILE_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_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}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/Simple-minsizerel-top-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-minsizerel-top-ninja-check.cmake
new file mode 100644
index 0000000..bf4be49
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-minsizerel-top-ninja-check.cmake
@@ -0,0 +1,51 @@
+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_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_OBJECT_FILES_simpleobj_RelWithDebInfo}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/Simple-reconfigure-config-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/Simple-reconfigure-config-ninja-stdout.txt
new file mode 100644
index 0000000..8877451
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-reconfigure-config-ninja-stdout.txt
@@ -0,0 +1,4 @@
+-- Configuring done
+-- Generating done
+-- Build files have been written to: [^
+]*/Tests/RunCMake/NinjaMultiConfig/Simple-build
diff --git a/Tests/RunCMake/NinjaMultiConfig/Simple-reconfigure-noconfig-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/Simple-reconfigure-noconfig-ninja-stdout.txt
new file mode 100644
index 0000000..8877451
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-reconfigure-noconfig-ninja-stdout.txt
@@ -0,0 +1,4 @@
+-- Configuring done
+-- Generating done
+-- Build files have been written to: [^
+]*/Tests/RunCMake/NinjaMultiConfig/Simple-build
diff --git a/Tests/RunCMake/NinjaMultiConfig/Simple-release-file-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-release-file-ninja-check.cmake
new file mode 100644
index 0000000..6e63aae
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-release-file-ninja-check.cmake
@@ -0,0 +1,39 @@
+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_OBJECT_FILES_simpleobj_Release}
+
+  EXCLUDE
+    ${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/Simple-release-filename-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-release-filename-build-check.cmake
new file mode 100644
index 0000000..a9bf42c
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-release-filename-build-check.cmake
@@ -0,0 +1,36 @@
+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_simpleshared_Release}
+    ${TARGET_LINKER_FILE_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simpleexe_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/Simple-release-in-minsizerel-graph-subdir-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-release-in-minsizerel-graph-subdir-ninja-check.cmake
new file mode 100644
index 0000000..b6c77ab
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-release-in-minsizerel-graph-subdir-ninja-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/Simple.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple.cmake
new file mode 100644
index 0000000..a32f551
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple.cmake
@@ -0,0 +1,13 @@
+enable_language(C)
+
+file(TOUCH ${CMAKE_BINARY_DIR}/empty.cmake)
+include(${CMAKE_BINARY_DIR}/empty.cmake)
+
+add_subdirectory(SimpleSubdir)
+
+add_library(simplestatic STATIC simplelib.c)
+
+include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake)
+generate_output_files(simpleexe simpleshared simplestatic simpleobj)
+
+file(APPEND "${CMAKE_BINARY_DIR}/target_files.cmake" "set(GENERATED_FILES [==[${CMAKE_BINARY_DIR}/empty.cmake]==])\n")
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/SimpleDefaultBuildAliasList-all-configs-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasList-all-configs-build-check.cmake
new file mode 100644
index 0000000..8ffdd20
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasList-all-configs-build-check.cmake
@@ -0,0 +1,39 @@
+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}
+
+  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/SimpleDefaultBuildAliasList-all-relwithdebinfo-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasList-all-relwithdebinfo-ninja-check.cmake
new file mode 100644
index 0000000..9e5baf9
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasList-all-relwithdebinfo-ninja-check.cmake
@@ -0,0 +1,46 @@
+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_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/SimpleDefaultBuildAliasList-clean-configs-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasList-clean-configs-ninja-check.cmake
new file mode 100644
index 0000000..3829d3e
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasList-clean-configs-ninja-check.cmake
@@ -0,0 +1,32 @@
+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_FILE_simplestatic_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simplestatic_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}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasList-target-configs-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasList-target-configs-ninja-check.cmake
new file mode 100644
index 0000000..b6c77ab
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasList-target-configs-ninja-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/SimpleDefaultBuildAliasList.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasList.cmake
new file mode 100644
index 0000000..2a5b708
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasList.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_SOURCE_DIR}/Simple.cmake")
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasListCross-target-configs-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasListCross-target-configs-ninja-check.cmake
new file mode 100644
index 0000000..b6c77ab
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasListCross-target-configs-ninja-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/SimpleDefaultBuildAliasListCross.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasListCross.cmake
new file mode 100644
index 0000000..2a5b708
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAliasListCross.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/SimpleSubdir/CMakeLists.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleSubdir/CMakeLists.txt
new file mode 100644
index 0000000..7e754a3
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleSubdir/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_library(simpleobj OBJECT ../empty.c)
+add_executable(simpleexe ../main.c $<TARGET_OBJECTS:simpleobj>)
+add_library(simpleshared SHARED ../simplelib.c)
+target_link_libraries(simpleexe PRIVATE simpleshared)
diff --git a/Tests/RunCMake/NinjaMultiConfig/WriteFile.cmake b/Tests/RunCMake/NinjaMultiConfig/WriteFile.cmake
new file mode 100644
index 0000000..82681a2
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/WriteFile.cmake
@@ -0,0 +1 @@
+file(WRITE "${OUTPUT_FILE}" "Genex config: ${GENEX_CONFIG}\nINTDIR config: ${INTDIR_CONFIG}\n")
diff --git a/Tests/RunCMake/NinjaMultiConfig/badmoc.c b/Tests/RunCMake/NinjaMultiConfig/badmoc.c
new file mode 100644
index 0000000..aec8dc3
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/badmoc.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+  printf("BadMoc Configuration: " CONFIG "\n");
+  return 1;
+}
diff --git a/Tests/RunCMake/NinjaMultiConfig/empty.c b/Tests/RunCMake/NinjaMultiConfig/empty.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/empty.c
diff --git a/Tests/RunCMake/NinjaMultiConfig/generator.c b/Tests/RunCMake/NinjaMultiConfig/generator.c
new file mode 100644
index 0000000..465ee2f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/generator.c
@@ -0,0 +1,101 @@
+#include <genex_config.h>
+#include <stdio.h>
+/* FIXME Get this working */
+/*#include <intdir_config.h>*/
+
+const char* generatorlib_genex_config_definition(void);
+const char* generatorlib_genex_config_include_dir(void);
+const char* generatorobj_genex_config_definition(void);
+const char* generatorobj_genex_config_include_dir(void);
+
+static const char contents[] =
+  /* clang-format off */
+"#include <stdio.h>\n"
+"\n"
+"#include <genex_config.h>\n"
+/* FIXME Get this working */
+/*"#include <intdir_config.h>\n"*/
+"\n"
+"const char* generatorlib_genex_config_definition(void);\n"
+"const char* generatorlib_genex_config_include_dir(void);\n"
+"const char* generatorobj_genex_config_definition(void);\n"
+"const char* generatorobj_genex_config_include_dir(void);\n"
+"\n"
+"int main(void)\n"
+"{\n"
+"  printf(\n"
+"    \"Generator genex config definition: "
+  GENEX_CONFIG_DEFINITION "\\n\"\n"
+/* FIXME Get this working */
+/*"    \"Generator INTDIR config definition: "
+  INTDIR_CONFIG_DEFINITION "\\n\"\n"*/
+"    \"Generator genex config include dir: "
+  GENEX_CONFIG_INCLUDE_DIR "\\n\"\n"
+/* FIXME Get this working */
+/*"    \"Generator INTDIR config include dir: "
+  INTDIR_CONFIG_INCLUDE_DIR "\\n\"\n"*/
+"    \"Generator library genex config definition: %s\\n\"\n"
+/* FIXME Get this working */
+/*"    \"Generator library INTDIR config definition: %s\\n\"\n"*/
+"    \"Generator library genex config include dir: %s\\n\"\n"
+/* FIXME Get this working */
+/*"    \"Generator library INTDIR config include dir: %s\\n\"\n"*/
+"    \"Generator object genex config definition: %s\\n\"\n"
+/* FIXME Get this working */
+/*"    \"Generator object INTDIR config definition: %s\\n\"\n"*/
+"    \"Generator object genex config include dir: %s\\n\"\n"
+/* FIXME Get this working */
+/*"    \"Generator object INTDIR config include dir: %s\\n\"\n"*/
+"    \"Generated genex config definition: \""
+  " GENEX_CONFIG_DEFINITION \"\\n\"\n"
+/* FIXME Get this working */
+/*"    \"Generated INTDIR config definition: \""
+  " INTDIR_CONFIG_DEFINITION \"\\n\"\n"*/
+"    \"Generated genex config include dir: \""
+  " GENEX_CONFIG_INCLUDE_DIR \"\\n\"\n"
+/* FIXME Get this working */
+/*"    \"Generated INTDIR config include dir: \""
+  " INTDIR_CONFIG_INCLUDE_DIR \"\\n\"\n"*/
+"    \"Generated library genex config definition: %%s\\n\"\n"
+/* FIXME Get this working */
+/*"    \"Generated library INTDIR config definition: %%s\\n\"\n"*/
+"    \"Generated library genex config include dir: %%s\\n\"\n"
+/* FIXME Get this working */
+/*"    \"Generated library INTDIR config include dir: %%s\\n\"\n"*/
+"    \"Generated object genex config definition: %%s\\n\"\n"
+/* FIXME Get this working */
+/*"    \"Generated object INTDIR config definition: %%s\\n\"\n"*/
+"    \"Generated object genex config include dir: %%s\\n\"\n"
+/* FIXME Get this working */
+/*"    \"Generated object INTDIR config include dir: %%s\\n\"\n"*/
+"    , generatorlib_genex_config_definition()\n"
+"    , generatorlib_genex_config_include_dir()\n"
+"    , generatorobj_genex_config_definition()\n"
+"    , generatorobj_genex_config_include_dir());\n"
+"  return 0;\n"
+"}\n";
+/* clang-format on */
+
+int main(int argc, char** argv)
+{
+  const char* filename;
+  FILE* fout;
+
+  if (argc < 2) {
+    fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
+    return 1;
+  }
+
+  filename = argv[1];
+  if (!(fout = fopen(filename, "w"))) {
+    fprintf(stderr, "Could not open %s for writing\n", filename);
+    return 1;
+  }
+  fprintf(fout, contents, generatorlib_genex_config_definition(),
+          generatorlib_genex_config_include_dir(),
+          generatorobj_genex_config_definition(),
+          generatorobj_genex_config_include_dir());
+  fclose(fout);
+
+  return 0;
+}
diff --git a/Tests/RunCMake/NinjaMultiConfig/generatorlib.c b/Tests/RunCMake/NinjaMultiConfig/generatorlib.c
new file mode 100644
index 0000000..de5c8f3
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/generatorlib.c
@@ -0,0 +1,24 @@
+#include <genex_config.h>
+/* FIXME Get this working */
+/*#include <intdir_config.h>*/
+
+const char* generatorlib_genex_config_definition(void)
+{
+  return GENEX_CONFIG_DEFINITION;
+}
+
+const char* generatorlib_genex_config_include_dir(void)
+{
+  return GENEX_CONFIG_INCLUDE_DIR;
+}
+
+/* FIXME Get this working */
+/*const char* generatorlib_intdir_config_definition(void)
+{
+  return INTDIR_CONFIG_DEFINITION;
+}
+
+const char* generatorlib_intdir_config_include_dir(void)
+{
+  return INTDIR_CONFIG_INCLUDE_DIR;
+}*/
diff --git a/Tests/RunCMake/NinjaMultiConfig/generatorobj.c b/Tests/RunCMake/NinjaMultiConfig/generatorobj.c
new file mode 100644
index 0000000..7bb5aa6
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/generatorobj.c
@@ -0,0 +1,24 @@
+#include <genex_config.h>
+/* FIXME Get this working */
+/*#include <intdir_config.h>*/
+
+const char* generatorobj_genex_config_definition(void)
+{
+  return GENEX_CONFIG_DEFINITION;
+}
+
+const char* generatorobj_genex_config_include_dir(void)
+{
+  return GENEX_CONFIG_INCLUDE_DIR;
+}
+
+/* FIXME Get this working */
+/*const char* generatorobj_intdir_config_definition(void)
+{
+  return INTDIR_CONFIG_DEFINITION;
+}
+
+const char* generatorobj_intdir_config_include_dir(void)
+{
+  return INTDIR_CONFIG_INCLUDE_DIR;
+}*/
diff --git a/Tests/RunCMake/NinjaMultiConfig/main.c b/Tests/RunCMake/NinjaMultiConfig/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+  return 0;
+}
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/qt5.cxx b/Tests/RunCMake/NinjaMultiConfig/qt5.cxx
new file mode 100644
index 0000000..972227f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/qt5.cxx
@@ -0,0 +1,9 @@
+#include <QCoreApplication>
+
+int main(int argc, char** argv)
+{
+  QCoreApplication app(argc, argv);
+  return app.exec();
+}
+
+#include "moc_qt5.cpp"
diff --git a/Tests/RunCMake/NinjaMultiConfig/qt5.h b/Tests/RunCMake/NinjaMultiConfig/qt5.h
new file mode 100644
index 0000000..b365b92
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/qt5.h
@@ -0,0 +1,5 @@
+#include <QObject>
+class QBuffer : public QObject
+{
+  Q_OBJECT
+};
diff --git a/Tests/RunCMake/NinjaMultiConfig/simplelib.c b/Tests/RunCMake/NinjaMultiConfig/simplelib.c
new file mode 100644
index 0000000..76ff921
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/simplelib.c
@@ -0,0 +1,6 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+  void simplelib(void)
+{
+}
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/ParseImplicitData/mingw.org-C-GNU-4.9.3.input b/Tests/RunCMake/ParseImplicitData/mingw.org-C-GNU-4.9.3.input
index 81e9ee0..b1c4ce0 100644
--- a/Tests/RunCMake/ParseImplicitData/mingw.org-C-GNU-4.9.3.input
+++ b/Tests/RunCMake/ParseImplicitData/mingw.org-C-GNU-4.9.3.input
@@ -53,7 +53,7 @@
 COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_ab097.dir\CMakeCCompilerABI.c.obj' '-c' '-mtune=generic' '-march=i586'
 Linking C executable cmTC_ab097.exe
 "C:\CMake\bin\cmake.exe" -E cmake_link_script CMakeFiles\cmTC_ab097.dir\link.txt --verbose=1
-"C:\CMake\bin\cmake.exe" -E remove -f CMakeFiles\cmTC_ab097.dir/objects.a
+"C:\CMake\bin\cmake.exe" -E rm -f CMakeFiles\cmTC_ab097.dir/objects.a
 C:\DoesNotExist\MinGW\bin\ar.exe cr CMakeFiles\cmTC_ab097.dir/objects.a @CMakeFiles\cmTC_ab097.dir\objects1.rsp
 C:\DoesNotExist\MinGW\bin\gcc.exe  -v    -Wl,--whole-archive CMakeFiles\cmTC_ab097.dir/objects.a -Wl,--no-whole-archive  -o cmTC_ab097.exe -Wl,--out-implib,libcmTC_ab097.dll.a -Wl,--major-image-version,0,--minor-image-version,0
 Using built-in specs.
diff --git a/Tests/RunCMake/ParseImplicitData/mingw.org-CXX-GNU-4.9.3.input b/Tests/RunCMake/ParseImplicitData/mingw.org-CXX-GNU-4.9.3.input
index cd77340..aae67bb 100644
--- a/Tests/RunCMake/ParseImplicitData/mingw.org-CXX-GNU-4.9.3.input
+++ b/Tests/RunCMake/ParseImplicitData/mingw.org-CXX-GNU-4.9.3.input
@@ -59,7 +59,7 @@
 COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_2b790.dir\CMakeCXXCompilerABI.cpp.obj' '-c' '-shared-libgcc' '-mtune=generic' '-march=i586'
 Linking CXX executable cmTC_2b790.exe
 "C:\CMake\bin\cmake.exe" -E cmake_link_script CMakeFiles\cmTC_2b790.dir\link.txt --verbose=1
-"C:\CMake\bin\cmake.exe" -E remove -f CMakeFiles\cmTC_2b790.dir/objects.a
+"C:\CMake\bin\cmake.exe" -E rm -f CMakeFiles\cmTC_2b790.dir/objects.a
 C:\DoesNotExist\MinGW\bin\ar.exe cr CMakeFiles\cmTC_2b790.dir/objects.a @CMakeFiles\cmTC_2b790.dir\objects1.rsp
 C:\DoesNotExist\MinGW\bin\g++.exe  -v    -Wl,--whole-archive CMakeFiles\cmTC_2b790.dir/objects.a -Wl,--no-whole-archive  -o cmTC_2b790.exe -Wl,--out-implib,libcmTC_2b790.dll.a -Wl,--major-image-version,0,--minor-image-version,0
 Using built-in specs.
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/RunCMake.cmake b/Tests/RunCMake/RunCMake.cmake
index da4d1e5..cb20fb1 100644
--- a/Tests/RunCMake/RunCMake.cmake
+++ b/Tests/RunCMake/RunCMake.cmake
@@ -146,6 +146,12 @@
     "|clang[^:]*: warning: the object size sanitizer has no effect at -O0, but is explicitly enabled:"
     "|Error kstat returned"
     "|Hit xcodebuild bug"
+
+    "|LICENSE WARNING:"
+    "|Your license to use PGI[^\n]*expired"
+    "|Please obtain a new version at"
+    "|contact PGI Sales at"
+
     "|[^\n]*xcodebuild[^\n]*warning: file type[^\n]*is based on missing file type"
     "|[^\n]*is a member of multiple groups"
     "|[^\n]*from Time Machine by path"
@@ -204,5 +210,28 @@
   run_cmake(${test})
 endfunction()
 
+function(ensure_files_match expected_file actual_file)
+  if(NOT EXISTS "${expected_file}")
+    message(FATAL_ERROR "Expected file does not exist:\n  ${expected_file}")
+  endif()
+  if(NOT EXISTS "${actual_file}")
+    message(FATAL_ERROR "Actual file does not exist:\n  ${actual_file}")
+  endif()
+  file(READ "${expected_file}" expected_file_content)
+  file(READ "${actual_file}" actual_file_content)
+  if(NOT "${expected_file_content}" STREQUAL "${actual_file_content}")
+    message(FATAL_ERROR "Actual file content does not match expected:\n
+    \n
+      expected file: ${expected_file}\n
+      expected content:\n
+      ${expected_file_content}\n
+    \n
+      actual file: ${actual_file}\n
+      actual content:\n
+      ${actual_file_content}\n
+    ")
+  endif()
+endfunction()
+
 # Protect RunCMake tests from calling environment.
 unset(ENV{MAKEFLAGS})
diff --git a/Tests/RunCMake/RuntimePath/Relative.cmake b/Tests/RunCMake/RuntimePath/Relative.cmake
index 203241f..80ed189 100644
--- a/Tests/RunCMake/RuntimePath/Relative.cmake
+++ b/Tests/RunCMake/RuntimePath/Relative.cmake
@@ -1,5 +1,12 @@
 enable_language(C)
 
+set(cfg_up)
+set(cfg_slash /)
+if(cfg_dir)
+  set(cfg_up /..)
+  set(cfg_slash)
+endif()
+
 if(NOT CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN)
   if(CMAKE_C_PLATFORM_ID STREQUAL "Linux")
     # Sanity check for platform that is definitely known to support $ORIGIN.
@@ -45,25 +52,25 @@
 add_executable(main-norel main.c)
 target_link_libraries(main-norel utils)
 set_property(TARGET main-norel PROPERTY BUILD_RPATH_USE_ORIGIN OFF)
-CheckRpath(main-norel "${CMAKE_CURRENT_BINARY_DIR}")
+CheckRpath(main-norel "${CMAKE_CURRENT_BINARY_DIR}${cfg_dir}")
 
 add_executable(mainsub main.c)
 target_link_libraries(mainsub utils)
 set_property(TARGET mainsub PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
-CheckRpath(mainsub "\$ORIGIN/../")
+CheckRpath(mainsub "\$ORIGIN${cfg_up}/..${cfg_dir}${cfg_slash}")
 
 add_executable(main-sub main.c)
 target_link_libraries(main-sub utils-sub)
-CheckRpath(main-sub "\$ORIGIN/libs")
+CheckRpath(main-sub "\$ORIGIN${cfg_up}/libs${cfg_dir}")
 
 add_executable(mainsub-sub main.c)
 target_link_libraries(mainsub-sub utils-sub)
 set_property(TARGET mainsub-sub PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
-CheckRpath(mainsub-sub "\$ORIGIN/../libs")
+CheckRpath(mainsub-sub "\$ORIGIN${cfg_up}/../libs${cfg_dir}")
 
 if(externDir)
   # Binaries linking to libraries outside the build tree should have an absolute RPATH.
   add_executable(main-extern main.c)
   target_link_libraries(main-extern utils-extern)
-  CheckRpath(main-extern "${externDir}")
+  CheckRpath(main-extern "${externDir}${cfg_dir}")
 endif()
diff --git a/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake b/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake
index 4c9ddcd..ad446e9 100644
--- a/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake
+++ b/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake
@@ -6,7 +6,9 @@
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build)
   set(RunCMake_TEST_NO_CLEAN 1)
   if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
-    set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+    set(RunCMake_TEST_OPTIONS -Dcfg_dir= -DCMAKE_BUILD_TYPE=Debug)
+  else()
+    set(RunCMake_TEST_OPTIONS -Dcfg_dir=/$<CONFIG>)
   endif()
   file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
   file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
@@ -14,12 +16,16 @@
   run_cmake_command(${name}-build ${CMAKE_COMMAND} --build . --config Debug)
 endfunction()
 
+set(cfg_dir)
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(cfg_dir /Debug)
+endif()
+
 run_RuntimePath(SymlinkImplicit)
 run_cmake_command(SymlinkImplicitCheck
-  ${CMAKE_COMMAND} -Ddir=${RunCMake_BINARY_DIR}/SymlinkImplicit-build -P ${RunCMake_SOURCE_DIR}/SymlinkImplicitCheck.cmake)
+  ${CMAKE_COMMAND} -Ddir=${RunCMake_BINARY_DIR}/SymlinkImplicit-build -Dcfg_dir=${cfg_dir} -P ${RunCMake_SOURCE_DIR}/SymlinkImplicitCheck.cmake)
 
 run_RuntimePath(Relative)
-# FIXME: Run RelativeCheck (appears to be broken currently)
 
 run_RuntimePath(Genex)
 run_cmake_command(GenexCheck
diff --git a/Tests/RunCMake/RuntimePath/SymlinkImplicitCheck.cmake b/Tests/RunCMake/RuntimePath/SymlinkImplicitCheck.cmake
index d34742e..4f50d4b 100644
--- a/Tests/RunCMake/RuntimePath/SymlinkImplicitCheck.cmake
+++ b/Tests/RunCMake/RuntimePath/SymlinkImplicitCheck.cmake
@@ -1,2 +1,2 @@
-file(COPY ${dir}/bin/exe DESTINATION ${dir})
+file(COPY ${dir}/bin${cfg_dir}/exe DESTINATION ${dir})
 file(RPATH_CHANGE FILE "${dir}/exe" OLD_RPATH "${dir}/libLink" NEW_RPATH "old-should-not-exist")
diff --git a/Tests/RunCMake/Swift/L.swift b/Tests/RunCMake/Swift/L.swift
new file mode 100644
index 0000000..79ff87e
--- /dev/null
+++ b/Tests/RunCMake/Swift/L.swift
@@ -0,0 +1 @@
+public let ThirtyTwo: Int = 32
diff --git a/Tests/RunCMake/Swift/RunCMakeTest.cmake b/Tests/RunCMake/Swift/RunCMakeTest.cmake
index 4817045..1db202e 100644
--- a/Tests/RunCMake/Swift/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Swift/RunCMakeTest.cmake
@@ -7,6 +7,16 @@
 elseif(RunCMake_GENERATOR STREQUAL Ninja)
   if(CMAKE_Swift_COMPILER)
     run_cmake(Win32ExecutableDisallowed)
+
+    set(RunCMake_TEST_OPTIONS -DCMAKE_SYSTEM_NAME=Darwin)
+    run_cmake(SwiftMultiArch)
+    unset(RunCMake_TEST_OPTIONS)
+  endif()
+elseif(RunCMake_GENERATOR STREQUAL "Ninja Multi-Config")
+  if(CMAKE_Swift_COMPILER)
+    set(RunCMake_TEST_OPTIONS "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release")
+    run_cmake(SwiftSimple)
+    unset(RunCMake_TEST_OPTIONS)
   endif()
 else()
   run_cmake(NotSupported)
diff --git a/Tests/RunCMake/Swift/SwiftMultiArch-result.txt b/Tests/RunCMake/Swift/SwiftMultiArch-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/Swift/SwiftMultiArch-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/Swift/SwiftMultiArch-stderr.txt b/Tests/RunCMake/Swift/SwiftMultiArch-stderr.txt
new file mode 100644
index 0000000..874bdc7
--- /dev/null
+++ b/Tests/RunCMake/Swift/SwiftMultiArch-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at SwiftMultiArch.cmake:3 \(project\):
+  multiple values for CMAKE_OSX_ARCHITECTURES not supported with Swift
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3
diff --git a/Tests/RunCMake/Swift/SwiftMultiArch.cmake b/Tests/RunCMake/Swift/SwiftMultiArch.cmake
new file mode 100644
index 0000000..5fdb688
--- /dev/null
+++ b/Tests/RunCMake/Swift/SwiftMultiArch.cmake
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.15.1)
+set(CMAKE_OSX_ARCHITECTURES "armv7;arm64;i386;x86_64")
+project(SwiftMultiArch
+  LANGUAGES Swift)
diff --git a/Tests/RunCMake/Swift/SwiftSimple.cmake b/Tests/RunCMake/Swift/SwiftSimple.cmake
new file mode 100644
index 0000000..1f2702d
--- /dev/null
+++ b/Tests/RunCMake/Swift/SwiftSimple.cmake
@@ -0,0 +1,2 @@
+enable_language(Swift)
+add_library(L L.swift)
diff --git a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
index 6d72fac..9a1e027 100644
--- a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
+++ b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
@@ -28,6 +28,7 @@
    \* CMP0081
    \* CMP0083
    \* CMP0095
+   \* CMP0099
 
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/TargetProperties/CMakeLists.txt b/Tests/RunCMake/TargetProperties/CMakeLists.txt
new file mode 100644
index 0000000..be9d403
--- /dev/null
+++ b/Tests/RunCMake/TargetProperties/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.4)
+project(${RunCMake_TEST})
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/TargetProperties/Deprecation-stderr.txt b/Tests/RunCMake/TargetProperties/Deprecation-stderr.txt
new file mode 100644
index 0000000..11a4cd8
--- /dev/null
+++ b/Tests/RunCMake/TargetProperties/Deprecation-stderr.txt
@@ -0,0 +1,9 @@
+^CMake Warning \(dev\) at Deprecation\.cmake:[0-9]+ \(target_link_libraries\):
+  The library that is being linked to, testLibDeprecation, is marked as being
+  deprecated by the owner\.  The message provided by the developer is:
+
+  Deprecated version\.  Please use latest version
+
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/TargetProperties/Deprecation.cmake b/Tests/RunCMake/TargetProperties/Deprecation.cmake
new file mode 100644
index 0000000..9361273
--- /dev/null
+++ b/Tests/RunCMake/TargetProperties/Deprecation.cmake
@@ -0,0 +1,5 @@
+add_library(testLibDeprecation STATIC empty.cpp)
+set_property(TARGET testLibDeprecation PROPERTY DEPRECATION "Deprecated version. Please use latest version")
+
+add_executable(testExe1 empty.cpp)
+target_link_libraries(testExe1 testLibDeprecation)
diff --git a/Tests/RunCMake/TargetProperties/RunCMakeTest.cmake b/Tests/RunCMake/TargetProperties/RunCMakeTest.cmake
new file mode 100644
index 0000000..5af31da
--- /dev/null
+++ b/Tests/RunCMake/TargetProperties/RunCMakeTest.cmake
@@ -0,0 +1,3 @@
+include(RunCMake)
+
+run_cmake(Deprecation)
diff --git a/Tests/RunCMake/TargetProperties/empty.cpp b/Tests/RunCMake/TargetProperties/empty.cpp
new file mode 100644
index 0000000..4086dcc
--- /dev/null
+++ b/Tests/RunCMake/TargetProperties/empty.cpp
@@ -0,0 +1,4 @@
+int empty()
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/TargetSources/RunCMakeTest.cmake b/Tests/RunCMake/TargetSources/RunCMakeTest.cmake
index bee8c4e..0d462ba 100644
--- a/Tests/RunCMake/TargetSources/RunCMakeTest.cmake
+++ b/Tests/RunCMake/TargetSources/RunCMakeTest.cmake
@@ -1,6 +1,6 @@
 include(RunCMake)
 
-if(RunCMake_GENERATOR MATCHES "Visual Studio|Xcode")
+if(RunCMake_GENERATOR STREQUAL "Xcode")
   run_cmake(ConfigNotAllowed)
 endif()
 
diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
index 44ccd6b..8a04f78 100644
--- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
@@ -1,3 +1,5 @@
+cmake_policy(SET CMP0057 NEW)
+
 include(RunCMake)
 cmake_policy(SET CMP0054 NEW)
 
@@ -15,6 +17,7 @@
 run_cmake(VsDebuggerCommandArguments)
 run_cmake(VsDebuggerEnvironment)
 run_cmake(VsCSharpCustomTags)
+run_cmake(VsCSharpDocumentationFile)
 run_cmake(VsCSharpReferenceProps)
 run_cmake(VsCSharpWithoutSources)
 run_cmake(VsCSharpDeployFiles)
@@ -28,6 +31,12 @@
 run_cmake(VsPrecompileHeaders)
 run_cmake(VsPrecompileHeadersReuseFromCompilePDBName)
 
+run_cmake(VsWinRTByDefault)
+
+set(RunCMake_GENERATOR_TOOLSET "VCTargetsPath=$(VCTargetsPath)")
+run_cmake(VsVCTargetsPath)
+unset(RunCMake_GENERATOR_TOOLSET)
+
 if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.05)
   run_cmake(VsJustMyCode)
 endif()
@@ -44,3 +53,6 @@
 else()
   run_cmake(UnityBuildNative)
 endif()
+
+run_cmake(VsDotnetTargetFramework)
+run_cmake(VsDotnetTargetFrameworkVersion)
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/VsCSharpDefines-check.cmake b/Tests/RunCMake/VS10Project/VsCSharpDefines-check.cmake
index 152bf9c..631abac 100644
--- a/Tests/RunCMake/VS10Project/VsCSharpDefines-check.cmake
+++ b/Tests/RunCMake/VS10Project/VsCSharpDefines-check.cmake
@@ -27,15 +27,15 @@
   elseif(inDebug AND
      (line MATCHES "^ *<DefineConstants>.*MY_FOO_DEFINE.*</DefineConstants> *$") AND
      (line MATCHES "^ *<DefineConstants>.*DEFINE_ONLY_FOR_DEBUG.*</DefineConstants> *$") AND
-     (line MATCHES "^ *<DefineConstants>.*MY_BAR_ASSIGNMENT=bar.*</DefineConstants> *$") AND
-     (NOT (line MATCHES "^ *<DefineConstants>.*DEFINE_ONLY_FOR_RELEASE.*</DefineConstants> *$"))
+     (NOT (line MATCHES "^ *<DefineConstants>.*DEFINE_ONLY_FOR_RELEASE.*</DefineConstants> *$")) AND
+     (NOT (line MATCHES "^ *<DefineConstants>.*MY_BAR_ASSIGNMENT=bar.*</DefineConstants> *$"))
     )
     set(debugOK TRUE)
   elseif(inRelease AND
      (line MATCHES "^ *<DefineConstants>.*MY_FOO_DEFINE.*</DefineConstants> *$") AND
      (line MATCHES "^ *<DefineConstants>.*DEFINE_ONLY_FOR_RELEASE.*</DefineConstants> *$") AND
-     (line MATCHES "^ *<DefineConstants>.*MY_BAR_ASSIGNMENT=bar.*</DefineConstants> *$") AND
-     (NOT (line MATCHES "^ *<DefineConstants>.*DEFINE_ONLY_FOR_DEBUG.*</DefineConstants> *$"))
+     (NOT (line MATCHES "^ *<DefineConstants>.*DEFINE_ONLY_FOR_DEBUG.*</DefineConstants> *$")) AND
+     (NOT (line MATCHES "^ *<DefineConstants>.*MY_BAR_ASSIGNMENT=bar.*</DefineConstants> *$"))
     )
     set(releaseOK TRUE)
   endif()
diff --git a/Tests/RunCMake/VS10Project/VsCSharpDocumentationFile-check.cmake b/Tests/RunCMake/VS10Project/VsCSharpDocumentationFile-check.cmake
new file mode 100644
index 0000000..0393362
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCSharpDocumentationFile-check.cmake
@@ -0,0 +1,26 @@
+#
+# Check C# VS project for required elements
+#
+set(csProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.csproj")
+if(NOT EXISTS "${csProjectFile}")
+  set(RunCMake_TEST_FAILED "Project file ${csProjectFile} does not exist.")
+  return()
+endif()
+
+file(STRINGS "${csProjectFile}" lines)
+
+set(HAVE_DocumentationFile 0)
+foreach(line IN LISTS lines)
+  if(line MATCHES "^ *<DocumentationFile>([^<>]+)</DocumentationFile>")
+    if(HAVE_DocumentationFile)
+      set(RunCMake_TEST_FAILED "Documentation node has been generated more than once for\n  ${csProjectFile}")
+      return()
+    endif()
+    set(HAVE_DocumentationFile 1)
+  endif()
+endforeach()
+
+if(NOT HAVE_DocumentationFile)
+  set(RunCMake_TEST_FAILED "Documentation node has not been generated for\n  ${csProjectFile}")
+  return()
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsCSharpDocumentationFile.cmake b/Tests/RunCMake/VS10Project/VsCSharpDocumentationFile.cmake
new file mode 100644
index 0000000..83b6b97
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCSharpDocumentationFile.cmake
@@ -0,0 +1,8 @@
+set(CMAKE_CONFIGURATION_TYPES Debug)
+enable_language(CSharp)
+
+add_library(foo SHARED
+  foo.cs)
+
+set_target_properties(foo PROPERTIES
+  VS_DOTNET_DOCUMENTATION_FILE foo.xml)
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/VsGlobals-check.cmake b/Tests/RunCMake/VS10Project/VsGlobals-check.cmake
index 0e7fd45..6a30099 100644
--- a/Tests/RunCMake/VS10Project/VsGlobals-check.cmake
+++ b/Tests/RunCMake/VS10Project/VsGlobals-check.cmake
@@ -1,44 +1,65 @@
-set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
-if(NOT EXISTS "${vcProjectFile}")
-  set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.")
-  return()
-endif()
-
-set(InsideGlobals FALSE)
-set(DefaultLanguageSet FALSE)
-set(MinimumVisualStudioVersionSet FALSE)
-
-file(STRINGS "${vcProjectFile}" lines)
-foreach(line IN LISTS lines)
-  if(line MATCHES "^ *<PropertyGroup Label=\"Globals\"> *$")
-    set(InsideGlobals TRUE)
-  elseif(line MATCHES "^ *<DefaultLanguage>([a-zA-Z\\-]+)</DefaultLanguage> *$")
-    if("${CMAKE_MATCH_1}" STREQUAL "en-US")
-      if(InsideGlobals)
-        message(STATUS "foo.vcxproj has correct DefaultLanguage global property")
-        set(DefaultLanguageSet TRUE)
-      else()
-        message(STATUS "DefaultLanguage is set but not within \"Globals\" property group")
-      endif()
-    endif()
-  elseif(line MATCHES "^ *<MinimumVisualStudioVersion>([0-9\\.]+)</MinimumVisualStudioVersion> *$")
-    if("${CMAKE_MATCH_1}" STREQUAL "14.0")
-      if(InsideGlobals)
-        message(STATUS "foo.vcxproj has correct MinimumVisualStudioVersion global property")
-        set(MinimumVisualStudioVersionSet TRUE)
-      else()
-        message(STATUS "MinimumVisualStudioVersion is set but not within \"Globals\" property group")
-      endif()
-    endif()
+macro(check_project_file projectFile)
+  if(NOT EXISTS "${projectFile}")
+    set(RunCMake_TEST_FAILED "Project file ${projectFile} does not exist.")
+    return()
   endif()
-endforeach()
 
-if(NOT DefaultLanguageSet)
-  set(RunCMake_TEST_FAILED "DefaultLanguageSet not found or not set correctly.")
-  return()
-endif()
+  string(REPLACE "${RunCMake_TEST_BINARY_DIR}/" "" projectName ${projectFile})
 
-if(NOT MinimumVisualStudioVersionSet)
-  set(RunCMake_TEST_FAILED "MinimumVisualStudioVersionSet not found or not set correctly.")
-  return()
-endif()
+  set(InsideGlobals FALSE)
+  set(DefaultLanguageSet FALSE)
+  set(MinimumVisualStudioVersionSet FALSE)
+  set(TestPropertySet FALSE)
+
+  file(STRINGS "${projectFile}" lines)
+  foreach(line IN LISTS lines)
+    if(line MATCHES "^ *<PropertyGroup Label=\"Globals\"> *$")
+      set(InsideGlobals TRUE)
+    elseif(line MATCHES "^ *<DefaultLanguage>([a-zA-Z\\-]+)</DefaultLanguage> *$")
+      if("${CMAKE_MATCH_1}" STREQUAL "en-US")
+        if(InsideGlobals)
+          message(STATUS "${projectName} has correct DefaultLanguage global property")
+          set(DefaultLanguageSet TRUE)
+        else()
+          message(STATUS "DefaultLanguage is set but not within \"Globals\" property group")
+        endif()
+      endif()
+    elseif(line MATCHES "^ *<MinimumVisualStudioVersion>([0-9\\.]+)</MinimumVisualStudioVersion> *$")
+      if("${CMAKE_MATCH_1}" STREQUAL "10.0")
+        if(InsideGlobals)
+          message(STATUS "${projectName} has correct MinimumVisualStudioVersion global property")
+          set(MinimumVisualStudioVersionSet TRUE)
+        else()
+          message(STATUS "MinimumVisualStudioVersion is set but not within \"Globals\" property group")
+        endif()
+      endif()
+    elseif(line MATCHES "^ *<TestProperty>(.+)</TestProperty> *$")
+      if("${CMAKE_MATCH_1}" STREQUAL "TestValue")
+        if(InsideGlobals)
+          message(STATUS "${projectName} has correct TestProperty global property")
+          set(TestPropertySet TRUE)
+        else()
+          message(STATUS "TestProperty is set but not within \"Globals\" property group")
+        endif()
+      endif()
+    endif()
+  endforeach()
+
+  if(NOT DefaultLanguageSet)
+    set(RunCMake_TEST_FAILED "DefaultLanguage not found or not set correctly in ${projectName}.")
+    return()
+  endif()
+
+  if(NOT MinimumVisualStudioVersionSet)
+    set(RunCMake_TEST_FAILED "MinimumVisualStudioVersion not found or not set correctly in ${projectName}.")
+    return()
+  endif()
+
+  if(NOT TestPropertySet)
+    set(RunCMake_TEST_FAILED "TestProperty not found or not set correctly in ${projectName}.")
+    return()
+  endif()
+endmacro()
+
+check_project_file("${RunCMake_TEST_BINARY_DIR}/CMakeFiles/${CMAKE_VERSION}/CompilerIdCXX/CompilerIdCXX.vcxproj")
+check_project_file("${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
diff --git a/Tests/RunCMake/VS10Project/VsGlobals.cmake b/Tests/RunCMake/VS10Project/VsGlobals.cmake
index a3ed5af..09d806d 100644
--- a/Tests/RunCMake/VS10Project/VsGlobals.cmake
+++ b/Tests/RunCMake/VS10Project/VsGlobals.cmake
@@ -1,8 +1,9 @@
-enable_language(CXX)
-
 set(CMAKE_VS_GLOBALS
     "DefaultLanguage=en-US"
-    "MinimumVisualStudioVersion=14.0"
+    "MinimumVisualStudioVersion=10.0"
+    "TestProperty=TestValue"
 )
 
+enable_language(CXX)
+
 add_library(foo foo.cpp)
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/VS10Project/VsVCTargetsPath-check.cmake b/Tests/RunCMake/VS10Project/VsVCTargetsPath-check.cmake
new file mode 100644
index 0000000..5b1701c
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsVCTargetsPath-check.cmake
@@ -0,0 +1,32 @@
+macro(check_project_file projectFile)
+  set(insideGlobals FALSE)
+  set(pathFound FALSE)
+
+  if(NOT EXISTS "${projectFile}")
+    set(RunCMake_TEST_FAILED "Project file ${projectFile} does not exist.")
+    return()
+  endif()
+
+  string(REPLACE "${RunCMake_TEST_BINARY_DIR}/" "" projectName ${projectFile})
+
+  file(STRINGS "${projectFile}" lines)
+  foreach(line IN LISTS lines)
+    if(line MATCHES "^ *<PropertyGroup Label=\"Globals\">.*$")
+      set(insideGlobals TRUE)
+    elseif(insideGlobals)
+      if(line MATCHES "^ *</PropertyGroup>.*$")
+        set(insideGlobals FALSE)
+      elseif(line MATCHES "^ *<VCTargetsPath>(.+)</VCTargetsPath>*$")
+        message(STATUS "Found VCTargetsPath = ${CMAKE_MATCH_1} in PropertyGroup 'Globals' in ${projectName}")
+        set(pathFound TRUE)
+      endif()
+    endif()
+  endforeach()
+  if(NOT pathFound)
+    set(RunCMake_TEST_FAILED "VCTargetsPath not found in \"Globals\" propertygroup in ${projectName}")
+    return() # This should intentionally return from the caller, not the macro
+  endif()
+endmacro()
+
+check_project_file("${RunCMake_TEST_BINARY_DIR}/CMakeFiles/${CMAKE_VERSION}/CompilerIdCXX/CompilerIdCXX.vcxproj")
+check_project_file("${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
diff --git a/Tests/RunCMake/VS10Project/VsVCTargetsPath.cmake b/Tests/RunCMake/VS10Project/VsVCTargetsPath.cmake
new file mode 100644
index 0000000..6a6088f
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsVCTargetsPath.cmake
@@ -0,0 +1,3 @@
+enable_language(CXX)
+
+add_library(foo foo.cpp)
diff --git a/Tests/RunCMake/VS10Project/VsWinRTByDefault-check.cmake b/Tests/RunCMake/VS10Project/VsWinRTByDefault-check.cmake
new file mode 100644
index 0000000..15bbaf2
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsWinRTByDefault-check.cmake
@@ -0,0 +1,66 @@
+macro(checkCompileAsWinRT projectPath)
+  if(RunCMake_TEST_FAILED)
+    return()
+  endif()
+
+  if (NOT EXISTS "${projectPath}")
+    set(RunCMake_TEST_FAILED "Project file ${projectPath} does not exist.")
+    return()
+  endif()
+
+  get_filename_component(projectName "${projectPath}" NAME_WE)
+
+  cmake_parse_arguments("" "" "GLOBAL" "OVERRIDES_ENABLE;OVERRIDES_DISABLE" ${ARGN})
+
+  unset(sourceOverride)
+
+  file(STRINGS "${projectPath}" lines)
+  set(foundGlobalWinRT false)
+
+  foreach(line IN LISTS lines)
+    if(line MATCHES "^ *<CompileAsWinRT( Condition=\"[^\\\"]+\")?>(true|false)</CompileAsWinRT>$")
+      set(value ${CMAKE_MATCH_2})
+
+      if(sourceOverride)
+        set(expectedList)
+
+        if(value)
+          set(expectedList _OVERRIDES_ENABLE)
+        else()
+          set(expectedList _OVERRIDES_DISABLE)
+        endif()
+
+        if(NOT sourceOverride IN_LIST ${expectedList})
+          set(RunCMake_TEST_FAILED
+            "${projectName}: Unexpected CompileAsWinRT override ${value} for ${sourceOverride}")
+          return()
+        endif()
+      else()
+        if (NOT _GLOBAL STREQUAL value)
+          set(RunCMake_TEST_FAILED
+            "${projectName}: Global CompileAsWinRT value is ${value}, but expected ${_GLOBAL}")
+          return()
+        endif()
+
+        set(foundGlobalWinRT true)
+      endif()
+    elseif(line MATCHES "^ *<ClCompile Include=\"([^\"]+)\">$")
+      get_filename_component(sourceOverride "${CMAKE_MATCH_1}" NAME)
+    elseif(line MATCHES "^ *</ClCompile>$")
+      unset(sourceOverride)
+    endif()
+  endforeach()
+
+  if(NOT foundGlobalWinRT AND DEFINED _GLOBAL)
+    set(RunCMake_TEST_FAILED "${projectName}: Global CompileAsWinRT not found or have invalid value, but expected")
+    return()
+  endif()
+endmacro()
+
+checkCompileAsWinRT("${RunCMake_TEST_BINARY_DIR}/noFlagOnlyC.vcxproj" GLOBAL false)
+checkCompileAsWinRT("${RunCMake_TEST_BINARY_DIR}/noFlagMixedCAndCxx.vcxproj" GLOBAL false)
+checkCompileAsWinRT("${RunCMake_TEST_BINARY_DIR}/noFlagOnlyCxx.vcxproj" GLOBAL false)
+
+checkCompileAsWinRT("${RunCMake_TEST_BINARY_DIR}/flagOnlyC.vcxproj" GLOBAL true OVERRIDES_DISABLE empty.c)
+checkCompileAsWinRT("${RunCMake_TEST_BINARY_DIR}/flagMixedCAndCxx.vcxproj" GLOBAL true OVERRIDES_DISABLE empty.c)
+checkCompileAsWinRT("${RunCMake_TEST_BINARY_DIR}/flagOnlyCxx.vcxproj" GLOBAL true)
diff --git a/Tests/RunCMake/VS10Project/VsWinRTByDefault.cmake b/Tests/RunCMake/VS10Project/VsWinRTByDefault.cmake
new file mode 100644
index 0000000..139048b
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsWinRTByDefault.cmake
@@ -0,0 +1,16 @@
+set(CMAKE_VS_WINRT_BY_DEFAULT true)
+
+enable_language(C)
+enable_language(CXX)
+
+add_library(noFlagOnlyC empty.c)
+add_library(noFlagMixedCAndCXX empty.c foo.cpp)
+add_library(noFlagOnlyCXX foo.cpp)
+
+add_library(flagOnlyC empty.c)
+add_library(flagMixedCAndCXX empty.c foo.cpp)
+add_library(flagOnlyCXX foo.cpp)
+
+target_compile_options(flagOnlyC PRIVATE /ZW)
+target_compile_options(flagMixedCAndCXX PRIVATE /ZW)
+target_compile_options(flagOnlyCXX PRIVATE /ZW)
diff --git a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
index 6ecf3f2..342dbbc 100644
--- a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
+++ b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
@@ -8,6 +8,16 @@
 run_cmake(XcodeAttributeGenex)
 run_cmake(XcodeAttributeGenexError)
 run_cmake(XcodeGenerateTopLevelProjectOnly)
+
+function(XcodeGenerateTopLevelProjectOnlyWithObjectLibrary)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XcodeGenerateTopLevelProjectOnlyWithObjectLibrary-build)
+  run_cmake(XcodeGenerateTopLevelProjectOnlyWithObjectLibrary)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(XcodeGenerateTopLevelProjectOnlyWithObjectLibrary-build ${CMAKE_COMMAND} --build . --target shared_lib)
+endfunction()
+
+XcodeGenerateTopLevelProjectOnlyWithObjectLibrary()
+
 run_cmake(XcodeObjectNeedsEscape)
 run_cmake(XcodeObjectNeedsQuote)
 run_cmake(XcodeOptimizationFlags)
@@ -68,6 +78,15 @@
 XcodeObjcxxFlags(XcodeObjcFlags)
 XcodeObjcxxFlags(XcodeObjcxxFlags)
 
+function(XcodeRemoveExcessiveISystem)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XcodeRemoveExcessiveISystem-build)
+  run_cmake(XcodeRemoveExcessiveISystem)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(XcodeRemoveExcessiveISystem-build ${CMAKE_COMMAND} --build .)
+endfunction()
+
+XcodeRemoveExcessiveISystem()
+
 # Isolate device tests from host architecture selection.
 unset(ENV{CMAKE_OSX_ARCHITECTURES})
 
@@ -287,4 +306,16 @@
   xctest_lookup_test(tvOS appletvsimulator)
 endif()
 
+if(XCODE_VERSION VERSION_GREATER_EQUAL 8)
+  function(XcodeRemoveExcessiveISystemSDK SDK)
+    set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XcodeRemoveExcessiveISystemSDK-${SDK}-build)
+    set(RunCMake_TEST_OPTIONS "-DCMAKE_SYSTEM_NAME=iOS")
+    run_cmake(XcodeRemoveExcessiveISystem)
+    set(RunCMake_TEST_NO_CLEAN 1)
+    run_cmake_command(XcodeRemoveExcessiveISystemSDK-${SDK}-build ${CMAKE_COMMAND} --build . -- -sdk ${SDK})
+  endfunction()
+
+  XcodeRemoveExcessiveISystemSDK(iphoneos)
+  XcodeRemoveExcessiveISystemSDK(iphonesimulator)
+endif()
 # Please add macOS-only tests above before the device-specific tests.
diff --git a/Tests/RunCMake/XcodeProject/XcodeGenerateTopLevelProjectOnlyWithObjectLibrary.cmake b/Tests/RunCMake/XcodeProject/XcodeGenerateTopLevelProjectOnlyWithObjectLibrary.cmake
new file mode 100644
index 0000000..67e4a00
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/XcodeGenerateTopLevelProjectOnlyWithObjectLibrary.cmake
@@ -0,0 +1,3 @@
+set(CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY TRUE)
+project(XcodeGenerateTopLevelProjectOnly NONE)
+add_subdirectory(subproject_with_object_lib)
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/XcodeProject/XcodeRemoveExcessiveISystem.cmake b/Tests/RunCMake/XcodeProject/XcodeRemoveExcessiveISystem.cmake
new file mode 100644
index 0000000..44052f0
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/XcodeRemoveExcessiveISystem.cmake
@@ -0,0 +1,52 @@
+cmake_minimum_required (VERSION 3.14)
+
+if(NOT "$ENV{CMAKE_OSX_ARCHITECTURES}" MATCHES "[;$]")
+  set(USE_SWIFT 1)
+else()
+  set(USE_SWIFT 0)
+endif()
+
+if(IOS)
+  set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED NO)
+  set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+  if(XCODE_VERSION VERSION_LESS 9)
+    set(USE_SWIFT 0)
+  endif()
+endif ()
+
+enable_language (CXX)
+
+if(USE_SWIFT)
+  enable_language (Swift)
+  if(NOT XCODE_VERSION VERSION_LESS 10.2)
+    set(CMAKE_Swift_LANGUAGE_VERSION 5.0)
+  elseif(NOT XCODE_VERSION VERSION_LESS 8.0)
+    set(CMAKE_Swift_LANGUAGE_VERSION 3.0)
+  endif()
+endif()
+
+# Try to find ZLIB in the SDK rather than in system locations.
+set(CMAKE_FIND_USE_PACKAGE_ROOT_PATH FALSE)
+set(CMAKE_FIND_USE_CMAKE_PATH FALSE)
+set(CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH FALSE)
+set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH FALSE)
+list(REMOVE_ITEM CMAKE_SYSTEM_PREFIX_PATH /usr/local /usr / /usr/X11R6 /usr/pkg /opt /sw /opt/local)
+
+find_package(ZLIB REQUIRED)
+add_library (framework_dependency STATIC)
+target_sources (framework_dependency PRIVATE use_cmath.cpp)
+target_link_libraries(framework_dependency INTERFACE ZLIB::ZLIB)
+
+add_library (framework_test SHARED use_cmath.cpp)
+if(USE_SWIFT)
+  target_sources(framework_test PRIVATE foo.swift)
+endif()
+target_link_libraries (framework_test PRIVATE framework_dependency)
+
+set_target_properties (framework_test PROPERTIES
+    FRAMEWORK TRUE
+    FRAMEWORK_VERSION A
+    MACOSX_FRAMEWORK_IDENTIFIER "framework.test"
+    VERSION "1.0"
+    SOVERSION 1.0
+  )
diff --git a/Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake b/Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake
index 7d83a70..c742f50 100644
--- a/Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake
+++ b/Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake
@@ -45,6 +45,7 @@
 check_property("ENVIRONMENT" [=[value="foo"]=])
 check_property("ENVIRONMENT" [=[key="BAR"]=])
 check_property("ENVIRONMENT" [=[value="bar"]=])
+check_property("WORKING_DIRECTORY" [=["/working/dir"]=])
 
 expect_no_schema("NoSchema")
 
diff --git a/Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake b/Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake
index be219f4..ce5c0c9 100644
--- a/Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake
+++ b/Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake
@@ -35,6 +35,7 @@
 create_scheme_for_property(EXECUTABLE myExecutable)
 create_scheme_for_property(ARGUMENTS "--foo;--bar=baz")
 create_scheme_for_property(ENVIRONMENT "FOO=foo;BAR=bar")
+create_scheme_for_property(WORKING_DIRECTORY "/working/dir")
 
 add_executable(NoSchema main.cpp)
 set_target_properties(NoSchema PROPERTIES XCODE_GENERATE_SCHEME OFF)
diff --git a/Tests/RunCMake/XcodeProject/foo.swift b/Tests/RunCMake/XcodeProject/foo.swift
new file mode 100644
index 0000000..fb2d3dc
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/foo.swift
@@ -0,0 +1,2 @@
+func foo() {
+}
diff --git a/Tests/RunCMake/XcodeProject/subproject_with_object_lib/CMakeLists.txt b/Tests/RunCMake/XcodeProject/subproject_with_object_lib/CMakeLists.txt
new file mode 100644
index 0000000..ab400f4
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/subproject_with_object_lib/CMakeLists.txt
@@ -0,0 +1,7 @@
+project(subproject_with_object_lib)
+
+add_library(object_lib_dependency OBJECT dummy.cpp)
+
+add_library(shared_lib SHARED dummy.cpp)
+target_sources(shared_lib PRIVATE $<TARGET_OBJECTS:object_lib_dependency>)
+set_target_properties(shared_lib PROPERTIES MACOSX_RPATH ON)
diff --git a/Tests/RunCMake/XcodeProject/subproject_with_object_lib/dummy.cpp b/Tests/RunCMake/XcodeProject/subproject_with_object_lib/dummy.cpp
new file mode 100644
index 0000000..bb4218a
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/subproject_with_object_lib/dummy.cpp
@@ -0,0 +1,5 @@
+namespace {
+void dummy()
+{
+}
+}
diff --git a/Tests/RunCMake/XcodeProject/use_cmath.cpp b/Tests/RunCMake/XcodeProject/use_cmath.cpp
new file mode 100644
index 0000000..8a58af5
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/use_cmath.cpp
@@ -0,0 +1,6 @@
+#include <cmath>
+
+bool foo(double arg)
+{
+  return std::isfinite(arg);
+}
diff --git a/Tests/RunCMake/add_link_options/LINKER_expansion-list.cmake b/Tests/RunCMake/add_link_options/LINKER_expansion-list.cmake
index 34dcc67..c77b43c 100644
--- a/Tests/RunCMake/add_link_options/LINKER_expansion-list.cmake
+++ b/Tests/RunCMake/add_link_options/LINKER_expansion-list.cmake
@@ -11,7 +11,7 @@
 
 add_library(example SHARED LinkOptionsLib.c)
 # use LAUNCH facility to dump linker command
-set_property(TARGET example PROPERTY RULE_LAUNCH_LINK "\"${CMAKE_CURRENT_BINARY_DIR}/dump${CMAKE_EXECUTABLE_SUFFIX}\"")
+set_property(TARGET example PROPERTY RULE_LAUNCH_LINK "\"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/dump${CMAKE_EXECUTABLE_SUFFIX}\"")
 
 add_dependencies (example dump)
 
diff --git a/Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariableCommandLine-stderr.txt b/Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariableCommandLine-stderr.txt
index 38566fb..206ab21 100644
--- a/Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariableCommandLine-stderr.txt
+++ b/Tests/RunCMake/ctest_labels_for_subprojects/CTestScriptVariableCommandLine-stderr.txt
@@ -1 +1,2 @@
-Unable to find executable:.*MyThirdPartyDependency/src/thirdparty
+Unable to find executable:.*MyThirdPartyDependency/src(/[^/
+]+)?/thirdparty
diff --git a/Tests/RunCMake/ctest_test/RunCMakeTest.cmake b/Tests/RunCMake/ctest_test/RunCMakeTest.cmake
index 6877e6a..84d1d66 100644
--- a/Tests/RunCMake/ctest_test/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ctest_test/RunCMakeTest.cmake
@@ -1,6 +1,9 @@
 include(RunCTest)
 set(RunCMake_TEST_TIMEOUT 60)
 
+unset(ENV{CTEST_PARALLEL_LEVEL})
+unset(ENV{CTEST_OUTPUT_ON_FAILURE})
+
 set(CASE_CTEST_TEST_ARGS "")
 set(CASE_CTEST_TEST_LOAD "")
 
@@ -71,7 +74,24 @@
 add_test(NAME FailingTest COMMAND ${CMAKE_COMMAND} -E no_such_command)
   ]])
 
-  unset(ENV{CTEST_PARALLEL_LEVEL})
   run_ctest(TestOutputSize)
 endfunction()
 run_TestOutputSize()
+
+run_ctest_test(TestRepeatBad1 REPEAT UNKNOWN:3)
+run_ctest_test(TestRepeatBad2 REPEAT UNTIL_FAIL:-1)
+
+function(run_TestRepeat case)
+  set(CASE_CTEST_TEST_ARGS EXCLUDE RunCMakeVersion ${ARGN})
+  string(CONCAT CASE_CMAKELISTS_SUFFIX_CODE [[
+add_test(NAME testRepeat
+  COMMAND ${CMAKE_COMMAND} -D COUNT_FILE=${CMAKE_CURRENT_BINARY_DIR}/count.cmake
+                           -P "]] "${RunCMake_SOURCE_DIR}/TestRepeat${case}" [[.cmake")
+set_property(TEST testRepeat PROPERTY TIMEOUT 5)
+  ]])
+
+  run_ctest(TestRepeat${case})
+endfunction()
+run_TestRepeat(UntilFail REPEAT UNTIL_FAIL:3)
+run_TestRepeat(UntilPass REPEAT UNTIL_PASS:3)
+run_TestRepeat(AfterTimeout REPEAT AFTER_TIMEOUT:3)
diff --git a/Tests/RunCMake/ctest_test/TestRepeatAfterTimeout-stdout.txt b/Tests/RunCMake/ctest_test/TestRepeatAfterTimeout-stdout.txt
new file mode 100644
index 0000000..17657c5
--- /dev/null
+++ b/Tests/RunCMake/ctest_test/TestRepeatAfterTimeout-stdout.txt
@@ -0,0 +1,10 @@
+Test project [^
+]*/Tests/RunCMake/ctest_test/TestRepeatAfterTimeout-build
+    Start 1: testRepeat
+1/1 Test #1: testRepeat .......................\*\*\*Timeout +[0-9.]+ sec
+    Start 1: testRepeat
+    Test #1: testRepeat .......................   Passed +[0-9.]+ sec
++
+100% tests passed, 0 tests failed out of 1
++
+Total Test time \(real\) = +[0-9.]+ sec$
diff --git a/Tests/RunCMake/ctest_test/TestRepeatAfterTimeout.cmake b/Tests/RunCMake/ctest_test/TestRepeatAfterTimeout.cmake
new file mode 100644
index 0000000..abde4f0
--- /dev/null
+++ b/Tests/RunCMake/ctest_test/TestRepeatAfterTimeout.cmake
@@ -0,0 +1,10 @@
+include("${COUNT_FILE}" OPTIONAL)
+if(NOT COUNT)
+  set(COUNT 0)
+endif()
+math(EXPR COUNT "${COUNT} + 1")
+file(WRITE "${COUNT_FILE}" "set(COUNT ${COUNT})\n")
+if(NOT COUNT EQUAL 2)
+  message("this test times out except on the 2nd run")
+  execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 10)
+endif()
diff --git a/Tests/RunCMake/ctest_test/TestRepeatBad1-result.txt b/Tests/RunCMake/ctest_test/TestRepeatBad1-result.txt
new file mode 100644
index 0000000..b57e2de
--- /dev/null
+++ b/Tests/RunCMake/ctest_test/TestRepeatBad1-result.txt
@@ -0,0 +1 @@
+(-1|255)
diff --git a/Tests/RunCMake/ctest_test/TestRepeatBad1-stderr.txt b/Tests/RunCMake/ctest_test/TestRepeatBad1-stderr.txt
new file mode 100644
index 0000000..37cffbf
--- /dev/null
+++ b/Tests/RunCMake/ctest_test/TestRepeatBad1-stderr.txt
@@ -0,0 +1 @@
+Repeat option invalid value: UNKNOWN:3
diff --git a/Tests/RunCMake/ctest_test/TestRepeatBad2-result.txt b/Tests/RunCMake/ctest_test/TestRepeatBad2-result.txt
new file mode 100644
index 0000000..b57e2de
--- /dev/null
+++ b/Tests/RunCMake/ctest_test/TestRepeatBad2-result.txt
@@ -0,0 +1 @@
+(-1|255)
diff --git a/Tests/RunCMake/ctest_test/TestRepeatBad2-stderr.txt b/Tests/RunCMake/ctest_test/TestRepeatBad2-stderr.txt
new file mode 100644
index 0000000..ca5cef7
--- /dev/null
+++ b/Tests/RunCMake/ctest_test/TestRepeatBad2-stderr.txt
@@ -0,0 +1 @@
+Repeat option invalid value: UNTIL_FAIL:-1
diff --git a/Tests/RunCMake/ctest_test/TestRepeatUntilFail-stdout.txt b/Tests/RunCMake/ctest_test/TestRepeatUntilFail-stdout.txt
new file mode 100644
index 0000000..5f91a67
--- /dev/null
+++ b/Tests/RunCMake/ctest_test/TestRepeatUntilFail-stdout.txt
@@ -0,0 +1,13 @@
+Test project [^
+]*/Tests/RunCMake/ctest_test/TestRepeatUntilFail-build
+    Start 1: testRepeat
+    Test #1: testRepeat .......................   Passed +[0-9.]+ sec
+    Start 1: testRepeat
+    Test #1: testRepeat .......................\*\*\*Failed +[0-9.]+ sec
++
+0% tests passed, 1 tests failed out of 1
++
+Total Test time \(real\) = +[0-9.]+ sec
++
+The following tests FAILED:
+[	 ]+1 - testRepeat \(Failed\)$
diff --git a/Tests/RunCMake/ctest_test/TestRepeatUntilFail.cmake b/Tests/RunCMake/ctest_test/TestRepeatUntilFail.cmake
new file mode 100644
index 0000000..5eb0d8a
--- /dev/null
+++ b/Tests/RunCMake/ctest_test/TestRepeatUntilFail.cmake
@@ -0,0 +1,9 @@
+include("${COUNT_FILE}" OPTIONAL)
+if(NOT COUNT)
+  set(COUNT 0)
+endif()
+math(EXPR COUNT "${COUNT} + 1")
+file(WRITE "${COUNT_FILE}" "set(COUNT ${COUNT})\n")
+if(COUNT EQUAL 2)
+  message(FATAL_ERROR "this test fails on the 2nd run")
+endif()
diff --git a/Tests/RunCMake/ctest_test/TestRepeatUntilPass-stdout.txt b/Tests/RunCMake/ctest_test/TestRepeatUntilPass-stdout.txt
new file mode 100644
index 0000000..bc6939a
--- /dev/null
+++ b/Tests/RunCMake/ctest_test/TestRepeatUntilPass-stdout.txt
@@ -0,0 +1,10 @@
+Test project [^
+]*/Tests/RunCMake/ctest_test/TestRepeatUntilPass-build
+    Start 1: testRepeat
+1/1 Test #1: testRepeat .......................\*\*\*Failed +[0-9.]+ sec
+    Start 1: testRepeat
+    Test #1: testRepeat .......................   Passed +[0-9.]+ sec
++
+100% tests passed, 0 tests failed out of 1
++
+Total Test time \(real\) = +[0-9.]+ sec$
diff --git a/Tests/RunCMake/ctest_test/TestRepeatUntilPass.cmake b/Tests/RunCMake/ctest_test/TestRepeatUntilPass.cmake
new file mode 100644
index 0000000..0662522
--- /dev/null
+++ b/Tests/RunCMake/ctest_test/TestRepeatUntilPass.cmake
@@ -0,0 +1,9 @@
+include("${COUNT_FILE}" OPTIONAL)
+if(NOT COUNT)
+  set(COUNT 0)
+endif()
+math(EXPR COUNT "${COUNT} + 1")
+file(WRITE "${COUNT_FILE}" "set(COUNT ${COUNT})\n")
+if(NOT COUNT EQUAL 2)
+  message(FATAL_ERROR "this test passes only on the 2nd run")
+endif()
diff --git a/Tests/RunCMake/export/Repeat.cmake b/Tests/RunCMake/export/Repeat.cmake
new file mode 100644
index 0000000..f3262e7
--- /dev/null
+++ b/Tests/RunCMake/export/Repeat.cmake
@@ -0,0 +1,5 @@
+add_library(foo INTERFACE)
+export(TARGETS foo FILE foo.cmake)
+export(TARGETS foo FILE foo.cmake)
+add_subdirectory(Repeat)
+include(CMakePackageConfigHelpers)
diff --git a/Tests/RunCMake/export/Repeat/CMakeLists.txt b/Tests/RunCMake/export/Repeat/CMakeLists.txt
new file mode 100644
index 0000000..b37f6ca
--- /dev/null
+++ b/Tests/RunCMake/export/Repeat/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_library(bar INTERFACE)
+export(TARGETS bar FILE ${CMAKE_BINARY_DIR}/foo.cmake)
diff --git a/Tests/RunCMake/export/RunCMakeTest.cmake b/Tests/RunCMake/export/RunCMakeTest.cmake
index 4d2f217..df35d95 100644
--- a/Tests/RunCMake/export/RunCMakeTest.cmake
+++ b/Tests/RunCMake/export/RunCMakeTest.cmake
@@ -2,6 +2,7 @@
 
 run_cmake(CustomTarget)
 run_cmake(Empty)
+run_cmake(Repeat)
 run_cmake(TargetNotFound)
 run_cmake(AppendExport)
 run_cmake(OldIface)
diff --git a/Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake-build-stdout.txt b/Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake-build-stdout.txt
new file mode 100644
index 0000000..05c9a91
--- /dev/null
+++ b/Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake-build-stdout.txt
@@ -0,0 +1 @@
+test2/test_folder_symlink
diff --git a/Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake-rebuild-stdout.txt b/Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake-rebuild-stdout.txt
new file mode 100644
index 0000000..05c9a91
--- /dev/null
+++ b/Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake-rebuild-stdout.txt
@@ -0,0 +1 @@
+test2/test_folder_symlink
diff --git a/Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake-stdout.txt b/Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake-stdout.txt
new file mode 100644
index 0000000..1fbac01
--- /dev/null
+++ b/Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake-stdout.txt
@@ -0,0 +1 @@
+.*Running CMake on GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake
diff --git a/Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake.cmake b/Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake.cmake
new file mode 100644
index 0000000..da40534
--- /dev/null
+++ b/Tests/RunCMake/file/GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake.cmake
@@ -0,0 +1,10 @@
+cmake_policy(SET CMP0009 NEW)
+message(STATUS "Running CMake on GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake")
+file(GLOB_RECURSE
+  CONTENT_LIST
+  CONFIGURE_DEPENDS
+  LIST_DIRECTORIES false
+  RELATIVE "${CMAKE_CURRENT_BINARY_DIR}"
+  "${CMAKE_CURRENT_BINARY_DIR}/test2/*"
+  )
+add_custom_target(CONTENT_ECHO ALL ${CMAKE_COMMAND} -E echo ${CONTENT_LIST})
diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake
index 5db4b3b..f5461ad 100644
--- a/Tests/RunCMake/file/RunCMakeTest.cmake
+++ b/Tests/RunCMake/file/RunCMakeTest.cmake
@@ -69,7 +69,7 @@
   run_cmake(INSTALL-FOLLOW_SYMLINK_CHAIN)
 endif()
 
-if(RunCMake_GENERATOR STREQUAL "Ninja")
+if(RunCMake_GENERATOR MATCHES "Ninja")
   # Detect ninja version so we know what tests can be supported.
   execute_process(
     COMMAND "${RunCMake_MAKE_PROGRAM}" --version
@@ -90,7 +90,7 @@
   endif()
 endif()
 
-if(RunCMake_GENERATOR STREQUAL "Ninja" AND "${ninja_version}" VERSION_LESS 1.8)
+if(RunCMake_GENERATOR MATCHES "Ninja" AND "${ninja_version}" VERSION_LESS 1.8)
   run_cmake(GLOB_RECURSE-warn-CONFIGURE_DEPENDS-ninja-version)
 else()
   run_cmake(GLOB-warn-CONFIGURE_DEPENDS-late)
@@ -111,7 +111,7 @@
   set(tf_1  "${RunCMake_TEST_BINARY_DIR}/test/1.txt")
   file(WRITE "${tf_1}" "1")
 
-  message(STATUS "GLOB-RerunCMake: first configuration...")
+  message(STATUS "GLOB-CONFIGURE_DEPENDS-RerunCMake: first configuration...")
   run_cmake(GLOB-CONFIGURE_DEPENDS-RerunCMake)
   run_cmake_command(GLOB-CONFIGURE_DEPENDS-RerunCMake-build ${CMAKE_COMMAND} --build .)
 
@@ -125,10 +125,25 @@
 
   execute_process(COMMAND ${CMAKE_COMMAND} -E sleep ${fs_delay})
   message(STATUS "GLOB-CONFIGURE_DEPENDS-RerunCMake: remove first test file...")
-  file(REMOVE "${RunCMake_TEST_BINARY_DIR}/test/1.txt")
+  file(REMOVE "${tf_1}")
   run_cmake_command(GLOB-CONFIGURE_DEPENDS-RerunCMake-rebuild_second ${CMAKE_COMMAND} --build .)
   run_cmake_command(GLOB-CONFIGURE_DEPENDS-RerunCMake-nowork ${CMAKE_COMMAND} --build .)
 
+  if(NOT WIN32 OR CYGWIN)
+    message(STATUS "GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake: link the first test directory into a new directory...")
+    file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}/test2")
+    execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${RunCMake_TEST_BINARY_DIR}/test" "${RunCMake_TEST_BINARY_DIR}/test2/test_folder_symlink")
+
+    message(STATUS "GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake: first configuration...")
+    run_cmake(GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake)
+    run_cmake_command(GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake-build ${CMAKE_COMMAND} --build .)
+
+    message(STATUS "GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake: add another file in the linked directory...")
+    set(tf_3  "${RunCMake_TEST_BINARY_DIR}/test/3.txt")
+    file(WRITE "${tf_3}" "3")
+    run_cmake_command(GLOB-CONFIGURE_DEPENDS-CMP0009-RerunCMake-rebuild ${CMAKE_COMMAND} --build .)
+  endif()
+
   unset(RunCMake_TEST_BINARY_DIR)
   unset(RunCMake_TEST_NO_CLEAN)
   unset(RunCMake_DEFAULT_stderr)
diff --git a/Tests/RunCMake/find_file/PrefixInPATH-stderr.txt b/Tests/RunCMake/find_file/PrefixInPATH-stderr.txt
new file mode 100644
index 0000000..0d77571
--- /dev/null
+++ b/Tests/RunCMake/find_file/PrefixInPATH-stderr.txt
@@ -0,0 +1,13 @@
+  find_file called with the following settings:.*
+    VAR: PrefixInPATH_INCLUDE_DIR
+    NAMES: \"PrefixInPATH\.h\"
+    Documentation.*
+    Framework.*
+    AppBundle.*
+    CMAKE_FIND_USE_CMAKE_PATH: 1
+    CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH: 1
+    CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH: 1
+    CMAKE_FIND_USE_CMAKE_SYSTEM_PATH: 1
+
+  find_file considered the following locations:.*
+.*include/PrefixInPATH.*
diff --git a/Tests/RunCMake/find_file/PrefixInPATH.cmake b/Tests/RunCMake/find_file/PrefixInPATH.cmake
index 1e33c08..c334d89 100644
--- a/Tests/RunCMake/find_file/PrefixInPATH.cmake
+++ b/Tests/RunCMake/find_file/PrefixInPATH.cmake
@@ -1,4 +1,10 @@
 set(ENV_PATH "$ENV{PATH}")
+
+set(CMAKE_FIND_DEBUG_MODE 1)
+set(ENV{PATH} "${CMAKE_CURRENT_SOURCE_DIR}/bin")
+find_file(PrefixInPATH_INCLUDE_DIR NAMES PrefixInPATH.h)
+set(CMAKE_FIND_DEBUG_MODE 0)
+
 foreach(path "/does_not_exist" "" "/bin" "/sbin")
   unset(PrefixInPATH_INCLUDE_DIR CACHE)
   set(ENV{PATH} "${CMAKE_CURRENT_SOURCE_DIR}${path}")
diff --git a/Tests/RunCMake/find_library/FromPATHEnv-stderr.txt b/Tests/RunCMake/find_library/FromPATHEnv-stderr.txt
new file mode 100644
index 0000000..a690eec
--- /dev/null
+++ b/Tests/RunCMake/find_library/FromPATHEnv-stderr.txt
@@ -0,0 +1,28 @@
+  find_library called with the following settings:.*
+    VAR: CREATED_LIBRARY
+    NAMES: \"created\"
+           \"created_no_exist\"
+    Documentation.*
+    Framework.*
+    AppBundle.*
+    CMAKE_FIND_USE_CMAKE_PATH: 1
+    CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH: 1
+    CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH: 0
+    CMAKE_FIND_USE_CMAKE_SYSTEM_PATH: 1
+
+  find_library considered the following locations:.*
+  The item was not found.*
+  find_library called with the following settings:.*
+    VAR: CREATED_LIBRARY
+    NAMES: \"created\"
+    Documentation.*
+    Framework.*
+    AppBundle.*
+    CMAKE_FIND_USE_CMAKE_PATH: 1
+    CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH: 1
+    CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH: 1
+    CMAKE_FIND_USE_CMAKE_SYSTEM_PATH: 1
+
+  find_library considered the following locations:.*
+  The item was found at.*
+.*lib/libcreated.a
diff --git a/Tests/RunCMake/find_library/FromPATHEnv.cmake b/Tests/RunCMake/find_library/FromPATHEnv.cmake
index fec041d..c24e640 100644
--- a/Tests/RunCMake/find_library/FromPATHEnv.cmake
+++ b/Tests/RunCMake/find_library/FromPATHEnv.cmake
@@ -4,6 +4,19 @@
 file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
 file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib/libcreated.a" "created")
 
+set(CMAKE_FIND_DEBUG_MODE 1)
+set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH OFF)
+
+set(ENV{PATH} "${CMAKE_CURRENT_BINARY_DIR}/lib")
+find_library(CREATED_LIBRARY NAMES created created_no_exist)
+
+set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH ON)
+
+set(ENV{PATH} "${CMAKE_CURRENT_BINARY_DIR}/lib")
+find_library(CREATED_LIBRARY NAMES created)
+set(CMAKE_FIND_DEBUG_MODE 0)
+
+
 foreach(path "/does_not_exist" "/lib" "")
   unset(CREATED_LIBRARY CACHE)
   set(ENV{PATH} "${CMAKE_CURRENT_BINARY_DIR}${path}")
diff --git a/Tests/RunCMake/find_library/PrefixInPATH-stderr.txt b/Tests/RunCMake/find_library/PrefixInPATH-stderr.txt
new file mode 100644
index 0000000..1d24c84
--- /dev/null
+++ b/Tests/RunCMake/find_library/PrefixInPATH-stderr.txt
@@ -0,0 +1,14 @@
+  find_library called with the following settings:.*
+    VAR: PrefixInPATH_LIBRARY
+    NAMES: \"PrefixInPATH\"
+    Documentation.*
+    Framework.*
+    AppBundle.*
+    CMAKE_FIND_USE_CMAKE_PATH: 1
+    CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH: 1
+    CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH: 1
+    CMAKE_FIND_USE_CMAKE_SYSTEM_PATH: 1
+
+  find_library considered the following locations:.*
+.*/does_not_exist.*
+  The item was not found
diff --git a/Tests/RunCMake/find_library/PrefixInPATH.cmake b/Tests/RunCMake/find_library/PrefixInPATH.cmake
index f1b8b18..e27d362 100644
--- a/Tests/RunCMake/find_library/PrefixInPATH.cmake
+++ b/Tests/RunCMake/find_library/PrefixInPATH.cmake
@@ -2,6 +2,12 @@
 list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES .a)
 
 set(ENV_PATH "$ENV{PATH}")
+
+set(CMAKE_FIND_DEBUG_MODE 1)
+set(ENV{PATH} "${CMAKE_CURRENT_SOURCE_DIR}/does_not_exist")
+find_library(PrefixInPATH_LIBRARY NAMES PrefixInPATH)
+set(CMAKE_FIND_DEBUG_MODE 0)
+
 foreach(path "/does_not_exist" "" "/bin" "/sbin")
   unset(PrefixInPATH_LIBRARY CACHE)
   set(ENV{PATH} "${CMAKE_CURRENT_SOURCE_DIR}${path}")
diff --git a/Tests/RunCMake/find_package/FromPATHEnv-stderr.txt b/Tests/RunCMake/find_package/FromPATHEnv-stderr.txt
new file mode 100644
index 0000000..b35f05e
--- /dev/null
+++ b/Tests/RunCMake/find_package/FromPATHEnv-stderr.txt
@@ -0,0 +1,20 @@
+CMake Debug Log at FromPATHEnv.cmake:5 \(find_package\):
+  find_package considered the following paths for Resolved.cmake.*
+.*/Modules/FindResolved.cmake.*
+  The file was not found.*
+  <PackageName>_ROOT CMake variable.*
+  CMAKE_PREFIX_PATH variable.*
+  CMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH variables.*
+  Env variable Resolved_DIR.*
+  CMAKE_PREFIX_PATH env variable.*
+  Paths specified by the find_package HINTS option.*
+  Standard system environment variables.*
+.*Tests/RunCMake/find_package/PackageRoot.*
+  CMake User Package Registry.*
+  CMake variables defined in the Platform file.*
+  CMake System Package Registry.*
+  Paths specified by the find_package PATHS option.*
+  find_package considered the following locations for the Config module:.*
+.*Tests/RunCMake/find_package/PackageRoot/ResolvedConfig\.cmake.*
+  The file was found at.*
+.*Tests/RunCMake/find_package/PackageRoot/ResolvedConfig\.cmake
diff --git a/Tests/RunCMake/find_package/FromPATHEnv.cmake b/Tests/RunCMake/find_package/FromPATHEnv.cmake
index 4822b13..ceb79b6 100644
--- a/Tests/RunCMake/find_package/FromPATHEnv.cmake
+++ b/Tests/RunCMake/find_package/FromPATHEnv.cmake
@@ -1,4 +1,10 @@
 set(ENV_PATH "$ENV{PATH}")
+
+set(CMAKE_FIND_DEBUG_MODE ON)
+set(ENV{PATH} "${CMAKE_CURRENT_SOURCE_DIR}/PackageRoot")
+find_package(Resolved QUIET)
+set(CMAKE_FIND_DEBUG_MODE OFF)
+
 foreach(path "/does_not_exist" "/PackageRoot" "")
   unset(Resolved_FOUND CACHE)
   set(Resolved_DIR "")
diff --git a/Tests/RunCMake/find_package/MissingConfigDebug-stderr.txt b/Tests/RunCMake/find_package/MissingConfigDebug-stderr.txt
new file mode 100644
index 0000000..379bf7a
--- /dev/null
+++ b/Tests/RunCMake/find_package/MissingConfigDebug-stderr.txt
@@ -0,0 +1,18 @@
+  <PackageName>_ROOT CMake variable.*
+  CMAKE_PREFIX_PATH variable.*
+  CMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH variables.*
+  Env variable NotHere_DIR.*
+  CMAKE_PREFIX_PATH env variable.*
+  Standard system environment variables.*
+  CMake User Package Registry.*
+  CMake variables defined in the Platform file.*
+  CMake System Package Registry.*
+  Paths specified by the find_package PATHS option.*
+.*
+    .*NotHereConfig.cmake
+    .*nothere-config.cmake
+.*
+CMake Warning at MissingConfigDebug.cmake:3 \(message\):
+  This warning must be reachable.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/find_package/MissingConfigDebug.cmake b/Tests/RunCMake/find_package/MissingConfigDebug.cmake
new file mode 100644
index 0000000..4e3bb22
--- /dev/null
+++ b/Tests/RunCMake/find_package/MissingConfigDebug.cmake
@@ -0,0 +1,4 @@
+set(CMAKE_FIND_DEBUG_MODE ON)
+find_package(NotHere CONFIG)
+message(WARNING "This warning must be reachable.")
+set(CMAKE_FIND_DEBUG_MODE OFF)
diff --git a/Tests/RunCMake/find_package/RunCMakeTest.cmake b/Tests/RunCMake/find_package/RunCMakeTest.cmake
index 208f83c..5186297 100644
--- a/Tests/RunCMake/find_package/RunCMakeTest.cmake
+++ b/Tests/RunCMake/find_package/RunCMakeTest.cmake
@@ -13,6 +13,7 @@
 run_cmake(MissingModule)
 run_cmake(MissingModuleRequired)
 run_cmake(MissingConfig)
+run_cmake(MissingConfigDebug)
 run_cmake(MissingConfigOneName)
 run_cmake(MissingConfigRequired)
 run_cmake(MissingConfigVersion)
diff --git a/Tests/RunCMake/find_path/FromPATHEnv-stderr.txt b/Tests/RunCMake/find_path/FromPATHEnv-stderr.txt
new file mode 100644
index 0000000..088efd5
--- /dev/null
+++ b/Tests/RunCMake/find_path/FromPATHEnv-stderr.txt
@@ -0,0 +1,27 @@
+  find_path called with the following settings:.*
+    VAR: PATH_IN_ENV_PATH
+    NAMES: \"PrefixInPATH\.h\"
+    Documentation.*
+    Framework.*
+    AppBundle.*
+    CMAKE_FIND_USE_CMAKE_PATH: 1
+    CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH: 1
+    CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH: 0
+    CMAKE_FIND_USE_CMAKE_SYSTEM_PATH: 1
+
+  find_path considered the following locations:.*
+  The item was not found.*
+  find_path called with the following settings:.*
+    VAR: PATH_IN_ENV_PATH
+    NAMES: \"PrefixInPATH\.h\"
+    Documentation.*
+    Framework.*
+    AppBundle.*
+    CMAKE_FIND_USE_CMAKE_PATH: 1
+    CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH: 1
+    CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH: 1
+    CMAKE_FIND_USE_CMAKE_SYSTEM_PATH: 1
+
+  find_path considered the following locations:.*
+  The item was found at.*
+.*include/PrefixInPATH.*
diff --git a/Tests/RunCMake/find_path/FromPATHEnv.cmake b/Tests/RunCMake/find_path/FromPATHEnv.cmake
index af13d09..535e624 100644
--- a/Tests/RunCMake/find_path/FromPATHEnv.cmake
+++ b/Tests/RunCMake/find_path/FromPATHEnv.cmake
@@ -1,4 +1,16 @@
 set(ENV_PATH "$ENV{PATH}")
+
+set(CMAKE_FIND_DEBUG_MODE 1)
+set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH OFF)
+
+set(ENV{PATH} "${CMAKE_CURRENT_SOURCE_DIR}/include")
+find_path(PATH_IN_ENV_PATH NAMES PrefixInPATH.h)
+
+set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH ON)
+find_path(PATH_IN_ENV_PATH NAMES PrefixInPATH.h)
+
+set(CMAKE_FIND_DEBUG_MODE 0)
+
 foreach(path "/does_not_exist" "/include" "")
   unset(PATH_IN_ENV_PATH CACHE)
   set(ENV{PATH} "${CMAKE_CURRENT_SOURCE_DIR}${path}")
diff --git a/Tests/RunCMake/find_program/EnvAndHints-stderr.txt b/Tests/RunCMake/find_program/EnvAndHints-stderr.txt
new file mode 100644
index 0000000..8951345
--- /dev/null
+++ b/Tests/RunCMake/find_program/EnvAndHints-stderr.txt
@@ -0,0 +1,28 @@
+  find_program called with the following settings:.*
+    VAR: PROG
+    NAMES: \"testAandB\"
+    Documentation.*
+    Framework.*
+    AppBundle.*
+    CMAKE_FIND_USE_CMAKE_PATH: 1
+    CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH: 1
+    CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH: 1
+    CMAKE_FIND_USE_CMAKE_SYSTEM_PATH: 1
+
+  find_program considered the following locations:.*
+  The item was found at.*
+.*testAandB
+.*
+  find_program called with the following settings:.*
+    VAR: PROG
+    NAMES: \"testAandB\"
+    Documentation.*
+    Framework.*
+    AppBundle.*
+    CMAKE_FIND_USE_CMAKE_PATH: 1
+    CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH: 1
+    CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH: 0
+    CMAKE_FIND_USE_CMAKE_SYSTEM_PATH: 1
+
+  find_program considered the following locations:.*
+  The item was not found.*
diff --git a/Tests/RunCMake/find_program/EnvAndHints.cmake b/Tests/RunCMake/find_program/EnvAndHints.cmake
index 0f12eff..beed873 100644
--- a/Tests/RunCMake/find_program/EnvAndHints.cmake
+++ b/Tests/RunCMake/find_program/EnvAndHints.cmake
@@ -1,4 +1,5 @@
 
+set(CMAKE_FIND_DEBUG_MODE 1)
 set(ENV_PATH "$ENV{PATH}")
 set(ENV{PATH} ${CMAKE_CURRENT_SOURCE_DIR}/A)
 find_program(PROG
@@ -13,6 +14,7 @@
   )
 message(STATUS "PROG='${PROG}'")
 unset(PROG CACHE)
+set(CMAKE_FIND_DEBUG_MODE 0)
 
 find_program(PROG
   NAMES testAandB
diff --git a/Tests/RunCMake/foreach/RunCMakeTest.cmake b/Tests/RunCMake/foreach/RunCMakeTest.cmake
index 4b74cfe..22a0a75 100644
--- a/Tests/RunCMake/foreach/RunCMakeTest.cmake
+++ b/Tests/RunCMake/foreach/RunCMakeTest.cmake
@@ -1,3 +1,21 @@
 include(RunCMake)
 
 run_cmake(BadRangeInFunction)
+run_cmake(foreach-all-test)
+run_cmake(foreach-ITEMS-multiple-iter-vars-test)
+run_cmake(foreach-LISTS-multiple-iter-vars-test)
+run_cmake(foreach-ZIP_LISTS-test)
+run_cmake(foreach-ITEMS-with-ZIP_LISTS-mix-test)
+run_cmake(foreach-LISTS-with-ZIP_LISTS-mix-test)
+run_cmake(foreach-ZIP_LISTS-with-ITEMS-mix-test)
+run_cmake(foreach-ZIP_LISTS-with-LISTS-mix-test)
+run_cmake(foreach-ZIP_LISTS-multiple-iter-vars-test)
+run_cmake(foreach-ZIP_LISTS-iter-vars-mismatch-test-1)
+run_cmake(foreach-ZIP_LISTS-iter-vars-mismatch-test-2)
+run_cmake(foreach-RANGE-non-int-test-1)
+run_cmake(foreach-RANGE-non-int-test-2-1)
+run_cmake(foreach-RANGE-non-int-test-2-2)
+run_cmake(foreach-RANGE-non-int-test-3-1)
+run_cmake(foreach-RANGE-non-int-test-3-2)
+run_cmake(foreach-RANGE-non-int-test-3-3)
+run_cmake(foreach-RANGE-invalid-test)
diff --git a/Tests/RunCMake/foreach/foreach-ITEMS-multiple-iter-vars-test-result.txt b/Tests/RunCMake/foreach/foreach-ITEMS-multiple-iter-vars-test-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ITEMS-multiple-iter-vars-test-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/foreach/foreach-ITEMS-multiple-iter-vars-test-stderr.txt b/Tests/RunCMake/foreach/foreach-ITEMS-multiple-iter-vars-test-stderr.txt
new file mode 100644
index 0000000..d174bb1
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ITEMS-multiple-iter-vars-test-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at foreach-ITEMS-multiple-iter-vars-test.cmake:1 \(foreach\):
+  ITEMS or LISTS require exactly one iteration variable
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/foreach/foreach-ITEMS-multiple-iter-vars-test.cmake b/Tests/RunCMake/foreach/foreach-ITEMS-multiple-iter-vars-test.cmake
new file mode 100644
index 0000000..55d33a8
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ITEMS-multiple-iter-vars-test.cmake
@@ -0,0 +1,2 @@
+foreach(one two IN ITEMS one two)
+endforeach()
diff --git a/Tests/RunCMake/foreach/foreach-ITEMS-with-ZIP_LISTS-mix-test-result.txt b/Tests/RunCMake/foreach/foreach-ITEMS-with-ZIP_LISTS-mix-test-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ITEMS-with-ZIP_LISTS-mix-test-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/foreach/foreach-ITEMS-with-ZIP_LISTS-mix-test-stderr.txt b/Tests/RunCMake/foreach/foreach-ITEMS-with-ZIP_LISTS-mix-test-stderr.txt
new file mode 100644
index 0000000..f7d5ae7
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ITEMS-with-ZIP_LISTS-mix-test-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at foreach-ITEMS-with-ZIP_LISTS-mix-test.cmake:1 \(foreach\):
+  ZIP_LISTS can not be used with LISTS or ITEMS
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/foreach/foreach-ITEMS-with-ZIP_LISTS-mix-test.cmake b/Tests/RunCMake/foreach/foreach-ITEMS-with-ZIP_LISTS-mix-test.cmake
new file mode 100644
index 0000000..28099a0
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ITEMS-with-ZIP_LISTS-mix-test.cmake
@@ -0,0 +1,2 @@
+foreach(i IN ITEMS one two three ZIP_LISTS blah)
+endforeach()
diff --git a/Tests/RunCMake/foreach/foreach-LISTS-multiple-iter-vars-test-result.txt b/Tests/RunCMake/foreach/foreach-LISTS-multiple-iter-vars-test-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-LISTS-multiple-iter-vars-test-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/foreach/foreach-LISTS-multiple-iter-vars-test-stderr.txt b/Tests/RunCMake/foreach/foreach-LISTS-multiple-iter-vars-test-stderr.txt
new file mode 100644
index 0000000..f2f83c2
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-LISTS-multiple-iter-vars-test-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at foreach-LISTS-multiple-iter-vars-test.cmake:1 \(foreach\):
+  ITEMS or LISTS require exactly one iteration variable
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/foreach/foreach-LISTS-multiple-iter-vars-test.cmake b/Tests/RunCMake/foreach/foreach-LISTS-multiple-iter-vars-test.cmake
new file mode 100644
index 0000000..78f3847
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-LISTS-multiple-iter-vars-test.cmake
@@ -0,0 +1,2 @@
+foreach(one two IN LISTS one two)
+endforeach()
diff --git a/Tests/RunCMake/foreach/foreach-LISTS-with-ZIP_LISTS-mix-test-result.txt b/Tests/RunCMake/foreach/foreach-LISTS-with-ZIP_LISTS-mix-test-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-LISTS-with-ZIP_LISTS-mix-test-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/foreach/foreach-LISTS-with-ZIP_LISTS-mix-test-stderr.txt b/Tests/RunCMake/foreach/foreach-LISTS-with-ZIP_LISTS-mix-test-stderr.txt
new file mode 100644
index 0000000..42f8d1e
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-LISTS-with-ZIP_LISTS-mix-test-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at foreach-LISTS-with-ZIP_LISTS-mix-test.cmake:1 \(foreach\):
+  ZIP_LISTS can not be used with LISTS or ITEMS
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/foreach/foreach-LISTS-with-ZIP_LISTS-mix-test.cmake b/Tests/RunCMake/foreach/foreach-LISTS-with-ZIP_LISTS-mix-test.cmake
new file mode 100644
index 0000000..8a919dd
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-LISTS-with-ZIP_LISTS-mix-test.cmake
@@ -0,0 +1,2 @@
+foreach(i IN LISTS one two three ZIP_LISTS blah)
+endforeach()
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-invalid-test-result.txt b/Tests/RunCMake/foreach/foreach-RANGE-invalid-test-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-invalid-test-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-invalid-test-stderr.txt b/Tests/RunCMake/foreach/foreach-RANGE-invalid-test-stderr.txt
new file mode 100644
index 0000000..66efdc1
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-invalid-test-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at foreach-RANGE-invalid-test\.cmake:[0-9]+ \(foreach\):
+  foreach called with incorrect range specification: start 2, stop 1, step 1
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)$
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-invalid-test.cmake b/Tests/RunCMake/foreach/foreach-RANGE-invalid-test.cmake
new file mode 100644
index 0000000..2f8eaba
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-invalid-test.cmake
@@ -0,0 +1,2 @@
+foreach(a RANGE 2 1 1)
+endforeach()
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-1-result.txt b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-1-stderr.txt b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-1-stderr.txt
new file mode 100644
index 0000000..78355dc
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-1-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at foreach-RANGE-non-int-test-1\.cmake:[0-9]+ \(foreach\):
+  foreach Invalid integer: 'b'
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)$
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-1.cmake b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-1.cmake
new file mode 100644
index 0000000..452fbdf
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-1.cmake
@@ -0,0 +1,2 @@
+foreach(a RANGE b)
+endforeach()
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-1-result.txt b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-1-stderr.txt b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-1-stderr.txt
new file mode 100644
index 0000000..787ffc1
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-1-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at foreach-RANGE-non-int-test-2-1\.cmake:[0-9]+ \(foreach\):
+  foreach Invalid integer: 'b'
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)$
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-1.cmake b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-1.cmake
new file mode 100644
index 0000000..885c805
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-1.cmake
@@ -0,0 +1,2 @@
+foreach(a RANGE b 1)
+endforeach()
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-2-result.txt b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-2-stderr.txt b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-2-stderr.txt
new file mode 100644
index 0000000..70cc73f
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-2-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at foreach-RANGE-non-int-test-2-2\.cmake:[0-9]+ \(foreach\):
+  foreach Invalid integer: 'b'
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)$
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-2.cmake b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-2.cmake
new file mode 100644
index 0000000..d52aeb9
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-2.cmake
@@ -0,0 +1,2 @@
+foreach(a RANGE 1 b)
+endforeach()
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-1-result.txt b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-1-stderr.txt b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-1-stderr.txt
new file mode 100644
index 0000000..5803fe8
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-1-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at foreach-RANGE-non-int-test-3-1\.cmake:[0-9]+ \(foreach\):
+  foreach Invalid integer: 'b'
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)$
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-1.cmake b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-1.cmake
new file mode 100644
index 0000000..33a488d
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-1.cmake
@@ -0,0 +1,2 @@
+foreach(a RANGE b 1 1)
+endforeach()
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-2-result.txt b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-2-stderr.txt b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-2-stderr.txt
new file mode 100644
index 0000000..189c60d
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-2-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at foreach-RANGE-non-int-test-3-2\.cmake:[0-9]+ \(foreach\):
+  foreach Invalid integer: 'b'
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)$
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-2.cmake b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-2.cmake
new file mode 100644
index 0000000..ff119d3
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-2.cmake
@@ -0,0 +1,2 @@
+foreach(a RANGE 1 b 1)
+endforeach()
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-3-result.txt b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-3-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-3-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-3-stderr.txt b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-3-stderr.txt
new file mode 100644
index 0000000..ee9e62c
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-3-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at foreach-RANGE-non-int-test-3-3\.cmake:[0-9]+ \(foreach\):
+  foreach Invalid integer: 'b'
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)$
diff --git a/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-3.cmake b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-3.cmake
new file mode 100644
index 0000000..fdebdf0
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-3.cmake
@@ -0,0 +1,2 @@
+foreach(a RANGE 1 1 b)
+endforeach()
diff --git a/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-1-result.txt b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-1-stderr.txt b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-1-stderr.txt
new file mode 100644
index 0000000..fa51e46
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-1-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at foreach-ZIP_LISTS-iter-vars-mismatch-test-1.cmake:1 \(foreach\):
+  Expected 3 list variables, but given 4
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-1.cmake b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-1.cmake
new file mode 100644
index 0000000..458b6ca
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-1.cmake
@@ -0,0 +1,2 @@
+foreach(less than lists IN ZIP_LISTS list_1 list_2 list_3 list_4)
+endforeach()
diff --git a/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-2-result.txt b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-2-stderr.txt b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-2-stderr.txt
new file mode 100644
index 0000000..7b6b484
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-2-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at foreach-ZIP_LISTS-iter-vars-mismatch-test-2.cmake:1 \(foreach\):
+  Expected 3 list variables, but given 2
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-2.cmake b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-2.cmake
new file mode 100644
index 0000000..d24d99c
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-iter-vars-mismatch-test-2.cmake
@@ -0,0 +1,2 @@
+foreach(greater than lists IN ZIP_LISTS list_1 list_2)
+endforeach()
diff --git a/Tests/RunCMake/foreach/foreach-ZIP_LISTS-multiple-iter-vars-test-stdout.txt b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-multiple-iter-vars-test-stdout.txt
new file mode 100644
index 0000000..e009d15
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-multiple-iter-vars-test-stdout.txt
@@ -0,0 +1,6 @@
+-- foreach\(\.\.\. IN ZIP_LISTS\):
+--   Begin output
+--   | one, satu, raz
+--   | two, dua, dva
+--   | three, tiga, tri
+--   End output
diff --git a/Tests/RunCMake/foreach/foreach-ZIP_LISTS-multiple-iter-vars-test.cmake b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-multiple-iter-vars-test.cmake
new file mode 100644
index 0000000..9647dea
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-multiple-iter-vars-test.cmake
@@ -0,0 +1,42 @@
+function(foreachTest result list_var_1 list_var_2 list_var_3)
+    set(_options MUTE)
+    set(_one_value_args)
+    set(_multi_value_args)
+    cmake_parse_arguments(PARSE_ARGV 3 _arg "${_options}" "${_one_value_args}" "${_multi_value_args}")
+
+    set(_has_any_output FALSE)
+    list(APPEND CMAKE_MESSAGE_INDENT "| ")
+    foreach(first second third IN ZIP_LISTS ${list_var_1} ${list_var_2} ${list_var_3})
+        if(NOT first)
+            set(first "[undefiend]")
+        endif()
+        if(NOT second)
+            set(second "[undefiend]")
+        endif()
+        if(NOT third)
+            set(third "[undefiend]")
+        endif()
+        if(NOT _arg_MUTE)
+            message(STATUS "${first}, ${second}, ${third}")
+        endif()
+        set(_has_any_output TRUE)
+    endforeach()
+    set(${result} ${_has_any_output} PARENT_SCOPE)
+endfunction()
+
+function(foreachTestDecorated list_var_1 list_var_2 list_var_3)
+    list(APPEND CMAKE_MESSAGE_INDENT "  ")
+    message(STATUS "Begin output")
+    foreachTest(_has_any_output ${list_var_1} ${list_var_2} ${list_var_3})
+    if(NOT _has_any_output)
+        message(STATUS "--> empty-output <--")
+    endif()
+    message(STATUS "End output")
+endfunction()
+
+list(APPEND english one two three)
+list(APPEND bahasa satu dua tiga)
+list(APPEND russian raz dva tri)
+
+message(STATUS "foreach(... IN ZIP_LISTS):")
+foreachTestDecorated(english bahasa russian)
diff --git a/Tests/RunCMake/foreach/foreach-ZIP_LISTS-test-stdout.txt b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-test-stdout.txt
new file mode 100644
index 0000000..25433fd
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-test-stdout.txt
@@ -0,0 +1,19 @@
+-- foreach\(IN ZIP_LISTS\):
+--   <<< empty lists case >>>
+--     Begin output
+--     --> empty-output <--
+--     End output
+--   <<< same lengths lists case >>>
+--     Begin output
+--     | one, satu, raz
+--     | two, dua, dva
+--     | three, tiga, tri
+--     End output
+--   <<< different lengths lists case >>>
+--     Begin output
+--     | one, satu, raz
+--     | two, dua, dva
+--     | three, tiga, tri
+--     | \[undefiend\], empat, \[undefiend\]
+--     End output
+--   <<< test variable value restored -- PASSED >>>
diff --git a/Tests/RunCMake/foreach/foreach-ZIP_LISTS-test.cmake b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-test.cmake
new file mode 100644
index 0000000..56cfe64
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-test.cmake
@@ -0,0 +1,68 @@
+function(foreachTest result list_var_1 list_var_2 list_var_3)
+    set(_options MUTE)
+    set(_one_value_args)
+    set(_multi_value_args)
+    cmake_parse_arguments(PARSE_ARGV 3 _arg "${_options}" "${_one_value_args}" "${_multi_value_args}")
+
+    set(_has_any_output FALSE)
+    list(APPEND CMAKE_MESSAGE_INDENT "| ")
+    foreach(num IN ZIP_LISTS ${list_var_1} ${list_var_2} ${list_var_3})
+        foreach(i RANGE 2)
+            if(NOT num_${i})
+                set(num_${i} "[undefiend]")
+            endif()
+        endforeach()
+        if(NOT _arg_MUTE)
+            message(STATUS "${num_0}, ${num_1}, ${num_2}")
+        endif()
+        set(_has_any_output TRUE)
+    endforeach()
+    set(${result} ${_has_any_output} PARENT_SCOPE)
+endfunction()
+
+function(foreachTestDecorated list_var_1 list_var_2 list_var_3)
+    list(APPEND CMAKE_MESSAGE_INDENT "  ")
+    message(STATUS "Begin output")
+    foreachTest(_has_any_output ${list_var_1} ${list_var_2} ${list_var_3})
+    if(NOT _has_any_output)
+        message(STATUS "--> empty-output <--")
+    endif()
+    message(STATUS "End output")
+endfunction()
+
+message(STATUS "foreach(IN ZIP_LISTS):")
+list(APPEND CMAKE_MESSAGE_INDENT "  ")
+
+set(english)
+set(bahasa)
+set(russian)
+
+message(STATUS "<<< empty lists case >>>")
+foreachTestDecorated(english bahasa russian)
+
+list(APPEND english one two three)
+list(APPEND bahasa satu dua tiga)
+list(APPEND russian raz dva tri)
+
+message(STATUS "<<< same lengths lists case >>>")
+foreachTestDecorated(english bahasa russian)
+
+list(APPEND bahasa empat)
+
+message(STATUS "<<< different lengths lists case >>>")
+foreachTestDecorated(english bahasa russian)
+
+set(num_0 "old-0")
+set(num_1 "old-1")
+set(num_2 "old-2")
+foreachTest(_ english bahasa russian MUTE)
+set(check PASSED)
+foreach(i RANGE 2)
+    if(NOT "${num_${i}}" STREQUAL "old-${i}")
+        message(SEND_ERROR "num_${i} value is corrupted")
+        set(check FAILED)
+    endif()
+endforeach()
+message(STATUS "<<< test variable value restored -- ${check} >>>")
+
+list(POP_BACK CMAKE_MESSAGE_INDENT)
diff --git a/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-ITEMS-mix-test-result.txt b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-ITEMS-mix-test-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-ITEMS-mix-test-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-ITEMS-mix-test-stderr.txt b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-ITEMS-mix-test-stderr.txt
new file mode 100644
index 0000000..0dcab01
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-ITEMS-mix-test-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at foreach-ZIP_LISTS-with-ITEMS-mix-test.cmake:1 \(foreach\):
+  ZIP_LISTS can not be used with LISTS or ITEMS
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-ITEMS-mix-test.cmake b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-ITEMS-mix-test.cmake
new file mode 100644
index 0000000..71ed842
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-ITEMS-mix-test.cmake
@@ -0,0 +1,2 @@
+foreach(i IN ZIP_LISTS blah ITEMS blah)
+endforeach()
diff --git a/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-LISTS-mix-test-result.txt b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-LISTS-mix-test-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-LISTS-mix-test-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-LISTS-mix-test-stderr.txt b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-LISTS-mix-test-stderr.txt
new file mode 100644
index 0000000..a6b6e9c
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-LISTS-mix-test-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at foreach-ZIP_LISTS-with-LISTS-mix-test.cmake:1 \(foreach\):
+  ZIP_LISTS can not be used with LISTS or ITEMS
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-LISTS-mix-test.cmake b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-LISTS-mix-test.cmake
new file mode 100644
index 0000000..11a97b2
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-ZIP_LISTS-with-LISTS-mix-test.cmake
@@ -0,0 +1,2 @@
+foreach(i IN ZIP_LISTS blah LISTS blah)
+endforeach()
diff --git a/Tests/RunCMake/foreach/foreach-all-test-stdout.txt b/Tests/RunCMake/foreach/foreach-all-test-stdout.txt
new file mode 100644
index 0000000..e8f622d
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-all-test-stdout.txt
@@ -0,0 +1,44 @@
+-- foreach\(RANGE\):
+--   \[0\.\.1\]/1
+--     < 0
+--     < 1
+--   \[1\.\.1\]/1
+--     < 1
+--   \[0\.\.10\]/2
+--     < 0
+--     < 2
+--     < 4
+--     < 6
+--     < 8
+--     < 10
+--   \[-10\.\.0\]/3
+--     < -10
+--     < -7
+--     < -4
+--     < -1
+--   \[0\.\.-10\]/-5
+--     < 0
+--     < -5
+--     < -10
+-- foreach\(IN ITEMS\):
+--   < one
+--   < two
+--   < three
+-- foreach\(IN LISTS\):
+--   < satu
+--   < dua
+--   < tiga
+-- foreach\(IN LISTS and ITEMS\):
+--   < satu
+--   < dua
+--   < tiga
+--   < one
+--   < two
+--   < three
+-- foreach\(IN ITEMS and LISTS\):
+--   < one
+--   < two
+--   < three
+--   < satu
+--   < dua
+--   < tiga
diff --git a/Tests/RunCMake/foreach/foreach-all-test.cmake b/Tests/RunCMake/foreach/foreach-all-test.cmake
new file mode 100644
index 0000000..2e377c8
--- /dev/null
+++ b/Tests/RunCMake/foreach/foreach-all-test.cmake
@@ -0,0 +1,67 @@
+message(STATUS "foreach(RANGE):")
+list(APPEND CMAKE_MESSAGE_INDENT "  ")
+
+message(STATUS "[0..1]/1")
+list(APPEND CMAKE_MESSAGE_INDENT "  < ")
+foreach(i RANGE 1)
+    message(STATUS ${i})
+endforeach()
+list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+message(STATUS "[1..1]/1")
+list(APPEND CMAKE_MESSAGE_INDENT "  < ")
+foreach(i RANGE 1 1)
+    message(STATUS ${i})
+endforeach()
+list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+message(STATUS "[0..10]/2")
+list(APPEND CMAKE_MESSAGE_INDENT "  < ")
+foreach(i RANGE 0 10 2)
+    message(STATUS ${i})
+endforeach()
+list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+message(STATUS "[-10..0]/3")
+list(APPEND CMAKE_MESSAGE_INDENT "  < ")
+foreach(i RANGE -10 0 3)
+    message(STATUS ${i})
+endforeach()
+list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+message(STATUS "[0..-10]/-5")
+list(APPEND CMAKE_MESSAGE_INDENT "  < ")
+foreach(i RANGE 0 -10 -5)
+    message(STATUS ${i})
+endforeach()
+list(POP_BACK CMAKE_MESSAGE_INDENT)
+list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+message(STATUS "foreach(IN ITEMS):")
+list(APPEND CMAKE_MESSAGE_INDENT "  < ")
+foreach(i IN ITEMS one two three)
+    message(STATUS ${i})
+endforeach()
+list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+message(STATUS "foreach(IN LISTS):")
+list(APPEND CMAKE_MESSAGE_INDENT "  < ")
+list(APPEND count satu dua tiga)
+foreach(i IN LISTS count)
+    message(STATUS ${i})
+endforeach()
+list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+message(STATUS "foreach(IN LISTS and ITEMS):")
+list(APPEND CMAKE_MESSAGE_INDENT "  < ")
+foreach(i IN LISTS count ITEMS one two three)
+    message(STATUS ${i})
+endforeach()
+list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+message(STATUS "foreach(IN ITEMS and LISTS):")
+list(APPEND CMAKE_MESSAGE_INDENT "  < ")
+foreach(i IN ITEMS one two three LISTS count)
+    message(STATUS ${i})
+endforeach()
+list(POP_BACK CMAKE_MESSAGE_INDENT)
diff --git a/Tests/RunCMake/function/CMAKE_CURRENT_FUNCTION-stdout.txt b/Tests/RunCMake/function/CMAKE_CURRENT_FUNCTION-stdout.txt
new file mode 100644
index 0000000..5ebc89a
--- /dev/null
+++ b/Tests/RunCMake/function/CMAKE_CURRENT_FUNCTION-stdout.txt
@@ -0,0 +1,7 @@
+function\(print_self\)
+    file\(STRINGS "\${CMAKE_CURRENT_FUNCTION_LIST_FILE}" _lines\)
+    math\(EXPR _begin "\${CMAKE_CURRENT_FUNCTION_LIST_LINE} - 1"\)
+    list\(SUBLIST _lines \${_begin} 7 _lines\) # This function has 7 lines only
+    list\(JOIN _lines "\\n" _lines\)
+    message\(STATUS "Print the `\${CMAKE_CURRENT_FUNCTION}` function:\\n\${_lines}"\)
+endfunction\(\)
diff --git a/Tests/RunCMake/function/CMAKE_CURRENT_FUNCTION.cmake b/Tests/RunCMake/function/CMAKE_CURRENT_FUNCTION.cmake
new file mode 100644
index 0000000..38c032f
--- /dev/null
+++ b/Tests/RunCMake/function/CMAKE_CURRENT_FUNCTION.cmake
@@ -0,0 +1,94 @@
+set(_THIS_FILE "${CMAKE_CURRENT_LIST_FILE}")
+set(_THIS_DIR "${CMAKE_CURRENT_LIST_DIR}")
+
+if(CMAKE_CURRENT_FUNCTION)
+  message(SEND_ERROR "`CMAKE_CURRENT_FUNCTION` is not expected to be set here")
+endif()
+if(CMAKE_CURRENT_FUNCTION_LIST_FILE)
+  message(SEND_ERROR "`CMAKE_CURRENT_FUNCTION_LIST_FILE` is not expected to be set here")
+endif()
+if(CMAKE_CURRENT_FUNCTION_LIST_DIR)
+  message(SEND_ERROR "`CMAKE_CURRENT_FUNCTION_LIST_DIR` is not expected to be set here")
+endif()
+if(CMAKE_CURRENT_FUNCTION_LIST_LINE)
+  message(SEND_ERROR "`CMAKE_CURRENT_FUNCTION_LIST_LINE` is not expected to be set here")
+endif()
+
+function(bar)
+  if(NOT CMAKE_CURRENT_FUNCTION STREQUAL "bar")
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION`")
+  endif()
+  if(NOT CMAKE_CURRENT_FUNCTION_LIST_FILE MATCHES "^.*/CMAKE_CURRENT_FUNCTION.cmake$")
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_FILE`")
+  endif()
+  if(NOT CMAKE_CURRENT_FUNCTION_LIST_FILE STREQUAL _THIS_FILE)
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_FILE`")
+  endif()
+  if(NOT CMAKE_CURRENT_FUNCTION_LIST_DIR MATCHES "^.*/Tests/RunCMake/function$")
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_DIR`")
+  endif()
+  if(NOT CMAKE_CURRENT_FUNCTION_LIST_DIR STREQUAL _THIS_DIR)
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_DIR`")
+  endif()
+  if(NOT CMAKE_CURRENT_FUNCTION_LIST_LINE EQUAL 17)
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_LINE`")
+  endif()
+endfunction()
+
+function(foo)
+  if(NOT CMAKE_CURRENT_FUNCTION STREQUAL "foo")
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION`")
+  endif()
+  if(NOT CMAKE_CURRENT_FUNCTION_LIST_FILE MATCHES "^.*/function/CMAKE_CURRENT_FUNCTION.cmake$")
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_FILE`")
+  endif()
+  if(NOT CMAKE_CURRENT_FUNCTION_LIST_FILE STREQUAL _THIS_FILE)
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_FILE`")
+  endif()
+  if(NOT CMAKE_CURRENT_FUNCTION_LIST_DIR MATCHES "^.*/Tests/RunCMake/function$")
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_DIR`")
+  endif()
+  if(NOT CMAKE_CURRENT_FUNCTION_LIST_LINE EQUAL 38)
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_LINE`")
+  endif()
+  if(NOT CMAKE_CURRENT_FUNCTION_LIST_DIR STREQUAL _THIS_DIR)
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_DIR`")
+  endif()
+  bar()
+endfunction()
+
+foo()
+
+if(CMAKE_CURRENT_FUNCTION)
+  message(SEND_ERROR "`CMAKE_CURRENT_FUNCTION` is not expected to be set here")
+endif()
+if(CMAKE_CURRENT_FUNCTION_LIST_FILE)
+  message(SEND_ERROR "`CMAKE_CURRENT_FUNCTION_LIST_FILE` is not expected to be set here")
+endif()
+if(CMAKE_CURRENT_FUNCTION_LIST_DIR)
+  message(SEND_ERROR "`CMAKE_CURRENT_FUNCTION_LIST_DIR` is not expected to be set here")
+endif()
+if(CMAKE_CURRENT_FUNCTION_LIST_LINE)
+  message(SEND_ERROR "`CMAKE_CURRENT_FUNCTION_LIST_LINE` is not expected to be set here")
+endif()
+
+include("${CMAKE_CURRENT_LIST_DIR}/DummyMacro.cmake")
+
+function(calling_macro)
+  dummy()
+endfunction()
+
+calling_macro()
+
+cmake_policy(SET CMP0007 NEW)
+
+# ATTENTION `CMAKE_CURRENT_LIST_LINE` can't be used in `math()'
+function(print_self)
+    file(STRINGS "${CMAKE_CURRENT_FUNCTION_LIST_FILE}" _lines)
+    math(EXPR _begin "${CMAKE_CURRENT_FUNCTION_LIST_LINE} - 1")
+    list(SUBLIST _lines ${_begin} 7 _lines) # This function has 7 lines only
+    list(JOIN _lines "\n" _lines)
+    message(STATUS "Print the `${CMAKE_CURRENT_FUNCTION}` function:\n${_lines}")
+endfunction()
+
+print_self()
diff --git a/Tests/RunCMake/function/CMakeLists.txt b/Tests/RunCMake/function/CMakeLists.txt
new file mode 100644
index 0000000..2632ffa
--- /dev/null
+++ b/Tests/RunCMake/function/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.16)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/function/DummyMacro.cmake b/Tests/RunCMake/function/DummyMacro.cmake
new file mode 100644
index 0000000..1ab53e4
--- /dev/null
+++ b/Tests/RunCMake/function/DummyMacro.cmake
@@ -0,0 +1,20 @@
+macro(dummy)
+  if(NOT CMAKE_CURRENT_FUNCTION STREQUAL "calling_macro")
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION`")
+  endif()
+  if(NOT CMAKE_CURRENT_FUNCTION_LIST_FILE MATCHES "^.*/function/CMAKE_CURRENT_FUNCTION.cmake$")
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_FILE`")
+  endif()
+  if(NOT CMAKE_CURRENT_FUNCTION_LIST_FILE STREQUAL _THIS_FILE)
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_FILE`")
+  endif()
+  if(NOT CMAKE_CURRENT_FUNCTION_LIST_DIR MATCHES "^.*/Tests/RunCMake/function$")
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_DIR`")
+  endif()
+  if(NOT CMAKE_CURRENT_FUNCTION_LIST_LINE EQUAL 77)
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_LINE`")
+  endif()
+  if(NOT CMAKE_CURRENT_FUNCTION_LIST_DIR STREQUAL _THIS_DIR)
+    message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_DIR`")
+  endif()
+endmacro()
diff --git a/Tests/RunCMake/function/RunCMakeTest.cmake b/Tests/RunCMake/function/RunCMakeTest.cmake
new file mode 100644
index 0000000..88f48af
--- /dev/null
+++ b/Tests/RunCMake/function/RunCMakeTest.cmake
@@ -0,0 +1,3 @@
+include(RunCMake)
+
+run_cmake(CMAKE_CURRENT_FUNCTION)
diff --git a/Tests/RunCMake/get_property/RunCMakeTest.cmake b/Tests/RunCMake/get_property/RunCMakeTest.cmake
index 06a0c67..6e36473 100644
--- a/Tests/RunCMake/get_property/RunCMakeTest.cmake
+++ b/Tests/RunCMake/get_property/RunCMakeTest.cmake
@@ -27,7 +27,7 @@
 # don't rely on RunCMake_GENERATOR_IS_MULTI_CONFIG being set correctly
 # and instead explicitly check for a match against those generators we
 # expect to be multi-config
-if(RunCMake_GENERATOR MATCHES "Visual Studio|Xcode")
+if(RunCMake_GENERATOR MATCHES "Visual Studio|Xcode|Ninja Multi-Config")
   run_cmake(IsMultiConfig)
 else()
   run_cmake(NotMultiConfig)
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/RunCMakeTest.cmake b/Tests/RunCMake/install/RunCMakeTest.cmake
index 21c320b..70570b7 100644
--- a/Tests/RunCMake/install/RunCMakeTest.cmake
+++ b/Tests/RunCMake/install/RunCMakeTest.cmake
@@ -156,10 +156,12 @@
 run_install_test(InstallRequiredSystemLibraries)
 
 if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
-  run_install_test(file-GET_RUNTIME_DEPENDENCIES-macos)
-  run_install_test(file-GET_RUNTIME_DEPENDENCIES-macos-unresolved)
-  run_install_test(file-GET_RUNTIME_DEPENDENCIES-macos-conflict)
-  run_install_test(file-GET_RUNTIME_DEPENDENCIES-macos-notfile)
+  if(NOT CMake_INSTALL_NAME_TOOL_BUG)
+    run_install_test(file-GET_RUNTIME_DEPENDENCIES-macos)
+    run_install_test(file-GET_RUNTIME_DEPENDENCIES-macos-unresolved)
+    run_install_test(file-GET_RUNTIME_DEPENDENCIES-macos-conflict)
+    run_install_test(file-GET_RUNTIME_DEPENDENCIES-macos-notfile)
+  endif()
   run_cmake(file-GET_RUNTIME_DEPENDENCIES-project)
   run_cmake(file-GET_RUNTIME_DEPENDENCIES-badargs1)
   run_cmake(file-GET_RUNTIME_DEPENDENCIES-badargs2)
diff --git a/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath-stderr.txt b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath-stderr.txt
index 1e123f6..2561263 100644
--- a/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath-stderr.txt
+++ b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-new_rpath-stderr.txt
@@ -1,4 +1,4 @@
-^CMake Warning \(dev\) at TARGETS-FILE_RPATH_CHANGE-new_rpath\.cmake:[0-9]+ \(install\):
+CMake Warning \(dev\) at TARGETS-FILE_RPATH_CHANGE-new_rpath\.cmake:[0-9]+ \(install\):
   Policy CMP0095 is not set: RPATH entries are properly escaped in the
   intermediary CMake install script\.  Run "cmake --help-policy CMP0095" for
   policy details\.  Use the cmake_policy command to set the policy and
@@ -20,4 +20,4 @@
   intermediary cmake_install\.cmake script\.
 Call Stack \(most recent call first\):
   CMakeLists\.txt:[0-9]+ \(include\)
-This warning is for project developers\.  Use -Wno-dev to suppress it\.$
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/load_cache/CMakeLists.txt b/Tests/RunCMake/load_cache/CMakeLists.txt
new file mode 100644
index 0000000..2632ffa
--- /dev/null
+++ b/Tests/RunCMake/load_cache/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.16)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/load_cache/NewForm_Project.cmake b/Tests/RunCMake/load_cache/NewForm_Project.cmake
new file mode 100644
index 0000000..13a450b
--- /dev/null
+++ b/Tests/RunCMake/load_cache/NewForm_Project.cmake
@@ -0,0 +1,16 @@
+load_cache(${CMAKE_CURRENT_BINARY_DIR}/../test_project READ_WITH_PREFIX LOAD_CACHE_TEST_
+  CACHE_STRING
+  CACHE_BOOL
+  CACHE_INTERNAL)
+
+if(NOT LOAD_CACHE_TEST_CACHE_STRING STREQUAL "cache string")
+  message(FATAL_ERROR "CACHE_STRING: was ${CACHE_STRING}, expected \"cache string\"")
+endif()
+
+if(NOT LOAD_CACHE_TEST_CACHE_BOOL)
+  message(FATAL_ERROR "CACHE_BOOL: was falsey, expected ON")
+endif()
+
+if(NOT LOAD_CACHE_TEST_CACHE_INTERNAL STREQUAL "cache internal")
+  message(FATAL_ERROR "CACHE_INTERNAL: was ${CACHE_INTENRAL}, expected \"cache internal\"")
+endif()
diff --git a/Tests/RunCMake/load_cache/NewForm_Script.cmake b/Tests/RunCMake/load_cache/NewForm_Script.cmake
new file mode 100644
index 0000000..f3cee92
--- /dev/null
+++ b/Tests/RunCMake/load_cache/NewForm_Script.cmake
@@ -0,0 +1,16 @@
+load_cache(${RunCMake_BINARY_DIR}/test_project READ_WITH_PREFIX LOAD_CACHE_TEST_
+  CACHE_STRING
+  CACHE_BOOL
+  CACHE_INTERNAL)
+
+if(NOT LOAD_CACHE_TEST_CACHE_STRING STREQUAL "cache string")
+  message(FATAL_ERROR "CACHE_STRING: was ${CACHE_STRING}, expected \"cache string\"")
+endif()
+
+if(NOT LOAD_CACHE_TEST_CACHE_BOOL)
+  message(FATAL_ERROR "CACHE_BOOL: was falsey, expected ON")
+endif()
+
+if(NOT LOAD_CACHE_TEST_CACHE_INTERNAL STREQUAL "cache internal")
+  message(FATAL_ERROR "CACHE_INTERNAL: was ${CACHE_INTENRAL}, expected \"cache internal\"")
+endif()
diff --git a/Tests/RunCMake/load_cache/OldForm_Script-result.txt b/Tests/RunCMake/load_cache/OldForm_Script-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/load_cache/OldForm_Script-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/load_cache/OldForm_Script-stderr.txt b/Tests/RunCMake/load_cache/OldForm_Script-stderr.txt
new file mode 100644
index 0000000..9ad5c80
--- /dev/null
+++ b/Tests/RunCMake/load_cache/OldForm_Script-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error at.*/Tests/RunCMake/load_cache/OldForm_Script.cmake:1 \(load_cache\):
+  load_cache Only load_cache\(READ_WITH_PREFIX\) may be used in script mode$
diff --git a/Tests/RunCMake/load_cache/OldForm_Script.cmake b/Tests/RunCMake/load_cache/OldForm_Script.cmake
new file mode 100644
index 0000000..9560f61
--- /dev/null
+++ b/Tests/RunCMake/load_cache/OldForm_Script.cmake
@@ -0,0 +1,13 @@
+load_cache(${RunCMake_BINARY_DIR}/test_project INCLUDE_INTERNALS CACHE_INTERNAL)
+
+if(NOT CACHE_STRING STREQUAL "cache string")
+  message(FATAL_ERROR "CACHE_STRING: was ${CACHE_STRING}, expected \"cache string\"")
+endif()
+
+if(NOT CACHE_BOOL)
+  message(FATAL_ERROR "CACHE_BOOL: was falsey, expected ON")
+endif()
+
+if(NOT CACHE_INTERNAL STREQUAL "cache internal")
+  message(FATAL_ERROR "CACHE_INTERNAL: was ${CACHE_INTENRAL}, expected \"cache internal\"")
+endif()
diff --git a/Tests/RunCMake/load_cache/RunCMakeTest.cmake b/Tests/RunCMake/load_cache/RunCMakeTest.cmake
new file mode 100644
index 0000000..a0d54ea
--- /dev/null
+++ b/Tests/RunCMake/load_cache/RunCMakeTest.cmake
@@ -0,0 +1,13 @@
+include(RunCMake)
+
+file(WRITE ${RunCMake_BINARY_DIR}/test_project/CMakeCache.txt [[
+CACHE_STRING:STRING=cache string
+CACHE_BOOL:BOOL=ON
+CACHE_INTERNAL:INTERNAL=cache internal
+]])
+
+run_cmake(NewForm_Project)
+run_cmake_command(NewForm_Script ${CMAKE_COMMAND} -DRunCMake_BINARY_DIR=${RunCMake_BINARY_DIR}
+  -P "${RunCMake_SOURCE_DIR}/NewForm_Script.cmake")
+run_cmake_command(OldForm_Script ${CMAKE_COMMAND} -DRunCMake_BINARY_DIR=${RunCMake_BINARY_DIR}
+  -P "${RunCMake_SOURCE_DIR}/OldForm_Script.cmake")
diff --git a/Tests/RunCMake/message/RunCMakeTest.cmake b/Tests/RunCMake/message/RunCMakeTest.cmake
index 681839d..0313ed1 100644
--- a/Tests/RunCMake/message/RunCMakeTest.cmake
+++ b/Tests/RunCMake/message/RunCMakeTest.cmake
@@ -65,6 +65,11 @@
 endforeach()
 
 run_cmake_command(
+    message-log-level-override
+    ${CMAKE_COMMAND} --log-level=debug -DCMAKE_MESSAGE_LOG_LEVEL=TRACE -P ${RunCMake_SOURCE_DIR}/message-all-loglevels.cmake
+  )
+
+run_cmake_command(
     message-indent
     ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/message-indent.cmake
   )
@@ -72,3 +77,23 @@
     message-indent-multiline
     ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/message-indent-multiline.cmake
   )
+
+run_cmake_command(
+    message-context-cli
+    ${CMAKE_COMMAND} --log-level=trace --log-context -P ${RunCMake_SOURCE_DIR}/message-context.cmake
+  )
+
+run_cmake_command(
+    message-context-cache
+    ${CMAKE_COMMAND} -DCMAKE_MESSAGE_LOG_LEVEL=TRACE -DCMAKE_MESSAGE_CONTEXT_SHOW=ON -P ${RunCMake_SOURCE_DIR}/message-context.cmake
+  )
+
+run_cmake_command(
+    message-context-cli-wins-cache
+    ${CMAKE_COMMAND} --log-level=verbose --log-context -DCMAKE_MESSAGE_CONTEXT_SHOW=OFF -P ${RunCMake_SOURCE_DIR}/message-context.cmake
+  )
+
+run_cmake_command(
+    message-checks
+    ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/message-checks.cmake
+  )
diff --git a/Tests/RunCMake/message/message-checks-stderr.txt b/Tests/RunCMake/message/message-checks-stderr.txt
new file mode 100644
index 0000000..fdacdb2
--- /dev/null
+++ b/Tests/RunCMake/message/message-checks-stderr.txt
@@ -0,0 +1,3 @@
+^CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-checks.cmake:13 \(message\):
+  Ignored CHECK_FAIL without CHECK_START
+This warning is for project developers.  Use -Wno-dev to suppress it.$
diff --git a/Tests/RunCMake/message/message-checks-stdout.txt b/Tests/RunCMake/message/message-checks-stdout.txt
new file mode 100644
index 0000000..4f5f2ef
--- /dev/null
+++ b/Tests/RunCMake/message/message-checks-stdout.txt
@@ -0,0 +1,10 @@
+-- Find `libfoo`
+-- Looking for `libfoo\.h`
+-- Looking for `libfoo\.h` - found \[/usr/include\]
+-- Looking for `libfoo\.so`
+-- Looking for `libfoo\.so` - found \[/usr/lib/libfoo\.so\]
+-- Getting `libfoo` version
+-- Looking for `libfoo/version\.h`
+-- Looking for `libfoo/version\.h` - found
+-- Getting `libfoo` version - 1\.2\.3
+-- Find `libfoo` - required version 4\.5\.6 but found 1\.2\.3
diff --git a/Tests/RunCMake/message/message-checks.cmake b/Tests/RunCMake/message/message-checks.cmake
new file mode 100644
index 0000000..605846e
--- /dev/null
+++ b/Tests/RunCMake/message/message-checks.cmake
@@ -0,0 +1,13 @@
+message(CHECK_START "Find `libfoo`")
+message(CHECK_START "Looking for `libfoo.h`")
+message(CHECK_PASS "found [/usr/include]")
+message(CHECK_START "Looking for `libfoo.so`")
+message(CHECK_PASS "found [/usr/lib/libfoo.so]")
+message(CHECK_START "Getting `libfoo` version")
+message(CHECK_START "Looking for `libfoo/version.h`")
+message(CHECK_PASS "found")
+message(CHECK_PASS "1.2.3")
+message(CHECK_FAIL "required version 4.5.6 but found 1.2.3")
+
+# Should generate an error, no associated CHECK_START
+message(CHECK_FAIL "unmatched check fail case")
diff --git a/Tests/RunCMake/message/message-context-cache-stdout.txt b/Tests/RunCMake/message/message-context-cache-stdout.txt
new file mode 100644
index 0000000..af18c15
--- /dev/null
+++ b/Tests/RunCMake/message/message-context-cache-stdout.txt
@@ -0,0 +1,8 @@
+-- Begin context output test
+-- \[top\] Top: before
+-- \[top\.foo\.bar\] <-- indent -->bar VERBOSE message
+-- \[top\.foo\] foo TRACE message
+-- \[top\.foo\.baz\] This is the multi-line
+\[top\.foo\.baz\] baz DEBUG message
+-- \[top\] Top: after
+-- End of context output test
diff --git a/Tests/RunCMake/message/message-context-cli-stdout.txt b/Tests/RunCMake/message/message-context-cli-stdout.txt
new file mode 100644
index 0000000..af18c15
--- /dev/null
+++ b/Tests/RunCMake/message/message-context-cli-stdout.txt
@@ -0,0 +1,8 @@
+-- Begin context output test
+-- \[top\] Top: before
+-- \[top\.foo\.bar\] <-- indent -->bar VERBOSE message
+-- \[top\.foo\] foo TRACE message
+-- \[top\.foo\.baz\] This is the multi-line
+\[top\.foo\.baz\] baz DEBUG message
+-- \[top\] Top: after
+-- End of context output test
diff --git a/Tests/RunCMake/message/message-context-cli-wins-cache-stdout.txt b/Tests/RunCMake/message/message-context-cli-wins-cache-stdout.txt
new file mode 100644
index 0000000..157db97
--- /dev/null
+++ b/Tests/RunCMake/message/message-context-cli-wins-cache-stdout.txt
@@ -0,0 +1,5 @@
+-- Begin context output test
+-- \[top\] Top: before
+-- \[top\.foo\.bar\] <-- indent -->bar VERBOSE message
+-- \[top\] Top: after
+-- End of context output test
diff --git a/Tests/RunCMake/message/message-context.cmake b/Tests/RunCMake/message/message-context.cmake
new file mode 100644
index 0000000..93d4cd9
--- /dev/null
+++ b/Tests/RunCMake/message/message-context.cmake
@@ -0,0 +1,27 @@
+function(bar)
+    list(APPEND CMAKE_MESSAGE_CONTEXT "bar")
+    list(APPEND CMAKE_MESSAGE_INDENT "<-- indent -->")
+    message(VERBOSE "bar VERBOSE message")
+endfunction()
+
+function(baz)
+    list(APPEND CMAKE_MESSAGE_CONTEXT "baz")
+    message(DEBUG "This is the multi-line\nbaz DEBUG message")
+endfunction()
+
+function(foo)
+    list(APPEND CMAKE_MESSAGE_CONTEXT "foo")
+    bar()
+    message(TRACE "foo TRACE message")
+    baz()
+endfunction()
+
+message(STATUS "Begin context output test")
+list(APPEND CMAKE_MESSAGE_CONTEXT "top")
+
+message(STATUS "Top: before")
+foo()
+message(STATUS "Top: after")
+
+list(POP_BACK CMAKE_MESSAGE_CONTEXT)
+message(STATUS "End of context output test")
diff --git a/Tests/RunCMake/message/message-log-level-debug-stdout.txt b/Tests/RunCMake/message/message-log-level-debug-stdout.txt
index 1452137..feee110 100644
--- a/Tests/RunCMake/message/message-log-level-debug-stdout.txt
+++ b/Tests/RunCMake/message/message-log-level-debug-stdout.txt
@@ -1,3 +1,3 @@
 -- STATUS message
 -- VERBOSE message
--- DEBUG message
+-- DEBUG message$
diff --git a/Tests/RunCMake/message/message-log-level-default-stdout.txt b/Tests/RunCMake/message/message-log-level-default-stdout.txt
index 809f4cc..b5d6acb 100644
--- a/Tests/RunCMake/message/message-log-level-default-stdout.txt
+++ b/Tests/RunCMake/message/message-log-level-default-stdout.txt
@@ -1 +1 @@
--- STATUS message
+-- STATUS message$
diff --git a/Tests/RunCMake/message/message-log-level-override-stderr.txt b/Tests/RunCMake/message/message-log-level-override-stderr.txt
new file mode 100644
index 0000000..efec736
--- /dev/null
+++ b/Tests/RunCMake/message/message-log-level-override-stderr.txt
@@ -0,0 +1,12 @@
+^CMake Deprecation Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:2 \(message\):
+  Deprecation warning
++
+CMake Warning \(dev\) at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:3 \(message\):
+  Author warning message
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+CMake Warning at.*/Tests/RunCMake/message/message-all-loglevels\.cmake:4 \(message\):
+  Warning message
++
+Default NOTICE message
+NOTICE message$
diff --git a/Tests/RunCMake/message/message-log-level-override-stdout.txt b/Tests/RunCMake/message/message-log-level-override-stdout.txt
new file mode 100644
index 0000000..feee110
--- /dev/null
+++ b/Tests/RunCMake/message/message-log-level-override-stdout.txt
@@ -0,0 +1,3 @@
+-- STATUS message
+-- VERBOSE message
+-- DEBUG message$
diff --git a/Tests/RunCMake/message/message-log-level-status-stdout.txt b/Tests/RunCMake/message/message-log-level-status-stdout.txt
index 809f4cc..b5d6acb 100644
--- a/Tests/RunCMake/message/message-log-level-status-stdout.txt
+++ b/Tests/RunCMake/message/message-log-level-status-stdout.txt
@@ -1 +1 @@
--- STATUS message
+-- STATUS message$
diff --git a/Tests/RunCMake/message/message-log-level-trace-stdout.txt b/Tests/RunCMake/message/message-log-level-trace-stdout.txt
index 1cfce6f..3d36a7f 100644
--- a/Tests/RunCMake/message/message-log-level-trace-stdout.txt
+++ b/Tests/RunCMake/message/message-log-level-trace-stdout.txt
@@ -1,4 +1,4 @@
 -- STATUS message
 -- VERBOSE message
 -- DEBUG message
--- TRACE message
+-- TRACE message$
diff --git a/Tests/RunCMake/message/message-log-level-verbose-stdout.txt b/Tests/RunCMake/message/message-log-level-verbose-stdout.txt
index c15d43f..47c0846 100644
--- a/Tests/RunCMake/message/message-log-level-verbose-stdout.txt
+++ b/Tests/RunCMake/message/message-log-level-verbose-stdout.txt
@@ -1,2 +1,2 @@
 -- STATUS message
--- VERBOSE message
+-- VERBOSE message$
diff --git a/Tests/RunCMake/message/message-loglevel-debug-stdout.txt b/Tests/RunCMake/message/message-loglevel-debug-stdout.txt
index 1452137..feee110 100644
--- a/Tests/RunCMake/message/message-loglevel-debug-stdout.txt
+++ b/Tests/RunCMake/message/message-loglevel-debug-stdout.txt
@@ -1,3 +1,3 @@
 -- STATUS message
 -- VERBOSE message
--- DEBUG message
+-- DEBUG message$
diff --git a/Tests/RunCMake/message/message-loglevel-default-stdout.txt b/Tests/RunCMake/message/message-loglevel-default-stdout.txt
index 809f4cc..b5d6acb 100644
--- a/Tests/RunCMake/message/message-loglevel-default-stdout.txt
+++ b/Tests/RunCMake/message/message-loglevel-default-stdout.txt
@@ -1 +1 @@
--- STATUS message
+-- STATUS message$
diff --git a/Tests/RunCMake/message/message-loglevel-status-stdout.txt b/Tests/RunCMake/message/message-loglevel-status-stdout.txt
index 809f4cc..b5d6acb 100644
--- a/Tests/RunCMake/message/message-loglevel-status-stdout.txt
+++ b/Tests/RunCMake/message/message-loglevel-status-stdout.txt
@@ -1 +1 @@
--- STATUS message
+-- STATUS message$
diff --git a/Tests/RunCMake/message/message-loglevel-trace-stdout.txt b/Tests/RunCMake/message/message-loglevel-trace-stdout.txt
index 1cfce6f..3d36a7f 100644
--- a/Tests/RunCMake/message/message-loglevel-trace-stdout.txt
+++ b/Tests/RunCMake/message/message-loglevel-trace-stdout.txt
@@ -1,4 +1,4 @@
 -- STATUS message
 -- VERBOSE message
 -- DEBUG message
--- TRACE message
+-- TRACE message$
diff --git a/Tests/RunCMake/message/message-loglevel-verbose-stdout.txt b/Tests/RunCMake/message/message-loglevel-verbose-stdout.txt
index c15d43f..47c0846 100644
--- a/Tests/RunCMake/message/message-loglevel-verbose-stdout.txt
+++ b/Tests/RunCMake/message/message-loglevel-verbose-stdout.txt
@@ -1,2 +1,2 @@
 -- STATUS message
--- VERBOSE message
+-- VERBOSE message$
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_directories/CMP0099-NEW-basic-check.cmake b/Tests/RunCMake/target_link_directories/CMP0099-NEW-basic-check.cmake
new file mode 100644
index 0000000..2fffddd
--- /dev/null
+++ b/Tests/RunCMake/target_link_directories/CMP0099-NEW-basic-check.cmake
@@ -0,0 +1,4 @@
+
+if (NOT actual_stdout MATCHES "DIR_INTERFACE")
+  string (APPEND RunCMake_TEST_FAILED "\nNot found expected 'DIR_INTERFACE'.")
+endif()
diff --git a/Tests/RunCMake/target_link_directories/CMP0099-NEW-basic-result.txt b/Tests/RunCMake/target_link_directories/CMP0099-NEW-basic-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_directories/CMP0099-NEW-basic-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_directories/CMP0099-NEW.cmake b/Tests/RunCMake/target_link_directories/CMP0099-NEW.cmake
new file mode 100644
index 0000000..17dd68e
--- /dev/null
+++ b/Tests/RunCMake/target_link_directories/CMP0099-NEW.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0099 NEW)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/CMP0099.cmake)
diff --git a/Tests/RunCMake/target_link_directories/CMP0099-OLD-basic-check.cmake b/Tests/RunCMake/target_link_directories/CMP0099-OLD-basic-check.cmake
new file mode 100644
index 0000000..16573a7
--- /dev/null
+++ b/Tests/RunCMake/target_link_directories/CMP0099-OLD-basic-check.cmake
@@ -0,0 +1,4 @@
+
+if (actual_stdout MATCHES "DIR_INTERFACE")
+  string (APPEND RunCMake_TEST_FAILED "\nFound unexpected 'DIR_INTERFACE'.")
+endif()
diff --git a/Tests/RunCMake/target_link_directories/CMP0099-OLD-basic-result.txt b/Tests/RunCMake/target_link_directories/CMP0099-OLD-basic-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_directories/CMP0099-OLD-basic-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_directories/CMP0099-OLD.cmake b/Tests/RunCMake/target_link_directories/CMP0099-OLD.cmake
new file mode 100644
index 0000000..193a4c7
--- /dev/null
+++ b/Tests/RunCMake/target_link_directories/CMP0099-OLD.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0099 OLD)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/CMP0099.cmake)
diff --git a/Tests/RunCMake/target_link_directories/CMP0099.cmake b/Tests/RunCMake/target_link_directories/CMP0099.cmake
new file mode 100644
index 0000000..a2be279
--- /dev/null
+++ b/Tests/RunCMake/target_link_directories/CMP0099.cmake
@@ -0,0 +1,14 @@
+
+enable_language(C)
+
+set(CMAKE_VERBOSE_MAKEFILE TRUE)
+set(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES FALSE)
+
+add_library(LinkDirs_interface INTERFACE)
+target_link_directories (LinkDirs_interface INTERFACE "/DIR_INTERFACE"})
+
+add_library(LinkDirs_static STATIC lib.c)
+target_link_libraries (LinkDirs_static PRIVATE LinkDirs_interface)
+
+add_executable(LinkDirs_exe exe.c)
+target_link_libraries (LinkDirs_exe PRIVATE LinkDirs_static)
diff --git a/Tests/RunCMake/target_link_directories/RunCMakeTest.cmake b/Tests/RunCMake/target_link_directories/RunCMakeTest.cmake
index b67c598..a74ee25 100644
--- a/Tests/RunCMake/target_link_directories/RunCMakeTest.cmake
+++ b/Tests/RunCMake/target_link_directories/RunCMakeTest.cmake
@@ -1,3 +1,33 @@
 include(RunCMake)
 
+macro(run_cmake_target test subtest target)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
+  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_NO_CLEAN)
+endmacro()
+
 run_cmake(empty_keyword_args)
+
+if(RunCMake_GENERATOR MATCHES "(Ninja|Makefiles)" AND
+    NOT RunCMake_GENERATOR MATCHES "(NMake|Borland)")
+  set(RunCMake_TEST_OUTPUT_MERGE TRUE)
+  if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+    set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
+  endif()
+  if (RunCMake_GENERATOR MATCHES "Ninja")
+    set(VERBOSE -- -v)
+  endif()
+
+  run_cmake(CMP0099-NEW)
+  run_cmake_target(CMP0099-NEW basic LinkDirs_exe ${VERBOSE})
+
+
+  run_cmake(CMP0099-OLD)
+  run_cmake_target(CMP0099-OLD basic LinkDirs_exe ${VERBOSE})
+
+  unset(RunCMake_TEST_OPTIONS)
+  unset(RunCMake_TEST_OUTPUT_MERGE)
+endif()
diff --git a/Tests/RunCMake/target_link_directories/exe.c b/Tests/RunCMake/target_link_directories/exe.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/target_link_directories/exe.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/target_link_directories/lib.c b/Tests/RunCMake/target_link_directories/lib.c
new file mode 100644
index 0000000..9bbd24c
--- /dev/null
+++ b/Tests/RunCMake/target_link_directories/lib.c
@@ -0,0 +1,7 @@
+#if defined(_WIN32)
+__declspec(dllexport)
+#endif
+  int flags_lib(void)
+{
+  return 0;
+}
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/Tests/RunCMake/target_link_options/CMP0099-NEW-basic-check.cmake b/Tests/RunCMake/target_link_options/CMP0099-NEW-basic-check.cmake
new file mode 100644
index 0000000..555bc37
--- /dev/null
+++ b/Tests/RunCMake/target_link_options/CMP0099-NEW-basic-check.cmake
@@ -0,0 +1,4 @@
+
+if (NOT actual_stdout MATCHES "BADFLAG_INTERFACE")
+  string (APPEND RunCMake_TEST_FAILED "\nNot found expected 'BADFLAG_INTERFACE'.")
+endif()
diff --git a/Tests/RunCMake/target_link_options/CMP0099-NEW-basic-result.txt b/Tests/RunCMake/target_link_options/CMP0099-NEW-basic-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_options/CMP0099-NEW-basic-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_options/CMP0099-NEW.cmake b/Tests/RunCMake/target_link_options/CMP0099-NEW.cmake
new file mode 100644
index 0000000..17dd68e
--- /dev/null
+++ b/Tests/RunCMake/target_link_options/CMP0099-NEW.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0099 NEW)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/CMP0099.cmake)
diff --git a/Tests/RunCMake/target_link_options/CMP0099-OLD-basic-check.cmake b/Tests/RunCMake/target_link_options/CMP0099-OLD-basic-check.cmake
new file mode 100644
index 0000000..4f159f1
--- /dev/null
+++ b/Tests/RunCMake/target_link_options/CMP0099-OLD-basic-check.cmake
@@ -0,0 +1,4 @@
+
+if (actual_stdout MATCHES "BADFLAG_INTERFACE")
+  string (APPEND RunCMake_TEST_FAILED "\nFound unexpected 'BADFLAG_INTERFACE'.")
+endif()
diff --git a/Tests/RunCMake/target_link_options/CMP0099-OLD-basic-result.txt b/Tests/RunCMake/target_link_options/CMP0099-OLD-basic-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_options/CMP0099-OLD-basic-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_options/CMP0099-OLD.cmake b/Tests/RunCMake/target_link_options/CMP0099-OLD.cmake
new file mode 100644
index 0000000..193a4c7
--- /dev/null
+++ b/Tests/RunCMake/target_link_options/CMP0099-OLD.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0099 OLD)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/CMP0099.cmake)
diff --git a/Tests/RunCMake/target_link_options/CMP0099.cmake b/Tests/RunCMake/target_link_options/CMP0099.cmake
new file mode 100644
index 0000000..edb457e
--- /dev/null
+++ b/Tests/RunCMake/target_link_options/CMP0099.cmake
@@ -0,0 +1,19 @@
+
+enable_language(C)
+
+set(obj "${CMAKE_C_OUTPUT_EXTENSION}")
+if(BORLAND)
+  set(pre -)
+endif()
+
+add_library(LinkOptions_interface INTERFACE)
+target_link_options (LinkOptions_interface INTERFACE ${pre}BADFLAG_INTERFACE${obj})
+
+add_library(LinkOptions_static1 STATIC LinkOptionsLib.c)
+target_link_libraries (LinkOptions_static1 PRIVATE LinkOptions_interface)
+
+add_library(LinkOptions_static2 STATIC LinkOptionsLib.c)
+target_link_libraries (LinkOptions_static2 PRIVATE LinkOptions_static1)
+
+add_executable(LinkOptions_exe LinkOptionsExe.c)
+target_link_libraries (LinkOptions_exe PRIVATE LinkOptions_static2)
diff --git a/Tests/RunCMake/target_link_options/LINKER_expansion.cmake b/Tests/RunCMake/target_link_options/LINKER_expansion.cmake
index b344867..f86d19f 100644
--- a/Tests/RunCMake/target_link_options/LINKER_expansion.cmake
+++ b/Tests/RunCMake/target_link_options/LINKER_expansion.cmake
@@ -1,6 +1,13 @@
 
 enable_language(C)
 
+set(cfg_dir)
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+  set(cfg_dir /Debug)
+endif()
+set(DUMP_EXE "${CMAKE_CURRENT_BINARY_DIR}${cfg_dir}/dump${CMAKE_EXECUTABLE_SUFFIX}")
+
 add_executable(dump dump.c)
 
 # ensure no temp file will be used
@@ -13,7 +20,7 @@
 target_link_options(linker PRIVATE "LINKER:-foo,bar")
 
 # use LAUNCH facility to dump linker command
-set_property(TARGET linker PROPERTY RULE_LAUNCH_LINK "\"${CMAKE_CURRENT_BINARY_DIR}/dump${CMAKE_EXECUTABLE_SUFFIX}\"")
+set_property(TARGET linker PROPERTY RULE_LAUNCH_LINK "\"${DUMP_EXE}\"")
 
 add_dependencies (linker dump)
 
@@ -23,7 +30,7 @@
 target_link_options(linker_shell PRIVATE "LINKER:SHELL:-foo bar")
 
 # use LAUNCH facility to dump linker command
-set_property(TARGET linker_shell PROPERTY RULE_LAUNCH_LINK "\"${CMAKE_CURRENT_BINARY_DIR}/dump${CMAKE_EXECUTABLE_SUFFIX}\"")
+set_property(TARGET linker_shell PROPERTY RULE_LAUNCH_LINK "\"${DUMP_EXE}\"")
 
 add_dependencies (linker_shell dump)
 
diff --git a/Tests/RunCMake/target_link_options/RunCMakeTest.cmake b/Tests/RunCMake/target_link_options/RunCMakeTest.cmake
index 1d9ef8b..cdfdd7b 100644
--- a/Tests/RunCMake/target_link_options/RunCMakeTest.cmake
+++ b/Tests/RunCMake/target_link_options/RunCMakeTest.cmake
@@ -41,3 +41,21 @@
 endif()
 
 run_cmake(empty_keyword_args)
+
+if (NOT CMAKE_C_COMPILER_ID STREQUAL "Intel")
+  # Intel compiler does not reject bad flags or objects!
+  set(RunCMake_TEST_OUTPUT_MERGE TRUE)
+  if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+    set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
+  endif()
+
+  run_cmake(CMP0099-NEW)
+  run_cmake_target(CMP0099-NEW basic LinkOptions_exe)
+
+
+  run_cmake(CMP0099-OLD)
+  run_cmake_target(CMP0099-OLD basic LinkOptions_exe)
+
+  unset(RunCMake_TEST_OPTIONS)
+  unset(RunCMake_TEST_OUTPUT_MERGE)
+endif()
diff --git a/Tests/RunCMake/try_compile/CleanupNoFollowSymlink.cmake b/Tests/RunCMake/try_compile/CleanupNoFollowSymlink.cmake
new file mode 100644
index 0000000..dea0f61
--- /dev/null
+++ b/Tests/RunCMake/try_compile/CleanupNoFollowSymlink.cmake
@@ -0,0 +1,21 @@
+enable_language(C)
+
+set(out "${CMAKE_CURRENT_BINARY_DIR}/folder")
+set(link_folder "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CMakeTmp")
+set(link_dir "${link_folder}/link_dir")
+file(MAKE_DIRECTORY "${out}")
+file(MAKE_DIRECTORY "${link_folder}")
+file(WRITE ${out}/empty_file "")
+file(CREATE_LINK ${out} ${link_dir} SYMBOLIC)
+
+try_compile(res ${CMAKE_CURRENT_BINARY_DIR}
+  SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.c)
+
+if(EXISTS ${link_dir})
+  message(FATAL_ERROR "did not remove ${link_dir}")
+endif()
+if(NOT EXISTS ${out})
+  message(FATAL_ERROR "should not have removed ${out}/dir")
+endif()
+
+file(REMOVE_RECURSE "${out}")
diff --git a/Tests/RunCMake/try_compile/RunCMakeTest.cmake b/Tests/RunCMake/try_compile/RunCMakeTest.cmake
index 91f014e..bee9e5b 100644
--- a/Tests/RunCMake/try_compile/RunCMakeTest.cmake
+++ b/Tests/RunCMake/try_compile/RunCMakeTest.cmake
@@ -49,11 +49,7 @@
   run_cmake(ObjCxxStandard)
 endif()
 if(CMake_TEST_CUDA)
-  if(CMAKE_HOST_WIN32)
-    run_cmake(CudaStandardNoDefault)
-  else()
-    run_cmake(CudaStandard)
-  endif()
+  run_cmake(CudaStandard)
 endif()
 if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.4)
   run_cmake(CStandardGNU)
@@ -98,3 +94,7 @@
   unset(RunCMake_TEST_BINARY_DIR)
   unset(RunCMake_TEST_NO_CLEAN)
 endif()
+
+if(UNIX)
+  run_cmake(CleanupNoFollowSymlink)
+endif()
diff --git a/Tests/StagingPrefix/CMakeLists.txt b/Tests/StagingPrefix/CMakeLists.txt
index 8d2519e..9ed5c12 100644
--- a/Tests/StagingPrefix/CMakeLists.txt
+++ b/Tests/StagingPrefix/CMakeLists.txt
@@ -5,7 +5,7 @@
 # Wipe out the install tree
 add_custom_command(
   OUTPUT ${CMAKE_BINARY_DIR}/CleanupProject
-  COMMAND ${CMAKE_COMMAND} -E remove_directory
+  COMMAND ${CMAKE_COMMAND} -E rm -rf
     ${CMAKE_BINARY_DIR}/ConsumerBuild
     ${CMAKE_BINARY_DIR}/ProducerBuild
     ${CMAKE_BINARY_DIR}/stage
diff --git a/Tests/SubDir/Examples/example1/CMakeLists.txt b/Tests/SubDir/Examples/example1/CMakeLists.txt
index 20d065e..8ec1c02 100644
--- a/Tests/SubDir/Examples/example1/CMakeLists.txt
+++ b/Tests/SubDir/Examples/example1/CMakeLists.txt
@@ -3,5 +3,5 @@
 add_executable(example1 example1.cxx)
 
 add_custom_command(TARGET example1 POST_BUILD
-  COMMAND "${CMAKE_COMMAND}" ARGS -E remove ${SUBDIR_BINARY_DIR}/ShouldBeHere
+  COMMAND "${CMAKE_COMMAND}" ARGS -E rm -f ${SUBDIR_BINARY_DIR}/ShouldBeHere
   COMMENT "Remove marker file that should exist because this should not be run")
diff --git a/Tests/SubDirSpaces/Some Examples/example1/CMakeLists.txt b/Tests/SubDirSpaces/Some Examples/example1/CMakeLists.txt
index 20d065e..8ec1c02 100644
--- a/Tests/SubDirSpaces/Some Examples/example1/CMakeLists.txt
+++ b/Tests/SubDirSpaces/Some Examples/example1/CMakeLists.txt
@@ -3,5 +3,5 @@
 add_executable(example1 example1.cxx)
 
 add_custom_command(TARGET example1 POST_BUILD
-  COMMAND "${CMAKE_COMMAND}" ARGS -E remove ${SUBDIR_BINARY_DIR}/ShouldBeHere
+  COMMAND "${CMAKE_COMMAND}" ARGS -E rm -f ${SUBDIR_BINARY_DIR}/ShouldBeHere
   COMMENT "Remove marker file that should exist because this should not be run")
diff --git a/Tests/VSMidl/CMakeLists.txt b/Tests/VSMidl/CMakeLists.txt
index 432506c..3ff7c27 100644
--- a/Tests/VSMidl/CMakeLists.txt
+++ b/Tests/VSMidl/CMakeLists.txt
@@ -56,8 +56,8 @@
 #
 ExternalProject_Add(clean-${PROJECT_NAME}
   DOWNLOAD_COMMAND ""
-  CONFIGURE_COMMAND ${CMAKE_COMMAND} -E remove_directory "${source_dir}"
-  BUILD_COMMAND ${CMAKE_COMMAND} -E remove_directory "${binary_dir}"
+  CONFIGURE_COMMAND ${CMAKE_COMMAND} -E rm -rf "${source_dir}"
+  BUILD_COMMAND ${CMAKE_COMMAND} -E rm -rf "${binary_dir}"
   INSTALL_COMMAND ""
   )
 
diff --git a/Utilities/CMakeLists.txt b/Utilities/CMakeLists.txt
index 0564540..22a3d5a 100644
--- a/Utilities/CMakeLists.txt
+++ b/Utilities/CMakeLists.txt
@@ -13,7 +13,7 @@
   endif()
   add_custom_command(
     OUTPUT ${dir}.stamp
-    COMMAND cmake -E remove_directory ${dir}
+    COMMAND cmake -E rm -rf ${dir}
     COMMAND cmake -E tar xf ${CMAKE_DOC_TARBALL}
     COMMAND cmake -E touch ${dir}.stamp
     DEPENDS ${CMAKE_DOC_TARBALL}
diff --git a/Utilities/GitSetup/setup-user b/Utilities/GitSetup/setup-user
index 1af439c..0b98879 100755
--- a/Utilities/GitSetup/setup-user
+++ b/Utilities/GitSetup/setup-user
@@ -20,12 +20,12 @@
 # Project configuration instructions: NONE
 
 for (( ; ; )); do
-	user_name=$(git config user.name || echo '') &&
-	user_email=$(git config user.email || echo '') &&
-	if test -n "$user_name" -a -n "$user_email"; then
+	ident="$(git var GIT_AUTHOR_IDENT 2>/dev/null | rev | cut -d' ' -f3- | rev)"
+
+	if test -n "$ident"; then
 		echo 'Your commits will record as Author:
 
-  '"$user_name <$user_email>"'
+  '"$ident"'
 ' &&
 		read -ep 'Is the author name and email address above correct? [Y/n] ' correct &&
 		if test "$correct" != "n" -a "$correct" != "N"; then
diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp
index ef31e8b..3497b53 100644
--- a/Utilities/IWYU/mapping.imp
+++ b/Utilities/IWYU/mapping.imp
@@ -24,6 +24,7 @@
   { include: [ "<bits/shared_ptr.h>", private, "<memory>", public ] },
   { include: [ "<bits/std_function.h>", private, "<functional>", public ] },
   { include: [ "<bits/refwrap.h>", private, "<functional>", public ] },
+  { include: [ "<bits/std_abs.h>", private, "<stdlib.h>", public ] },
   { include: [ "<bits/stdint-intn.h>", private, "<stdint.h>", public ] },
   { include: [ "<bits/stdint-uintn.h>", private, "<stdint.h>", public ] },
   { include: [ "<bits/time.h>", private, "<time.h>", public ] },
@@ -46,6 +47,8 @@
   # HACK: iwyu suggests <ext/alloc_traits.h> and <memory> each time vector[] is used.
   # https://github.com/include-what-you-use/include-what-you-use/issues/166
   { include: [ "<ext/alloc_traits.h>", private, "<vector>", public ] },
+  { symbol: [ "std::allocator_traits<std::allocator<cmFileLock> >::value_type", private, "<vector>", public ] },
+  { symbol: [ "std::allocator_traits<std::allocator<cmFileLockPool::ScopePool> >::value_type", private, "<vector>", public ] },
   { symbol: [ "std::allocator_traits<std::allocator<cmComputeComponentGraph::TarjanEntry> >::value_type", private, "<vector>", public ] },
   { symbol: [ "std::allocator_traits<std::allocator<cmFortranFile> >::value_type", private, "<vector>", public ] },
   { symbol: [ "std::allocator_traits<std::allocator<cmGraphEdgeList> >::value_type", private, "<vector>", public ] },
diff --git a/Utilities/Release/push.bash b/Utilities/Release/push.bash
index 1c8efe9..a1c6651 100755
--- a/Utilities/Release/push.bash
+++ b/Utilities/Release/push.bash
@@ -50,6 +50,9 @@
     dir="v${version}"
 fi
 readonly dir
+if ! test -d "${dest}/${dir}"; then
+    mkdir "${dest}/${dir}"
+fi
 
 for f in cmake-${version}*; do
     if ! test -f "${f}"; then
diff --git a/Utilities/Scripts/regenerate-lexers.bash b/Utilities/Scripts/regenerate-lexers.bash
index 1b61b70..186802a 100755
--- a/Utilities/Scripts/regenerate-lexers.bash
+++ b/Utilities/Scripts/regenerate-lexers.bash
@@ -14,7 +14,8 @@
     CTestResourceGroups \
     DependsJava         \
     Expr                \
-    Fortran
+    Fortran             \
+    GccDepfile
 do
     cxx_file=cm${lexer}Lexer.cxx
     h_file=cm${lexer}Lexer.h
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/cmcurl/CMake/cmake_uninstall.cmake.in b/Utilities/cmcurl/CMake/cmake_uninstall.cmake.in
index db8e536..5178fd8 100644
--- a/Utilities/cmcurl/CMake/cmake_uninstall.cmake.in
+++ b/Utilities/cmcurl/CMake/cmake_uninstall.cmake.in
@@ -13,7 +13,7 @@
   message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
   if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
     exec_program(
-      "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+      "@CMAKE_COMMAND@" ARGS "-E rm -f \"$ENV{DESTDIR}${file}\""
       OUTPUT_VARIABLE rm_out
       RETURN_VALUE rm_retval
       )
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/cmlibarchive/libarchive/archive_pack_dev.c b/Utilities/cmlibarchive/libarchive/archive_pack_dev.c
index 53bddd7..f8286d8 100644
--- a/Utilities/cmlibarchive/libarchive/archive_pack_dev.c
+++ b/Utilities/cmlibarchive/libarchive/archive_pack_dev.c
@@ -57,8 +57,12 @@
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
-#ifdef HAVE_SYS_SYSMACROS_H
+#if MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#define HAVE_MAJOR
+#elif MAJOR_IN_SYSMACROS
 #include <sys/sysmacros.h>
+#define HAVE_MAJOR
 #endif
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt
index fe2ef75..7625cf6 100644
--- a/Utilities/cmlibuv/CMakeLists.txt
+++ b/Utilities/cmlibuv/CMakeLists.txt
@@ -137,6 +137,25 @@
     )
 endif()
 
+if(CMAKE_SYSTEM_NAME STREQUAL "OS400")
+  list(APPEND uv_headers
+    include/uv/posix.h
+    )
+  list(APPEND uv_defines
+    _ALL_SOURCE
+    _XOPEN_SOURCE=500
+    _LINUX_SOURCE_COMPAT
+    _THREAD_SAFE
+    )
+  list(APPEND uv_sources
+    src/unix/aix-common.c
+    src/unix/ibmi.c
+    src/unix/posix-poll.c
+    src/unix/no-fsevents.c
+    src/unix/no-proctitle.c
+    )
+endif()
+
 if(CMAKE_SYSTEM_NAME MATCHES "CYGWIN")
   list(APPEND uv_libraries
     )
diff --git a/Utilities/std/.gitattributes b/Utilities/std/.gitattributes
index cd20549..ad5459d 100644
--- a/Utilities/std/.gitattributes
+++ b/Utilities/std/.gitattributes
@@ -1 +1,2 @@
-cm/* 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/memory b/Utilities/std/cm/memory
index 8ebded2..dd0f822 100644
--- a/Utilities/std/cm/memory
+++ b/Utilities/std/cm/memory
@@ -8,6 +8,8 @@
 
 #include <memory> // IWYU pragma: export
 #if !defined(CMake_HAVE_CXX_MAKE_UNIQUE)
+#  include <cstddef>
+#  include <type_traits>
 #  include <utility>
 #endif
 
@@ -19,12 +21,45 @@
 
 #else
 
+namespace internals {
+
+template <typename T>
+struct make_unique_if
+{
+  using single = std::unique_ptr<T>;
+};
+
+template <typename T>
+struct make_unique_if<T[]>
+{
+  using unbound_array = std::unique_ptr<T[]>;
+};
+
+template <typename T, std::size_t N>
+struct make_unique_if<T[N]>
+{
+  using bound_array = void;
+};
+}
+
 template <typename T, typename... Args>
-std::unique_ptr<T> make_unique(Args&&... args)
+typename internals::make_unique_if<T>::single make_unique(Args&&... args)
 {
   return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
 }
 
+template <typename T>
+typename internals::make_unique_if<T>::unbound_array make_unique(std::size_t n)
+{
+  using E = typename std::remove_extent<T>::type;
+
+  return std::unique_ptr<T>(new E[n]());
+}
+
+template <typename T, typename... Args>
+typename internals::make_unique_if<T>::bound_array make_unique(Args&&...) =
+  delete;
+
 #endif
 
 } // namespace cm
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
new file mode 100644
index 0000000..e32c2c6
--- /dev/null
+++ b/Utilities/std/cm/type_traits
@@ -0,0 +1,63 @@
+// -*-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_type_traits
+#define cm_type_traits
+
+#include <type_traits> // IWYU pragma: export
+
+namespace cm {
+
+#if __cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
+
+// Miscellaneous transformations
+template <bool B, typename T = void>
+using enable_if_t = std::enable_if_t<B, T>;
+
+#else
+
+// Miscellaneous transformations
+template <bool B, typename T = void>
+using enable_if_t = typename std::enable_if<B, T>::type;
+
+#endif
+
+#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703)
+
+// Helper classes
+using std::bool_constant;
+
+// Miscellaneous transformations
+using std::invoke_result;
+using std::invoke_result_t;
+
+using std::void_t;
+
+#else
+
+// Helper classes
+template <bool B>
+using bool_constant = std::integral_constant<bool, B>;
+
+// Miscellaneous transformations
+template <typename F, typename... ArgTypes>
+using invoke_result = std::result_of<F(ArgTypes...)>;
+
+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
+
+#endif
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/algorithm b/Utilities/std/cmext/algorithm
new file mode 100644
index 0000000..44e61f4
--- /dev/null
+++ b/Utilities/std/cmext/algorithm
@@ -0,0 +1,163 @@
+// -*-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_algorithm
+#define cmext_algorithm
+
+#include <algorithm>
+#include <iterator>
+#include <memory>
+#include <utility>
+
+#include <cm/type_traits>
+#include <cmext/iterator>
+
+#if defined(__SUNPRO_CC) && defined(__sparc)
+#  include <list>
+#  include <vector>
+#else
+#  include <cmext/type_traits>
+#endif
+
+namespace cm {
+
+#if defined(__SUNPRO_CC) && defined(__sparc)
+// Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile
+// templates with constraints.
+// So, on this platform, use only simple templates.
+#  define APPEND_TWO(C1, C2)                                                  \
+    template <typename T, typename U>                                         \
+    void append(C1<std::unique_ptr<T>>& v, C2<std::unique_ptr<U>>&& r)        \
+    {                                                                         \
+      std::transform(                                                         \
+        r.begin(), r.end(), std::back_inserter(v),                            \
+        [](std::unique_ptr<U>& item) { return std::move(item); });            \
+      r.clear();                                                              \
+    }                                                                         \
+                                                                              \
+    template <typename T, typename U>                                         \
+    void append(C1<T*>& v, C2<std::unique_ptr<U>> const& r)                   \
+    {                                                                         \
+      std::transform(                                                         \
+        r.begin(), r.end(), std::back_inserter(v),                            \
+        [](const std::unique_ptr<U>& item) { return item.get(); });           \
+    }
+
+#  define APPEND_ONE(C)                                                       \
+    template <typename T, typename InputIt,                                   \
+              cm::enable_if_t<cm::is_input_iterator<InputIt>::value, int> =   \
+                0>                                                            \
+    void append(C<T>& v, InputIt first, InputIt last)                         \
+    {                                                                         \
+      v.insert(v.end(), first, last);                                         \
+    }                                                                         \
+                                                                              \
+    template <typename T, typename Range,                                     \
+              cm::enable_if_t<cm::is_input_range<Range>::value, int> = 0>     \
+    void append(C<T>& v, Range const& r)                                      \
+    {                                                                         \
+      v.insert(v.end(), r.begin(), r.end());                                  \
+    }
+
+#  define APPEND(C)                                                           \
+    APPEND_TWO(C, C)                                                          \
+    APPEND_ONE(C)
+
+#  define APPEND_MIX(C1, C2)                                                  \
+    APPEND_TWO(C1, C2)                                                        \
+    APPEND_TWO(C2, C1)
+
+// For now, manage only support for std::vector and std::list.
+// Other sequential container support can be added if needed.
+APPEND(std::vector)
+APPEND(std::list)
+APPEND_MIX(std::vector, std::list)
+
+#  undef APPEND
+#  undef APPEND_MIX
+#  undef APPEND_TWO
+#  undef APPEND_ONE
+
+#else
+
+template <
+  typename Container1, typename Container2,
+  cm::enable_if_t<
+    cm::is_sequence_container<Container1>::value &&
+      cm::is_unique_ptr<typename Container1::value_type>::value &&
+      cm::is_unique_ptr<typename Container2::value_type>::value &&
+      std::is_convertible<typename Container2::value_type::pointer,
+                          typename Container1::value_type::pointer>::value,
+    int> = 0>
+void append(Container1& v, Container2&& r)
+{
+  std::transform(
+    r.begin(), r.end(), std::back_inserter(v),
+    [](typename Container2::value_type& item) { return std::move(item); });
+  r.clear();
+}
+
+template <typename Container1, typename Container2,
+          cm::enable_if_t<
+            cm::is_sequence_container<Container1>::value &&
+              std::is_pointer<typename Container1::value_type>::value &&
+              cm::is_unique_ptr<typename Container2::value_type>::value &&
+              std::is_convertible<typename Container2::value_type::pointer,
+                                  typename Container1::value_type>::value,
+            int> = 0>
+#  if defined(__SUNPRO_CC)
+void append(Container1& v, Container2 const& r, detail::overload_selector<0>)
+#  else
+void append(Container1& v, Container2 const& r)
+#  endif
+{
+  std::transform(
+    r.begin(), r.end(), std::back_inserter(v),
+    [](const typename Container2::value_type& item) { return item.get(); });
+}
+
+template <
+  typename Container, typename InputIt,
+  cm::enable_if_t<
+    cm::is_sequence_container<Container>::value &&
+      cm::is_input_iterator<InputIt>::value &&
+      std::is_convertible<typename std::iterator_traits<InputIt>::value_type,
+                          typename Container::value_type>::value,
+    int> = 0>
+void append(Container& v, InputIt first, InputIt last)
+{
+  v.insert(v.end(), first, last);
+}
+
+template <typename Container, typename Range,
+          cm::enable_if_t<
+            cm::is_sequence_container<Container>::value &&
+              cm::is_input_range<Range>::value &&
+              !cm::is_unique_ptr<typename Container::value_type>::value &&
+              !cm::is_unique_ptr<typename Range::value_type>::value &&
+              std::is_convertible<typename Range::value_type,
+                                  typename Container::value_type>::value,
+            int> = 0>
+#  if defined(__SUNPRO_CC)
+void append(Container& v, Range const& r, detail::overload_selector<1>)
+#  else
+void append(Container& v, Range const& r)
+#  endif
+{
+  v.insert(v.end(), r.begin(), r.end());
+}
+
+#  if defined(__SUNPRO_CC)
+template <typename T, typename U>
+void append(T& v, U const& r)
+{
+  cm::append(v, r, detail::overload_selector<1>{});
+}
+#  endif
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cmext/iterator b/Utilities/std/cmext/iterator
new file mode 100644
index 0000000..ffe94b1
--- /dev/null
+++ b/Utilities/std/cmext/iterator
@@ -0,0 +1,49 @@
+// -*-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_iterator
+#define cmext_iterator
+
+#include <iterator>
+
+#include <cm/type_traits>
+
+namespace cm {
+
+// checks if a type is an iterator type
+template <typename I>
+using is_iterator =
+  std::is_integral<typename std::iterator_traits<I>::difference_type>;
+
+// checks if a type is an input iterator type
+template <typename I>
+using is_input_iterator =
+  std::is_base_of<std::input_iterator_tag,
+                  typename std::iterator_traits<I>::iterator_category>;
+
+// checks if a type is a range type: must have a difference_type type
+template <typename Range>
+using is_range = cm::bool_constant<
+  cm::is_iterator<decltype(std::declval<const Range>().begin())>::value &&
+  cm::is_iterator<decltype(std::declval<const Range>().end())>::value>;
+
+// checks if a type is an input range type: must have methods begin() and end()
+// returning an input iterator
+template <typename Range>
+using is_input_range =
+#if defined(_MSC_VER) && _MSC_VER < 1920
+  // MS C++ is not able to evaluate complex type introspection,
+  // so use a simplified version
+  cm::is_input_iterator<typename Range::const_iterator>;
+#else
+  cm::bool_constant<
+    cm::is_input_iterator<decltype(
+      std::declval<const Range>().begin())>::value &&
+    cm::is_input_iterator<decltype(std::declval<const Range>().end())>::value>;
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cmext/memory b/Utilities/std/cmext/memory
new file mode 100644
index 0000000..50e79df
--- /dev/null
+++ b/Utilities/std/cmext/memory
@@ -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 cmext_memory
+#define cmext_memory
+
+#include <typeinfo>
+
+#include <cm/type_traits>
+
+namespace cm {
+
+template <typename T, typename O,
+          cm::enable_if_t<
+            std::is_pointer<cm::invoke_result_t<decltype(&O::get), O>>::value,
+            int> = 0>
+T& static_reference_cast(O& item)
+{
+  return *(static_cast<T*>(item.get()));
+}
+template <typename T, typename O,
+          cm::enable_if_t<
+            std::is_pointer<cm::invoke_result_t<decltype(&O::get), O>>::value,
+            int> = 0>
+T& dynamic_reference_cast(O& item)
+{
+  auto p = dynamic_cast<T*>(item.get());
+
+  if (p == nullptr) {
+    throw std::bad_cast();
+  }
+
+  return *p;
+}
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cmext/type_traits b/Utilities/std/cmext/type_traits
new file mode 100644
index 0000000..00984cb
--- /dev/null
+++ b/Utilities/std/cmext/type_traits
@@ -0,0 +1,86 @@
+// -*-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 {
+
+#if defined(__SUNPRO_CC)
+// Oracle DeveloperStudio C++ compiler do not support overloaded templates with
+// same signature but different constraints over template arguments
+// (i.e. meta-programming).
+// As a work-around, use a structure to avoid templates with same signature.
+namespace detail {
+template <int N>
+struct overload_selector : overload_selector<N - 1>
+{
+};
+
+template <>
+struct overload_selector<0>
+{
+};
+}
+#endif
+
+// 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
diff --git a/bootstrap b/bootstrap
index 1f8eaa5..d529f3b 100755
--- a/bootstrap
+++ b/bootstrap
@@ -294,6 +294,7 @@
   cmCreateTestSourceList \
   cmCustomCommand \
   cmCustomCommandGenerator \
+  cmCustomCommandLines \
   cmDefinePropertyCommand \
   cmDefinitions \
   cmDepends \
@@ -372,6 +373,7 @@
   cmLDConfigTool \
   cmLinkDirectoriesCommand \
   cmLinkItem \
+  cmLinkItemGraphVisitor \
   cmLinkLineComputer \
   cmLinkLineDeviceComputer \
   cmListCommand \
@@ -1166,10 +1168,20 @@
 }
 #endif
 
-#if __cplusplus >= 201703L
+#if (__cplusplus >= 201703L || defined(__INTEL_COMPILER) && defined(__cpp_if_constexpr))
 #include <optional>
+template <typename T,
+          typename std::invoke_result<decltype(&T::get), T>::type = nullptr>
+typename T::pointer get_ptr(T& item)
+{
+  return item.get();
+}
+
 int check_cxx17()
 {
+  // Intel compiler do not handle correctly 'decltype' inside 'invoke_result'
+  std::unique_ptr<int> u(new int(0));
+  get_ptr(u);
   std::optional<int> oi = 0;
   return oi.value();
 }
@@ -1222,6 +1234,29 @@
 echo "C++ compiler on this system is: ${cmake_cxx_compiler} ${cmake_cxx_flags}"
 
 #-----------------------------------------------------------------------------
+# Test CXX features
+
+cmake_cxx_features="make_unique"
+
+for feature in ${cmake_cxx_features}; do
+  eval "cmake_have_cxx_${feature}=0"
+  echo "Checking whether '${cmake_cxx_compiler} ${cmake_cxx_flags}' supports '${feature}'." >> cmake_bootstrap.log 2>&1
+  if cmake_try_run "${cmake_cxx_compiler}" "${cmake_cxx_flags}" \
+                   "${cmake_source_dir}/Source/Checks/cm_cxx_${feature}.cxx" >> cmake_bootstrap.log 2>&1; then
+    eval "cmake_have_cxx_${feature}=1"
+  fi
+done
+
+cmake_have_cxx_features=""
+for feature in ${cmake_cxx_features}; do
+  feature_variable="cmake_have_cxx_${feature}"
+  eval "feature_value=\${${feature_variable}}"
+  if [ "${feature_value}" -eq "1" ]; then
+    cmake_have_cxx_features="${cmake_have_cxx_features} -DCMake_HAVE_CXX_`cmake_toupper ${feature}`=${feature_value}"
+  fi
+done
+
+#-----------------------------------------------------------------------------
 # Test Make
 
 cmake_make_processor=
@@ -1522,6 +1557,7 @@
   -I`cmake_escape \"${cmake_source_dir}/Utilities\"`"
 cmake_cxx_flags="${cmake_cxx_flags} \
   -DCMAKE_BOOTSTRAP \
+  ${cmake_have_cxx_features} \
   -I`cmake_escape \"${cmake_bootstrap_dir}\"` \
   -I`cmake_escape \"${cmake_source_dir}/Source\"` \
   -I`cmake_escape \"${cmake_source_dir}/Source/LexerParser\"` \
@@ -1583,6 +1619,7 @@
 echo '
 # Generated by '"${cmake_source_dir}"'/bootstrap
 # Default cmake settings.  These may be overridden any settings below.
+set (CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build.") # not FORCE to preserve defaults specified elsewhere
 set (CMAKE_INSTALL_PREFIX "'"${cmake_prefix_dir}"'" CACHE PATH "Install path prefix, prepended onto install directories." FORCE)
 set (CMAKE_DOC_DIR "'"${cmake_doc_dir}"'" CACHE PATH "Install location for documentation (relative to prefix)." FORCE)
 set (CMAKE_MAN_DIR "'"${cmake_man_dir}"'" CACHE PATH "Install location for man pages (relative to prefix)." FORCE)
diff --git a/cmake_uninstall.cmake.in b/cmake_uninstall.cmake.in
index d81f62a..b5fc700 100644
--- a/cmake_uninstall.cmake.in
+++ b/cmake_uninstall.cmake.in
@@ -8,7 +8,7 @@
   message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
   if(EXISTS "$ENV{DESTDIR}${file}")
     exec_program(
-      "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+      "@CMAKE_COMMAND@" ARGS "-E rm -f \"$ENV{DESTDIR}${file}\""
       OUTPUT_VARIABLE rm_out
       RETURN_VALUE rm_retval
       )