Merge topic 'add_cuda_meta_compiler_features'

2467a2b318 CUDA: Add cuda meta-features (e.g. ``cuda_std_11``) support

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !3992
diff --git a/CompileFlags.cmake b/CompileFlags.cmake
index 91f2adf..053259f 100644
--- a/CompileFlags.cmake
+++ b/CompileFlags.cmake
@@ -54,12 +54,20 @@
 endif()
 
 # Workaround for TOC Overflow on ppc64
+set(bigTocFlag "")
 if(CMAKE_SYSTEM_NAME STREQUAL "AIX" AND
    CMAKE_SYSTEM_PROCESSOR MATCHES "powerpc")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-bbigtoc")
+  set(bigTocFlag "-Wl,-bbigtoc")
 elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND
    CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-multi-toc")
+  set(bigTocFlag "-Wl,--no-multi-toc")
+endif()
+if(bigTocFlag)
+  include(CheckCXXLinkerFlag)
+  check_cxx_linker_flag(${bigTocFlag} BIG_TOC_FLAG_SUPPORTED)
+  if(BIG_TOC_FLAG_SUPPORTED)
+    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${bigTocFlag}")
+  endif()
 endif()
 
 if (CMAKE_CXX_COMPILER_ID STREQUAL SunPro AND
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index eceeac7..2118031 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -57,6 +57,7 @@
 .. toctree::
    :maxdepth: 1
 
+   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/ctest.1.rst b/Help/manual/ctest.1.rst
index 17bddb6..25cb639 100644
--- a/Help/manual/ctest.1.rst
+++ b/Help/manual/ctest.1.rst
@@ -1113,6 +1113,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
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/release/dev/Link-properties-transitive.rst b/Help/release/dev/Link-properties-transitive.rst
new file mode 100644
index 0000000..535b40c
--- /dev/null
+++ b/Help/release/dev/Link-properties-transitive.rst
@@ -0,0 +1,8 @@
+Link-properties-transitive
+--------------------------
+
+* Target link properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
+  :prop_tgt:`INTERFACE_LINK_DIRECTORIES` and
+  :prop_tgt:`INTERFACE_LINK_DEPENDS` are now transitive over private
+  dependency on static libraries.
+  See policy :policy:`CMP0099`.
diff --git a/Help/release/dev/ctest-configuration-type.rst b/Help/release/dev/ctest-configuration-type.rst
new file mode 100644
index 0000000..89e36c4
--- /dev/null
+++ b/Help/release/dev/ctest-configuration-type.rst
@@ -0,0 +1,5 @@
+ctest-configuration-type
+------------------------
+
+* The :variable:`CTEST_CONFIGURATION_TYPE` variable is now set from the command
+  line when :manual:`ctest(1)` is invoked with ``-C <cfg>``.
diff --git a/Help/release/dev/ctest-drmemory-support.rst b/Help/release/dev/ctest-drmemory-support.rst
new file mode 100644
index 0000000..b329995
--- /dev/null
+++ b/Help/release/dev/ctest-drmemory-support.rst
@@ -0,0 +1,5 @@
+ctest-drmemory-support
+----------------------
+
+* The :manual:`ctest(1)` gained support for Dr. Memory to run
+  memcheck runs.
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/CTest.cmake b/Modules/CTest.cmake
index 3a111ca..1a51bc8 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."
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/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/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/FindThreads.cmake b/Modules/FindThreads.cmake
index 64576eb..85174d9 100644
--- a/Modules/FindThreads.cmake
+++ b/Modules/FindThreads.cmake
@@ -63,6 +63,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);
diff --git a/Modules/FindwxWidgets.cmake b/Modules/FindwxWidgets.cmake
index 4334e22..93ac51d 100644
--- a/Modules/FindwxWidgets.cmake
+++ b/Modules/FindwxWidgets.cmake
@@ -852,6 +852,8 @@
         separate_arguments(wxWidgets_LIBRARIES)
         string(REPLACE "-framework;" "-framework "
           wxWidgets_LIBRARIES "${wxWidgets_LIBRARIES}")
