Browse Source

file(GET_RUNTIME_DEPENDENCIES): Normalize paths before matching

Regex-based filtering should not have to account for slash differences.
Add policy CMP0207 for compatibility.

Fixes: #26202
hanna.rusakovich 1 month ago
parent
commit
bf3f69834d
27 changed files with 297 additions and 8 deletions
  1. 1 0
      CMP0207-NEW-all-result.txt
  2. 5 0
      CMP0207-NEW-all-stderr.txt
  3. 2 0
      Help/command/file.rst
  4. 1 0
      Help/manual/cmake-policies.7.rst
  5. 26 0
      Help/policy/CMP0207.rst
  6. 6 0
      Help/release/dev/file-GET_RUNTIME_DEPENDENCIES-matching.rst
  7. 31 0
      Source/cmBinUtilsLinker.cxx
  8. 2 0
      Source/cmBinUtilsLinker.h
  9. 1 0
      Source/cmBinUtilsLinuxELFLinker.cxx
  10. 7 2
      Source/cmBinUtilsMacOSMachOLinker.cxx
  11. 1 0
      Source/cmBinUtilsWindowsPELinker.cxx
  12. 2 1
      Source/cmInstallCommand.cxx
  13. 16 1
      Source/cmInstallGetRuntimeDependenciesGenerator.cxx
  14. 4 2
      Source/cmInstallGetRuntimeDependenciesGenerator.h
  15. 4 1
      Source/cmPolicies.h
  16. 1 1
      Source/cmRuntimeDependencyArchive.cxx
  17. 1 0
      Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/CMakeLists.txt
  18. 13 0
      Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMP0207-NEW.cmake
  19. 13 0
      Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMP0207-OLD.cmake
  20. 44 0
      Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMP0207-WARN-all-stderr.txt
  21. 12 0
      Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMP0207-WARN.cmake
  22. 93 0
      Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMP0207-common.cmake
  23. 1 0
      Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMP0207-subdir/CMakeLists.txt
  24. 3 0
      Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake
  25. 1 0
      Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows.cmake
  26. 1 0
      b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMP0207-NEW-all-result.txt
  27. 5 0
      b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMP0207-NEW-all-stderr.txt

+ 1 - 0
CMP0207-NEW-all-result.txt

@@ -0,0 +1 @@
+1

+ 5 - 0
CMP0207-NEW-all-stderr.txt

@@ -0,0 +1,5 @@
+^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
+  file Could not resolve runtime dependencies:
+
+    [^
+]*test\.dll$

+ 2 - 0
Help/command/file.rst

@@ -1122,6 +1122,8 @@ Handling Runtime Binaries
 
   The following arguments specify filters for including or excluding libraries
   to be resolved. See below for a full description of how they work.
+  Directory separators in file paths may be matched using forward
+  slashes unless policy :policy:`CMP0207` is not set to ``NEW``.
 
     ``PRE_INCLUDE_REGEXES <regexes>...``
       List of pre-include regexes through which to filter the names of

+ 1 - 0
Help/manual/cmake-policies.7.rst

@@ -98,6 +98,7 @@ Policies Introduced by CMake 4.3
 .. toctree::
    :maxdepth: 1
 
+   CMP0207: file(GET_RUNTIME_DEPENDENCIES) normalizes paths before matching. </policy/CMP0207>
    CMP0206: The CPack Archive Generator defaults to UID 0 and GID 0. </policy/CMP0206>
    CMP0205: file(CREATE_LINK) with COPY_ON_ERROR copies directory content. </policy/CMP0205>
 

+ 26 - 0
Help/policy/CMP0207.rst

