From dba4962b868c3baa7886dcd3f8b597e971a479a2 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 16 Oct 2013 09:52:37 -0400 Subject: Makefile: Always create clean target command Borland Make complains if the phony clean target has no rule to build it. If there are no files to clean, generate and run an empty clean script. --- Source/cmLocalUnixMakefileGenerator3.cxx | 74 ++++++++++++++++---------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 2443583..dc401dc 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1158,27 +1158,25 @@ cmLocalUnixMakefileGenerator3 const std::vector& files, cmTarget& target, const char* filename) { + std::string cleanfile = this->Makefile->GetCurrentOutputDirectory(); + cleanfile += "/"; + cleanfile += this->GetTargetDirectory(target); + cleanfile += "/cmake_clean"; + if(filename) + { + cleanfile += "_"; + cleanfile += filename; + } + cleanfile += ".cmake"; + std::string cleanfilePath = this->Convert(cleanfile.c_str(), FULL); + std::ofstream fout(cleanfilePath.c_str()); + if(!fout) + { + cmSystemTools::Error("Could not create ", cleanfilePath.c_str()); + } if(!files.empty()) { - std::string cleanfile = this->Makefile->GetCurrentOutputDirectory(); - cleanfile += "/"; - cleanfile += this->GetTargetDirectory(target); - cleanfile += "/cmake_clean"; - if(filename) - { - cleanfile += "_"; - cleanfile += filename; - } - cleanfile += ".cmake"; - std::string cleanfilePath = this->Convert(cleanfile.c_str(), FULL); - std::ofstream fout(cleanfilePath.c_str()); - if(!fout) - { - cmSystemTools::Error("Could not create ", cleanfilePath.c_str()); - } fout << "file(REMOVE_RECURSE\n"; - std::string remove = "$(CMAKE_COMMAND) -P "; - remove += this->Convert(cleanfile.c_str(), START_OUTPUT, SHELL); for(std::vector::const_iterator f = files.begin(); f != files.end(); ++f) { @@ -1186,27 +1184,29 @@ cmLocalUnixMakefileGenerator3 fout << " " << this->EscapeForCMake(fc.c_str()) << "\n"; } fout << ")\n"; - commands.push_back(remove); - - // For the main clean rule add per-language cleaning. - if(!filename) + } + std::string remove = "$(CMAKE_COMMAND) -P "; + remove += this->Convert(cleanfile.c_str(), START_OUTPUT, SHELL); + commands.push_back(remove); + + // For the main clean rule add per-language cleaning. + if(!filename) + { + // Get the set of source languages in the target. + std::set languages; + target.GetLanguages(languages); + fout << "\n" + << "# Per-language clean rules from dependency scanning.\n" + << "foreach(lang"; + for(std::set::const_iterator l = languages.begin(); + l != languages.end(); ++l) { - // Get the set of source languages in the target. - std::set languages; - target.GetLanguages(languages); - fout << "\n" - << "# Per-language clean rules from dependency scanning.\n" - << "foreach(lang"; - for(std::set::const_iterator l = languages.begin(); - l != languages.end(); ++l) - { - fout << " " << *l; - } - fout << ")\n" - << " include(" << this->GetTargetDirectory(target) - << "/cmake_clean_${lang}.cmake OPTIONAL)\n" - << "endforeach()\n"; + fout << " " << *l; } + fout << ")\n" + << " include(" << this->GetTargetDirectory(target) + << "/cmake_clean_${lang}.cmake OPTIONAL)\n" + << "endforeach()\n"; } } -- cgit v0.12 From b04f3b9a2a116b1956d5342637cda1348a5ee07b Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Wed, 21 Aug 2013 22:00:48 +0200 Subject: 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 | 92 +++++++++++++++++------------ 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, 135 insertions(+), 38 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 0829add..7fd4754 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 7ab107f..ce95c08 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(); + // add requires if we need it for this generator + if (needRequiresStep) + { + makeTargetName = localName; + makeTargetName += "/requires"; + 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())); - 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) + // Write the rule. + localName += "/all"; + depends.clear(); + + std::string progressDir = + lg->GetMakefile()->GetHomeOutputDirectory(); + progressDir += cmake::GetCMakeFilesDirectory(); { - progCmd << " " << *i; + 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()); } - commands.push_back(progCmd.str()); + progressDir = "Built target "; + progressDir += t->first; + lg->AppendEcho(commands,progressDir.c_str()); + } + else + { + depends.clear(); } - progressDir = "Built target "; - progressDir += t->first; - lg->AppendEcho(commands,progressDir.c_str()); - 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 dc401dc..508eca1 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 ea9663f..29365a3 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 9ca9149..6770e10 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 5e10e25..bd37a54 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -1112,6 +1112,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 3c36da7..e8f4e08 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 2f6a456..198ce04 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 0000000..a00e5d5 --- /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 0000000..e9ad257 --- /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 0000000..02bd6b0 --- /dev/null +++ b/Tests/InterfaceBuildTargets/testlib.cxx @@ -0,0 +1,5 @@ + +void testlib(void) +{ + +} -- cgit v0.12