Browse Source

Make targets depend on the link interface of their dependees.

Stephen Kelly 13 years ago
parent
commit
3096202932

+ 59 - 0
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<cmStdString> &emitted)
+{
+  if(cmTarget::LinkInterface const* iface =
+                                dependee->GetLinkInterface(config))
+    {
+    for(std::vector<std::string>::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<cmStdString> &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<std::string> configs;
+    depender->GetMakefile()->GetConfigurations(configs);
+    for (std::vector<std::string>::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,

+ 5 - 1
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<cmStdString> &emitted);
+  void AddInterfaceDepends(int depender_index, cmTarget* dependee,
+                           const char *config,
+                           std::set<cmStdString> &emitted);
   cmGlobalGenerator* GlobalGenerator;
   bool DebugMode;
   bool NoCycles;

+ 7 - 0
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)

+ 7 - 0
Tests/CMakeCommands/target_link_libraries/depIfaceOnly.cpp

@@ -0,0 +1,7 @@
+
+#include "depIfaceOnly.h"
+
+int DepIfaceOnly::foo()
+{
+  return 0;
+}

+ 7 - 0
Tests/CMakeCommands/target_link_libraries/depIfaceOnly.h

@@ -0,0 +1,7 @@
+
+#include "depifaceonly_export.h"
+
+struct DEPIFACEONLY_EXPORT DepIfaceOnly
+{
+  int foo();
+};

+ 4 - 1
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();
 }