@@ -0,0 +1,26 @@
+CMP0207
+-------
+
+.. versionadded:: 4.3
+
+:command:`file(GET_RUNTIME_DEPENDENCIES)` normalizes paths before matching.
+
+The :command:`file(GET_RUNTIME_DEPENDENCIES)` and
+:command:`install(RUNTIME_DEPENDENCY_SET)` commands support filtering
+resolved dependencies using regular expressions matching their paths.
+In CMake 4.2 and below, callers were responsible for matching both forward
+and backward slashes as path separators on Windows, e.g., via ``[\/]``.
+CMake 4.3 and above prefer to normalize paths to use forward slashes before
+matching.  This policy provides compaitiblity for projects that may have
+been relying on matching backslashes only.
+
+The ``OLD`` behavior for this policy matches filters against paths that
+may contain any combination of forward and backward slashes on Windows.
+The ``NEW`` behavior for this policy to convert all paths to forward
+slashes before matching filters.
+
+.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.3
+.. |WARNS_OR_DOES_NOT_WARN| replace:: warns
+.. include:: include/STANDARD_ADVICE.rst
+
+.. include:: include/DEPRECATED.rst

+ 6 - 0
Help/release/dev/file-GET_RUNTIME_DEPENDENCIES-matching.rst

@@ -0,0 +1,6 @@
+file-GET_RUNTIME_DEPENDENCIES-matching
+--------------------------------------
+
+* The :command:`file(GET_RUNTIME_DEPENDENCIES)`
+  and :command:`install(RUNTIME_DEPENDENCY_SET)` commands now normalize
+  paths before matching filters.  See policy :policy:`CMP0207`.

+ 31 - 0
Source/cmBinUtilsLinker.cxx

@@ -3,7 +3,14 @@
 
 #include "cmBinUtilsLinker.h"
 
+#include <utility>
+
+#include "cmCMakePath.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
 #include "cmRuntimeDependencyArchive.h"
+#include "cmStringAlgorithms.h"
 
 cmBinUtilsLinker::cmBinUtilsLinker(cmRuntimeDependencyArchive* archive)
   : Archive(archive)
@@ -14,3 +21,27 @@ void cmBinUtilsLinker::SetError(std::string const& e)
 {
   this->Archive->SetError(e);
 }
+
+void cmBinUtilsLinker::NormalizePath(std::string& path) const
+{
+  std::string normalizedPath =
+    cmCMakePath(path, cmCMakePath::auto_format).GenericString();
+
+  if (path == normalizedPath) {
+    return;
+  }
+
+  cmPolicies::PolicyStatus policy =
+    this->Archive->GetMakefile()->GetPolicyStatus(cmPolicies::CMP0207);
+  if (policy == cmPolicies::WARN) {
+    this->Archive->GetMakefile()->IssueMessage(
+      MessageType::AUTHOR_WARNING,
+      cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0207), '\n',
+               "Path\n  \"", path,
+               "\"\n"
+               "would be converted to\n  \"",
+               normalizedPath, "\"\n"));
+  } else if (policy == cmPolicies::NEW) {
+    path = std::move(normalizedPath);
+  }
+}

+ 2 - 0
Source/cmBinUtilsLinker.h

@@ -24,4 +24,6 @@ protected:
   cmRuntimeDependencyArchive* Archive;
 
   void SetError(std::string const& e);
+
+  void NormalizePath(std::string& path) const;
 };

+ 1 - 0
Source/cmBinUtilsLinuxELFLinker.cxx

@@ -204,6 +204,7 @@ bool cmBinUtilsLinuxELFLinker::ResolveDependency(
     path = cmStrCat(searchPath, '/', name);
     if (cmSystemTools::PathExists(path) &&
         FileHasArchitecture(path.c_str(), this->Machine)) {
+      this->NormalizePath(path);
       resolved = true;
       return true;
     }

+ 7 - 2
Source/cmBinUtilsMacOSMachOLinker.cxx

@@ -170,6 +170,7 @@ bool cmBinUtilsMacOSMachOLinker::ResolveDependency(
   } else {
     resolved = true;
     path = name;
+    this->NormalizePath(path);
   }
 
   if (resolved && !cmSystemTools::FileIsFullPath(path)) {
@@ -198,6 +199,7 @@ bool cmBinUtilsMacOSMachOLinker::ResolveExecutablePathDependency(
     return true;
   }
 
+  this->NormalizePath(path);
   resolved = true;
   return true;
 }
@@ -220,6 +222,7 @@ bool cmBinUtilsMacOSMachOLinker::ResolveLoaderPathDependency(
     return true;
   }
 
+  this->NormalizePath(path);
   resolved = true;
   return true;
 }
