From 30962029325b2126b0b986db0c5ce8e0660428a0 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Wed, 26 Dec 2012 10:58:21 +0100 Subject: [PATCH] Make targets depend on the link interface of their dependees. --- Source/cmComputeTargetDepends.cxx | 59 +++++++++++++++++++ Source/cmComputeTargetDepends.h | 6 +- .../target_link_libraries/CMakeLists.txt | 7 +++ .../target_link_libraries/depIfaceOnly.cpp | 7 +++ .../target_link_libraries/depIfaceOnly.h | 7 +++ .../target_link_libraries/targetA.cpp | 5 +- 6 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 Tests/CMakeCommands/target_link_libraries/depIfaceOnly.cpp create mode 100644 Tests/CMakeCommands/target_link_libraries/depIfaceOnly.h diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index ab77c6bc9..3b15ec11a 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -214,6 +214,8 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) if(emitted.insert(lib->first).second) { this->AddTargetDepend(depender_index, lib->first.c_str(), true); + this->AddInterfaceDepends(depender_index, lib->first.c_str(), + true, emitted); } } } @@ -236,6 +238,63 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) } } +//---------------------------------------------------------------------------- +void cmComputeTargetDepends::AddInterfaceDepends(int depender_index, + cmTarget* dependee, + const char *config, + std::set &emitted) +{ + if(cmTarget::LinkInterface const* iface = + dependee->GetLinkInterface(config)) + { + for(std::vector::const_iterator + lib = iface->Libraries.begin(); + lib != iface->Libraries.end(); ++lib) + { + // Don't emit the same library twice for this target. + if(emitted.insert(*lib).second) + { + this->AddTargetDepend(depender_index, lib->c_str(), true); + } + } + } +} + +//---------------------------------------------------------------------------- +void cmComputeTargetDepends::AddInterfaceDepends(int depender_index, + const char* dependee_name, + bool linking, + std::set &emitted) +{ + cmTarget* depender = this->Targets[depender_index]; + cmTarget* dependee = + depender->GetMakefile()->FindTargetToUse(dependee_name); + // Skip targets that will not really be linked. This is probably a + // name conflict between an external library and an executable + // within the project. + if(linking && dependee && + dependee->GetType() == cmTarget::EXECUTABLE && + !dependee->IsExecutableWithExports()) + { + dependee = 0; + } + + if(dependee) + { + this->AddInterfaceDepends(depender_index, dependee, 0, emitted); + std::vector configs; + depender->GetMakefile()->GetConfigurations(configs); + for (std::vector::const_iterator it = configs.begin(); + it != configs.end(); ++it) + { + // A target should not depend on itself. + emitted.insert(depender->GetName()); + this->AddInterfaceDepends(depender_index, dependee, + it->c_str(), emitted); + } + } +} + //---------------------------------------------------------------------------- void cmComputeTargetDepends::AddTargetDepend(int depender_index, const char* dependee_name, diff --git a/Source/cmComputeTargetDepends.h b/Source/cmComputeTargetDepends.h index 67bce72d9..d6131cf1c 100644 --- a/Source/cmComputeTargetDepends.h +++ b/Source/cmComputeTargetDepends.h @@ -48,7 +48,11 @@ private: bool linking); void AddTargetDepend(int depender_index, cmTarget* dependee, bool linking); bool ComputeFinalDepends(cmComputeComponentGraph const& ccg); - + void AddInterfaceDepends(int depender_index, const char* dependee_name, + bool linking, std::set &emitted); + void AddInterfaceDepends(int depender_index, cmTarget* dependee, + const char *config, + std::set &emitted); cmGlobalGenerator* GlobalGenerator; bool DebugMode; bool NoCycles; diff --git a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt index 1faa88848..60b36fc27 100644 --- a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt +++ b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt @@ -56,3 +56,10 @@ assert_property(targetA LINK_INTERFACE_LIBRARIES "") target_link_libraries(targetA depB depC) assert_property(targetA LINK_INTERFACE_LIBRARIES "") + +# Exclude depIfaceOnly from ALL so that it will only be built if something +# depends on it. As it is in the link interface of depB, targetA +# will depend on it. That dependency is what is being tested here. +add_library(depIfaceOnly SHARED EXCLUDE_FROM_ALL depIfaceOnly.cpp) +generate_export_header(depIfaceOnly) +set_property(TARGET depB APPEND PROPERTY LINK_INTERFACE_LIBRARIES depIfaceOnly) diff --git a/Tests/CMakeCommands/target_link_libraries/depIfaceOnly.cpp b/Tests/CMakeCommands/target_link_libraries/depIfaceOnly.cpp new file mode 100644 index 000000000..3b90af008 --- /dev/null +++ b/Tests/CMakeCommands/target_link_libraries/depIfaceOnly.cpp @@ -0,0 +1,7 @@ + +#include "depIfaceOnly.h" + +int DepIfaceOnly::foo() +{ + return 0; +} diff --git a/Tests/CMakeCommands/target_link_libraries/depIfaceOnly.h b/Tests/CMakeCommands/target_link_libraries/depIfaceOnly.h new file mode 100644 index 000000000..dddf6a5e4 --- /dev/null +++ b/Tests/CMakeCommands/target_link_libraries/depIfaceOnly.h @@ -0,0 +1,7 @@ + +#include "depifaceonly_export.h" + +struct DEPIFACEONLY_EXPORT DepIfaceOnly +{ + int foo(); +}; diff --git a/Tests/CMakeCommands/target_link_libraries/targetA.cpp b/Tests/CMakeCommands/target_link_libraries/targetA.cpp index 3c6472e9a..6ff65b106 100644 --- a/Tests/CMakeCommands/target_link_libraries/targetA.cpp +++ b/Tests/CMakeCommands/target_link_libraries/targetA.cpp @@ -1,6 +1,7 @@ #include "depB.h" #include "depC.h" +#include "depIfaceOnly.h" int main(int argc, char **argv) { @@ -8,5 +9,7 @@ int main(int argc, char **argv) DepB b; DepC c; - return a.foo() + b.foo() + c.foo(); + DepIfaceOnly iface_only; + + return a.foo() + b.foo() + c.foo() + iface_only.foo(); }