+        string(REPLACE "-weak_framework;" "-weak_framework "
+          wxWidgets_LIBRARIES "${wxWidgets_LIBRARIES}")
         string(REPLACE "-arch;" "-arch "
           wxWidgets_LIBRARIES "${wxWidgets_LIBRARIES}")
         string(REPLACE "-isysroot;" "-isysroot "
diff --git a/Modules/Internal/CPack/CPackDeb.cmake b/Modules/Internal/CPack/CPackDeb.cmake
index ad8e078..fe0fe09 100644
--- a/Modules/Internal/CPack/CPackDeb.cmake
+++ b/Modules/Internal/CPack/CPackDeb.cmake
@@ -546,8 +546,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/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/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/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index cdd0893..fe319de 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 20191209)
+set(CMake_VERSION_PATCH 20191212)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
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/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/Modules/CheckCXXLinkerFlag.cmake b/Source/Modules/CheckCXXLinkerFlag.cmake
new file mode 100644
index 0000000..6cb1ba3
--- /dev/null
+++ b/Source/Modules/CheckCXXLinkerFlag.cmake
@@ -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_guard(GLOBAL)
+include(CheckCXXSourceCompiles)
+include(CMakeCheckCompilerFlagCommonPatterns)
+
+function(check_cxx_linker_flag _flag _var)
+  if(CMAKE_VERSION VERSION_LESS "3.14")
+    set(CMAKE_REQUIRED_LIBRARIES "${_flag}")
+  else()
+    set(CMAKE_REQUIRED_LINK_OPTIONS "${_flag}")
+  endif()
+
+  # 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(_common_patterns)
+  check_cxx_source_compiles("int main() { return 0; }" ${_var}
+    ${_common_patterns}
+    )
+  foreach(v IN LISTS _locale_vars)
+    set(ENV{${v}} ${_locale_vars_saved_${v}})
+  endforeach()
+  set(${_var} "${${_var}}" PARENT_SCOPE)
+endfunction()
diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx
index 563e0f1..896b6a9 100644
--- a/Source/cmCommands.cxx
+++ b/Source/cmCommands.cxx
@@ -78,6 +78,7 @@
 #include "cmTargetCompileOptionsCommand.h"
 #include "cmTargetIncludeDirectoriesCommand.h"
 #include "cmTargetLinkLibrariesCommand.h"
+#include "cmTargetLinkOptionsCommand.h"
 #include "cmTargetPrecompileHeadersCommand.h"
 #include "cmTargetSourcesCommand.h"
 #include "cmTryCompileCommand.h"
@@ -107,7 +108,6 @@
 #  include "cmSourceGroupCommand.h"
 #  include "cmSubdirDependsCommand.h"
 #  include "cmTargetLinkDirectoriesCommand.h"
-#  include "cmTargetLinkOptionsCommand.h"
 #  include "cmUseMangledMesaCommand.h"
 #  include "cmUtilitySourceCommand.h"
 #  include "cmVariableRequiresCommand.h"
@@ -257,6 +257,7 @@
                            cmTargetIncludeDirectoriesCommand);
   state->AddBuiltinCommand("target_link_libraries",
                            cmTargetLinkLibrariesCommand);
+  state->AddBuiltinCommand("target_link_options", cmTargetLinkOptionsCommand);
   state->AddBuiltinCommand("target_sources", cmTargetSourcesCommand);
   state->AddBuiltinCommand("try_compile",
                            cm::make_unique<cmTryCompileCommand>());
@@ -277,7 +278,6 @@
   state->AddBuiltinCommand("install_programs", cmInstallProgramsCommand);
   state->AddBuiltinCommand("add_link_options", cmAddLinkOptionsCommand);
   state->AddBuiltinCommand("link_libraries", cmLinkLibrariesCommand);
-  state->AddBuiltinCommand("target_link_options", cmTargetLinkOptionsCommand);
   state->AddBuiltinCommand("target_link_directories",
                            cmTargetLinkDirectoriesCommand);
   state->AddBuiltinCommand("qt_wrap_cpp", cmQTWrapCPPCommand);
diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx
index c22cf4a..58ec53a 100644
--- a/Source/cmComputeTargetDepends.cxx
+++ b/Source/cmComputeTargetDepends.cxx
@@ -158,9 +158,8 @@
 void cmComputeTargetDepends::CollectTargets()
 {
   // Collect all targets from all generators.
-  std::vector<cmLocalGenerator*> const& lgens =
-    this->GlobalGenerator->GetLocalGenerators();
-  for (cmLocalGenerator* lgen : lgens) {
+  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.get()] = index;
diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx
index 3557e5c..de40c77 100644
--- a/Source/cmExtraCodeLiteGenerator.cxx
+++ b/Source/cmExtraCodeLiteGenerator.cxx
@@ -117,9 +117,8 @@
 {
   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) {
+  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();
diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx
index cf79375..78cabce 100644
--- a/Source/cmExtraEclipseCDT4Generator.cxx
+++ b/Source/cmExtraEclipseCDT4Generator.cxx
@@ -99,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");
@@ -176,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 =
@@ -199,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));
@@ -232,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:
@@ -244,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;
@@ -257,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;
@@ -273,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());
     }
   }
 
@@ -284,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";
@@ -351,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());
@@ -495,7 +495,7 @@
   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 auto& targets = lg->GetGeneratorTargets();
 
@@ -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,7 +859,7 @@
 
   // include dirs
   emmited.clear();
-  for (cmLocalGenerator* lgen : this->GlobalGenerator->GetLocalGenerators()) {
+  for (const auto& lgen : this->GlobalGenerator->GetLocalGenerators()) {
     const auto& targets = lgen->GetGeneratorTargets();
     for (const auto& target : targets) {
       if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
@@ -914,7 +914,7 @@
 
   // add all executable and library targets and some of the GLOBAL
   // and UTILITY targets
-  for (cmLocalGenerator* lgen : this->GlobalGenerator->GetLocalGenerators()) {
+  for (const auto& lgen : this->GlobalGenerator->GetLocalGenerators()) {
     const auto& targets = lgen->GetGeneratorTargets();
     std::string subdir = lgen->MaybeConvertToRelativePath(
       this->HomeOutputDirectory, lgen->GetCurrentBinaryDirectory());
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 bbbc281..e463420 100644
--- a/Source/cmExtraKateGenerator.cxx
+++ b/Source/cmExtraKateGenerator.cxx
@@ -41,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;
@@ -65,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 <<
@@ -110,8 +110,7 @@
 
   // add all executable and library targets and some of the GLOBAL
   // and UTILITY targets
-  for (cmLocalGenerator* localGen :
-       this->GlobalGenerator->GetLocalGenerators()) {
+  for (const auto& localGen : this->GlobalGenerator->GetLocalGenerators()) {
     const auto& targets = localGen->GetGeneratorTargets();
     std::string currentDir = localGen->GetCurrentBinaryDirectory();
     bool topLevel = (currentDir == localGen->GetBinaryDirectory());
@@ -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) {
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/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..d6afb77 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -469,17 +469,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);
@@ -554,7 +554,7 @@
   std::vector<cmGeneratorTarget*> targetList;
   cmGlobalGenerator* gg =
     this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
-  for (cmLocalGenerator const* lg : gg->GetLocalGenerators()) {
+  for (const auto& lg : gg->GetLocalGenerators()) {
     cmAppend(targetList, lg->GetGeneratorTargets());
   }
   std::sort(targetList.begin(), targetList.end(),
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 2204c5a..a4a074f 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -1116,7 +1116,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);
@@ -1135,7 +1136,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.
@@ -1145,7 +1146,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;
             }
@@ -1159,12 +1161,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;
   }
 
@@ -1196,8 +1200,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
@@ -1240,7 +1244,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)) {
@@ -1253,9 +1258,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));
       }
@@ -3663,7 +3668,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);
@@ -3918,7 +3924,8 @@
                                   this->LinkDirectoriesEntries);
 
   AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES", language,
-                      &dagChecker, entries);
+                      &dagChecker, entries,
+                      this->GetPolicyStatusCMP0099() != cmPolicies::NEW);
 
   processLinkDirectories(this, entries, result, uniqueDirectories,
                          debugDirectories);
@@ -3956,7 +3963,8 @@
     }
   }
   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);
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 336c91f..761e58a 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -707,7 +707,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;
 