@@ -252,7 +255,7 @@ bool cmBinUtilsMacOSMachOLinker::ResolveRPathDependency(
       /*
        * paraphrasing @ben.boeckel:
        *  if /b/libB.dylib is supposed to be used,
-       *  /a/libbB.dylib will be found first if it exists. CMake tries to
+       *  /a/libB.dylib will be found first if it exists. CMake tries to
        *  sort rpath directories to avoid this, but sometimes there is no
        *  right answer.
        *
@@ -268,7 +271,9 @@ bool cmBinUtilsMacOSMachOLinker::ResolveRPathDependency(
        *  so as long as this method's resolution guarantees priority
        *  in that manner further checking should not be necessary?
        */
-      path = searchFile;
+      path = std::move(searchFile);
+
+      this->NormalizePath(path);
       resolved = true;
       return true;
     }

+ 1 - 0
Source/cmBinUtilsWindowsPELinker.cxx

@@ -155,6 +155,7 @@ bool cmBinUtilsWindowsPELinker::ResolveDependency(std::string const& name,
   for (auto const& searchPath : dirs) {
     path = cmStrCat(searchPath, '/', name);
     if (cmSystemTools::PathExists(path)) {
+      this->NormalizePath(path);
       resolved = true;
       return true;
     }

+ 2 - 1
Source/cmInstallCommand.cxx

@@ -247,7 +247,8 @@ void AddInstallRuntimeDependenciesGenerator(
       cmInstallGenerator::SelectMessageLevel(helper.Makefile),
       runtimeDependenciesArgsRef.GetExcludeFromAll() &&
         (apple ? frameworkArgs.GetExcludeFromAll() : true),
-      helper.Makefile->GetBacktrace());
+      helper.Makefile->GetBacktrace(),
+      helper.Makefile->GetPolicyStatus(cmPolicies::CMP0207));
   helper.Makefile->AddInstallGenerator(
     std::move(getRuntimeDependenciesGenerator));
 

+ 16 - 1
Source/cmInstallGetRuntimeDependenciesGenerator.cxx

@@ -19,6 +19,7 @@
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmOutputConverter.h"
+#include "cmPolicies.h"
 #include "cmScriptGenerator.h"
 #include "cmStringAlgorithms.h"
 
@@ -83,7 +84,8 @@ cmInstallGetRuntimeDependenciesGenerator::
     std::vector<std::string> postExcludeFiles, std::string libraryComponent,
     std::string frameworkComponent, bool noInstallRPath, char const* depsVar,
     char const* rpathPrefix, std::vector<std::string> const& configurations,
-    MessageLevel message, bool exclude_from_all, cmListFileBacktrace backtrace)
+    MessageLevel message, bool exclude_from_all, cmListFileBacktrace backtrace,
+    cmPolicies::PolicyStatus policyStatusCMP0207)
   : cmInstallGenerator("", configurations, "", message, exclude_from_all,
                        false, std::move(backtrace))
   , RuntimeDependencySet(runtimeDependencySet)
@@ -96,6 +98,7 @@ cmInstallGetRuntimeDependenciesGenerator::
   , PostExcludeFiles(std::move(postExcludeFiles))
   , LibraryComponent(std::move(libraryComponent))
   , FrameworkComponent(std::move(frameworkComponent))
+  , PolicyStatusCMP0207(policyStatusCMP0207)
   , NoInstallRPath(noInstallRPath)
   , DepsVar(depsVar)
   , RPathPrefix(rpathPrefix)
