Merge topic 'step5'

fc2d1b1347 Tutorial: Clarify Step 5

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !4231
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim
index 31ec1d0..0676f7e 100644
--- a/Auxiliary/vim/syntax/cmake.vim
+++ b/Auxiliary/vim/syntax/cmake.vim
@@ -221,6 +221,7 @@
             \ JOB_POOLS
             \ JOB_POOL_COMPILE
             \ JOB_POOL_LINK
+            \ JOB_POOL_PRECOMPILE_HEADER
             \ KEEP_EXTENSION
             \ LABELS
             \ LANGUAGE
@@ -1066,6 +1067,7 @@
             \ CMAKE_JOB_POOLS
             \ CMAKE_JOB_POOL_COMPILE
             \ CMAKE_JOB_POOL_LINK
+            \ CMAKE_JOB_POOL_PRECOMPILE_HEADER
             \ CMAKE_Java
             \ CMAKE_Java_ANDROID_TOOLCHAIN_MACHINE
             \ CMAKE_Java_ANDROID_TOOLCHAIN_PREFIX
@@ -2864,6 +2866,11 @@
             \ _LINKER_WRAPPER_FLAG
             \ _LINKER_WRAPPER_FLAG_SEP
 
+syn keyword cmakeKWtarget_precompile_headers contained
+            \ INTERFACE
+            \ PRIVATE
+            \ PUBLIC
+
 syn keyword cmakeKWtarget_sources contained
             \ ALIAS
             \ IMPORTED
@@ -3168,6 +3175,7 @@
             \ target_link_directories
             \ target_link_libraries
             \ target_link_options
+            \ target_precompile_headers
             \ target_sources
             \ try_compile
             \ try_run
@@ -3324,6 +3332,7 @@
 hi def link cmakeKWtarget_link_directories ModeMsg
 hi def link cmakeKWtarget_link_libraries ModeMsg
 hi def link cmakeKWtarget_link_options ModeMsg
+hi def link cmakeKWtarget_precompile_headers ModeMsg
 hi def link cmakeKWtarget_sources ModeMsg
 hi def link cmakeKWtry_compile ModeMsg
 hi def link cmakeKWtry_run ModeMsg
diff --git a/Help/cpack_gen/dmg.rst b/Help/cpack_gen/dmg.rst
index 1e37889..35320c2 100644
--- a/Help/cpack_gen/dmg.rst
+++ b/Help/cpack_gen/dmg.rst
@@ -81,6 +81,13 @@
   ``<language>.menu.txt`` and ``<language>.license.txt`` in the directory
   specified by the :variable:`CPACK_DMG_SLA_DIR` variable.
 
+.. variable:: CPACK_DMG_<component>_FILE_NAME
+
+ File name when packaging ``<component>`` as its own DMG
+ (``CPACK_COMPONENTS_GROUPING`` set to IGNORE).
+
+ - Default: ``CPACK_PACKAGE_FILE_NAME-<component>``
+
 .. variable:: CPACK_COMMAND_HDIUTIL
 
  Path to the ``hdiutil(1)`` command used to operate on disk image files on
diff --git a/Help/generator/Ninja Multi-Config.rst b/Help/generator/Ninja Multi-Config.rst
index 92ca760..248eb05 100644
--- a/Help/generator/Ninja Multi-Config.rst
+++ b/Help/generator/Ninja Multi-Config.rst
@@ -19,8 +19,8 @@
 ``build-<Config>.ninja`` as the ``-f`` file and ``<target>`` as the build
 target.
 
-If :variable:`CMAKE_NINJA_CROSS_CONFIG_ENABLE` is turned on, executables and
-libraries of any configuration can be built regardless of which
+If :variable:`CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE` is turned on, executables
+and libraries of any configuration can be built regardless of which
 ``build-<Config>.ninja`` file is used, simply by specifying
 ``<target>:<OtherConfig>`` as the Ninja target. You can also specify
 ``<target>:all`` to build a target in all configurations. Each
@@ -31,8 +31,8 @@
 Ninja for the same file to be output with different commands in the same build
 graph.
 
-If :variable:`CMAKE_NINJA_CROSS_CONFIG_ENABLE` is not enabled, you can still
-build any target in ``build-<Config>.ninja`` by specifying
+If :variable:`CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE` is not enabled, you can
+still build any target in ``build-<Config>.ninja`` by specifying
 ``<target>:<Config>`` or ``<target>``, but not ``<target>:<OtherConfig>`` or
 ``<target>:all``.
 
@@ -60,8 +60,8 @@
 used to generate ``generated.c``, which would be used to build the ``Debug``
 configuration of ``generated``.
 
-But if :variable:`CMAKE_NINJA_CROSS_CONFIG_ENABLE` is enabled, and you run the
-following instead:
+But if :variable:`CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE` is enabled, and you
+run the following instead:
 
 .. code-block:: shell
 
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index b3802d1..393735e 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -253,6 +253,7 @@
    /prop_tgt/IOS_INSTALL_COMBINED
    /prop_tgt/JOB_POOL_COMPILE
    /prop_tgt/JOB_POOL_LINK
+   /prop_tgt/JOB_POOL_PRECOMPILE_HEADER
    /prop_tgt/LABELS
    /prop_tgt/LANG_CLANG_TIDY
    /prop_tgt/LANG_COMPILER_LAUNCHER
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 26f1d80..a8fbc09 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -65,6 +65,7 @@
    /variable/CMAKE_IMPORT_LIBRARY_SUFFIX
    /variable/CMAKE_JOB_POOL_COMPILE
    /variable/CMAKE_JOB_POOL_LINK
+   /variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER
    /variable/CMAKE_JOB_POOLS
    /variable/CMAKE_LANG_COMPILER_AR
    /variable/CMAKE_LANG_COMPILER_RANLIB
@@ -215,7 +216,6 @@
    /variable/CMAKE_MESSAGE_INDENT
    /variable/CMAKE_MESSAGE_LOG_LEVEL
    /variable/CMAKE_MODULE_PATH
-   /variable/CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE
    /variable/CMAKE_POLICY_DEFAULT_CMPNNNN
    /variable/CMAKE_POLICY_WARNING_CMPNNNN
    /variable/CMAKE_PREFIX_PATH
@@ -369,6 +369,7 @@
    /variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY
    /variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG
    /variable/CMAKE_CONFIG_POSTFIX
+   /variable/CMAKE_CTEST_ARGUMENTS
    /variable/CMAKE_CUDA_SEPARABLE_COMPILATION
    /variable/CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS
    /variable/CMAKE_DEBUG_POSTFIX
@@ -423,7 +424,8 @@
    /variable/CMAKE_MODULE_LINKER_FLAGS_INIT
    /variable/CMAKE_MSVCIDE_RUN_PATH
    /variable/CMAKE_MSVC_RUNTIME_LIBRARY
-   /variable/CMAKE_NINJA_CROSS_CONFIG_ENABLE
+   /variable/CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE
+   /variable/CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE
    /variable/CMAKE_NINJA_OUTPUT_PATH_PREFIX
    /variable/CMAKE_NO_BUILTIN_CHRPATH
    /variable/CMAKE_NO_SYSTEM_FROM_IMPORTED
diff --git a/Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst b/Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst
new file mode 100644
index 0000000..ece28a4
--- /dev/null
+++ b/Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst
@@ -0,0 +1,21 @@
+JOB_POOL_PRECOMPILE_HEADER
+--------------------------
+
+Ninja only: Pool used for generating pre-compiled headers.
+
+The number of parallel compile processes could be limited by defining
+pools with the global :prop_gbl:`JOB_POOLS`
+property and then specifying here the pool name.
+
+For instance:
+
+.. code-block:: cmake
+
+  set_property(TARGET myexe PROPERTY JOB_POOL_PRECOMPILE_HEADER two_jobs)
+
+This property is initialized by the value of
+:variable:`CMAKE_JOB_POOL_PRECOMPILE_HEADER`.
+
+If neither :prop_tgt:`JOB_POOL_PRECOMPILE_HEADER` nor
+:variable:`CMAKE_JOB_POOL_PRECOMPILE_HEADER` are set then
+:prop_tgt:`JOB_POOL_COMPILE` will be used for this task.
diff --git a/Help/prop_tgt/LINK_LIBRARIES_INDIRECTION.txt b/Help/prop_tgt/LINK_LIBRARIES_INDIRECTION.txt
index fab4418..476e4a6 100644
--- a/Help/prop_tgt/LINK_LIBRARIES_INDIRECTION.txt
+++ b/Help/prop_tgt/LINK_LIBRARIES_INDIRECTION.txt
@@ -1,9 +1,9 @@
 .. note::
   A call to :command:`target_link_libraries(<target> ...)` may update this
   property on ``<target>``.  If ``<target>`` was not created in the same