@@ -886,7 +887,8 @@
 
   mutable std::unordered_map<std::string, bool> MaybeInterfacePropertyExists;
   bool MaybeHaveInterfaceProperty(std::string const& prop,
-                                  cmGeneratorExpressionContext* context) const;
+                                  cmGeneratorExpressionContext* context,
+                                  bool usage_requirements_only) const;
 
   using TargetPropertyEntryVector =
     std::vector<std::unique_ptr<TargetPropertyEntry>>;
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..291220c 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.h
+++ b/Source/cmGlobalBorlandMakefileGenerator.h
@@ -4,6 +4,7 @@
 #define cmGlobalBorlandMakefileGenerator_h
 
 #include <iosfwd>
+#include <memory>
 
 #include "cmGlobalNMakeMakefileGenerator.h"
 
@@ -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 d6c0a87..e04eef1 100644
--- a/Source/cmGlobalCommonGenerator.cxx
+++ b/Source/cmGlobalCommonGenerator.cxx
@@ -25,11 +25,11 @@
 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.
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 0e782f2..9840025 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -300,7 +300,7 @@
 bool cmGlobalGenerator::CheckTargetsForMissingSources() const
 {
   bool failed = false;
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
+  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 ||
@@ -340,7 +340,7 @@
     return false;
   }
   bool failed = false;
-  for (cmLocalGenerator* generator : this->LocalGenerators) {
+  for (const auto& generator : this->LocalGenerators) {
     for (const auto& target : generator->GetGeneratorTargets()) {
       if (target->GetType() == cmStateEnums::EXECUTABLE &&
           target->GetPropertyAsBool("WIN32_EXECUTABLE")) {
@@ -368,7 +368,7 @@
     return false;
   }
   bool failed = false;
-  for (cmLocalGenerator* generator : this->LocalGenerators) {
+  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 ||
@@ -1204,13 +1204,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);
+    auto lg = this->CreateLocalGenerator(m);
+    this->IndexLocalGenerator(lg.get());
+    this->LocalGenerators.push_back(std::move(lg));
   }
 }
 
@@ -1300,7 +1299,7 @@
   this->CreateGenerationObjects(ImportedOnly);
   auto const mfit =
     std::find(this->Makefiles.begin(), this->Makefiles.end(), mf);
-  cmLocalGenerator* lg =
+  auto& lg =
     this->LocalGenerators[std::distance(this->Makefiles.begin(), mfit)];
   for (std::string const& t : targets) {
     cmGeneratorTarget* gt = lg->FindGeneratorTargetToUse(t);
@@ -1353,7 +1352,7 @@
     std::vector<cmExportBuildFileGenerator*> gens =
       this->Makefiles[i]->GetExportBuildFileGenerators();
     for (cmExportBuildFileGenerator* g : gens) {
-      g->Compute(this->LocalGenerators[i]);
+      g->Compute(this->LocalGenerators[i].get());
     }
   }
 }
@@ -1392,7 +1391,7 @@
   }
 
   // Add generator specific helper commands
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
+  for (const auto& localGen : this->LocalGenerators) {
     localGen->AddHelperCommands();
   }
 
@@ -1402,16 +1401,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)) {
+      if (!g->Compute(localGen.get())) {
         return false;
       }
     }
@@ -1421,7 +1420,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();
   }
 
@@ -1433,7 +1432,7 @@
   this->ForceLinkerLanguages();
 
   // Compute the manifest of main targets generated.
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
+  for (const auto& localGen : this->LocalGenerators) {
     localGen->ComputeTargetManifest();
   }
 
@@ -1450,7 +1449,7 @@
     return false;
   }
 
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
+  for (const auto& localGen : this->LocalGenerators) {
     localGen->ComputeHomeRelativeOutputPath();
   }
 