@@ -141,6 +144,14 @@ void cmInstallGetRuntimeDependenciesGenerator::GenerateScriptForConfig(
     this->LocalGenerator->GetMakefile()->GetSafeDefinition(
       "CMAKE_INSTALL_NAME_TOOL");
 
+  Indent inputIndent = indent;
+  if (this->PolicyStatusCMP0207 != cmPolicies::WARN) {
+    indent = indent.Next();
+    os << inputIndent << "block(SCOPE_FOR POLICIES)\n"
+       << indent << "cmake_policy(SET CMP0207 "
+       << (this->PolicyStatusCMP0207 == cmPolicies::NEW ? "NEW" : "OLD")
+       << ")\n";
+  }
   os << indent << "file(GET_RUNTIME_DEPENDENCIES\n"
      << indent << "  RESOLVED_DEPENDENCIES_VAR " << this->DepsVar << '\n';
   WriteFilesArgument(os, "EXECUTABLES"_s,
@@ -204,4 +215,8 @@ void cmInstallGetRuntimeDependenciesGenerator::GenerateScriptForConfig(
     os << indent << "  RPATH_PREFIX " << this->RPathPrefix << '\n';
   }
   os << indent << "  )\n";
+
+  if (this->PolicyStatusCMP0207 != cmPolicies::WARN) {
+    os << inputIndent << "endblock()\n";
+  }
 }

+ 4 - 2
Source/cmInstallGetRuntimeDependenciesGenerator.h

@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "cmInstallGenerator.h"
+#include "cmPolicies.h"
 
 class cmListFileBacktrace;
 class cmLocalGenerator;
@@ -26,8 +27,8 @@ public:
     std::vector<std::string> postExcludeFiles, std::string libraryComponent,
     std::string frameworkComponent, bool noInstallRPath, char const* depsVar,
     char const* rpathPrefix, std::vector<std::string> const& configurations,
-    MessageLevel message, bool exclude_from_all,
-    cmListFileBacktrace backtrace);
+    MessageLevel message, bool exclude_from_all, cmListFileBacktrace backtrace,
+    cmPolicies::PolicyStatus policyStatusCMP0207);
 
   bool Compute(cmLocalGenerator* lg) override;
 
@@ -48,6 +49,7 @@ private:
   std::vector<std::string> PostExcludeFiles;
   std::string LibraryComponent;
   std::string FrameworkComponent;
+  cmPolicies::PolicyStatus PolicyStatusCMP0207;
   bool NoInstallRPath;
   char const* DepsVar;
   char const* RPathPrefix;

+ 4 - 1
Source/cmPolicies.h

@@ -618,7 +618,10 @@ class cmMakefile;
          3, 0, WARN)                                                          \
   SELECT(POLICY, CMP0206,                                                     \
          "The CPack Archive Generator defaults to UID 0 and GID 0.", 4, 3, 0, \
-         WARN)
+         WARN)                                                                \
+  SELECT(POLICY, CMP0207,                                                     \
+         "file(GET_RUNTIME_DEPENDENCIES) normalizes paths before matching.",  \
+         4, 3, 0, WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \

+ 1 - 1
Source/cmRuntimeDependencyArchive.cxx

@@ -367,7 +367,7 @@ void cmRuntimeDependencyArchive::AddResolvedPath(
       break;
     }
   }
-  it->second.insert(path);
+  it->second.emplace(path);
   this->RPaths[path] = std::move(rpaths);
 }
 

+ 1 - 0
Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/CMakeLists.txt

@@ -1,4 +1,5 @@
 set(CMAKE_SKIP_RPATH OFF)
+cmake_policy(SET CMP0207 NEW)
 
 # Import targets from the install tree.
 include(${Import_BINARY_DIR}/../Root/install-RUNTIME_DEPENDENCY_SET/targets.cmake)

+ 13 - 0
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMP0207-NEW.cmake

@@ -0,0 +1,13 @@
+cmake_policy(SET CMP0207 NEW)
+
+include("${CMAKE_CURRENT_LIST_DIR}/CMP0207-common.cmake")
+
+install(CODE [[
+  if(results_old)
+    message(SEND_ERROR "Old dependencies are not empty: `${results_old}`")
+  endif()
+
+  if(NOT results_new)
+    message(SEND_ERROR "New dependencies are empty: `${results_new}`")
+  endif()
+  ]])