-  directory as the call then :command:`target_link_libraries` will add a
-  suffix of the form ``::@(directory-id)`` to each entry, where the
-  ``::@`` is a separator and the ``(directory-id)`` is unspecified.
+  directory as the call then :command:`target_link_libraries` will wrap each
+  entry with the form ``::@(directory-id);...;::@``, where the ``::@`` is
+  literal and the ``(directory-id)`` is unspecified.
   This tells the generators that the named libraries must be looked up in
   the scope of the caller rather than in the scope in which the
   ``<target>`` was created.  Valid directory ids are stripped on export
diff --git a/Help/release/dev/cmake-ctest-arguments.rst b/Help/release/dev/cmake-ctest-arguments.rst
new file mode 100644
index 0000000..72a264a
--- /dev/null
+++ b/Help/release/dev/cmake-ctest-arguments.rst
@@ -0,0 +1,6 @@
+cmake-ctest-arguments
+---------------------
+
+* A :variable:`CMAKE_CTEST_ARGUMENTS` variable was added to specify a list
+  of command-line arguments passed to CTest when running through the
+  ``test`` (or ``RUN_TESTS``) target of the generated build system.
diff --git a/Help/release/dev/custom-dmg-names.rst b/Help/release/dev/custom-dmg-names.rst
new file mode 100644
index 0000000..73a70a1
--- /dev/null
+++ b/Help/release/dev/custom-dmg-names.rst
@@ -0,0 +1,7 @@
+custom-dmg-names
+----------------
+
+* The :cpack_gen:`CPack DragNDrop Generator` learned to use
+  the :variable:`CPACK_DMG_<component>_FILE_NAME` variable
+  to set a custom filename when packaging components into
+  their own DMGs.
diff --git a/Help/variable/CMAKE_CTEST_ARGUMENTS.rst b/Help/variable/CMAKE_CTEST_ARGUMENTS.rst
new file mode 100644
index 0000000..0940b46
--- /dev/null
+++ b/Help/variable/CMAKE_CTEST_ARGUMENTS.rst
@@ -0,0 +1,6 @@
+CMAKE_CTEST_ARGUMENTS
+---------------------
+
+Set this to a :ref:`semicolon-separated list <CMake Language Lists>` of
+command-line arguments to pass to :manual:`ctest(1)` when running tests
+through the ``test`` (or ``RUN_TESTS``) target of the generated build system.
diff --git a/Help/variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER.rst b/Help/variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER.rst
new file mode 100644
index 0000000..f9467b3
--- /dev/null
+++ b/Help/variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER.rst
@@ -0,0 +1,6 @@
+CMAKE_JOB_POOL_PRECOMPILE_HEADER
+--------------------------------
+
+This variable is used to initialize the :prop_tgt:`JOB_POOL_PRECOMPILE_HEADER`
+property on all the targets. See :prop_tgt:`JOB_POOL_PRECOMPILE_HEADER`
+for additional information.
diff --git a/Help/variable/CMAKE_NINJA_CROSS_CONFIG_ENABLE.rst b/Help/variable/CMAKE_NINJA_CROSS_CONFIG_ENABLE.rst
deleted file mode 100644
index 5c9c1aa..0000000
--- a/Help/variable/CMAKE_NINJA_CROSS_CONFIG_ENABLE.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-CMAKE_NINJA_CROSS_CONFIG_ENABLE
--------------------------------
-
-If this variable is enabled, cross-configuration building is enabled in the
-:generator:`Ninja Multi-Config` generator. See the generator's description for
-more details.
diff --git a/Help/variable/CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE.rst b/Help/variable/CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE.rst
new file mode 100644
index 0000000..0571d52
--- /dev/null
+++ b/Help/variable/CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE.rst
@@ -0,0 +1,10 @@
+CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE
+-------------------------------------
+
+If this variable is enabled, cross-configuration building is enabled in the
+:generator:`Ninja Multi-Config` generator. See the generator's description for
+more details. This variable is ``OFF`` by default.
+
+This variable is meant to be set from the command line (via
+``-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE:BOOL=ON``) and should not be set from
+project code.
diff --git a/Modules/CMakeCSharpInformation.cmake b/Modules/CMakeCSharpInformation.cmake
index 48e1a1e..41cd449 100644
--- a/Modules/CMakeCSharpInformation.cmake
+++ b/Modules/CMakeCSharpInformation.cmake
@@ -10,7 +10,7 @@
 
 set(CMAKE_BUILD_TYPE_INIT Debug)
 
-set(CMAKE_CSharp_FLAGS_INIT "/define:TRACE /langversion:3")
+set(CMAKE_CSharp_FLAGS_INIT "/define:TRACE")
 set(CMAKE_CSharp_FLAGS_DEBUG_INIT "/debug:full /optimize- /warn:3 /errorreport:prompt /define:DEBUG")
 set(CMAKE_CSharp_FLAGS_RELEASE_INIT "/debug:none /optimize  /warn:1  /errorreport:queue")
 set(CMAKE_CSharp_FLAGS_RELWITHDEBINFO_INIT "/debug:full /optimize-")
diff --git a/Modules/Compiler/NAG-Fortran.cmake b/Modules/Compiler/NAG-Fortran.cmake
index c54ab9d..2111c65 100644
--- a/Modules/Compiler/NAG-Fortran.cmake
+++ b/Modules/Compiler/NAG-Fortran.cmake
@@ -28,6 +28,8 @@
   endif()
 endif()
 
+set(CMAKE_Fortran_SUBMODULE_SEP ".")
+set(CMAKE_Fortran_SUBMODULE_EXT ".sub")
 set(CMAKE_Fortran_MODDIR_FLAG "-mdir ")
 set(CMAKE_SHARED_LIBRARY_Fortran_FLAGS "-PIC")
 set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-fixed")
diff --git a/Modules/Platform/Windows-PGI.cmake b/Modules/Platform/Windows-PGI.cmake
index ad77e8a..8166240 100644
--- a/Modules/Platform/Windows-PGI.cmake
+++ b/Modules/Platform/Windows-PGI.cmake
@@ -9,9 +9,10 @@
 set(__WINDOWS_COMPILER_PGI 1)
 
 # PGI on Windows doesn't support parallel compile processes
-if(NOT DEFINED CMAKE_JOB_POOL_LINK OR NOT DEFINED CMAKE_JOB_POOL_COMPILE)
+if(NOT DEFINED CMAKE_JOB_POOL_LINK OR NOT DEFINED CMAKE_JOB_POOL_COMPILE OR NOT DEFINED CMAKE_JOB_POOL_PRECOMPILE_HEADER)
   set(CMAKE_JOB_POOL_LINK PGITaskPool)
   set(CMAKE_JOB_POOL_COMPILE PGITaskPool)
+  set(CMAKE_JOB_POOL_PRECOMPILE_HEADER PGITaskPool)
   get_property(_pgijp GLOBAL PROPERTY JOB_POOLS)
   if(NOT _pgijp MATCHES "PGITaskPool=")
       set_property(GLOBAL APPEND PROPERTY JOB_POOLS PGITaskPool=1)
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 7aa2fb8..721e823 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 20200115)
+set(CMake_VERSION_PATCH 20200117)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx
index ea71007..3516235 100644
--- a/Source/CPack/cmCPackDragNDropGenerator.cxx
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -775,6 +775,11 @@
     }
   }
 
+  std::string componentFileName =
+    "CPACK_DMG_" + cmSystemTools::UpperCase(componentName) + "_FILE_NAME";
+  if (this->IsSet(componentFileName)) {
+    return this->GetOption(componentFileName);
+  }
   return GetComponentPackageFileName(package_file_name, componentName, false);
 }
 
diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx
index ee43587..3692202 100644
--- a/Source/cmDependsFortran.cxx
+++ b/Source/cmDependsFortran.cxx
@@ -33,6 +33,8 @@
     ext_len = 4;
   } else if (cmHasLiteralSuffix(mod, ".smod")) {
     ext_len = 5;
+  } else if (cmHasLiteralSuffix(mod, ".sub")) {
+    ext_len = 4;
   }
   std::string const& name = mod.substr(0, mod.size() - ext_len);
   std::string const& ext = mod.substr(mod.size() - ext_len);