@@ -1563,7 +1562,7 @@
 
 bool cmGlobalGenerator::AddAutomaticSources()
 {
-  for (cmLocalGenerator* lg : this->LocalGenerators) {
+  for (const auto& lg : this->LocalGenerators) {
     lg->CreateEvaluationFileOutputs();
     for (const auto& gt : lg->GetGeneratorTargets()) {
       if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
@@ -1579,7 +1578,7 @@
   // 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 (const auto& lg : this->LocalGenerators) {
     for (const auto& gt : lg->GetGeneratorTargets()) {
       gt->ClearSourcesCache();
     }
@@ -1684,7 +1683,7 @@
   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];
+      cmLocalGenerator* lg = this->LocalGenerators[i].get();
       auto gt = cm::make_unique<cmGeneratorTarget>(ownedImpTgt, lg);
       importedMap[ownedImpTgt] = gt.get();
       lg->AddOwnedImportedGeneratorTarget(std::move(gt));
@@ -1694,7 +1693,7 @@
   // 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->LocalGenerators[i].get(), importedMap);
   }
 }
 
@@ -1706,7 +1705,6 @@
   cmDeleteAll(this->Makefiles);
   this->Makefiles.clear();
 
-  cmDeleteAll(this->LocalGenerators);
   this->LocalGenerators.clear();
 
   this->AliasTargets.clear();
@@ -2047,9 +2045,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,
@@ -2144,7 +2143,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;
@@ -2152,7 +2151,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());
@@ -2767,13 +2766,12 @@
             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;
@@ -2963,7 +2961,7 @@
                                "/CMakeFiles/TargetDirectories.txt");
   cmGeneratedFileStream fout(fname);
 
-  for (cmLocalGenerator* lg : this->LocalGenerators) {
+  for (const auto& lg : this->LocalGenerators) {
     for (const auto& tgt : lg->GetGeneratorTargets()) {
       if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
         continue;
@@ -3113,7 +3111,7 @@
 void cmGlobalGenerator::ProcessEvaluationFiles()
 {
   std::vector<std::string> generatedFiles;
-  for (cmLocalGenerator* localGen : this->LocalGenerators) {
+  for (auto& localGen : this->LocalGenerators) {
     localGen->ProcessEvaluationFiles(generatedFiles);
   }
 }
@@ -3129,7 +3127,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;
@@ -3148,8 +3146,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 0e87357..952b51e 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -90,11 +90,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"; }
@@ -249,7 +252,7 @@
   {
     return this->Makefiles;
   }
-  const std::vector<cmLocalGenerator*>& GetLocalGenerators() const
+  const LocalGeneratorVector& GetLocalGenerators() const
   {
     return this->LocalGenerators;
   }
@@ -477,12 +480,11 @@
   int RecursionDepth;
 
 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);
@@ -541,7 +543,7 @@
   std::string ConfiguredFilesPath;
   cmake* CMakeInstance;
   std::vector<cmMakefile*> Makefiles;
-  std::vector<cmLocalGenerator*> LocalGenerators;
+  LocalGeneratorVector LocalGenerators;
   cmMakefile* CurrentConfigureMakefile;
   // map from project name to vector of local generators in that project
   std::map<std::string, std::vector<cmLocalGenerator*>> ProjectMap;
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index 7afcd49..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)
diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h
index 7cd8c79..989b12c 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>
@@ -34,7 +35,8 @@
   }
 
   //! 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"; }
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index da21d6c..3500007 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -9,6 +9,7 @@
 #include <sstream>
 
 #include <cm/memory>
+#include <cmext/memory>
 
 #include "cmsys/FStream.hxx"
 
@@ -429,9 +430,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
@@ -819,10 +822,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(), '/', '\\');
@@ -1148,7 +1151,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()) {
@@ -1268,7 +1271,7 @@
   if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
     return;
   }
-  cmLocalGenerator* lg = this->LocalGenerators[0];
+  const auto& lg = this->LocalGenerators[0];
 
   {
     cmNinjaRule rule("RERUN_CMAKE");
@@ -1289,7 +1292,7 @@
   reBuild.Comment = "Re-run CMake if any of its inputs changed.";
   reBuild.Outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE));
 
-  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 +1379,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,7 +1416,7 @@
 
 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);
@@ -1809,11 +1812,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())));
+    auto lgd = this->CreateLocalGenerator(mfd.get());
     this->Makefiles.push_back(mfd.release());
-    this->LocalGenerators.push_back(lgd.release());
+    this->LocalGenerators.push_back(std::move(lgd));
   }
 
   std::vector<cmDyndepObjectInfo> objects;
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 244e9fd..41b41ac 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -156,7 +156,8 @@
     return new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaGenerator>();
   }
 
