Browse Source

Merge topic 'runtime-dll-deps'

f31e8d33ef Genex: Fix grammatical error in TARGET_OBJECTS error message
d34d28e688 Genex: Add TARGET_RUNTIME_DLLS genex

Acked-by: Kitware Robot <[email protected]>
Merge-request: !5837
Brad King 4 years ago
parent
commit
a5678e46f8
30 changed files with 270 additions and 8 deletions
  1. 23 0
      Help/manual/cmake-generator-expressions.7.rst
  2. 4 0
      Help/release/dev/runtime-dll-deps.rst
  3. 19 0
      Source/cmComputeLinkInformation.cxx
  4. 6 0
      Source/cmComputeLinkInformation.h
  5. 53 2
      Source/cmGeneratorExpressionNode.cxx
  6. 14 0
      Source/cmGeneratorTarget.cxx
  7. 5 0
      Source/cmGeneratorTarget.h
  8. 1 0
      Tests/RunCMake/CMakeLists.txt
  9. 2 2
      Tests/RunCMake/File_Generate/OutputNameMatchesObjects-stderr.txt
  10. 3 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/CMakeLists.txt
  11. 7 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/RunCMakeTest.cmake
  12. 15 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-check.cmake
  13. 1 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static-result.txt
  14. 9 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static-stderr.txt
  15. 9 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static.cmake
  16. 1 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1-result.txt
  17. 5 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1-stderr.txt
  18. 4 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1.cmake
  19. 1 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2-result.txt
  20. 5 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2-stderr.txt
  21. 6 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2.cmake
  22. 5 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries.cmake
  23. 37 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS.cmake
  24. 12 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib1.c
  25. 6 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib2.c
  26. 6 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib3.c
  27. 4 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/main.c
  28. 3 0
      Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/static.c
  29. 2 2
      Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt
  30. 2 2
      Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt

+ 23 - 0
Help/manual/cmake-generator-expressions.7.rst

@@ -938,6 +938,29 @@ which is just the string ``tgt``.
   :ref:`Target Usage Requirements` this is the consuming target rather
   than the target specifying the requirement.
 
+.. genex:: $<TARGET_RUNTIME_DLLS:tgt>
+
+  List of DLLs that the target depends on at runtime. This is determined by
+  the locations of all the ``SHARED`` and ``MODULE`` targets in the target's
+  transitive dependencies. Using this generator expression on targets other
+  than executables, ``SHARED`` libraries, and ``MODULE`` libraries is an error.
+  On non-DLL platforms, it evaluates to an empty string.
+
+  This generator expression can be used to copy all of the DLLs that a target
+  depends on into its output directory in a ``POST_BUILD`` custom command. For
+  example:
+
+  .. code-block:: cmake
+
+    find_package(foo REQUIRED)
+
+    add_executable(exe main.c)
+    target_link_libraries(exe PRIVATE foo::foo foo::bar)
+    add_custom_command(TARGET exe POST_BUILD
+      COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:exe> $<TARGET_FILE_DIR:exe>
+      COMMAND_EXPAND_LISTS
+      )
+
 .. genex:: $<INSTALL_PREFIX>
 
   Content of the install prefix when the target is exported via

+ 4 - 0
Help/release/dev/runtime-dll-deps.rst

@@ -0,0 +1,4 @@
+runtime-dll-deps
+----------------
+
+* A new :genex:`TARGET_RUNTIME_DLLS` generator expression was added.

+ 19 - 0
Source/cmComputeLinkInformation.cxx