@@ -284,7 +286,8 @@
       if (doing_provides) {
         std::string mod = line;
         if (!cmHasLiteralSuffix(mod, ".mod") &&
-            !cmHasLiteralSuffix(mod, ".smod")) {
+            !cmHasLiteralSuffix(mod, ".smod") &&
+            !cmHasLiteralSuffix(mod, ".sub")) {
           // Support fortran.internal files left by older versions of CMake.
           // They do not include the ".mod" extension.
           mod += ".mod";
@@ -470,7 +473,8 @@
   if (args.size() >= 5) {
     compilerId = args[4];
   }
-  if (!cmHasLiteralSuffix(mod, ".mod") && !cmHasLiteralSuffix(mod, ".smod")) {
+  if (!cmHasLiteralSuffix(mod, ".mod") && !cmHasLiteralSuffix(mod, ".smod") &&
+      !cmHasLiteralSuffix(mod, ".sub")) {
     // Support depend.make files left by older versions of CMake.
     // They do not include the ".mod" extension.
     mod += ".mod";
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 7a4b887..27e9906 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -14,6 +14,7 @@
 #include "cmComputeLinkInformation.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
 #include "cmLinkItem.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
@@ -640,6 +641,9 @@
   std::string sep;
   input.clear();
   for (std::string& li : parts) {
+    if (cmHasLiteralPrefix(li, CMAKE_DIRECTORY_ID_SEP)) {
+      continue;
+    }
     if (cmGeneratorExpression::Find(li) == std::string::npos) {
       this->AddTargetNamespace(li, target, missingTargets);
     } else {
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 1fdfa87..d1775a7 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -1707,7 +1707,8 @@
   // as we receive downloaded bits from curl...
   //
   std::string dir = cmSystemTools::GetFilenamePath(file);
-  if (!cmSystemTools::FileExists(dir) && !cmSystemTools::MakeDirectory(dir)) {
+  if (!dir.empty() && !cmSystemTools::FileExists(dir) &&
+      !cmSystemTools::MakeDirectory(dir)) {
     std::string errstring = "DOWNLOAD error: cannot create directory '" + dir +
       "' - Specify file by full path name and verify that you "
       "have directory creation and file write privileges.";
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index b3fb132..4158c53 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -5407,16 +5407,39 @@
                                                          areport);
 }
 
+bool cmGeneratorTarget::IsLinkLookupScope(std::string const& n,
+                                          cmLocalGenerator const*& lg) const
+{
+  if (cmHasLiteralPrefix(n, CMAKE_DIRECTORY_ID_SEP)) {
+    cmDirectoryId const dirId = n.substr(sizeof(CMAKE_DIRECTORY_ID_SEP) - 1);
+    if (dirId.String.empty()) {
+      lg = this->LocalGenerator;
+      return true;
+    }
+    if (cmLocalGenerator const* otherLG =
+          this->GlobalGenerator->FindLocalGenerator(dirId)) {
+      lg = otherLG;
+      return true;
+    }
+  }
+  return false;
+}
+
 void cmGeneratorTarget::LookupLinkItems(std::vector<std::string> const& names,
                                         cmListFileBacktrace const& bt,
                                         std::vector<cmLinkItem>& items) const
 {
+  cmLocalGenerator const* lg = this->LocalGenerator;
   for (std::string const& n : names) {
+    if (this->IsLinkLookupScope(n, lg)) {
+      continue;
+    }
+
     std::string name = this->CheckCMP0004(n);
     if (name == this->GetName() || name.empty()) {
       continue;
     }
-    items.push_back(this->ResolveLinkItem(name, bt));
+    items.push_back(this->ResolveLinkItem(name, bt, lg));
   }
 }
 
@@ -5425,6 +5448,7 @@
   cmGeneratorTarget const* headTarget, bool usage_requirements_only,
   std::vector<cmLinkItem>& items, bool& hadHeadSensitiveCondition) const
 {
+  // Keep this logic in sync with ComputeLinkImplementationLibraries.
   cmGeneratorExpression ge;
   cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr);
   // The $<LINK_ONLY> expression may be in a link interface to specify private
@@ -6500,6 +6524,7 @@
   const std::string& config, cmOptionalLinkImplementation& impl,
   cmGeneratorTarget const* head) const
 {
+  cmLocalGenerator const* lg = this->LocalGenerator;
   cmStringRange entryRange = this->Target->GetLinkImplementationEntries();
   cmBacktraceRange btRange = this->Target->GetLinkImplementationBacktraces();
   cmBacktraceRange::const_iterator btIt = btRange.begin();
@@ -6508,6 +6533,7 @@
                                      end = entryRange.end();
        le != end; ++le, ++btIt) {
     std::vector<std::string> llibs;
+    // Keep this logic in sync with ExpandLinkItems.
     cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr,
                                                nullptr);
     cmGeneratorExpression ge(*btIt);
@@ -6520,6 +6546,10 @@
     }
 
     for (std::string const& lib : llibs) {
+      if (this->IsLinkLookupScope(lib, lg)) {
+        continue;
+      }
+
       // Skip entries that resolve to the target itself or are empty.
       std::string name = this->CheckCMP0004(lib);
       if (name == this->GetName() || name.empty()) {
@@ -6554,7 +6584,7 @@
       }
 
       // The entry is meant for this configuration.
-      impl.Libraries.emplace_back(this->ResolveLinkItem(name, *btIt),
+      impl.Libraries.emplace_back(this->ResolveLinkItem(name, *btIt, lg),
                                   evaluated != *le);
     }
 
@@ -6591,38 +6621,16 @@
 cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference(
   std::string const& name) const
 {
-  cmLocalGenerator const* lg = this->LocalGenerator;
-  std::string const* lookupName = &name;
+  return this->ResolveTargetReference(name, this->LocalGenerator);
+}
 
-  // When target_link_libraries() is called with a LHS target that is
-  // not created in the calling directory it adds a directory id suffix
-  // that we can use to look up the calling directory.  It is that scope
-  // in which the item name is meaningful.  This case is relatively rare
-  // so we allocate a separate string only when the directory id is present.
-  std::string::size_type pos = name.find(CMAKE_DIRECTORY_ID_SEP);
-  std::string plainName;
-  if (pos != std::string::npos) {
-    // We will look up the plain name without the directory id suffix.
-    plainName = name.substr(0, pos);
-
-    // We will look up in the scope of the directory id.
-    // If we do not recognize the id then leave the original
-    // syntax in place to produce an indicative error later.
-    cmDirectoryId const dirId =
-      name.substr(pos + sizeof(CMAKE_DIRECTORY_ID_SEP) - 1);
-    if (cmLocalGenerator const* otherLG =
-          this->GlobalGenerator->FindLocalGenerator(dirId)) {
-      lg = otherLG;
-      lookupName = &plainName;
-    }
-  }
-
+cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference(
+  std::string const& name, cmLocalGenerator const* lg) const
+{
   TargetOrString resolved;
 
-  if (cmGeneratorTarget* tgt = lg->FindGeneratorTargetToUse(*lookupName)) {
+  if (cmGeneratorTarget* tgt = lg->FindGeneratorTargetToUse(name)) {
     resolved.Target = tgt;
-  } else if (lookupName == &plainName) {
-    resolved.String = std::move(plainName);
   } else {
     resolved.String = name;
   }
@@ -6633,7 +6641,14 @@
 cmLinkItem cmGeneratorTarget::ResolveLinkItem(
   std::string const& name, cmListFileBacktrace const& bt) const
 {
-  TargetOrString resolved = this->ResolveTargetReference(name);
+  return this->ResolveLinkItem(name, bt, this->LocalGenerator);
+}
+
+cmLinkItem cmGeneratorTarget::ResolveLinkItem(std::string const& name,
+                                              cmListFileBacktrace const& bt,
+                                              cmLocalGenerator const* lg) const
+{
+  TargetOrString resolved = this->ResolveTargetReference(name, lg);
 
   if (!resolved.Target) {
     return cmLinkItem(resolved.String, bt);
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 0a72cbe..9d06104 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -378,9 +378,14 @@
     cmGeneratorTarget* Target = nullptr;
   };
   TargetOrString ResolveTargetReference(std::string const& name) const;
+  TargetOrString ResolveTargetReference(std::string const& name,
+                                        cmLocalGenerator const* lg) const;
 
   cmLinkItem ResolveLinkItem(std::string const& name,
                              cmListFileBacktrace const& bt) const;
+  cmLinkItem ResolveLinkItem(std::string const& name,
+                             cmListFileBacktrace const& bt,
+                             cmLocalGenerator const* lg) const;
 
   // Compute the set of languages compiled by the target.  This is
   // computed every time it is called because the languages can change
@@ -919,6 +924,9 @@
 
   std::unordered_set<std::string> UnityBatchedSourceFiles;
 
+  bool IsLinkLookupScope(std::string const& n,
+                         cmLocalGenerator const*& lg) const;
+
   void ExpandLinkItems(std::string const& prop, std::string const& value,
                        std::string const& config,
                        const cmGeneratorTarget* headTarget,
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index c3ab4b7..b3eb8e4 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -2458,6 +2458,13 @@
   cmCustomCommandLine singleLine;
   singleLine.push_back(cmSystemTools::GetCTestCommand());
   singleLine.push_back("--force-new-ctest-process");
+  if (auto testArgs = mf->GetDefinition("CMAKE_CTEST_ARGUMENTS")) {
+    std::vector<std::string> args;
+    cmExpandList(testArgs, args);
+    for (auto const& arg : args) {
+      singleLine.push_back(arg);
+    }
+  }
   if (cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.') {
     singleLine.push_back("-C");
     singleLine.push_back(cmakeCfgIntDir);
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 0048ba4..0487ad1 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -2203,7 +2203,7 @@
 bool cmGlobalNinjaGenerator::EnableCrossConfigBuild() const
 {
   return this->IsMultiConfig() &&
-    this->Makefiles.front()->IsOn("CMAKE_NINJA_CROSS_CONFIG_ENABLE");
+    this->Makefiles.front()->IsOn("CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE");
 }
 
 int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index bd19b28..5a8c144 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -1196,6 +1196,13 @@
   this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
                              vars);
 
+  if (!pchSource.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
+    if (source->GetFullPath() == pchSource) {
+      this->addPoolNinjaVariable("JOB_POOL_PRECOMPILE_HEADER",
+                                 this->GetGeneratorTarget(), vars);
+    }
+  }
+
   this->SetMsvcTargetPdbVariable(vars, config);
 
   objBuild.RspFile = objectFileName + ".rsp";
diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx
index 2a345eb..60adf7f 100644
--- a/Source/cmSourceFile.cxx
+++ b/Source/cmSourceFile.cxx
@@ -128,7 +128,7 @@
   // The file is not generated.  It must exist on disk.
   cmMakefile const* makefile = this->Location.GetMakefile();
   // Location path
-  std::string const lPath = this->Location.GetFullPath();
+  std::string const& lPath = this->Location.GetFullPath();
   // List of extension lists
   std::array<std::vector<std::string> const*, 2> const extsLists = {
     { &makefile->GetCMakeInstance()->GetSourceExtensions(),
@@ -145,7 +145,7 @@
       return true;
     }
     // Try full path with extension
-    for (auto exts : extsLists) {
+    for (auto& exts : extsLists) {
       for (std::string const& ext : *exts) {
         if (!ext.empty()) {
           std::string extPath = cmStrCat(fullPath, '.', ext);
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 6590629..a0b3138 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -513,6 +513,7 @@
       this->GetType() != cmStateEnums::UTILITY) {
     initProp("JOB_POOL_COMPILE");
     initProp("JOB_POOL_LINK");
+    initProp("JOB_POOL_PRECOMPILE_HEADER");
   }
 
   if (impl->TargetType <= cmStateEnums::UTILITY) {
@@ -937,14 +938,7 @@
   return impl->OriginalLinkLibraries;
 }
 
-void cmTarget::AddLinkLibrary(cmMakefile& mf, const std::string& lib,
-                              cmTargetLinkLibraryType llt)
-{
-  this->AddLinkLibrary(mf, lib, lib, llt);
-}
-
 void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
-                              std::string const& libRef,
                               cmTargetLinkLibraryType llt)
 {
   cmTarget* tgt = mf.FindTargetToUse(lib);
@@ -953,13 +947,13 @@
 
     const std::string libName =
       (isNonImportedTarget && llt != GENERAL_LibraryType)
-      ? targetNameGenex(libRef)
-      : libRef;
+      ? targetNameGenex(lib)
+      : lib;
     this->AppendProperty("LINK_LIBRARIES",
                          this->GetDebugGeneratorExpressions(libName, llt));
   }
 
-  if (cmGeneratorExpression::Find(lib) != std::string::npos || lib != libRef ||
+  if (cmGeneratorExpression::Find(lib) != std::string::npos ||
       (tgt &&
        (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
         tgt->GetType() == cmStateEnums::OBJECT_LIBRARY)) ||
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index bdf8c0f..ca37f0d 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -110,10 +110,8 @@
   //! Clear the dependency information recorded for this target, if any.
   void ClearDependencyInformation(cmMakefile& mf);
 
-  void AddLinkLibrary(cmMakefile& mf, const std::string& lib,
-                      cmTargetLinkLibraryType llt);
   void AddLinkLibrary(cmMakefile& mf, std::string const& lib,
-                      std::string const& libRef, cmTargetLinkLibraryType llt);
+                      cmTargetLinkLibraryType llt);
 
   enum TLLSignature
   {
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index 1d9ecc2..df751da 100644
--- a/Source/cmTargetLinkLibrariesCommand.cxx
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -5,6 +5,8 @@
 #include <cstring>
 #include <memory>
 #include <sstream>
+#include <unordered_set>
+#include <utility>
 
 #include "cmExecutionStatus.h"
 #include "cmGeneratorExpression.h"
@@ -35,15 +37,30 @@
 
 const char* LinkLibraryTypeNames[3] = { "general", "debug", "optimized" };
 
+struct TLL
+{
+  cmMakefile& Makefile;
+  cmTarget* Target;
+  bool WarnRemoteInterface = false;
+  bool RejectRemoteLinking = false;
+  bool EncodeRemoteReference = false;
+  std::string DirectoryId;
+  std::unordered_set<std::string> Props;
+
+  TLL(cmMakefile& mf, cmTarget* target);
+  ~TLL();
+
+  bool HandleLibrary(ProcessingState currentProcessingState,
+                     const std::string& lib, cmTargetLinkLibraryType llt);
+  void AppendProperty(std::string const& prop, std::string const& value);
+  void AffectsProperty(std::string const& prop);
+};
+
 } // namespace
 
 static void LinkLibraryTypeSpecifierWarning(cmMakefile& mf, int left,
                                             int right);
 
-static bool HandleLibrary(cmMakefile& mf, cmTarget* target,
-                          ProcessingState currentProcessingState,
-                          const std::string& lib, cmTargetLinkLibraryType llt);
-
 bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args,
                                   cmExecutionStatus& status)
 {
@@ -148,6 +165,8 @@
     return true;
   }
 
+  TLL tll(mf, target);
+
   // Keep track of link configuration specifiers.
   cmTargetLinkLibraryType llt = GENERAL_LibraryType;
   bool haveLLT = false;
@@ -246,7 +265,7 @@
     } else if (haveLLT) {
       // The link type was specified by the previous argument.
       haveLLT = false;
-      if (!HandleLibrary(mf, target, currentProcessingState, args[i], llt)) {
+      if (!tll.HandleLibrary(currentProcessingState, args[i], llt)) {
         return false;
       }
     } else {
@@ -267,7 +286,7 @@
           llt = OPTIMIZED_LibraryType;
         }
       }
-      if (!HandleLibrary(mf, target, currentProcessingState, args[i], llt)) {
+      if (!tll.HandleLibrary(currentProcessingState, args[i], llt)) {
         return false;
       }
     }
@@ -310,21 +329,48 @@
       "\" instead of a library name.  The first specifier will be ignored."));
 }
 
-static bool HandleLibrary(cmMakefile& mf, cmTarget* target,
-                          ProcessingState currentProcessingState,
-                          const std::string& lib, cmTargetLinkLibraryType llt)
+namespace {
+
+TLL::TLL(cmMakefile& mf, cmTarget* target)
+  : Makefile(mf)
+  , Target(target)
 {
-  if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY &&
+  if (&this->Makefile != this->Target->GetMakefile()) {
+    // The LHS target was created in another directory.
+    switch (this->Makefile.GetPolicyStatus(cmPolicies::CMP0079)) {
+      case cmPolicies::WARN:
+        this->WarnRemoteInterface = true;
+        CM_FALLTHROUGH;
+      case cmPolicies::OLD:
+        this->RejectRemoteLinking = true;
+        break;
+      case cmPolicies::REQUIRED_ALWAYS:
+      case cmPolicies::REQUIRED_IF_USED:
+      case cmPolicies::NEW:
+        this->EncodeRemoteReference = true;
+        break;
+    }
+  }
+  if (this->EncodeRemoteReference) {
+    cmDirectoryId const dirId = this->Makefile.GetDirectoryId();
+    this->DirectoryId = cmStrCat(CMAKE_DIRECTORY_ID_SEP, dirId.String);
+  }
+}
+
+bool TLL::HandleLibrary(ProcessingState currentProcessingState,
+                        const std::string& lib, cmTargetLinkLibraryType llt)
+{
+  if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY &&
       currentProcessingState != ProcessingKeywordLinkInterface) {
-    mf.IssueMessage(
+    this->Makefile.IssueMessage(
       MessageType::FATAL_ERROR,
       "INTERFACE library can only be used with the INTERFACE keyword of "
       "target_link_libraries");
     return false;
   }
-  if (target->IsImported() &&
+  if (this->Target->IsImported() &&
       currentProcessingState != ProcessingKeywordLinkInterface) {
-    mf.IssueMessage(
+    this->Makefile.IssueMessage(
       MessageType::FATAL_ERROR,
       "IMPORTED library can only be used with the INTERFACE keyword of "
       "target_link_libraries");
@@ -339,11 +385,12 @@
      currentProcessingState == ProcessingKeywordLinkInterface)
     ? cmTarget::KeywordTLLSignature
     : cmTarget::PlainTLLSignature;
-  if (!target->PushTLLCommandTrace(sig, mf.GetExecutionContext())) {
+  if (!this->Target->PushTLLCommandTrace(
+        sig, this->Makefile.GetExecutionContext())) {
     std::ostringstream e;
     const char* modal = nullptr;
     MessageType messageType = MessageType::AUTHOR_WARNING;
-    switch (mf.GetPolicyStatus(cmPolicies::CMP0023)) {
+    switch (this->Makefile.GetPolicyStatus(cmPolicies::CMP0023)) {
       case cmPolicies::WARN:
         e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0023) << "\n";
         modal = "should";
@@ -364,77 +411,38 @@
       e << "The " << existingSig
         << " signature for target_link_libraries has "
            "already been used with the target \""
-        << target->GetName()
+        << this->Target->GetName()
         << "\".  All uses of target_link_libraries with a target " << modal
         << " be either all-keyword or all-plain.\n";
-      target->GetTllSignatureTraces(e,
-                                    sig == cmTarget::KeywordTLLSignature
-                                      ? cmTarget::PlainTLLSignature
-                                      : cmTarget::KeywordTLLSignature);
-      mf.IssueMessage(messageType, e.str());
+      this->Target->GetTllSignatureTraces(e,
+                                          sig == cmTarget::KeywordTLLSignature
+                                            ? cmTarget::PlainTLLSignature
+                                            : cmTarget::KeywordTLLSignature);
+      this->Makefile.IssueMessage(messageType, e.str());
       if (messageType == MessageType::FATAL_ERROR) {
         return false;
       }
     }
   }
 
-  bool warnRemoteInterface = false;
-  bool rejectRemoteLinking = false;
-  bool encodeRemoteReference = false;
-  if (&mf != target->GetMakefile()) {
-    // The LHS target was created in another directory.
-    switch (mf.GetPolicyStatus(cmPolicies::CMP0079)) {
-      case cmPolicies::WARN:
-        warnRemoteInterface = true;
-        CM_FALLTHROUGH;
-      case cmPolicies::OLD:
-        rejectRemoteLinking = true;
-        break;
-      case cmPolicies::REQUIRED_ALWAYS:
-      case cmPolicies::REQUIRED_IF_USED:
-      case cmPolicies::NEW:
-        encodeRemoteReference = true;
-        break;
-    }
-  }
-
-  std::string libRef;
-  if (encodeRemoteReference && !cmSystemTools::FileIsFullPath(lib)) {
-    // This is a library name added by a caller that is not in the
-    // same directory as the target was created.  Add a suffix to
-    // the name to tell ResolveLinkItem to look up the name in the
-    // caller's directory.
-    cmDirectoryId const dirId = mf.GetDirectoryId();
-    // FIXME: The "lib" may be a genex with a list inside it.
-    // After expansion this id will only attach to the last entry,
-    // or may attach to an empty string!  We will need another way
-    // to encode this that can apply to a whole list.  See issue #20204.
-    libRef = lib + CMAKE_DIRECTORY_ID_SEP + dirId.String;
-  } else {
-    // This is an absolute path or a library name added by a caller
-    // in the same directory as the target was created.  We can use
-    // the original name directly.
-    libRef = lib;
-  }
-
   // Handle normal case where the command was called with another keyword than
   // INTERFACE / LINK_INTERFACE_LIBRARIES or none at all. (The "LINK_LIBRARIES"
   // property of the target on the LHS shall be populated.)
   if (currentProcessingState != ProcessingKeywordLinkInterface &&
       currentProcessingState != ProcessingPlainLinkInterface) {
 
-    if (rejectRemoteLinking) {
-      mf.IssueMessage(
+    if (this->RejectRemoteLinking) {
+      this->Makefile.IssueMessage(
         MessageType::FATAL_ERROR,
         cmStrCat("Attempt to add link library \"", lib, "\" to target \"",
-                 target->GetName(),
+                 this->Target->GetName(),
                  "\" which is not built in this "
                  "directory.\nThis is allowed only when policy CMP0079 "
                  "is set to NEW."));
       return false;
     }
 
-    cmTarget* tgt = mf.GetGlobalGenerator()->FindTarget(lib);
+    cmTarget* tgt = this->Makefile.GetGlobalGenerator()->FindTarget(lib);
 
     if (tgt && (tgt->GetType() != cmStateEnums::STATIC_LIBRARY) &&
         (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) &&
@@ -442,7 +450,7 @@
         (tgt->GetType() != cmStateEnums::OBJECT_LIBRARY) &&
         (tgt->GetType() != cmStateEnums::INTERFACE_LIBRARY) &&
         !tgt->IsExecutableWithExports()) {
-      mf.IssueMessage(
+      this->Makefile.IssueMessage(
         MessageType::FATAL_ERROR,
         cmStrCat(
           "Target \"", lib, "\" of type ",
@@ -452,15 +460,16 @@
           "executables with the ENABLE_EXPORTS property set."));
     }
 
-    target->AddLinkLibrary(mf, lib, libRef, llt);
+    this->AffectsProperty("LINK_LIBRARIES");
+    this->Target->AddLinkLibrary(this->Makefile, lib, llt);
   }
 
-  if (warnRemoteInterface) {
-    mf.IssueMessage(
+  if (this->WarnRemoteInterface) {
+    this->Makefile.IssueMessage(
       MessageType::AUTHOR_WARNING,
       cmStrCat(
         cmPolicies::GetPolicyWarning(cmPolicies::CMP0079), "\nTarget\n  ",
-        target->GetName(),
+        this->Target->GetName(),
         "\nis not created in this "
         "directory.  For compatibility with older versions of CMake, link "
         "library\n  ",
@@ -475,15 +484,15 @@
   // STATIC library.)
   if (currentProcessingState == ProcessingKeywordPrivateInterface ||
       currentProcessingState == ProcessingPlainPrivateInterface) {
-    if (target->GetType() == cmStateEnums::STATIC_LIBRARY ||
-        target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+    if (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY ||
+        this->Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
       std::string configLib =
-        target->GetDebugGeneratorExpressions(libRef, llt);
+        this->Target->GetDebugGeneratorExpressions(lib, llt);
       if (cmGeneratorExpression::IsValidTargetName(lib) ||
           cmGeneratorExpression::Find(lib) != std::string::npos) {
         configLib = "$<LINK_ONLY:" + configLib + ">";
       }
-      target->AppendProperty("INTERFACE_LINK_LIBRARIES", configLib);
+      this->AppendProperty("INTERFACE_LINK_LIBRARIES", configLib);
     }
     return true;
   }
@@ -491,8 +500,8 @@
   // Handle general case where the command was called with another keyword than
   // PRIVATE / LINK_PRIVATE or none at all. (The "INTERFACE_LINK_LIBRARIES"
   // property of the target on the LHS shall be populated.)
-  target->AppendProperty("INTERFACE_LINK_LIBRARIES",
-                         target->GetDebugGeneratorExpressions(libRef, llt));
+  this->AppendProperty("INTERFACE_LINK_LIBRARIES",
+                       this->Target->GetDebugGeneratorExpressions(lib, llt));
 
   // Stop processing if called without any keyword.
   if (currentProcessingState == ProcessingLinkLibraries) {
@@ -500,13 +509,13 @@
   }
   // Stop processing if policy CMP0022 is set to NEW.
   const cmPolicies::PolicyStatus policy22Status =
-    target->GetPolicyStatusCMP0022();
+    this->Target->GetPolicyStatusCMP0022();
   if (policy22Status != cmPolicies::OLD &&
       policy22Status != cmPolicies::WARN) {
     return true;
   }
   // Stop processing if called with an INTERFACE library on the LHS.
-  if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+  if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
     return true;
   }
 
@@ -516,7 +525,7 @@
   {
     // Get the list of configurations considered to be DEBUG.
     std::vector<std::string> debugConfigs =
-      mf.GetCMakeInstance()->GetDebugConfigs();
+      this->Makefile.GetCMakeInstance()->GetDebugConfigs();
     std::string prop;
 
     // Include this library in the link interface for the target.
@@ -524,22 +533,49 @@
       // Put in the DEBUG configuration interfaces.
       for (std::string const& dc : debugConfigs) {
         prop = cmStrCat("LINK_INTERFACE_LIBRARIES_", dc);
-        target->AppendProperty(prop, libRef);
+        this->AppendProperty(prop, lib);
       }
     }
     if (llt == OPTIMIZED_LibraryType || llt == GENERAL_LibraryType) {
       // Put in the non-DEBUG configuration interfaces.
-      target->AppendProperty("LINK_INTERFACE_LIBRARIES", libRef);
+      this->AppendProperty("LINK_INTERFACE_LIBRARIES", lib);
 
       // Make sure the DEBUG configuration interfaces exist so that the
       // general one will not be used as a fall-back.
       for (std::string const& dc : debugConfigs) {
         prop = cmStrCat("LINK_INTERFACE_LIBRARIES_", dc);
-        if (!target->GetProperty(prop)) {
-          target->SetProperty(prop, "");
+        if (!this->Target->GetProperty(prop)) {
+          this->Target->SetProperty(prop, "");
         }
       }
     }
   }
   return true;
 }
+
+void TLL::AppendProperty(std::string const& prop, std::string const& value)
+{
+  this->AffectsProperty(prop);
+  this->Target->AppendProperty(prop, value);
+}
+
+void TLL::AffectsProperty(std::string const& prop)
+{
+  if (!this->EncodeRemoteReference) {
+    return;
+  }
+  // Add a wrapper to the expression to tell LookupLinkItems to look up
+  // names in the caller's directory.
+  if (this->Props.insert(prop).second) {
+    this->Target->AppendProperty(prop, this->DirectoryId);
+  }
+}
+
+TLL::~TLL()
+{
+  for (std::string const& prop : this->Props) {
+    this->Target->AppendProperty(prop, CMAKE_DIRECTORY_ID_SEP);
+  }
+}
+
+} // namespace
diff --git a/Tests/CMakeCommands/target_link_libraries/SubDirB/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/SubDirB/CMakeLists.txt
index b430834..06d1111 100644
--- a/Tests/CMakeCommands/target_link_libraries/SubDirB/CMakeLists.txt
+++ b/Tests/CMakeCommands/target_link_libraries/SubDirB/CMakeLists.txt
@@ -4,8 +4,9 @@
 # be visible to the directory in which TopDir is defined.
 target_link_libraries(TopDir PUBLIC debug SameNameImported optimized SameNameImported)
 
-#FIXME: Demonstrate known issue #20204.
-#target_link_libraries(TopDir PUBLIC "$<1:SameNameImported;SameNameImported>")
+# Link to a list of targets imported in this directory that would not
+# normally be visible to the directory in which TopDir is defined.
+target_link_libraries(TopDir PUBLIC "$<1:SameNameImported;SameNameImported>")
 
 # Link SubDirA to a target imported in this directory that has the same
 # name as a target imported in SubDirA's directory.  We verify when
diff --git a/Tests/CMakeTests/CMakeLists.txt b/Tests/CMakeTests/CMakeLists.txt
index 1619081..e32d693 100644
--- a/Tests/CMakeTests/CMakeLists.txt
+++ b/Tests/CMakeTests/CMakeLists.txt
@@ -33,8 +33,9 @@
 AddCMakeTest(CMakeHostSystemInformation "")
 
 AddCMakeTest(FileDownload "")
-set_property(TEST CMake.FileDownload PROPERTY
+set_tests_properties(CMake.FileDownload PROPERTIES
   PASS_REGULAR_EXPRESSION "file already exists with expected MD5 sum"
+  FAIL_REGULAR_EXPRESSION "Unexpected status"
   )
 AddCMakeTest(FileDownloadBadHash "")
 set_property(TEST CMake.FileDownloadBadHash PROPERTY
diff --git a/Tests/CMakeTests/FileDownloadTest.cmake.in b/Tests/CMakeTests/FileDownloadTest.cmake.in
index 3935449..5bd3803 100644
--- a/Tests/CMakeTests/FileDownloadTest.cmake.in
+++ b/Tests/CMakeTests/FileDownloadTest.cmake.in
@@ -1,23 +1,50 @@
+# We do not contact any real URLs, but do try a bogus one.
+# Remove any proxy configuration that may change behavior.
+unset(ENV{http_proxy})
+unset(ENV{https_proxy})
+
+set(timeout 4)
+
 if(NOT "@CMAKE_CURRENT_SOURCE_DIR@" MATCHES "^/")
   set(slash /)
 endif()
 set(url "file://${slash}@CMAKE_CURRENT_SOURCE_DIR@/FileDownloadInput.png")
 set(dir "@CMAKE_CURRENT_BINARY_DIR@/downloads")
 
+# Beware Windows asynchronous file/directory removal, rename and then
+# remove the renamed dir so we can be certain the dir isn't there when
+# we get to the file() commands below
+if(EXISTS "${dir}")
+  file(RENAME ${dir} "${dir}_beingRemoved")
+  file(REMOVE_RECURSE "${dir}_beingRemoved")
+endif()
+
+function(__reportIfWrongStatus statusPair expectedStatusCode)
+  list(GET statusPair 0 statusCode)
+  if(NOT statusCode EQUAL expectedStatusCode)
+    message(SEND_ERROR
+            "Unexpected status: ${statusCode}, expected: ${expectedStatusCode}")
+  endif()
+endfunction()
+
 message(STATUS "FileDownload:1")
 file(DOWNLOAD
   ${url}
   ${dir}/file1.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
+  STATUS status
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:2")
 file(DOWNLOAD
   ${url}
   ${dir}/file2.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
+  STATUS status
   SHOW_PROGRESS
   )
+__reportIfWrongStatus("${status}" 0)
 
 # Two calls in a row, exactly the same arguments.
 # Since downloaded file should exist already for 2nd call,
@@ -31,82 +58,108 @@
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
+  STATUS status
   EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:4")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH SHA1=67eee17f79d9ac557284fc0b8ad19f25723fb578
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:5")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH SHA224=ba283726bbb602776818b463943189afd91836cb7ee5dd6e2c7b5ae4
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:6")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH SHA256=cf3334b1275071e1da6e8c396ccb72cf1b2388d8c937526f3af26230affb9423
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:7")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH SHA384=43a5d13978d97c660db44481aee0604cb4ff6ca0775cd5c2cd68cd8000e107e507c4caf6c228941231041e282ffb8950
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:8")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH SHA512=6984e0909a1018030ccaa418e3be1654223cdccff0fe6adc745f9aea7e377f178be53b9fc7d54a6f81c2b62ef9ddcd38ba1978fedf4c5e7139baaf355eefad5b
   )
+__reportIfWrongStatus("${status}" 0)
+
 message(STATUS "FileDownload:9")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH MD5=dbd330d52f4dbd60115d4191904ded92
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:10")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92
   )
+__reportIfWrongStatus("${status}" 0)
+# Print status because we check its message too
 message(STATUS "${status}")
 
 message(STATUS "FileDownload:11")
 file(DOWNLOAD
   badhostname.png
   ${dir}/file11.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   )
 message(STATUS "${status}")
-list(GET status 0 status_code)
-if(NOT ${status_code} EQUAL 6)
-  message(SEND_ERROR "error: expected status code 6 for bad host name, got: ${status_code}")
+__reportIfWrongStatus("${status}" 6) # 6 corresponds to an unresolvable host name
+
+message(STATUS "FileDownload:12")
+set(absFile "@CMAKE_CURRENT_BINARY_DIR@/file12.png")
+if(EXISTS "${absFile}")
+  file(RENAME ${absFile} "${absFile}_beingRemoved")
+  file(REMOVE "${absFile}_beingRemoved")
+endif()
+file(DOWNLOAD
+  ${url}
+  file12.png
+  TIMEOUT ${timeout}
+  EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92
+  STATUS status
+  )
+__reportIfWrongStatus("${status}" 0)
+if(NOT EXISTS file12.png)
+  message(SEND_ERROR "file12.png not downloaded: ${status}")
 endif()
diff --git a/Tests/CMakeTests/FileTestScript.cmake b/Tests/CMakeTests/FileTestScript.cmake
index 9a43569..145f28a 100644
--- a/Tests/CMakeTests/FileTestScript.cmake
+++ b/Tests/CMakeTests/FileTestScript.cmake
@@ -183,7 +183,7 @@
 elseif(testname STREQUAL download_wrong_number_of_args) # fail
   file(DOWNLOAD zzzz://bogus/ffff)
 
-elseif(testname STREQUAL download_file_with_no_path) # fail
+elseif(testname STREQUAL download_file_with_no_path) # pass
   file(DOWNLOAD zzzz://bogus/ffff ffff)
 
 elseif(testname STREQUAL download_missing_time) # fail
diff --git a/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake b/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
index f70cd24..01b37c5 100644
--- a/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
+++ b/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
@@ -27,7 +27,7 @@
   message(STATUS "CPack_output=${CPack_output}")
 endif()
 
-set(expected_file_mask "${CPackNSISGenerator_BINARY_DIR}/_CPack_Packages/win32/NSIS/*.nsi")
+set(expected_file_mask "${CPackNSISGenerator_BINARY_DIR}/_CPack_Packages/*/NSIS/*.nsi")
 file(GLOB project_file "${expected_file_mask}")
 
 message(STATUS "project_file='${project_file}'")
diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt
index 7c81aea..387fe6b 100644
--- a/Tests/ExportImport/Export/CMakeLists.txt
+++ b/Tests/ExportImport/Export/CMakeLists.txt
@@ -156,6 +156,7 @@
 cmake_policy(POP)
 
 cmake_policy(PUSH)
+cmake_policy(SET CMP0022 NEW)
 cmake_policy(SET CMP0079 NEW)
 add_library(TopDirLib STATIC testTopDirLib.c)
 add_subdirectory(SubDirLinkA)
diff --git a/Tests/ExportImport/Export/SubDirLinkA/CMakeLists.txt b/Tests/ExportImport/Export/SubDirLinkA/CMakeLists.txt
index 1c3c9dc..1aa41d2 100644
--- a/Tests/ExportImport/Export/SubDirLinkA/CMakeLists.txt
+++ b/Tests/ExportImport/Export/SubDirLinkA/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_library(SubDirLinkAImported IMPORTED INTERFACE)
 target_compile_definitions(SubDirLinkAImported INTERFACE DEF_SubDirLinkAImportedForExport)
 
-target_link_libraries(TopDirLib PUBLIC SubDirLinkAImported)
+target_link_libraries(TopDirLib PUBLIC debug "$<1:SubDirLinkAImported;SubDirLinkAImported>" optimized "$<1:SubDirLinkAImported;SubDirLinkAImported>")
 
 add_library(SubDirLinkA STATIC SubDirLinkA.c)
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 7936f47..d302fe3 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -604,6 +604,9 @@
   STGZ
   External
   )
+if(APPLE)
+  list(APPEND cpack_tests DragNDrop)
+endif()
 add_RunCMake_test_group(CPack "${cpack_tests}")
 # add a test to make sure symbols are exported from a shared library
 # for MSVC compilers CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS property is used
diff --git a/Tests/RunCMake/CPack/DragNDrop/Helpers.cmake b/Tests/RunCMake/CPack/DragNDrop/Helpers.cmake
new file mode 100644
index 0000000..023e597
--- /dev/null
+++ b/Tests/RunCMake/CPack/DragNDrop/Helpers.cmake
@@ -0,0 +1,54 @@
+set(ALL_FILES_GLOB "*.dmg")
+
+function(getPackageContent FILE RESULT_VAR)
+  get_filename_component(path_ "${FILE}" DIRECTORY)
+  file(REMOVE_RECURSE "${path_}/content")
+  file(MAKE_DIRECTORY "${path_}/content")
+  execute_process(COMMAND ${HDIUTIL_EXECUTABLE} attach -mountroot ${path_}/content -nobrowse ${FILE}
+          RESULT_VARIABLE attach_result_
+          ERROR_VARIABLE attach_error_
+          OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+  if(attach_result_)
+    message(FATAL_ERROR "Failed to attach DMG: '${attach_result_}';"
+          " '${attach_error_}'.")
+  endif()
+
+  file(GLOB_RECURSE package_content_ LIST_DIRECTORIES true RELATIVE
+      "${path_}/content" "${path_}/content/*")
+  # Some versions of macOS have .Trashes, others do not.
+  list(FILTER package_content_ EXCLUDE REGEX "/.Trashes$")
+  set(${RESULT_VAR} "${package_content_}" PARENT_SCOPE)
+
+  execute_process(COMMAND ${HDIUTIL_EXECUTABLE} detach ${path_}/content/volume-name
+          RESULT_VARIABLE detach_result_
+          ERROR_VARIABLE detach_error_
+          OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+  if(detach_result_)
+    message(FATAL_ERROR "Failed to detach DMG: '${detach_result_}';"
+          " '${detach_error_}'.")
+  endif()
+endfunction()
+
+function(getPackageNameGlobexpr NAME COMPONENT VERSION REVISION FILE_NO RESULT_VAR)
+  if(COMPONENT)
+    set(COMPONENT "-${COMPONENT}")
+  endif()
+
+  set(${RESULT_VAR} "${NAME}-${VERSION}-Darwin${COMPONENT}.dmg" PARENT_SCOPE)
+endfunction()
+
+function(getPackageContentList FILE RESULT_VAR)
+  getPackageContent("${FILE}" package_content_)
+
+  set(${RESULT_VAR} "${package_content_}" PARENT_SCOPE)
+endfunction()
+
+function(toExpectedContentList FILE_NO CONTENT_VAR)
+  set(prefix_ "volume-name")
+  list(TRANSFORM ${CONTENT_VAR} PREPEND "${prefix_}" OUTPUT_VARIABLE prepared_)
+  list(APPEND prepared_ "${prefix_}")
+
+  set(${CONTENT_VAR} "${prepared_}" PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/DragNDrop/Prerequirements.cmake b/Tests/RunCMake/CPack/DragNDrop/Prerequirements.cmake
new file mode 100644
index 0000000..f0aaf2c
--- /dev/null
+++ b/Tests/RunCMake/CPack/DragNDrop/Prerequirements.cmake
@@ -0,0 +1,8 @@
+function(get_test_prerequirements found_var config_file)
+  find_program(HDIUTIL_EXECUTABLE hdiutil)
+
+  if(HDIUTIL_EXECUTABLE)
+    file(WRITE "${config_file}" "set(HDIUTIL_EXECUTABLE \"${HDIUTIL_EXECUTABLE}\")")
+    set(${found_var} true PARENT_SCOPE)
+  endif()
+endfunction()
diff --git a/Tests/RunCMake/CPack/DragNDrop/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/DragNDrop/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..aa6c8ff
--- /dev/null
+++ b/Tests/RunCMake/CPack/DragNDrop/packaging_COMPONENT_default.cmake
@@ -0,0 +1,3 @@
+set(CPACK_COMPONENTS_GROUPING "IGNORE")
+set(CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK ON)
+set(CPACK_DMG_VOLUME_NAME "volume-name")
diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake
index 6e413aa..0fb0cc4 100644
--- a/Tests/RunCMake/CPack/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake
@@ -5,7 +5,7 @@
 
 # run_cpack_test args: TEST_NAME "GENERATORS" RUN_CMAKE_BUILD_STEP "PACKAGING_TYPES"
 run_cpack_test(CUSTOM_BINARY_SPEC_FILE "RPM.CUSTOM_BINARY_SPEC_FILE" false "MONOLITHIC;COMPONENT")
-run_cpack_test(CUSTOM_NAMES "RPM.CUSTOM_NAMES;DEB.CUSTOM_NAMES;TGZ" true "COMPONENT")
+run_cpack_test(CUSTOM_NAMES "RPM.CUSTOM_NAMES;DEB.CUSTOM_NAMES;TGZ;DragNDrop" true "COMPONENT")
 run_cpack_test(DEBUGINFO "RPM.DEBUGINFO;DEB.DEBUGINFO" true "COMPONENT")
 run_cpack_test_subtests(DEFAULT_PERMISSIONS "CMAKE_var_set;CPACK_var_set;both_set;invalid_CMAKE_var;invalid_CPACK_var" "RPM.DEFAULT_PERMISSIONS;DEB.DEFAULT_PERMISSIONS" false "MONOLITHIC;COMPONENT")
 run_cpack_test(DEPENDENCIES "RPM.DEPENDENCIES;DEB.DEPENDENCIES" true "COMPONENT")
diff --git a/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/ExpectedFiles.cmake
index 07226df..9ac19e2 100644
--- a/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/ExpectedFiles.cmake
+++ b/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/ExpectedFiles.cmake
@@ -12,4 +12,7 @@
 elseif(GENERATOR_TYPE STREQUAL "TGZ")
   set(EXPECTED_FILE_2 "second.tar.gz")
   set(EXPECTED_FILE_3 "pkg_3_abc.tar.gz")
+elseif(GENERATOR_TYPE STREQUAL "DragNDrop")
+  set(EXPECTED_FILE_2 "second.dmg")
+  set(EXPECTED_FILE_3 "pkg_3_abc.dmg")
 endif()
diff --git a/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/test.cmake b/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/test.cmake
index 4c20e41..899258e 100644
--- a/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/test.cmake
+++ b/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/test.cmake
@@ -10,6 +10,9 @@
 elseif(GENERATOR_TYPE STREQUAL "TGZ")
   set(CPACK_ARCHIVE_PKG_2_FILE_NAME "second")
   set(CPACK_ARCHIVE_PKG_3_FILE_NAME "pkg_3_abc")
+elseif(GENERATOR_TYPE STREQUAL "DragNDrop")
+  set(CPACK_DMG_PKG_2_FILE_NAME "second")
+  set(CPACK_DMG_PKG_3_FILE_NAME "pkg_3_abc")
 endif()
 
 install(FILES CMakeLists.txt DESTINATION foo COMPONENT pkg_1)
diff --git a/Tests/RunCMake/CTest/CMakeCTestArguments-test-check.cmake b/Tests/RunCMake/CTest/CMakeCTestArguments-test-check.cmake
new file mode 100644
index 0000000..3e05953
--- /dev/null
+++ b/Tests/RunCMake/CTest/CMakeCTestArguments-test-check.cmake
@@ -0,0 +1,4 @@
+set(log "${RunCMake_TEST_BINARY_DIR}/output-log.txt")
+if(NOT EXISTS "${log}")
+  set(RunCMake_TEST_FAILED "The expected output log file is missing:\n  ${log}")
+endif()
diff --git a/Tests/RunCMake/CTest/CMakeCTestArguments.cmake b/Tests/RunCMake/CTest/CMakeCTestArguments.cmake
new file mode 100644
index 0000000..37f2933
--- /dev/null
+++ b/Tests/RunCMake/CTest/CMakeCTestArguments.cmake
@@ -0,0 +1,2 @@
+include(CTest)
+add_test(NAME CMakeCTestArguments COMMAND ${CMAKE_COMMAND} -E echo CMakeCTestArguments)
diff --git a/Tests/RunCMake/CTest/RunCMakeTest.cmake b/Tests/RunCMake/CTest/RunCMakeTest.cmake
index 1392240..761224a 100644
--- a/Tests/RunCMake/CTest/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CTest/RunCMakeTest.cmake
@@ -5,3 +5,16 @@
 unset(RunCMake_TEST_OPTIONS)
 
 run_cmake(NotOn)
+
+function(run_CMakeCTestArguments)
+  run_cmake_with_options(CMakeCTestArguments "-DCMAKE_CTEST_ARGUMENTS=--quiet\\;--output-log\\;output-log.txt")
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMakeCTestArguments-build)
+  if(RunCMake_GENERATOR MATCHES "Make|Ninja")
+    set(test "test")
+  else()
+    set(test "RUN_TESTS")
+  endif()
+  run_cmake_command(CMakeCTestArguments-test ${CMAKE_COMMAND} --build . --config Debug --target "${test}")
+endfunction()
+run_CMakeCTestArguments()
diff --git a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
index 4b9d3ed..f3208ed 100644
--- a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
+++ b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
@@ -76,7 +76,7 @@
 set(RunCMake_TEST_NO_CLEAN 1)
 
 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Simple-build)
-set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE=RelWithDebInfo;-DCMAKE_NINJA_CROSS_CONFIG_ENABLE=ON")
+set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE=RelWithDebInfo;-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE=ON")
 run_cmake_configure(Simple)
 unset(RunCMake_TEST_OPTIONS)
 include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
@@ -117,7 +117,7 @@
 run_cmake_build(SimpleNoCross all-clean Debug clean:all)
 
 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CustomCommandGenerator-build)
-set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_CROSS_CONFIG_ENABLE=ON")
+set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE=ON")
 run_cmake_configure(CustomCommandGenerator)
 unset(RunCMake_TEST_OPTIONS)
 include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
@@ -134,7 +134,7 @@
 run_cmake_command(CustomCommandGenerator-release-in-debug-graph-generated "${TARGET_FILE_generated_Release}")
 
 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CustomCommandsAndTargets-build)
-set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_CROSS_CONFIG_ENABLE=ON")
+set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE=ON")
 run_cmake_configure(CustomCommandsAndTargets)
 unset(RunCMake_TEST_OPTIONS)
 include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
@@ -150,7 +150,7 @@
 run_ninja(CustomCommandsAndTargets release-targetpostbuild build-Release.ninja SubdirTargetPostBuild)
 
 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/PostfixAndLocation-build)
-set(RunCMake_TEST_OPTIONS "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release;-DCMAKE_NINJA_CROSS_CONFIG_ENABLE=ON")
+set(RunCMake_TEST_OPTIONS "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release;-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE=ON")
 run_cmake_configure(PostfixAndLocation)
 unset(RunCMake_TEST_OPTIONS)
 include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
@@ -165,14 +165,14 @@
 run_cmake_build(Clean release-clean Release clean)
 
 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/AdditionalCleanFiles-build)
-set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_CROSS_CONFIG_ENABLE=ON")
+set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE=ON")
 run_cmake_configure(AdditionalCleanFiles)
 unset(RunCMake_TEST_OPTIONS)
 run_cmake_build(AdditionalCleanFiles release-clean Release clean)
 run_ninja(AdditionalCleanFiles all-clean build-Debug.ninja clean:all)
 
 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Install-build)
-set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_TEST_BINARY_DIR}/install;-DCMAKE_NINJA_CROSS_CONFIG_ENABLE=ON")
+set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_TEST_BINARY_DIR}/install;-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE=ON")
 run_cmake_configure(Install)
 unset(RunCMake_TEST_OPTIONS)
 include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
@@ -194,7 +194,7 @@
 
 if(CMake_TEST_Qt5)
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Qt5-build)
-  set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_CROSS_CONFIG_ENABLE=ON")
+  set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE=ON")
   run_cmake_configure(Qt5)
   unset(RunCMake_TEST_OPTIONS)
   include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW-stdout.txt b/Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW-stdout.txt
index 90a5f37..1c5cf45 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW-stdout.txt
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW-stdout.txt
@@ -1 +1 @@
--- INTERFACE_LINK_LIBRARIES='foo::@\([Xx0-9A-Fa-f]+\)'
+-- INTERFACE_LINK_LIBRARIES='::@\([Xx0-9A-Fa-f]+\);\$<\$<CONFIG:DEBUG>:\$<1:foo;foo>>;\$<\$<NOT:\$<CONFIG:DEBUG>>:\$<1:foo;foo>>;::@'
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stdout.txt b/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stdout.txt
index e575e16..4eb06d9 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stdout.txt
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stdout.txt
@@ -1 +1 @@
--- INTERFACE_LINK_LIBRARIES='foo'
+-- INTERFACE_LINK_LIBRARIES='\$<\$<CONFIG:DEBUG>:\$<1:foo;foo>>;\$<\$<NOT:\$<CONFIG:DEBUG>>:\$<1:foo;foo>>'
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stderr.txt b/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stderr.txt
index 6dd7d30..4c09a1f 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stderr.txt
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stderr.txt
@@ -10,7 +10,25 @@
   is not created in this directory.  For compatibility with older versions of
   CMake, link library
 
-    foo
+    \$<1:foo;foo>
+
+  will be looked up in the directory in which the target was created rather
+  than in this calling directory.
+This warning is for project developers.  Use -Wno-dev to suppress it.
++
+CMake Warning \(dev\) at CMP0079-iface/CMakeLists.txt:[0-9]+ \(target_link_libraries\):
+  Policy CMP0079 is not set: target_link_libraries allows use with targets in
+  other directories.  Run "cmake --help-policy CMP0079" for policy details.
+  Use the cmake_policy command to set the policy and suppress this warning.
+
+  Target
+
+    top
+
+  is not created in this directory.  For compatibility with older versions of
+  CMake, link library
+
+    \$<1:foo;foo>
 
   will be looked up in the directory in which the target was created rather
   than in this calling directory.
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stdout.txt b/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stdout.txt
index e575e16..4eb06d9 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stdout.txt
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stdout.txt
@@ -1 +1 @@
--- INTERFACE_LINK_LIBRARIES='foo'
+-- INTERFACE_LINK_LIBRARIES='\$<\$<CONFIG:DEBUG>:\$<1:foo;foo>>;\$<\$<NOT:\$<CONFIG:DEBUG>>:\$<1:foo;foo>>'
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface/CMakeLists.txt b/Tests/RunCMake/target_link_libraries/CMP0079-iface/CMakeLists.txt
index 4b15b32..e410607 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-iface/CMakeLists.txt
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface/CMakeLists.txt
@@ -1 +1 @@
-target_link_libraries(top INTERFACE foo)
+target_link_libraries(top INTERFACE debug "$<1:foo;foo>" optimized "$<1:foo;foo>")
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-stderr.txt b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-stderr.txt
index 8670403..9e38bec 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-stderr.txt
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-stderr.txt
@@ -1,5 +1,5 @@
 ^CMake Error at CMP0079-link-NEW-bogus.cmake:[0-9]+ \(add_executable\):
-  Target "top" links to target "foo::@\(0xdeadbeef\)" but the target was not
+  Target "top" links to target "::@\(0xdeadbeef\)" but the target was not
   found.  Perhaps a find_package\(\) call is missing for an IMPORTED target, or
   an ALIAS target is missing\?
 Call Stack \(most recent call first\):
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus.cmake b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus.cmake
index ea9e071..8932521 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus.cmake
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus.cmake
@@ -3,4 +3,4 @@
 enable_language(C)
 
 add_executable(top empty.c)
-set_property(TARGET top APPEND PROPERTY LINK_LIBRARIES "foo::@(0xdeadbeef)")
+set_property(TARGET top APPEND PROPERTY LINK_LIBRARIES "::@(0xdeadbeef);foo;::@")
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-stdout.txt b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-stdout.txt
index 3e8c7c6..fa5d4a3 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-stdout.txt
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-stdout.txt
@@ -1 +1 @@
--- LINK_LIBRARIES='foo::@\([Xx0-9A-Fa-f]+\)'
+-- LINK_LIBRARIES='::@\([Xx0-9A-Fa-f]+\);foo;::@'