-  cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
+  std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
+    cmMakefile* mf) override;
 
   std::string GetName() const override
   {
@@ -295,11 +296,6 @@
   void AppendTargetDependsClosure(cmGeneratorTarget const* target,
                                   cmNinjaOuts& outputs, bool omit_self);
 
-  const std::vector<cmLocalGenerator*>& GetLocalGenerators() const
-  {
-    return LocalGenerators;
-  }
-
   int GetRuleCmdLength(const std::string& name) { return RuleCmdLength[name]; }
 
   void AddTargetAlias(const std::string& alias, cmGeneratorTarget* target);
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index dfc495e..fe8c3f4 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include <cm/memory>
+#include <cmext/memory>
 
 #include "cmAlgorithms.h"
 #include "cmDocumentationEntry.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,7 +287,7 @@
 
   // 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());
   }
@@ -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,24 +371,23 @@
 
 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 (const auto& 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)) {
-        std::string tname = cmStrCat(lg->GetRelativeTargetDirectory(tgt.get()),
+        std::string tname = cmStrCat(lg.GetRelativeTargetDirectory(tgt.get()),
                                      "/DependInfo.cmake");
         cmSystemTools::ConvertToUnixSlashes(tname);
         cmakefileStream << "  \"" << tname << "\"\n";
@@ -544,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 (const auto& 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();
@@ -563,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.get());
+        std::string localName = lg.GetRelativeTargetDirectory(gtarget.get());
         std::string makefileName;
         makefileName = cmStrCat(localName, "/build.make");
         depends.clear();
@@ -587,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())) {
+        if (gtarget->NeedRelinkBeforeInstall(lg.GetConfigName())) {
           makeTargetName = cmStrCat(
-            lg->GetRelativeTargetDirectory(gtarget.get()), "/preinstall");
+            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);
         }
       }
     }
@@ -611,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;
@@ -624,7 +630,7 @@
   }
 
   // for each target Generate the rule files for each target.
-  for (const auto& gtarget : lg->GetGeneratorTargets()) {
+  for (const auto& gtarget : lg.GetGeneratorTargets()) {
     int type = gtarget->GetType();
     std::string name = gtarget->GetName();
     if (!name.empty() &&
@@ -636,27 +642,27 @@
          (type == cmStateEnums::UTILITY))) {
       std::string makefileName;
       // Add a rule to build the target by name.
-      localName = lg->GetRelativeTargetDirectory(gtarget.get());
+      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 = "";
@@ -675,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.get());
-      lg->WriteMakeRule(ruleFileStream, "All Build rule for target.",
-                        localName, depends, commands, true);
+      lg.WriteMakeRule(ruleFileStream, "All Build rule for target.", localName,
+                       depends, commands, true);
 
       // Write the rule.
       commands.clear();
@@ -691,7 +697,7 @@
         std::ostringstream progCmd;
         progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
         // # in target
-        progCmd << lg->ConvertToOutputFormat(
+        progCmd << lg.ConvertToOutputFormat(
           cmSystemTools::CollapseFullPath(progress.Dir),
           cmOutputConverter::SHELL);
         //
@@ -701,11 +707,11 @@
         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";
@@ -716,39 +722,38 @@
         depends.emplace_back("cmake_check_build_system");
       }
       localName =
-        cmStrCat(lg->GetRelativeTargetDirectory(gtarget.get()), "/rule");
-      lg->WriteMakeRule(ruleFileStream,
-                        "Build rule for subdir invocation for target.",
-                        localName, depends, commands, true);
+        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.get()),
+      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.get());
+      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();
     }
   }
