Parcourir la source

objlib: Allow other libraries to link to `OBJECT` libraries.

Note: This only allows `OBJECT` libraries to be on the right-hand side
of `target_link_libraries` but still does not link its object-files to
the target on the left-hand side.

Issue: #14778
Deniz Bahadir il y a 8 ans
Parent
commit
dfb6e84082

+ 3 - 0
Source/cmComputeLinkInformation.cxx

@@ -611,6 +611,9 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
       if (!libName.empty()) {
         this->AddItem(libName, nullptr);
       }
+    } else if (tgt->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+      // Ignore object library!
+      // Its object-files should already have been extracted for linking.
     } else {
       // Decide whether to use an import library.
       bool implib =

+ 3 - 3
Source/cmComputeTargetDepends.cxx

@@ -211,11 +211,11 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index)
           if (depender->GetType() != cmStateEnums::EXECUTABLE &&
               depender->GetType() != cmStateEnums::STATIC_LIBRARY &&
               depender->GetType() != cmStateEnums::SHARED_LIBRARY &&
-              depender->GetType() != cmStateEnums::MODULE_LIBRARY) {
+              depender->GetType() != cmStateEnums::MODULE_LIBRARY &&
+              depender->GetType() != cmStateEnums::OBJECT_LIBRARY) {
             this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
               cmake::FATAL_ERROR,
-              "Only executables and non-OBJECT libraries may "
-              "reference target objects.",
+              "Only executables and libraries may reference target objects.",
               depender->GetBacktrace());
             return;
           }

+ 3 - 1
Source/cmExportBuildFileGenerator.cxx