+ 13 - 0
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMP0207-OLD.cmake

@@ -0,0 +1,13 @@
+cmake_policy(SET CMP0207 OLD)
+
+include("${CMAKE_CURRENT_LIST_DIR}/CMP0207-common.cmake")
+
+install(CODE [[
+  if(NOT results_old)
+    message(SEND_ERROR "Old dependencies are empty: `${results_old}`")
+  endif()
+
+  if(results_new)
+    message(SEND_ERROR "New dependencies are not empty: `${results_new}`")
+  endif()
+  ]])

+ 44 - 0
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMP0207-WARN-all-stderr.txt

@@ -0,0 +1,44 @@
+^CMake Warning \(dev\) at cmake_install\.cmake:[0-9]+ \(file\):
+  Policy CMP0207 is not set: file\(GET_RUNTIME_DEPENDENCIES\) normalizes paths
+  before matching\.  Run "cmake --help-policy CMP0207" for policy details\.
+  Use the cmake_policy command to set the policy and suppress this warning\.
+
+  Path
+
+    "[^"]*test\.dll"
+
+  would be converted to
+
+    "[^"]*test\.dll"
+
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+CMake Warning \(dev\) at cmake_install\.cmake:[0-9]+ \(file\):
+  Policy CMP0207 is not set: file\(GET_RUNTIME_DEPENDENCIES\) normalizes paths
+  before matching\.  Run "cmake --help-policy CMP0207" for policy details\.
+  Use the cmake_policy command to set the policy and suppress this warning\.
+
+  Path
+
+    "[^"]*test\.dll"
+
+  would be converted to
+
+    "[^"]*test\.dll"
+
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+CMake Warning \(dev\) at cmake_install\.cmake:[0-9]+ \(file\):
+  Policy CMP0207 is not set: file\(GET_RUNTIME_DEPENDENCIES\) normalizes paths
+  before matching\.  Run "cmake --help-policy CMP0207" for policy details\.
+  Use the cmake_policy command to set the policy and suppress this warning\.
+
+  Path
+
+    "[^"]*test\.dll"
+
+  would be converted to
+
+    "[^"]*test\.dll"
+
+This warning is for project developers\.  Use -Wno-dev to suppress it\.$

+ 12 - 0
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMP0207-WARN.cmake

@@ -0,0 +1,12 @@
+# CMP0207 is unset
+include("${CMAKE_CURRENT_LIST_DIR}/CMP0207-common.cmake")
+
+install(CODE [[
+  if(NOT results_old)
+    message(SEND_ERROR "Old dependencies are empty: `${results_old}`")
+  endif()
+
+  if(results_new)
+    message(SEND_ERROR "New dependencies are not empty: `${results_new}`")
+  endif()
+  ]])

+ 93 - 0
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMP0207-common.cmake