@@ -760,7 +765,7 @@
 {
   this->DirectoryTargetsMap.clear();
   // Loop over all targets in all local generators.
-  for (cmLocalGenerator* lg : this->LocalGenerators) {
+  for (const auto& lg : this->LocalGenerators) {
     for (const auto& gt : lg->GetGeneratorTargets()) {
       cmLocalGenerator* tlg = gt->GetLocalGenerator();
 
@@ -810,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;
@@ -889,14 +894,14 @@
   std::set<std::string> emittedTargets;
 
   // 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 (const auto& target : lg2->GetGeneratorTargets()) {
+      for (const auto& target : lg2.GetGeneratorTargets()) {
         cmStateEnums::TargetType type = target->GetType();
         if ((type == cmStateEnums::EXECUTABLE) ||
             (type == cmStateEnums::STATIC_LIBRARY) ||
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
index 79db30e..5608baf 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>
@@ -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 5b83e2f..bdf4cf2 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"
@@ -574,10 +576,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()
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index 8a76047..c991c76 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"
 
@@ -31,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
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index 40b214c..04ec7b3 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>
@@ -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()));
   }
 }
 
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
index 7a9fcef..974bb1d 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;
diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx
index ea603b0..6e89fc4 100644
--- a/Source/cmGlobalVisualStudio8Generator.cxx
+++ b/Source/cmGlobalVisualStudio8Generator.cxx
@@ -3,6 +3,7 @@
 #include "cmGlobalVisualStudio8Generator.h"
 
 #include <cm/memory>
+#include <cmext/memory>
 
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
@@ -98,21 +99,22 @@
     return false;
   }
 
-  std::vector<cmLocalGenerator*> const& generators = this->LocalGenerators;
-  cmLocalVisualStudio7Generator* lg =
-    static_cast<cmLocalVisualStudio7Generator*>(generators[0]);
+  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 = lg->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, 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);
 
-  auto ptr = cm::make_unique<cmGeneratorTarget>(tgt, lg);
+  auto ptr = cm::make_unique<cmGeneratorTarget>(tgt, &lg);
   auto gt = ptr.get();
-  lg->AddGeneratorTarget(std::move(ptr));
+  lg.AddGeneratorTarget(std::move(ptr));
 
   // Organize in the "predefined targets" folder:
   //
@@ -130,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";
@@ -143,7 +145,7 @@
     // Collect the input files used to generate all targets in this
     // project.
     std::vector<std::string> listFiles;
-    for (cmLocalGenerator* gen : generators) {
+    for (const auto& gen : generators) {
       cmAppend(listFiles, gen->GetMakefile()->GetListFiles());
     }
 
@@ -155,7 +157,7 @@
       std::vector<std::string> byproducts;
       byproducts.push_back(cm->GetGlobVerifyStamp());
 
-      lg->AddCustomCommandToTarget(
+      lg.AddCustomCommandToTarget(
         CMAKE_CHECK_BUILD_SYSTEM_TARGET, byproducts, no_depends,
         verifyCommandLines, cmCustomCommandType::PRE_BUILD,
         "Checking File Globs", no_working_directory, false);
@@ -173,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 });
@@ -187,7 +189,7 @@
     // (this could be avoided with per-target source files)
     std::string no_main_dependency;
     cmImplicitDependsList no_implicit_depends;