@@ -701,6 +701,10 @@ void cmComputeLinkInformation::AddItem(BT<std::string> const& item,
 
       this->AddTargetItem(lib, tgt);
       this->AddLibraryRuntimeInfo(lib.Value, tgt);
+      if (tgt && tgt->GetType() == cmStateEnums::SHARED_LIBRARY &&
+          this->Target->IsDLLPlatform()) {
+        this->AddRuntimeDLL(tgt);
+      }
     }
   } else {
     // This is not a CMake target.  Use the name given.
@@ -728,6 +732,13 @@ void cmComputeLinkInformation::AddItem(BT<std::string> const& item,
 void cmComputeLinkInformation::AddSharedDepItem(BT<std::string> const& item,
                                                 const cmGeneratorTarget* tgt)
 {
+  // Record dependencies on DLLs.
+  if (tgt && tgt->GetType() == cmStateEnums::SHARED_LIBRARY &&
+      this->Target->IsDLLPlatform() &&
+      this->SharedDependencyMode != SharedDepModeLink) {
+    this->AddRuntimeDLL(tgt);
+  }
+
   // If dropping shared library dependencies, ignore them.
   if (this->SharedDependencyMode == SharedDepModeNone) {
     return;
@@ -799,6 +810,14 @@ void cmComputeLinkInformation::AddSharedDepItem(BT<std::string> const& item,
   }
 }
 
+void cmComputeLinkInformation::AddRuntimeDLL(cmGeneratorTarget const* tgt)
+{
+  if (std::find(this->RuntimeDLLs.begin(), this->RuntimeDLLs.end(), tgt) ==
+      this->RuntimeDLLs.end()) {
+    this->RuntimeDLLs.emplace_back(tgt);
+  }
+}
+
 void cmComputeLinkInformation::ComputeLinkTypeInfo()
 {
   // Check whether archives may actually be shared libraries.

+ 6 - 0
Source/cmComputeLinkInformation.h

@@ -64,6 +64,10 @@ public:
   std::string GetRPathString(bool for_install) const;
   std::string GetChrpathString() const;
   std::set<cmGeneratorTarget const*> const& GetSharedLibrariesLinked() const;
+  std::vector<cmGeneratorTarget const*> const& GetRuntimeDLLs() const
+  {
+    return this->RuntimeDLLs;
+  }
 
   std::string const& GetLibLinkFileFlag() const
   {
@@ -81,6 +85,7 @@ private:
   void AddItem(BT<std::string> const& item, const cmGeneratorTarget* tgt);
   void AddSharedDepItem(BT<std::string> const& item,
                         cmGeneratorTarget const* tgt);
+  void AddRuntimeDLL(cmGeneratorTarget const* tgt);
 
   // Output information.
   ItemVector Items;
@@ -89,6 +94,7 @@ private:
   std::vector<std::string> FrameworkPaths;
   std::vector<std::string> RuntimeSearchPath;
   std::set<cmGeneratorTarget const*> SharedLibrariesLinked;
+  std::vector<cmGeneratorTarget const*> RuntimeDLLs;
 
   // Context information.
   cmGeneratorTarget const* const Target;

+ 53 - 2
Source/cmGeneratorExpressionNode.cxx

@@ -14,6 +14,7 @@
 #include <utility>
 
 #include <cm/iterator>
+#include <cm/optional>
 #include <cm/string_view>
 #include <cm/vector>
 #include <cmext/algorithm>
@@ -23,6 +24,7 @@
 #include "cmsys/String.h"
 
 #include "cmAlgorithms.h"
+#include "cmComputeLinkInformation.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorExpressionContext.h"
 #include "cmGeneratorExpressionDAGChecker.h"
@@ -1627,8 +1629,8 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
         type != cmStateEnums::OBJECT_LIBRARY) {
       std::ostringstream e;
       e << "Objects of target \"" << tgtName
-        << "\" referenced but is not an allowed library types (EXECUTABLE, "
-        << "STATIC, SHARED, MODULE, OBJECT).";
+        << "\" referenced but is not one of the allowed target types "
+        << "(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT).";
       reportError(context, content->GetOriginalExpression(), e.str());
       return std::string();
     }
@@ -1687,6 +1689,54 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
   }
 } targetObjectsNode;
 
+static const struct TargetRuntimeDllsNode : public cmGeneratorExpressionNode
+{
+  TargetRuntimeDllsNode() {} // NOLINT(modernize-use-equals-default)
+
+  std::string Evaluate(
+    const std::vector<std::string>& parameters,
+    cmGeneratorExpressionContext* context,
+    const GeneratorExpressionContent* content,
+    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+  {
+    std::string tgtName = parameters.front();
+    cmGeneratorTarget* gt = context->LG->FindGeneratorTargetToUse(tgtName);
+    if (!gt) {
+      std::ostringstream e;
+      e << "Objects of target \"" << tgtName
+        << "\" referenced but no such target exists.";
+      reportError(context, content->GetOriginalExpression(), e.str());
+      return std::string();
+    }
+    cmStateEnums::TargetType type = gt->GetType();
+    if (type != cmStateEnums::EXECUTABLE &&
+        type != cmStateEnums::SHARED_LIBRARY &&
+        type != cmStateEnums::MODULE_LIBRARY) {
+      std::ostringstream e;
+      e << "Objects of target \"" << tgtName
+        << "\" referenced but is not one of the allowed target types "
+        << "(EXECUTABLE, SHARED, MODULE).";
+      reportError(context, content->GetOriginalExpression(), e.str());
+      return std::string();
+    }
+
+    if (auto* cli = gt->GetLinkInformation(context->Config)) {
+      std::vector<std::string> dllPaths;
+      auto const& dlls = cli->GetRuntimeDLLs();
+
+      for (auto const& dll : dlls) {
+        if (auto loc = dll->MaybeGetLocation(context->Config)) {
+          dllPaths.emplace_back(*loc);
+        }
+      }
+
+      return cmJoin(dllPaths, ";");
+    }
+
+    return "";
+  }
+} targetRuntimeDllsNode;
+
 static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
 {
   CompileFeaturesNode() {} // NOLINT(modernize-use-equals-default)
@@ -2603,6 +2653,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode(
     { "TARGET_EXISTS", &targetExistsNode },
     { "TARGET_NAME_IF_EXISTS", &targetNameIfExistsNode },
     { "TARGET_GENEX_EVAL", &targetGenexEvalNode },
+    { "TARGET_RUNTIME_DLLS", &targetRuntimeDllsNode },
     { "GENEX_EVAL", &genexEvalNode },
     { "BUILD_INTERFACE", &buildInterfaceNode },
     { "INSTALL_INTERFACE", &installInterfaceNode },

+ 14 - 0
Source/cmGeneratorTarget.cxx

@@ -1062,6 +1062,20 @@ const std::string& cmGeneratorTarget::GetLocation(
   return location;
 }
 
+cm::optional<std::string> cmGeneratorTarget::MaybeGetLocation(
+  std::string const& config) const
+{
+  cm::optional<std::string> location;
+  if (cmGeneratorTarget::ImportInfo const* imp = this->GetImportInfo(config)) {
+    if (!imp->Location.empty()) {
+      location = imp->Location;
+    }
+  } else {
+    location = this->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
+  }
+  return location;
+}
+
 std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreBuildCommands()
   const
 {

+ 5 - 0
Source/cmGeneratorTarget.h

@@ -14,6 +14,8 @@
 #include <utility>
 #include <vector>
 
+#include <cm/optional>
+
 #include "cmLinkItem.h"
 #include "cmListFileCache.h"
 #include "cmPolicies.h"
@@ -50,6 +52,9 @@ public:
   bool CanCompileSources() const;
   const std::string& GetLocation(const std::string& config) const;
 
+  /** Get the full path to the target's main artifact, if known.  */
+  cm::optional<std::string> MaybeGetLocation(std::string const& config) const;
+
   std::vector<cmCustomCommand> const& GetPreBuildCommands() const;
   std::vector<cmCustomCommand> const& GetPreLinkCommands() const;
   std::vector<cmCustomCommand> const& GetPostBuildCommands() const;

+ 1 - 0
Tests/RunCMake/CMakeLists.txt

@@ -258,6 +258,7 @@ add_RunCMake_test(GenEx-HOST_LINK)
 add_RunCMake_test(GenEx-DEVICE_LINK)
 add_RunCMake_test(GenEx-TARGET_FILE -DLINKER_SUPPORTS_PDB=${LINKER_SUPPORTS_PDB})
 add_RunCMake_test(GenEx-GENEX_EVAL)
+add_RunCMake_test(GenEx-TARGET_RUNTIME_DLLS)
 add_RunCMake_test(GeneratorExpression)
 add_RunCMake_test(GeneratorInstance)
 add_RunCMake_test(GeneratorPlatform)

+ 2 - 2
Tests/RunCMake/File_Generate/OutputNameMatchesObjects-stderr.txt

@@ -3,7 +3,7 @@ CMake Error at OutputNameMatchesObjects.cmake:[0-9]+ \(file\):
 
     \$<TARGET_OBJECTS:foo>
 
-  Objects of target "foo" referenced but is not an allowed library types
-  \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\).
+  Objects of target "foo" referenced but is not one of the allowed target
+  types \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\).
 Call Stack \(most recent call first\):
   CMakeLists.txt:[0-9]+ \(include\)

+ 3 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.19)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

+ 7 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/RunCMakeTest.cmake

@@ -0,0 +1,7 @@
+include(RunCMake)
+
+run_cmake(TARGET_RUNTIME_DLLS)
+run_cmake(TARGET_RUNTIME_DLLS-static)
+run_cmake(TARGET_RUNTIME_DLLS-target_link_libraries)
+run_cmake(TARGET_RUNTIME_DLLS-target_link_libraries-cycle1)
+run_cmake(TARGET_RUNTIME_DLLS-target_link_libraries-cycle2)

+ 15 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-check.cmake

@@ -0,0 +1,15 @@
+function(check_genex expected actual)
+  if(NOT expected STREQUAL actual)
+    string(APPEND RunCMake_TEST_FAILED "Expected DLLs:\n")
+    foreach(dll IN LISTS expected)
+      string(APPEND RunCMake_TEST_FAILED "  ${dll}\n")
+    endforeach()
+    string(APPEND RunCMake_TEST_FAILED "Actual DLLs:\n")
+    foreach(dll IN LISTS actual)
+      string(APPEND RunCMake_TEST_FAILED "  ${dll}\n")
+    endforeach()
+  endif()
+  set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+endfunction()
+
+include("${RunCMake_TEST_BINARY_DIR}/dlls.cmake")

+ 1 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static-result.txt

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

+ 9 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at TARGET_RUNTIME_DLLS-static\.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_RUNTIME_DLLS:static>
+
+  Objects of target "static" referenced but is not one of the allowed target
+  types \(EXECUTABLE, SHARED, MODULE\)\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)

+ 9 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static.cmake

@@ -0,0 +1,9 @@
+enable_language(C)
+
+add_library(static STATIC static.c)
+set(condition)
+get_property(multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(multi_config)
+  set(condition CONDITION "$<CONFIG:Debug>")
+endif()
+file(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/dlls.txt" CONTENT "$<TARGET_RUNTIME_DLLS:static>" ${condition})

+ 1 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1-result.txt

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

+ 5 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1-stderr.txt

@@ -0,0 +1,5 @@
+CMake Error at TARGET_RUNTIME_DLLS-target_link_libraries-cycle1\.cmake:[0-9]+ \(add_library\):
+  The SOURCES of "lib1" use a generator expression that depends on the
+  SOURCES themselves\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)

+ 4 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1.cmake

@@ -0,0 +1,4 @@
+enable_language(C)
+
+add_library(lib1 SHARED lib1.c)
+target_link_libraries(lib1 PRIVATE $<TARGET_RUNTIME_DLLS:lib1>)

+ 1 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2-result.txt

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

+ 5 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2-stderr.txt

@@ -0,0 +1,5 @@
+CMake Error at TARGET_RUNTIME_DLLS-target_link_libraries-cycle2\.cmake:[0-9]+ \(add_library\):
+  The SOURCES of "(lib1|lib2)" use a generator expression that depends on the
+  SOURCES themselves\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)

+ 6 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2.cmake

@@ -0,0 +1,6 @@
+enable_language(C)
+
+add_library(lib1 SHARED lib1.c)
+add_library(lib2 SHARED lib2.c)
+target_link_libraries(lib1 PRIVATE $<TARGET_RUNTIME_DLLS:lib2>)
+target_link_libraries(lib2 PRIVATE $<TARGET_RUNTIME_DLLS:lib1>)

+ 5 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries.cmake

@@ -0,0 +1,5 @@
+enable_language(C)
+
+add_library(lib1 SHARED lib1.c)
+add_library(lib2 SHARED lib2.c)
+target_link_libraries(lib1 PRIVATE $<TARGET_RUNTIME_DLLS:lib2>)

+ 37 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS.cmake

@@ -0,0 +1,37 @@
+enable_language(C)
+
+add_executable(exe main.c)
+add_library(lib1 SHARED lib1.c)
+add_library(lib2 SHARED lib2.c)
+add_library(lib3 SHARED lib3.c)
+add_library(static STATIC static.c)
+add_library(imported SHARED IMPORTED)
+set_property(TARGET imported PROPERTY IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/imported.dll")
+set_property(TARGET imported PROPERTY IMPORTED_IMPLIB "${CMAKE_SOURCE_DIR}/imported.lib")
+add_library(imported2 SHARED IMPORTED)
+if(NOT WIN32 AND NOT CYGWIN)
+  set_property(TARGET imported2 PROPERTY IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/imported2.dll")
+endif()
+set_property(TARGET imported2 PROPERTY IMPORTED_IMPLIB "${CMAKE_SOURCE_DIR}/imported2.lib")
+
+target_link_libraries(exe PRIVATE lib1 static imported imported2)
+target_link_libraries(lib1 PRIVATE lib2)
+target_link_libraries(lib1 INTERFACE lib3)
+
+set(expected_dlls "")
+if(WIN32 OR CYGWIN)
+  set(expected_dlls
+    "$<TARGET_FILE:lib1>"
+    "$<TARGET_FILE:imported>"
+    "$<TARGET_FILE:lib3>"
+    "$<TARGET_FILE:lib2>"
+    )
+endif()
+
+set(content "check_genex(\"${expected_dlls}\" \"$<TARGET_RUNTIME_DLLS:exe>\")\n")
+set(condition)
+get_property(multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(multi_config)
+  set(condition CONDITION "$<CONFIG:Debug>")
+endif()
+file(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/dlls.cmake" CONTENT "${content}" ${condition})

+ 12 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib1.c

@@ -0,0 +1,12 @@
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+  extern void lib2(void);
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+  void lib1(void)
+{
+  lib2();
+}

+ 6 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib2.c

@@ -0,0 +1,6 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+  void lib2(void)
+{
+}

+ 6 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib3.c

@@ -0,0 +1,6 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+  void lib3(void)
+{
+}

+ 4 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/main.c

@@ -0,0 +1,4 @@
+int main(void)
+{
+  return 0;
+}

+ 3 - 0
Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/static.c

@@ -0,0 +1,3 @@
+void static_func(void)
+{
+}

+ 2 - 2
Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt

@@ -3,7 +3,7 @@ CMake Error at BadSourceExpression3.cmake:2 \(add_library\):
 
     \$<TARGET_OBJECTS:NotObjLib>
 
-  Objects of target "NotObjLib" referenced but is not an allowed library
-  types \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\).
+  Objects of target "NotObjLib" referenced but is not one of the allowed
+  target types \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\).
 Call Stack \(most recent call first\):
   CMakeLists.txt:[0-9]+ \(include\)

+ 2 - 2
Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt

@@ -3,7 +3,7 @@ CMake Error at NotObjlibTarget.cmake:[0-9]+ \(file\):
 
     \$<TARGET_OBJECTS:IFaceLib>
 
-  Objects of target "IFaceLib" referenced but is not an allowed library types
-  \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\).
+  Objects of target "IFaceLib" referenced but is not one of the allowed
+  target types \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\).
 Call Stack \(most recent call first\):
   CMakeLists.txt:[0-9]+ \(include\)