@@ -159,7 +159,9 @@ cmStateEnums::TargetType cmExportBuildFileGenerator::GetExportTargetType(
 {
   cmStateEnums::TargetType targetType = target->GetType();
   // An object library exports as an interface library if we cannot
-  // tell clients where to find the objects.
+  // tell clients where to find the objects.  This is sufficient
+  // to support transitive usage requirements on other targets that
+  // use the object library.
   if (targetType == cmStateEnums::OBJECT_LIBRARY &&
       !this->LG->GetGlobalGenerator()->HasKnownObjectFileLocation(nullptr)) {
     targetType = cmStateEnums::INTERFACE_LIBRARY;

+ 7 - 16
Source/cmGeneratorTarget.cxx

@@ -240,13 +240,16 @@ const char* cmGeneratorTarget::GetOutputTargetType(
     case cmStateEnums::MODULE_LIBRARY:
       switch (artifact) {
         case cmStateEnums::RuntimeBinaryArtifact:
-          // Module import libraries are treated as archive targets.
+          // Module libraries are always treated as library targets.
           return "LIBRARY";
         case cmStateEnums::ImportLibraryArtifact:
-          // Module libraries are always treated as library targets.
+          // Module import libraries are treated as archive targets.
           return "ARCHIVE";
       }
       break;
+    case cmStateEnums::OBJECT_LIBRARY:
+      // Object libraries are always treated as object targets.
+      return "OBJECT";
     case cmStateEnums::EXECUTABLE:
       switch (artifact) {
         case cmStateEnums::RuntimeBinaryArtifact:
@@ -1671,6 +1674,7 @@ bool cmGeneratorTarget::HaveWellDefinedOutputFiles() const
   return this->GetType() == cmStateEnums::STATIC_LIBRARY ||
     this->GetType() == cmStateEnums::SHARED_LIBRARY ||
     this->GetType() == cmStateEnums::MODULE_LIBRARY ||
+    this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
     this->GetType() == cmStateEnums::EXECUTABLE;
 }
 
@@ -5323,20 +5327,6 @@ cmGeneratorTarget* cmGeneratorTarget::FindTargetToLink(
     tgt = nullptr;
   }
 
-  if (tgt && tgt->GetType() == cmStateEnums::OBJECT_LIBRARY) {
-    std::ostringstream e;
-    e << "Target \"" << this->GetName() << "\" links to "
-                                           "OBJECT library \""
-      << tgt->GetName()
-      << "\" but this is not "
-         "allowed.  "
-         "One may link only to STATIC or SHARED libraries, or to executables "
-         "with the ENABLE_EXPORTS property set.";
-    cmake* cm = this->LocalGenerator->GetCMakeInstance();
-    cm->IssueMessage(cmake::FATAL_ERROR, e.str(), this->GetBacktrace());
-    tgt = nullptr;
-  }
-
   return tgt;
 }
 
@@ -5400,6 +5390,7 @@ bool cmGeneratorTarget::IsLinkable() const
           this->GetType() == cmStateEnums::SHARED_LIBRARY ||
           this->GetType() == cmStateEnums::MODULE_LIBRARY ||
           this->GetType() == cmStateEnums::UNKNOWN_LIBRARY ||
+          this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
           this->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
           this->IsExecutableWithExports());
 }

+ 8 - 10
Source/cmTarget.cxx

@@ -114,15 +114,12 @@ const char* cmTargetPropertyComputer::GetSources<cmTarget>(
         }
         if (!noMessage) {
           e << "Target \"" << tgt->GetName()
-            << "\" contains "
-               "$<TARGET_OBJECTS> generator expression in its sources "
-               "list.  "
-               "This content was not previously part of the SOURCES "
-               "property "
-               "when that property was read at configure time.  Code "
-               "reading "
-               "that property needs to be adapted to ignore the generator "
-               "expression using the string(GENEX_STRIP) command.";
+            << "\" contains $<TARGET_OBJECTS> generator expression in its "
+               "sources list.  This content was not previously part of the "
+               "SOURCES property when that property was read at configure "
+               "time.  Code reading that property needs to be adapted to "
+               "ignore the generator expression using the string(GENEX_STRIP) "
+               "command.";
           messenger->IssueMessage(messageType, e.str(), context);
         }
         if (addContent) {
@@ -742,7 +739,8 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, const std::string& lib,
   }
 
   if (cmGeneratorExpression::Find(lib) != std::string::npos ||
-      (tgt && tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) ||
+      (tgt && (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
+               tgt->GetType() == cmStateEnums::OBJECT_LIBRARY)) ||
       (this->Name == lib)) {
     return;
   }

+ 3 - 2
Source/cmTargetLinkLibrariesCommand.cxx

@@ -391,14 +391,15 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib,
     if (tgt && (tgt->GetType() != cmStateEnums::STATIC_LIBRARY) &&
         (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) &&
         (tgt->GetType() != cmStateEnums::UNKNOWN_LIBRARY) &&
+        (tgt->GetType() != cmStateEnums::OBJECT_LIBRARY) &&
         (tgt->GetType() != cmStateEnums::INTERFACE_LIBRARY) &&
         !tgt->IsExecutableWithExports()) {
       std::ostringstream e;
       e << "Target \"" << lib << "\" of type "
         << cmState::GetTargetTypeName(tgt->GetType())
         << " may not be linked into another target.  One may link only to "
-           "INTERFACE, STATIC or SHARED libraries, or to executables with the "
-           "ENABLE_EXPORTS property set.";
+           "INTERFACE, OBJECT, STATIC or SHARED libraries, or to executables "
+           "with the ENABLE_EXPORTS property set.";
       this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
     }
 

+ 0 - 1
Tests/RunCMake/ObjectLibrary/LinkObjRHS1-result.txt

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

+ 0 - 6
Tests/RunCMake/ObjectLibrary/LinkObjRHS1-stderr.txt

@@ -1,6 +0,0 @@
-CMake Error at LinkObjRHS1.cmake:3 \(target_link_libraries\):
-  Target "AnObjLib" of type OBJECT_LIBRARY may not be linked into another
-  target.  One may link only to INTERFACE, STATIC or SHARED libraries, or to
-  executables with the ENABLE_EXPORTS property set.
-Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)

+ 0 - 3
Tests/RunCMake/ObjectLibrary/LinkObjRHS1.cmake

@@ -1,3 +0,0 @@
-add_library(A STATIC a.c)
-add_library(AnObjLib OBJECT a.c)
-target_link_libraries(A AnObjLib)

+ 0 - 1
Tests/RunCMake/ObjectLibrary/LinkObjRHS2-result.txt

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

+ 0 - 6
Tests/RunCMake/ObjectLibrary/LinkObjRHS2-stderr.txt

@@ -1,6 +0,0 @@
-CMake Error at LinkObjRHS2.cmake:1 \(add_library\):
-  Target "A" links to OBJECT library "AnObjLib" but this is not allowed.  One
-  may link only to STATIC or SHARED libraries, or to executables with the
-  ENABLE_EXPORTS property set.
-Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)

+ 0 - 3
Tests/RunCMake/ObjectLibrary/LinkObjRHS2.cmake

@@ -1,3 +0,0 @@
-add_library(A SHARED a.c)
-target_link_libraries(A AnObjLib)
-add_library(AnObjLib OBJECT a.c)