-    if (cmSourceFile* file = lg->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)) {
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index d75c489..37717f4 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -392,9 +392,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()
@@ -1363,7 +1365,7 @@
 
 void cmGlobalXCodeGenerator::ForceLinkerLanguages()
 {
-  for (auto localGenerator : this->LocalGenerators) {
+  for (const auto& localGenerator : this->LocalGenerators) {
     // All targets depend on the build-system check target.
     for (const auto& tgt : localGenerator->GetGeneratorTargets()) {
       // This makes sure all targets link using the proper language.
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index f60ea72..a12021d 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>
@@ -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
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
index 9c1a924..f48789a 100644
--- a/Source/cmGraphVizWriter.cxx
+++ b/Source/cmGraphVizWriter.cxx
@@ -277,7 +277,7 @@
   std::set<cmGeneratorTarget const*, cmGeneratorTarget::StrictTargetComparison>
     sortedGeneratorTargets;
 
-  for (cmLocalGenerator const* lg : gg->GetLocalGenerators()) {
+  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.
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 7b6d0f3..61cf9e9 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -1094,8 +1094,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 =
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index da32204..ecf892b 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -293,7 +293,11 @@
          3, 16, 0, cmPolicies::WARN)                                          \
   SELECT(POLICY, CMP0098,                                                     \
          "FindFLEX runs flex in CMAKE_CURRENT_BINARY_DIR when executing.", 3, \
-         17, 0, cmPolicies::WARN)
+         17, 0, cmPolicies::WARN)                                             \
+  SELECT(POLICY, CMP0099,                                                     \
+         "Link properties are transitive over private dependency on static "  \
+         "libraries.",                                                        \
+         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)                                         \
@@ -322,7 +326,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/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx
index ef70fce..db5a8ba 100644
--- a/Source/cmQtAutoGenGlobalInitializer.cxx
+++ b/Source/cmQtAutoGenGlobalInitializer.cxx
@@ -40,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;
@@ -55,7 +55,7 @@
         if (targetName.empty()) {
           targetName = "autogen";
         }
-        GlobalAutoGenTargets_.emplace(localGen, std::move(targetName));
+        GlobalAutoGenTargets_.emplace(localGen.get(), std::move(targetName));
         globalAutoGenTarget = true;
       }
 
@@ -66,7 +66,7 @@
         if (targetName.empty()) {
           targetName = "autorcc";
         }
-        GlobalAutoRccTargets_.emplace(localGen, std::move(targetName));
+        GlobalAutoRccTargets_.emplace(localGen.get(), std::move(targetName));
         globalAutoRccTarget = true;
       }
     }
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/cmake.cxx b/Source/cmake.cxx
index b1c6e8f..c9fe963 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -538,7 +538,7 @@
     std::vector<std::string> includeDirs = cmExpandedList(includes);
 
     gg->CreateGenerationObjects();
-    cmLocalGenerator* lg = gg->LocalGenerators[0];
+    const auto& lg = gg->LocalGenerators[0];
     std::string includeFlags =
       lg->GetIncludeFlags(includeDirs, nullptr, language);
 
@@ -2169,7 +2169,7 @@
     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);
     }
   }
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index d6df49c..9f4463c 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -1084,7 +1084,7 @@
         snapshot.GetDirectory().SetCurrentBinary(startOutDir);
         snapshot.GetDirectory().SetCurrentSource(startDir);
         cmMakefile mf(ggd, snapshot);
-        std::unique_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator(&mf));
+        auto lgd = ggd->CreateLocalGenerator(&mf);
 
         // Actually scan dependencies.
         return lgd->UpdateDependencies(depInfo, verbose, color) ? 0 : 2;
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 1b3577f..1e0cb86 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -556,6 +556,7 @@
   DEB.MD5SUMS
   DEB.DEB_PACKAGE_VERSION_BACK_COMPATIBILITY
   DEB.DEB_DESCRIPTION
+  DEB.PROJECT_META
 
   RPM.CUSTOM_BINARY_SPEC_FILE
   RPM.CUSTOM_NAMES
@@ -576,6 +577,7 @@
   RPM.SUGGESTS
   RPM.SYMLINKS
   RPM.USER_FILELIST
+  RPM.PROJECT_META
 
   7Z
   TBZ2
diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake
index b154c79..76d16e1 100644
--- a/Tests/RunCMake/CPack/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake
@@ -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/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/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 0953504..b2de596 100644
--- a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
@@ -1,4 +1,6 @@
 include(RunCMake)
+include(RunCTest)
+
 set(RunCMake_TEST_TIMEOUT 60)
 
 unset(ENV{CTEST_PARALLEL_LEVEL})
@@ -311,3 +313,6 @@
   run_cmake_command(show-only_json-v1 ${CMAKE_CTEST_COMMAND} --show-only=json-v1)
 endfunction()
 run_ShowOnly()
+
+# 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/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/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/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_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..9dee964
--- /dev/null
+++ b/Tests/RunCMake/target_link_options/CMP0099.cmake
@@ -0,0 +1,16 @@
+
+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_static STATIC LinkOptionsLib.c)
+target_link_libraries (LinkOptions_static PRIVATE LinkOptions_interface)
+
+add_executable(LinkOptions_exe LinkOptionsExe.c)
+target_link_libraries (LinkOptions_exe PRIVATE LinkOptions_static)
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/bootstrap b/bootstrap
index 8606dda..6e89589 100755
--- a/bootstrap
+++ b/bootstrap
@@ -437,6 +437,7 @@
   cmTargetCompileOptionsCommand \
   cmTargetIncludeDirectoriesCommand \
   cmTargetLinkLibrariesCommand \
+  cmTargetLinkOptionsCommand \
   cmTargetPrecompileHeadersCommand \
   cmTargetPropCommandBase \
   cmTargetPropertyComputer \