@@ -0,0 +1,93 @@
+enable_language(C)
+
+file(WRITE "${CMAKE_BINARY_DIR}/test.c" "__declspec(dllexport) void test(void) {}\n")
+file(WRITE "${CMAKE_BINARY_DIR}/main.c" [[__declspec(dllimport) extern void test(void);
+
+int main(void)
+{
+  test();
+  return 0;
+}
+]])
+
+add_subdirectory(CMP0207-subdir)
+
+add_executable(exe "${CMAKE_BINARY_DIR}/main.c")
+target_link_libraries(exe PRIVATE test)
+
+install(TARGETS test DESTINATION bin/lib1)
+
+install(
+  TARGETS exe
+  DESTINATION results_old
+  RUNTIME_DEPENDENCIES
+    DIRECTORIES "${CMAKE_BINARY_DIR}/root-all\\bin\\lib1"
+    PRE_INCLUDE_REGEXES "^(lib)?test\\.dll$"
+    PRE_EXCLUDE_REGEXES ".*"
+    POST_INCLUDE_REGEXES "\\\\lib1/(lib)?test\\.dll$"
+    POST_EXCLUDE_REGEXES ".*"
+)
+
+install(
+  TARGETS exe
+  DESTINATION results_new
+  RUNTIME_DEPENDENCIES
+    DIRECTORIES "${CMAKE_BINARY_DIR}/root-all\\bin\\lib1"
+    PRE_INCLUDE_REGEXES "^(lib)?test\\.dll$"
+    PRE_EXCLUDE_REGEXES ".*"
+    POST_INCLUDE_REGEXES "/lib1/(lib)?test\\.dll$"
+    POST_EXCLUDE_REGEXES ".*"
+)
+
+install(
+  TARGETS exe
+  DESTINATION results_any
+  RUNTIME_DEPENDENCIES
+    DIRECTORIES "${CMAKE_BINARY_DIR}/root-all\\bin\\lib1"
+    PRE_INCLUDE_REGEXES "^(lib)?test\\.dll$"
+    PRE_EXCLUDE_REGEXES ".*"
+    POST_INCLUDE_REGEXES "(\\\\|/)lib1/(lib)?test\\.dll$"
+    POST_EXCLUDE_REGEXES ".*"
+)
+
+install(
+  TARGETS exe
+  DESTINATION results_any_forward
+  RUNTIME_DEPENDENCIES
+    DIRECTORIES "${CMAKE_BINARY_DIR}/root-all/bin/lib1"
+    PRE_INCLUDE_REGEXES "^(lib)?test\\.dll$"
+    PRE_EXCLUDE_REGEXES ".*"
+    POST_INCLUDE_REGEXES "(\\\\|/)lib1/(lib)?test\\.dll$"
+    POST_EXCLUDE_REGEXES ".*"
+)
+
+install(
+  CODE [[
+    function(check_installed_lib directory out_var)
+      file(GLOB_RECURSE actual
+        LIST_DIRECTORIES FALSE
+        RELATIVE ${CMAKE_INSTALL_PREFIX}/${directory}
+        ${CMAKE_INSTALL_PREFIX}/${directory}/*.dll
+      )
+
+      if(actual)
+        list(SORT actual)
+      endif()
+
+      set(${out_var} "${actual}" PARENT_SCOPE)
+    endfunction()
+
+    check_installed_lib("results_old" results_old)
+    check_installed_lib("results_new" results_new)
+    check_installed_lib("results_any" results_any)
+    check_installed_lib("results_any_forward" results_any_forward)
+
+    if(NOT results_any)
+      message(SEND_ERROR "Any dependencies are empty: `${results_any}`")
+    endif()
+
+    if(NOT results_any_forward)
+      message(SEND_ERROR "Any forward dependencies are empty: `${results_any_forward}`")
+    endif()
+  ]]
+)

+ 1 - 0
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMP0207-subdir/CMakeLists.txt

@@ -0,0 +1 @@
+add_library(test SHARED "${CMAKE_BINARY_DIR}/test.c")

+ 3 - 0
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake

@@ -49,6 +49,9 @@ if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
   run_cmake(badargs1)
   run_cmake(badargs2)
 elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+  run_install_test(CMP0207-OLD)
+  run_install_test(CMP0207-WARN)
+  run_install_test(CMP0207-NEW)
   run_install_test(windows)
   run_install_test(windows-unresolved)
   run_install_test(windows-conflict)

+ 1 - 0
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows.cmake

@@ -50,6 +50,7 @@ install(TARGETS topexe toplib topmod DESTINATION bin)
 
 install(CODE [[
   function(exec_get_runtime_dependencies depsfile udepsfile cdepsfile)
+    cmake_policy(SET CMP0207 NEW)
     file(GET_RUNTIME_DEPENDENCIES
       RESOLVED_DEPENDENCIES_VAR deps
       UNRESOLVED_DEPENDENCIES_VAR udeps

+ 1 - 0
b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMP0207-NEW-all-result.txt

@@ -0,0 +1 @@
+1

+ 5 - 0
b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/CMP0207-NEW-all-stderr.txt

@@ -0,0 +1,5 @@
+^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
+  file Could not resolve runtime dependencies:
+
+    [^
+]*test\.dll$