+ 13 - 0
Tests/RunCMake/ObjectLibrary/LinkObjRHSShared.cmake

@@ -0,0 +1,13 @@
+enable_language(C)
+
+add_definitions(-DCOMPILE_FOR_SHARED_LIB)
+
+add_library(AnObjLib OBJECT a.c)
+target_compile_definitions(AnObjLib INTERFACE REQUIRED)
+set_target_properties(AnObjLib PROPERTIES POSITION_INDEPENDENT_CODE ON)
+
+add_library(A SHARED b.c $<TARGET_OBJECTS:AnObjLib>)
+target_link_libraries(A PUBLIC AnObjLib)
+
+add_executable(exe exe.c)
+target_link_libraries(exe A)

+ 10 - 0
Tests/RunCMake/ObjectLibrary/LinkObjRHSStatic.cmake

@@ -0,0 +1,10 @@
+enable_language(C)
+
+add_library(AnObjLib OBJECT a.c)
+target_compile_definitions(AnObjLib INTERFACE REQUIRED)
+
+add_library(A STATIC b.c $<TARGET_OBJECTS:AnObjLib>)
+target_link_libraries(A PUBLIC AnObjLib)
+
+add_executable(exe exe.c)
+target_link_libraries(exe A)

+ 9 - 3
Tests/RunCMake/ObjectLibrary/ObjWithObj-stderr.txt

@@ -1,4 +1,10 @@
-CMake Error at ObjWithObj.cmake:2 \(add_library\):
-  Only executables and non-OBJECT libraries may reference target objects.
+^CMake Error at ObjWithObj.cmake:[0-9]+ \(add_library\):
+  OBJECT library \"B\" contains:
+
+    [^
+]*a(\.c)?\.o(bj)?
+
+  but may contain only sources that compile, header files, and other files
+  that would not affect linking of a normal library.
 Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
+  CMakeLists.txt:[0-9]+ \(include\)$

+ 2 - 2
Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake

@@ -26,9 +26,9 @@ endfunction ()
 
 run_object_lib_build(LinkObjLHSShared)
 run_object_lib_build(LinkObjLHSStatic)
+run_object_lib_build(LinkObjRHSShared)
+run_object_lib_build(LinkObjRHSStatic)
 
-run_cmake(LinkObjRHS1)
-run_cmake(LinkObjRHS2)
 run_cmake(MissingSource)
 run_cmake(ObjWithObj)
 run_cmake(OwnSources)

+ 7 - 1
Tests/RunCMake/ObjectLibrary/a.c

@@ -1,4 +1,10 @@
-int a(void)
+#if defined(_WIN32) && defined(COMPILE_FOR_SHARED_LIB)
+#define EXPORT __declspec(dllexport)
+#else
+#define EXPORT
+#endif
+
+EXPORT int a(void)
 {
   return 0;
 }

+ 12 - 2
Tests/RunCMake/ObjectLibrary/b.c

@@ -1,4 +1,14 @@
-int b(void)
+#if defined(_WIN32) && defined(COMPILE_FOR_SHARED_LIB)
+#define EXPORT __declspec(dllexport)
+#else
+#define EXPORT
+#endif
+
+extern int a(void);
+EXPORT int b()
 {
-  return 0;
+  return a();
 }
+#ifndef REQUIRED
+#error "REQUIRED needs to be defined"
+#endif

+ 14 - 0
Tests/RunCMake/ObjectLibrary/exe.c

@@ -0,0 +1,14 @@
+#if defined(_WIN32) && defined(COMPILE_FOR_SHARED_LIB)
+#define IMPORT __declspec(dllimport)
+#else
+#define IMPORT
+#endif
+
+extern IMPORT int b(void);
+int main()
+{
+  return b();
+}
+#ifndef REQUIRED
+#error "REQUIRED needs to be defined"
+#endif

+ 0 - 6
Tests/RunCMake/add_library/OBJECTwithOnlyObjectSources-stderr.txt

@@ -6,11 +6,5 @@
 
   but may contain only sources that compile, header files, and other files
   that would not affect linking of a normal library.
-Call Stack \(most recent call first\):
-  CMakeLists.txt:[0-9]+ \(include\)
-
-
-CMake Error at OBJECTwithOnlyObjectSources.cmake:[0-9]+ \(add_library\):
-  Only executables and non-OBJECT libraries may reference target objects.
 Call Stack \(most recent call first\):
   CMakeLists.txt:[0-9]+ \(include\)$