From b04f3b9a2a116b1956d5342637cda1348a5ee07b Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Wed, 21 Aug 2013 22:00:48 +0200 Subject: [PATCH] Create make rules for INTERFACE_LIBRARY targets. The result is that the depends of the target are created. So, add_library(somelib foo.cpp) add_library(anotherlib EXCLUDE_FROM_ALL foo.cpp) add_library(extra EXCLUDE_FROM_ALL foo.cpp) target_link_libraries(anotherlib extra) add_library(iface INTERFACE) target_link_libraries(iface INTERFACE anotherlib) Executing 'make iface' will result in the anotherlib and extra targets being made. Adding a regular executable to the INTERFACE of an INTERFACE_LIBRARY will not result in the executable being built with 'make iface' because of the logic in cmComputeTargetDepends::AddTargetDepend. So far, this is implemented only for the Makefile generator. Other generators will follow if this feature is possible for them. Make INTERFACE_LIBRARY targets part of the all target by default. Test this by building the all target and making the expected library EXCLUDE_FROM_ALL. --- Source/cmComputeTargetDepends.cxx | 10 ++- Source/cmGlobalUnixMakefileGenerator3.cxx | 94 ++++++++++++--------- Source/cmLocalUnixMakefileGenerator3.cxx | 1 + Source/cmMakefileLibraryTargetGenerator.cxx | 3 + Source/cmMakefileTargetGenerator.cxx | 1 + Source/cmTarget.cxx | 23 +++++ Source/cmTarget.h | 3 + Tests/CMakeLists.txt | 17 ++++ Tests/InterfaceBuildTargets/CMakeLists.txt | 13 +++ Tests/InterfaceBuildTargets/main.cxx | 5 ++ Tests/InterfaceBuildTargets/testlib.cxx | 5 ++ 11 files changed, 136 insertions(+), 39 deletions(-) create mode 100644 Tests/InterfaceBuildTargets/CMakeLists.txt create mode 100644 Tests/InterfaceBuildTargets/main.cxx create mode 100644 Tests/InterfaceBuildTargets/testlib.cxx diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index 0829add20..7fd475489 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -208,7 +208,15 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) std::set emitted; { std::vector tlibs; - depender->GetDirectLinkLibraries(0, tlibs, depender); + if (depender->GetType() == cmTarget::INTERFACE_LIBRARY) + { + // For INTERFACE_LIBRARY depend on the interface instead. + depender->GetInterfaceLinkLibraries(0, tlibs, depender); + } + else + { + depender->GetDirectLinkLibraries(0, tlibs, depender); + } // A target should not depend on itself. emitted.insert(depender->GetName()); for(std::vector::const_iterator lib = tlibs.begin(); diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 7ab107f47..ce95c0861 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -435,6 +435,7 @@ cmGlobalUnixMakefileGenerator3 (l->second.GetType() == cmTarget::SHARED_LIBRARY) || (l->second.GetType() == cmTarget::MODULE_LIBRARY) || (l->second.GetType() == cmTarget::OBJECT_LIBRARY) || + (l->second.GetType() == cmTarget::INTERFACE_LIBRARY) || (l->second.GetType() == cmTarget::UTILITY)) { // Add this to the list of depends rules in this directory. @@ -612,6 +613,7 @@ cmGlobalUnixMakefileGenerator3 (t->second.GetType() == cmTarget::SHARED_LIBRARY) || (t->second.GetType() == cmTarget::MODULE_LIBRARY) || (t->second.GetType() == cmTarget::OBJECT_LIBRARY) || + (t->second.GetType() == cmTarget::INTERFACE_LIBRARY) || (t->second.GetType() == cmTarget::UTILITY))) { // Add a rule to build the target by name. @@ -633,6 +635,10 @@ cmGlobalUnixMakefileGenerator3 t->second.GetName(), depends, commands, true); + if (t->second.GetType() == cmTarget::INTERFACE_LIBRARY) + { + continue; + } // Add a fast rule to build the target std::string localName = lg->GetRelativeTargetDirectory(t->second); std::string makefileName; @@ -699,6 +705,7 @@ cmGlobalUnixMakefileGenerator3 || (t->second.GetType() == cmTarget::SHARED_LIBRARY) || (t->second.GetType() == cmTarget::MODULE_LIBRARY) || (t->second.GetType() == cmTarget::OBJECT_LIBRARY) + || (t->second.GetType() == cmTarget::INTERFACE_LIBRARY) || (t->second.GetType() == cmTarget::UTILITY))) { std::string makefileName; @@ -715,53 +722,64 @@ cmGlobalUnixMakefileGenerator3 << localName << "\n\n"; commands.clear(); - makeTargetName = localName; - makeTargetName += "/depend"; - commands.push_back(lg->GetRecursiveMakeCall - (makefileName.c_str(),makeTargetName.c_str())); - // add requires if we need it for this generator - if (needRequiresStep) + if(t->second.GetType() != cmTarget::INTERFACE_LIBRARY) { makeTargetName = localName; - makeTargetName += "/requires"; + makeTargetName += "/depend"; commands.push_back(lg->GetRecursiveMakeCall - (makefileName.c_str(),makeTargetName.c_str())); - } - makeTargetName = localName; - makeTargetName += "/build"; - commands.push_back(lg->GetRecursiveMakeCall (makefileName.c_str(),makeTargetName.c_str())); - // Write the rule. - localName += "/all"; - depends.clear(); - - std::string progressDir = - lg->GetMakefile()->GetHomeOutputDirectory(); - progressDir += cmake::GetCMakeFilesDirectory(); - { - cmOStringStream progCmd; - progCmd << "$(CMAKE_COMMAND) -E cmake_progress_report "; - // all target counts - progCmd << lg->Convert(progressDir.c_str(), - cmLocalGenerator::FULL, - cmLocalGenerator::SHELL); - progCmd << " "; - std::vector& progFiles = - this->ProgressMap[&t->second].Marks; - for (std::vector::iterator i = progFiles.begin(); - i != progFiles.end(); ++i) + // add requires if we need it for this generator + if (needRequiresStep) { - progCmd << " " << *i; + makeTargetName = localName; + makeTargetName += "/requires"; + commands.push_back(lg->GetRecursiveMakeCall + (makefileName.c_str(),makeTargetName.c_str())); } - commands.push_back(progCmd.str()); - } - progressDir = "Built target "; - progressDir += t->first; - lg->AppendEcho(commands,progressDir.c_str()); + makeTargetName = localName; + makeTargetName += "/build"; + commands.push_back(lg->GetRecursiveMakeCall + (makefileName.c_str(),makeTargetName.c_str())); + // Write the rule. + localName += "/all"; + depends.clear(); + + std::string progressDir = + lg->GetMakefile()->GetHomeOutputDirectory(); + progressDir += cmake::GetCMakeFilesDirectory(); + { + cmOStringStream progCmd; + progCmd << "$(CMAKE_COMMAND) -E cmake_progress_report "; + // all target counts + progCmd << lg->Convert(progressDir.c_str(), + cmLocalGenerator::FULL, + cmLocalGenerator::SHELL); + progCmd << " "; + std::vector& progFiles = + this->ProgressMap[&t->second].Marks; + for (std::vector::iterator i = progFiles.begin(); + i != progFiles.end(); ++i) + { + progCmd << " " << *i; + } + commands.push_back(progCmd.str()); + } + progressDir = "Built target "; + progressDir += t->first; + lg->AppendEcho(commands,progressDir.c_str()); + } + else + { + depends.clear(); + } this->AppendGlobalTargetDepends(depends,t->second); + if(depends.empty() && this->EmptyRuleHackDepends != "") + { + depends.push_back(this->EmptyRuleHackDepends); + } lg->WriteMakeRule(ruleFileStream, "All Build rule for target.", localName.c_str(), depends, commands, true); @@ -777,7 +795,7 @@ cmGlobalUnixMakefileGenerator3 // Write the rule. commands.clear(); - progressDir = lg->GetMakefile()->GetHomeOutputDirectory(); + std::string progressDir = lg->GetMakefile()->GetHomeOutputDirectory(); progressDir += cmake::GetCMakeFilesDirectory(); { diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index dc401dced..508eca1fa 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -381,6 +381,7 @@ void cmLocalUnixMakefileGenerator3 (t->second.GetType() == cmTarget::SHARED_LIBRARY) || (t->second.GetType() == cmTarget::MODULE_LIBRARY) || (t->second.GetType() == cmTarget::OBJECT_LIBRARY) || + (t->second.GetType() == cmTarget::INTERFACE_LIBRARY) || (t->second.GetType() == cmTarget::UTILITY)) { emitted.insert(t->second.GetName()); diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index ea9663f2e..29365a308 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -82,6 +82,9 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles() case cmTarget::OBJECT_LIBRARY: this->WriteObjectLibraryRules(); break; + case cmTarget::INTERFACE_LIBRARY: + // Nothing to do. + break; default: // If language is not known, this is an error. cmSystemTools::Error("Unknown Library Type"); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 9ca91497d..6770e106a 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -75,6 +75,7 @@ cmMakefileTargetGenerator::New(cmTarget *tgt) case cmTarget::SHARED_LIBRARY: case cmTarget::MODULE_LIBRARY: case cmTarget::OBJECT_LIBRARY: + case cmTarget::INTERFACE_LIBRARY: result = new cmMakefileLibraryTargetGenerator(tgt); break; case cmTarget::UTILITY: diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 5e10e25a1..bd37a540c 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -1111,6 +1111,29 @@ void cmTarget::GetDirectLinkLibraries(const char *config, } } +//---------------------------------------------------------------------------- +void cmTarget::GetInterfaceLinkLibraries(const char *config, + std::vector &libs, cmTarget *head) +{ + const char *prop = this->GetProperty("INTERFACE_LINK_LIBRARIES"); + if (prop) + { + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + const cmsys::auto_ptr cge = ge.Parse(prop); + + cmGeneratorExpressionDAGChecker dagChecker(lfbt, + this->GetName(), + "INTERFACE_LINK_LIBRARIES", 0, 0); + cmSystemTools::ExpandListArgument(cge->Evaluate(this->Makefile, + config, + false, + head, + &dagChecker), + libs); + } +} + //---------------------------------------------------------------------------- std::string cmTarget::GetDebugGeneratorExpressions(const std::string &value, cmTarget::LinkLibraryType llt) diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 3c36da789..e8f4e08b6 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -177,6 +177,9 @@ public: void GetDirectLinkLibraries(const char *config, std::vector &, cmTarget *head); + void GetInterfaceLinkLibraries(const char *config, + std::vector &, + cmTarget *head); /** Compute the link type to use for the given configuration. */ LinkLibraryType ComputeLinkType(const char* config); diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 2f6a45680..198ce0450 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -261,6 +261,23 @@ if(BUILD_TESTING) PASS_REGULAR_EXPRESSION "(file is not of required architecture|does not match cputype|not the architecture being linked)") endif() + if(CMAKE_TEST_GENERATOR MATCHES Make) + set(InterfaceBuildTargets_libname testlib) + if (CMAKE_TEST_GENERATOR MATCHES "Borland|Watcom") + set(InterfaceBuildTargets_libname testlib.lib) + endif() + add_test(InterfaceBuildTargets ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/InterfaceBuildTargets" + "${CMake_BINARY_DIR}/Tests/InterfaceBuildTargets" + --build-two-config + ${build_generator_args} + --build-project InterfaceBuildTargets + --test-command ${CMAKE_CMAKE_COMMAND} -E touch_nocreate ${InterfaceBuildTargets_libname} + ) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/InterfaceBuildTargets") + endif() + list(APPEND TEST_BUILD_DIRS ${CMake_TEST_INSTALL_PREFIX}) if(NOT QT4_FOUND) diff --git a/Tests/InterfaceBuildTargets/CMakeLists.txt b/Tests/InterfaceBuildTargets/CMakeLists.txt new file mode 100644 index 000000000..a00e5d573 --- /dev/null +++ b/Tests/InterfaceBuildTargets/CMakeLists.txt @@ -0,0 +1,13 @@ +project(InterfaceBuildTargets) + +add_library(testlib EXCLUDE_FROM_ALL testlib.cxx) +set_property(TARGET testlib PROPERTY PREFIX "") +if(CMAKE_GENERATOR MATCHES "Borland|Watcom") + # These librarians add the .lib suffix anyway. + set_property(TARGET testlib PROPERTY SUFFIX ".lib") +else() + set_property(TARGET testlib PROPERTY SUFFIX "") +endif() + +add_library(iface INTERFACE) +target_link_libraries(iface INTERFACE testlib) diff --git a/Tests/InterfaceBuildTargets/main.cxx b/Tests/InterfaceBuildTargets/main.cxx new file mode 100644 index 000000000..e9ad2573b --- /dev/null +++ b/Tests/InterfaceBuildTargets/main.cxx @@ -0,0 +1,5 @@ + +int main(int, char**) +{ + return 0; +} diff --git a/Tests/InterfaceBuildTargets/testlib.cxx b/Tests/InterfaceBuildTargets/testlib.cxx new file mode 100644 index 000000000..02bd6b08f --- /dev/null +++ b/Tests/InterfaceBuildTargets/testlib.cxx @@ -0,0 +1,5 @@ + +void testlib(void) +{ + +}