From dfb6e84082884f908ffad4594d2712d9edfd2cc0 Mon Sep 17 00:00:00 2001 From: Deniz Bahadir Date: Fri, 24 Nov 2017 17:20:18 +0100 Subject: 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 --- Source/cmComputeLinkInformation.cxx | 3 +++ Source/cmComputeTargetDepends.cxx | 6 +++--- Source/cmExportBuildFileGenerator.cxx | 4 +++- Source/cmGeneratorTarget.cxx | 23 +++++++--------------- Source/cmTarget.cxx | 18 ++++++++--------- Source/cmTargetLinkLibrariesCommand.cxx | 5 +++-- .../RunCMake/ObjectLibrary/LinkObjRHS1-result.txt | 1 - .../RunCMake/ObjectLibrary/LinkObjRHS1-stderr.txt | 6 ------ Tests/RunCMake/ObjectLibrary/LinkObjRHS1.cmake | 3 --- .../RunCMake/ObjectLibrary/LinkObjRHS2-result.txt | 1 - .../RunCMake/ObjectLibrary/LinkObjRHS2-stderr.txt | 6 ------ Tests/RunCMake/ObjectLibrary/LinkObjRHS2.cmake | 3 --- .../RunCMake/ObjectLibrary/LinkObjRHSShared.cmake | 13 ++++++++++++ .../RunCMake/ObjectLibrary/LinkObjRHSStatic.cmake | 10 ++++++++++ Tests/RunCMake/ObjectLibrary/ObjWithObj-stderr.txt | 12 ++++++++--- Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake | 4 ++-- Tests/RunCMake/ObjectLibrary/a.c | 8 +++++++- Tests/RunCMake/ObjectLibrary/b.c | 14 +++++++++++-- Tests/RunCMake/ObjectLibrary/exe.c | 14 +++++++++++++ .../OBJECTwithOnlyObjectSources-stderr.txt | 6 ------ 20 files changed, 94 insertions(+), 66 deletions(-) delete mode 100644 Tests/RunCMake/ObjectLibrary/LinkObjRHS1-result.txt delete mode 100644 Tests/RunCMake/ObjectLibrary/LinkObjRHS1-stderr.txt delete mode 100644 Tests/RunCMake/ObjectLibrary/LinkObjRHS1.cmake delete mode 100644 Tests/RunCMake/ObjectLibrary/LinkObjRHS2-result.txt delete mode 100644 Tests/RunCMake/ObjectLibrary/LinkObjRHS2-stderr.txt delete mode 100644 Tests/RunCMake/ObjectLibrary/LinkObjRHS2.cmake create mode 100644 Tests/RunCMake/ObjectLibrary/LinkObjRHSShared.cmake create mode 100644 Tests/RunCMake/ObjectLibrary/LinkObjRHSStatic.cmake create mode 100644 Tests/RunCMake/ObjectLibrary/exe.c diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 8a5a6de..e00450f 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/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 = diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index 18767a3..efdd3a5 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/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; } diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index a276d01..f0ae47b 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/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; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index e9b6daf..f6fd6d1 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/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()); } diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 734ac93..bb21022 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -114,15 +114,12 @@ const char* cmTargetPropertyComputer::GetSources( } if (!noMessage) { e << "Target \"" << tgt->GetName() - << "\" contains " - "$ 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 $ 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; } diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index 47c29db..699fff8 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/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()); } diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHS1-result.txt b/Tests/RunCMake/ObjectLibrary/LinkObjRHS1-result.txt deleted file mode 100644 index d00491f..0000000 --- a/Tests/RunCMake/ObjectLibrary/LinkObjRHS1-result.txt +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHS1-stderr.txt b/Tests/RunCMake/ObjectLibrary/LinkObjRHS1-stderr.txt deleted file mode 100644 index d5ee4f9..0000000 --- a/Tests/RunCMake/ObjectLibrary/LinkObjRHS1-stderr.txt +++ /dev/null @@ -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\) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHS1.cmake b/Tests/RunCMake/ObjectLibrary/LinkObjRHS1.cmake deleted file mode 100644 index 113d6a8..0000000 --- a/Tests/RunCMake/ObjectLibrary/LinkObjRHS1.cmake +++ /dev/null @@ -1,3 +0,0 @@ -add_library(A STATIC a.c) -add_library(AnObjLib OBJECT a.c) -target_link_libraries(A AnObjLib) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHS2-result.txt b/Tests/RunCMake/ObjectLibrary/LinkObjRHS2-result.txt deleted file mode 100644 index d00491f..0000000 --- a/Tests/RunCMake/ObjectLibrary/LinkObjRHS2-result.txt +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHS2-stderr.txt b/Tests/RunCMake/ObjectLibrary/LinkObjRHS2-stderr.txt deleted file mode 100644 index 3295fca..0000000 --- a/Tests/RunCMake/ObjectLibrary/LinkObjRHS2-stderr.txt +++ /dev/null @@ -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\) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHS2.cmake b/Tests/RunCMake/ObjectLibrary/LinkObjRHS2.cmake deleted file mode 100644 index 6163729..0000000 --- a/Tests/RunCMake/ObjectLibrary/LinkObjRHS2.cmake +++ /dev/null @@ -1,3 +0,0 @@ -add_library(A SHARED a.c) -target_link_libraries(A AnObjLib) -add_library(AnObjLib OBJECT a.c) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHSShared.cmake b/Tests/RunCMake/ObjectLibrary/LinkObjRHSShared.cmake new file mode 100644 index 0000000..b9030b3 --- /dev/null +++ b/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_link_libraries(A PUBLIC AnObjLib) + +add_executable(exe exe.c) +target_link_libraries(exe A) diff --git a/Tests/RunCMake/ObjectLibrary/LinkObjRHSStatic.cmake b/Tests/RunCMake/ObjectLibrary/LinkObjRHSStatic.cmake new file mode 100644 index 0000000..73fad06 --- /dev/null +++ b/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_link_libraries(A PUBLIC AnObjLib) + +add_executable(exe exe.c) +target_link_libraries(exe A) diff --git a/Tests/RunCMake/ObjectLibrary/ObjWithObj-stderr.txt b/Tests/RunCMake/ObjectLibrary/ObjWithObj-stderr.txt index d67b4ae..aadc5e0 100644 --- a/Tests/RunCMake/ObjectLibrary/ObjWithObj-stderr.txt +++ b/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\)$ diff --git a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake index 1660779..6724da1 100644 --- a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake +++ b/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) diff --git a/Tests/RunCMake/ObjectLibrary/a.c b/Tests/RunCMake/ObjectLibrary/a.c index 1636303..5beb3f1 100644 --- a/Tests/RunCMake/ObjectLibrary/a.c +++ b/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; } diff --git a/Tests/RunCMake/ObjectLibrary/b.c b/Tests/RunCMake/ObjectLibrary/b.c index 6751907..7549abf 100644 --- a/Tests/RunCMake/ObjectLibrary/b.c +++ b/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 diff --git a/Tests/RunCMake/ObjectLibrary/exe.c b/Tests/RunCMake/ObjectLibrary/exe.c new file mode 100644 index 0000000..6efdae7 --- /dev/null +++ b/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 diff --git a/Tests/RunCMake/add_library/OBJECTwithOnlyObjectSources-stderr.txt b/Tests/RunCMake/add_library/OBJECTwithOnlyObjectSources-stderr.txt index 77a72f1..6183f80 100644 --- a/Tests/RunCMake/add_library/OBJECTwithOnlyObjectSources-stderr.txt +++ b/Tests/RunCMake/add_library/OBJECTwithOnlyObjectSources-stderr.txt @@ -7,10 +7,4 @@ 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\)$ -- cgit v0.12