Browse Source

Merge topic 'LINK_LIBRARIES-property'

7653862 Add LINK_LIBRARIES property for direct target link dependencies
40cf3fb Make linking APIs aware of 'head' target
Brad King 12 years ago
parent
commit
a9f1bf4380

+ 6 - 5
Source/cmComputeLinkDepends.cxx

@@ -172,10 +172,11 @@ satisfy dependencies.
 
 //----------------------------------------------------------------------------
 cmComputeLinkDepends
-::cmComputeLinkDepends(cmTarget* target, const char* config)
+::cmComputeLinkDepends(cmTarget* target, const char* config, cmTarget* head)
 {
   // Store context information.
   this->Target = target;
+  this->HeadTarget = head;
   this->Makefile = this->Target->GetMakefile();
   this->LocalGenerator = this->Makefile->GetLocalGenerator();
   this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
@@ -352,7 +353,7 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
     {
     // Follow the target dependencies.
     if(cmTarget::LinkInterface const* iface =
-       entry.Target->GetLinkInterface(this->Config))
+       entry.Target->GetLinkInterface(this->Config, this->HeadTarget))
       {
       // This target provides its own link interface information.
       this->AddLinkEntries(depender_index, iface->Libraries);
@@ -444,7 +445,7 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep)
   if(entry.Target)
     {
     if(cmTarget::LinkInterface const* iface =
-       entry.Target->GetLinkInterface(this->Config))
+       entry.Target->GetLinkInterface(this->Config, this->HeadTarget))
       {
       // Follow public and private dependencies transitively.
       this->FollowSharedDeps(index, iface, true);
@@ -533,7 +534,7 @@ void cmComputeLinkDepends::AddDirectLinkEntries()
 {
   // Add direct link dependencies in this configuration.
   cmTarget::LinkImplementation const* impl =
-    this->Target->GetLinkImplementation(this->Config);
+    this->Target->GetLinkImplementation(this->Config, this->HeadTarget);
   this->AddLinkEntries(-1, impl->Libraries);
   for(std::vector<std::string>::const_iterator
         wi = impl->WrongConfigLibraries.begin();
@@ -944,7 +945,7 @@ int cmComputeLinkDepends::ComputeComponentCount(NodeList const& nl)
     if(cmTarget* target = this->EntryList[*ni].Target)
       {
       if(cmTarget::LinkInterface const* iface =
-         target->GetLinkInterface(this->Config))
+         target->GetLinkInterface(this->Config, this->HeadTarget))
         {
         if(iface->Multiplicity > count)
           {

+ 2 - 1
Source/cmComputeLinkDepends.h

@@ -32,7 +32,7 @@ class cmake;
 class cmComputeLinkDepends
 {
 public:
-  cmComputeLinkDepends(cmTarget* target, const char* config);
+  cmComputeLinkDepends(cmTarget* target, const char* config, cmTarget *head);
   ~cmComputeLinkDepends();
 
   // Basic information about each link item.
@@ -59,6 +59,7 @@ private:
 
   // Context information.
   cmTarget* Target;
+  cmTarget* HeadTarget;
   cmMakefile* Makefile;
   cmLocalGenerator* LocalGenerator;
   cmGlobalGenerator* GlobalGenerator;

+ 7 - 4
Source/cmComputeLinkInformation.cxx

@@ -239,10 +239,12 @@ because this need be done only for shared libraries without soname-s.
 
 //----------------------------------------------------------------------------
 cmComputeLinkInformation
-::cmComputeLinkInformation(cmTarget* target, const char* config)
+::cmComputeLinkInformation(cmTarget* target, const char* config,
+                           cmTarget *headTarget)
 {
   // Store context information.
   this->Target = target;
+  this->HeadTarget = headTarget;
   this->Makefile = this->Target->GetMakefile();
   this->LocalGenerator = this->Makefile->GetLocalGenerator();
   this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
@@ -265,7 +267,7 @@ cmComputeLinkInformation
   this->OrderDependentRPath = 0;
 
   // Get the language used for linking this target.
-  this->LinkLanguage = this->Target->GetLinkerLanguage(config);
+  this->LinkLanguage = this->Target->GetLinkerLanguage(config, headTarget);
   if(!this->LinkLanguage)
     {
     // The Compute method will do nothing, so skip the rest of the
@@ -503,7 +505,7 @@ bool cmComputeLinkInformation::Compute()
     }
 
   // Compute the ordered link line items.
-  cmComputeLinkDepends cld(this->Target, this->Config);
+  cmComputeLinkDepends cld(this->Target, this->Config, this->HeadTarget);
   cld.SetOldLinkDirMode(this->OldLinkDirMode);
   cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute();
 
@@ -569,7 +571,8 @@ bool cmComputeLinkInformation::Compute()
 void cmComputeLinkInformation::AddImplicitLinkInfo()
 {
   // The link closure lists all languages whose implicit info is needed.
-  cmTarget::LinkClosure const* lc=this->Target->GetLinkClosure(this->Config);
+  cmTarget::LinkClosure const* lc=this->Target->GetLinkClosure(this->Config,
+                                                          this->HeadTarget);
   for(std::vector<std::string>::const_iterator li = lc->Languages.begin();
       li != lc->Languages.end(); ++li)
     {

+ 3 - 1
Source/cmComputeLinkInformation.h

@@ -29,7 +29,8 @@ class cmOrderDirectories;
 class cmComputeLinkInformation
 {
 public:
-  cmComputeLinkInformation(cmTarget* target, const char* config);
+  cmComputeLinkInformation(cmTarget* target, const char* config,
+                           cmTarget* headTarget);
   ~cmComputeLinkInformation();
   bool Compute();
 
@@ -74,6 +75,7 @@ private:
 
   // Context information.
   cmTarget* Target;
+  cmTarget* HeadTarget;
   cmMakefile* Makefile;
   cmLocalGenerator* LocalGenerator;
   cmGlobalGenerator* GlobalGenerator;

+ 35 - 8
Source/cmComputeTargetDepends.cxx

@@ -200,25 +200,51 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index)
   // Get the depender.
   cmTarget* depender = this->Targets[depender_index];
 
-  // Loop over all targets linked directly.
+  // Loop over all targets linked directly in all configs.
+  // We need to make targets depend on the union of all config-specific
+  // dependencies in all targets, because the generated build-systems can't
+  // deal with config-specific dependencies.
   {
-  cmTarget::LinkLibraryVectorType const& tlibs =
-    depender->GetOriginalLinkLibraries();
   std::set<cmStdString> emitted;
+  {
+  std::vector<std::string> tlibs;
+  depender->GetDirectLinkLibraries(0, tlibs, depender);
   // A target should not depend on itself.
   emitted.insert(depender->GetName());
-  for(cmTarget::LinkLibraryVectorType::const_iterator lib = tlibs.begin();
+  for(std::vector<std::string>::const_iterator lib = tlibs.begin();
       lib != tlibs.end(); ++lib)
     {
     // Don't emit the same library twice for this target.
-    if(emitted.insert(lib->first).second)
+    if(emitted.insert(*lib).second)
       {
-      this->AddTargetDepend(depender_index, lib->first.c_str(), true);
-      this->AddInterfaceDepends(depender_index, lib->first.c_str(),
+      this->AddTargetDepend(depender_index, lib->c_str(), true);
+      this->AddInterfaceDepends(depender_index, lib->c_str(),
                                 true, emitted);
       }
     }
   }
+  std::vector<std::string> configs;
+  depender->GetMakefile()->GetConfigurations(configs);
+  for (std::vector<std::string>::const_iterator it = configs.begin();
+    it != configs.end(); ++it)
+    {
+    std::vector<std::string> tlibs;
+    depender->GetDirectLinkLibraries(it->c_str(), tlibs, depender);
+    // A target should not depend on itself.
+    emitted.insert(depender->GetName());
+    for(std::vector<std::string>::const_iterator lib = tlibs.begin();
+        lib != tlibs.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);
+        this->AddInterfaceDepends(depender_index, lib->c_str(),
+                                  true, emitted);
+        }
+      }
+    }
+  }
 
   // Loop over all utility dependencies.
   {
@@ -244,8 +270,9 @@ void cmComputeTargetDepends::AddInterfaceDepends(int depender_index,
                                                  const char *config,
                                                std::set<cmStdString> &emitted)
 {
+  cmTarget* depender = this->Targets[depender_index];
   if(cmTarget::LinkInterface const* iface =
-                                dependee->GetLinkInterface(config))
+                                dependee->GetLinkInterface(config, depender))
     {
     for(std::vector<std::string>::const_iterator
         lib = iface->Libraries.begin();

+ 2 - 1
Source/cmExportFileGenerator.cxx

@@ -357,7 +357,8 @@ cmExportFileGenerator
     }
 
   // Add the transitive link dependencies for this configuration.
-  if(cmTarget::LinkInterface const* iface = target->GetLinkInterface(config))
+  if(cmTarget::LinkInterface const* iface = target->GetLinkInterface(config,
+                                                                     target))
     {
     this->SetImportLinkProperty(suffix, target,
                                 "IMPORTED_LINK_INTERFACE_LANGUAGES",

+ 1 - 1
Source/cmGlobalXCodeGenerator.cxx

@@ -1206,7 +1206,7 @@ void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmTarget& cmtarget)
 
   // If the language is compiled as a source trust Xcode to link with it.
   cmTarget::LinkImplementation const* impl =
-    cmtarget.GetLinkImplementation("NOCONFIG");
+    cmtarget.GetLinkImplementation("NOCONFIG", &cmtarget);
   for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
       li != impl->Languages.end(); ++li)
     {

+ 169 - 52
Source/cmTarget.cxx

@@ -72,6 +72,11 @@ struct cmTarget::ImportInfo
   cmTarget::LinkInterface LinkInterface;
 };
 
+struct TargetConfigPair : public std::pair<cmTarget*, std::string> {
+  TargetConfigPair(cmTarget* tgt, const std::string &config)
+    : std::pair<cmTarget*, std::string>(tgt, config) {}
+};
+
 //----------------------------------------------------------------------------
 class cmTargetInternals
 {
@@ -100,20 +105,24 @@ public:
     OptionalLinkInterface(): Exists(false) {}
     bool Exists;
   };
-  typedef std::map<cmStdString, OptionalLinkInterface> LinkInterfaceMapType;
+  typedef std::map<TargetConfigPair, OptionalLinkInterface>
+                                                          LinkInterfaceMapType;
   LinkInterfaceMapType LinkInterfaceMap;
 
   typedef std::map<cmStdString, cmTarget::OutputInfo> OutputInfoMapType;
   OutputInfoMapType OutputInfoMap;
 
-  typedef std::map<cmStdString, cmTarget::ImportInfo> ImportInfoMapType;
+  typedef std::map<TargetConfigPair, cmTarget::ImportInfo>
+                                                            ImportInfoMapType;
   ImportInfoMapType ImportInfoMap;
 
   // Cache link implementation computation from each configuration.
-  typedef std::map<cmStdString, cmTarget::LinkImplementation> LinkImplMapType;
+  typedef std::map<TargetConfigPair,
+                   cmTarget::LinkImplementation> LinkImplMapType;
   LinkImplMapType LinkImplMap;
 
-  typedef std::map<cmStdString, cmTarget::LinkClosure> LinkClosureMapType;
+  typedef std::map<TargetConfigPair, cmTarget::LinkClosure>
+                                                          LinkClosureMapType;
   LinkClosureMapType LinkClosureMap;
 
   struct SourceEntry { std::vector<cmSourceFile*> Depends; };
@@ -510,6 +519,22 @@ void cmTarget::DefineProperties(cmake *cm)
      "Installing a target with EXCLUDE_FROM_ALL set to true has "
      "undefined behavior.");
 
+  cm->DefineProperty
+    ("LINK_LIBRARIES", cmProperty::TARGET,
+     "List of direct link dependencies.",
+     "This property specifies the list of libraries or targets which will be "
+     "used for linking. "
+     "In addition to accepting values from the target_link_libraries "
+     "command, values may be set directly on any target using the "
+     "set_property command. "
+     "\n"
+     "The target property values are used by the generators to set "
+     "the link libraries for the compiler.  "
+     "See also the target_link_libraries command.\n"
+     "Contents of LINK_LIBRARIES may use \"generator expressions\" with "
+     "the syntax \"$<...>\".  "
+     CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS);
+
   cm->DefineProperty
     ("INCLUDE_DIRECTORIES", cmProperty::TARGET,
      "List of preprocessor include file search directories.",
@@ -2130,6 +2155,66 @@ bool cmTarget::NameResolvesToFramework(const std::string& libname)
     NameResolvesToFramework(libname);
 }
 
+//----------------------------------------------------------------------------
+void cmTarget::GetDirectLinkLibraries(const char *config,
+                            std::vector<std::string> &libs, cmTarget *head)
+{
+  const char *prop = this->GetProperty("LINK_LIBRARIES");
+  if (prop)
+    {
+    cmListFileBacktrace lfbt;
+    cmGeneratorExpression ge(lfbt);
+
+    cmGeneratorExpressionDAGChecker dagChecker(lfbt,
+                                        this->GetName(),
+                                        "LINK_LIBRARIES", 0, 0);
+    cmSystemTools::ExpandListArgument(ge.Parse(prop)->Evaluate(this->Makefile,
+                                        config,
+                                        false,
+                                        head,
+                                        &dagChecker),
+                                      libs);
+    }
+}
+
+//----------------------------------------------------------------------------
+std::string cmTarget::GetDebugGeneratorExpressions(const std::string &value,
+                                  cmTarget::LinkLibraryType llt)
+{
+  if (llt == GENERAL)
+    {
+    return value;
+    }
+
+  // Get the list of configurations considered to be DEBUG.
+  std::vector<std::string> const& debugConfigs =
+                      this->Makefile->GetCMakeInstance()->GetDebugConfigs();
+
+  std::string configString = "$<CONFIG:" + debugConfigs[0] + ">";
+
+  if (debugConfigs.size() > 1)
+    {
+    for(std::vector<std::string>::const_iterator
+          li = debugConfigs.begin() + 1; li != debugConfigs.end(); ++li)
+      {
+      configString += ",$<CONFIG:" + *li + ">";
+      }
+    configString = "$<OR:" + configString + ">";
+    }
+
+  if (llt == OPTIMIZED)
+    {
+    configString = "$<NOT:" + configString + ">";
+    }
+  return "$<" + configString + ":" + value + ">";
+}
+
+//----------------------------------------------------------------------------
+static std::string targetNameGenex(const char *lib)
+{
+  return std::string("$<TARGET_NAME:") + lib + ">";
+}
+
 //----------------------------------------------------------------------------
 void cmTarget::AddLinkLibrary(cmMakefile& mf,
                               const char *target, const char* lib,
@@ -2140,6 +2225,18 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf,
     {
     return;
     }
+
+  {
+  cmTarget *tgt = this->Makefile->FindTargetToUse(lib);
+  const bool isNonImportedTarget = tgt && !tgt->IsImported();
+
+  std::string libName = isNonImportedTarget ? targetNameGenex(lib)
+                                          : std::string(lib);
+  this->AppendProperty("LINK_LIBRARIES",
+                       this->GetDebugGeneratorExpressions(libName,
+                                                          llt).c_str());
+  }
+
   cmTarget::LibraryID tmp;
   tmp.first = lib;
   tmp.second = llt;
@@ -3024,8 +3121,11 @@ class cmTargetCollectLinkLanguages
 {
 public:
   cmTargetCollectLinkLanguages(cmTarget* target, const char* config,
-                               std::set<cmStdString>& languages):
-    Config(config), Languages(languages) { this->Visited.insert(target); }
+                               std::set<cmStdString>& languages,
+                               cmTarget* head):
+    Config(config), Languages(languages), HeadTarget(head)
+  { this->Visited.insert(target); }
+
   void Visit(cmTarget* target)
     {
     if(!target || !this->Visited.insert(target).second)
@@ -3034,7 +3134,7 @@ public:
       }
 
     cmTarget::LinkInterface const* iface =
-      target->GetLinkInterface(this->Config);
+      target->GetLinkInterface(this->Config, this->HeadTarget);
     if(!iface) { return; }
 
     for(std::vector<std::string>::const_iterator
@@ -3053,26 +3153,30 @@ public:
 private:
   const char* Config;
   std::set<cmStdString>& Languages;
+  cmTarget* HeadTarget;
   std::set<cmTarget*> Visited;
 };
 
 //----------------------------------------------------------------------------
-const char* cmTarget::GetLinkerLanguage(const char* config)
+const char* cmTarget::GetLinkerLanguage(const char* config, cmTarget *head)
 {
-  const char* lang = this->GetLinkClosure(config)->LinkerLanguage.c_str();
+  cmTarget *headTarget = head ? head : this;
+  const char* lang = this->GetLinkClosure(config, headTarget)
+                                                    ->LinkerLanguage.c_str();
   return *lang? lang : 0;
 }
 
 //----------------------------------------------------------------------------
-cmTarget::LinkClosure const* cmTarget::GetLinkClosure(const char* config)
+cmTarget::LinkClosure const* cmTarget::GetLinkClosure(const char* config,
+                                                      cmTarget *head)
 {
-  std::string key = cmSystemTools::UpperCase(config? config : "");
+  TargetConfigPair key(head, cmSystemTools::UpperCase(config ? config : ""));
   cmTargetInternals::LinkClosureMapType::iterator
     i = this->Internal->LinkClosureMap.find(key);
   if(i == this->Internal->LinkClosureMap.end())
     {
     LinkClosure lc;
-    this->ComputeLinkClosure(config, lc);
+    this->ComputeLinkClosure(config, lc, head);
     cmTargetInternals::LinkClosureMapType::value_type entry(key, lc);
     i = this->Internal->LinkClosureMap.insert(entry).first;
     }
@@ -3133,11 +3237,12 @@ public:
 };
 
 //----------------------------------------------------------------------------
-void cmTarget::ComputeLinkClosure(const char* config, LinkClosure& lc)
+void cmTarget::ComputeLinkClosure(const char* config, LinkClosure& lc,
+                                  cmTarget *head)
 {
   // Get languages built in this target.
   std::set<cmStdString> languages;
-  LinkImplementation const* impl = this->GetLinkImplementation(config);
+  LinkImplementation const* impl = this->GetLinkImplementation(config, head);
   for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
       li != impl->Languages.end(); ++li)
     {
@@ -3145,7 +3250,7 @@ void cmTarget::ComputeLinkClosure(const char* config, LinkClosure& lc)
     }
 
   // Add interface languages from linked targets.
-  cmTargetCollectLinkLanguages cll(this, config, languages);
+  cmTargetCollectLinkLanguages cll(this, config, languages, head);
   for(std::vector<std::string>::const_iterator li = impl->Libraries.begin();
       li != impl->Libraries.end(); ++li)
     {
@@ -3284,7 +3389,8 @@ bool cmTarget::HasSOName(const char* config)
   return ((this->GetType() == cmTarget::SHARED_LIBRARY ||
            this->GetType() == cmTarget::MODULE_LIBRARY) &&
           !this->GetPropertyAsBool("NO_SONAME") &&
-          this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config)));
+          this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config,
+                                                                this)));
 }
 
 //----------------------------------------------------------------------------
@@ -3293,7 +3399,7 @@ std::string cmTarget::GetSOName(const char* config)
   if(this->IsImported())
     {
     // Lookup the imported soname.
-    if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
+    if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this))
       {
       if(info->NoSOName)
         {
@@ -3330,7 +3436,7 @@ bool cmTarget::IsImportedSharedLibWithoutSOName(const char* config)
 {
   if(this->IsImported() && this->GetType() == cmTarget::SHARED_LIBRARY)
     {
-    if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
+    if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this))
       {
       return info->NoSOName;
       }
@@ -3444,7 +3550,7 @@ std::string cmTarget::NormalGetFullPath(const char* config, bool implib,
 std::string cmTarget::ImportedGetFullPath(const char* config, bool implib)
 {
   std::string result;
-  if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
+  if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this))
     {
     result = implib? info->ImportLibrary : info->Location;
     }
@@ -3529,7 +3635,7 @@ void cmTarget::GetFullNameInternal(const char* config,
   const char* suffixVar = this->GetSuffixVariableInternal(implib);
 
   // Check for language-specific default prefix and suffix.
-  if(const char* ll = this->GetLinkerLanguage(config))
+  if(const char* ll = this->GetLinkerLanguage(config, this))
     {
     if(!targetSuffix && suffixVar && *suffixVar)
       {
@@ -3900,7 +4006,7 @@ bool cmTarget::NeedRelinkBeforeInstall(const char* config)
     }
 
   // Check for rpath support on this platform.
-  if(const char* ll = this->GetLinkerLanguage(config))
+  if(const char* ll = this->GetLinkerLanguage(config, this))
     {
     std::string flagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
     flagVar += ll;
@@ -4322,7 +4428,7 @@ bool cmTarget::IsChrpathUsed(const char* config)
 
   // Enable if the rpath flag uses a separator and the target uses ELF
   // binaries.
-  if(const char* ll = this->GetLinkerLanguage(config))
+  if(const char* ll = this->GetLinkerLanguage(config, this))
     {
     std::string sepVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
     sepVar += ll;
@@ -4346,7 +4452,7 @@ bool cmTarget::IsChrpathUsed(const char* config)
 
 //----------------------------------------------------------------------------
 cmTarget::ImportInfo const*
-cmTarget::GetImportInfo(const char* config)
+cmTarget::GetImportInfo(const char* config, cmTarget *headTarget)
 {
   // There is no imported information for non-imported targets.
   if(!this->IsImported())
@@ -4365,14 +4471,16 @@ cmTarget::GetImportInfo(const char* config)
     {
     config_upper = "NOCONFIG";
     }
+  TargetConfigPair key(headTarget, config_upper);
   typedef cmTargetInternals::ImportInfoMapType ImportInfoMapType;
+
   ImportInfoMapType::const_iterator i =
-    this->Internal->ImportInfoMap.find(config_upper);
+    this->Internal->ImportInfoMap.find(key);
   if(i == this->Internal->ImportInfoMap.end())
     {
     ImportInfo info;
-    this->ComputeImportInfo(config_upper, info);
-    ImportInfoMapType::value_type entry(config_upper, info);
+    this->ComputeImportInfo(config_upper, info, headTarget);
+    ImportInfoMapType::value_type entry(key, info);
     i = this->Internal->ImportInfoMap.insert(entry).first;
     }
 
@@ -4511,8 +4619,10 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config,
 
 //----------------------------------------------------------------------------
 void cmTarget::ComputeImportInfo(std::string const& desired_config,
-                                 ImportInfo& info)
+                                 ImportInfo& info,
+                                 cmTarget *headTarget)
 {
+  (void)headTarget;
   // This method finds information about an imported target from its
   // properties.  The "IMPORTED_" namespace is reserved for properties
   // defined by the project exporting the target.
@@ -4669,12 +4779,13 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config,
 }
 
 //----------------------------------------------------------------------------
-cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config)
+cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config,
+                                                      cmTarget *head)
 {
   // Imported targets have their own link interface.
   if(this->IsImported())
     {
-    if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
+    if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, head))
       {
       return &info->LinkInterface;
       }
@@ -4690,14 +4801,15 @@ cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config)
     }
 
   // Lookup any existing link interface for this configuration.
-  std::string key = cmSystemTools::UpperCase(config? config : "");
+  TargetConfigPair key(head, cmSystemTools::UpperCase(config? config : ""));
+
   cmTargetInternals::LinkInterfaceMapType::iterator
     i = this->Internal->LinkInterfaceMap.find(key);
   if(i == this->Internal->LinkInterfaceMap.end())
     {
     // Compute the link interface for this configuration.
     cmTargetInternals::OptionalLinkInterface iface;
-    iface.Exists = this->ComputeLinkInterface(config, iface);
+    iface.Exists = this->ComputeLinkInterface(config, iface, head);
 
     // Store the information for this configuration.
     cmTargetInternals::LinkInterfaceMapType::value_type entry(key, iface);
@@ -4708,7 +4820,8 @@ cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config)
 }
 
 //----------------------------------------------------------------------------
-bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface)
+bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface,
+                                    cmTarget *headTarget)
 {
   // Construct the property name suffix for this configuration.
   std::string suffix = "_";
@@ -4765,7 +4878,8 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface)
         {
         emitted.insert(*li);
         }
-      LinkImplementation const* impl = this->GetLinkImplementation(config);
+      LinkImplementation const* impl = this->GetLinkImplementation(config,
+                                                                headTarget);
       for(std::vector<std::string>::const_iterator
             li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li)
         {
@@ -4793,7 +4907,8 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface)
   else
     {
     // The link implementation is the default link interface.
-    LinkImplementation const* impl = this->GetLinkImplementation(config);
+    LinkImplementation const* impl = this->GetLinkImplementation(config,
+                                                              headTarget);
     iface.Libraries = impl->Libraries;
     iface.WrongConfigLibraries = impl->WrongConfigLibraries;
     if(this->GetType() == cmTarget::STATIC_LIBRARY)
@@ -4825,7 +4940,7 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface)
 
 //----------------------------------------------------------------------------
 cmTarget::LinkImplementation const*
-cmTarget::GetLinkImplementation(const char* config)
+cmTarget::GetLinkImplementation(const char* config, cmTarget *head)
 {
   // There is no link implementation for imported targets.
   if(this->IsImported())
@@ -4834,14 +4949,15 @@ cmTarget::GetLinkImplementation(const char* config)
     }
 
   // Lookup any existing link implementation for this configuration.
-  std::string key = cmSystemTools::UpperCase(config? config : "");
+  TargetConfigPair key(head, cmSystemTools::UpperCase(config? config : ""));
+
   cmTargetInternals::LinkImplMapType::iterator
     i = this->Internal->LinkImplMap.find(key);
   if(i == this->Internal->LinkImplMap.end())
     {
     // Compute the link implementation for this configuration.
     LinkImplementation impl;
-    this->ComputeLinkImplementation(config, impl);
+    this->ComputeLinkImplementation(config, impl, head);
 
     // Store the information for this configuration.
     cmTargetInternals::LinkImplMapType::value_type entry(key, impl);
@@ -4853,27 +4969,26 @@ cmTarget::GetLinkImplementation(const char* config)
 
 //----------------------------------------------------------------------------
 void cmTarget::ComputeLinkImplementation(const char* config,
-                                         LinkImplementation& impl)
+                                         LinkImplementation& impl,
+                                         cmTarget *head)
 {
   // Compute which library configuration to link.
   cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config);
 
   // Collect libraries directly linked in this configuration.
-  LinkLibraryVectorType const& llibs = this->GetOriginalLinkLibraries();
-  for(cmTarget::LinkLibraryVectorType::const_iterator li = llibs.begin();
+  std::vector<std::string> llibs;
+  this->GetDirectLinkLibraries(config, llibs, head);
+  for(std::vector<std::string>::const_iterator li = llibs.begin();
       li != llibs.end(); ++li)
     {
     // Skip entries that resolve to the target itself or are empty.
-    std::string item = this->CheckCMP0004(li->first);
+    std::string item = this->CheckCMP0004(*li);
     if(item == this->GetName() || item.empty())
       {
       continue;
       }
-    if(li->second == cmTarget::GENERAL || li->second == linkType)
-      {
-      // The entry is meant for this configuration.
-      impl.Libraries.push_back(item);
-      }
+    // The entry is meant for this configuration.
+    impl.Libraries.push_back(item);
     }
 
   LinkLibraryVectorType const& oldllibs = this->GetOriginalLinkLibraries();
@@ -4977,16 +5092,19 @@ std::string cmTarget::CheckCMP0004(std::string const& item)
 
 //----------------------------------------------------------------------------
 cmComputeLinkInformation*
-cmTarget::GetLinkInformation(const char* config)
+cmTarget::GetLinkInformation(const char* config, cmTarget *head)
 {
+  cmTarget *headTarget = head ? head : this;
   // Lookup any existing information for this configuration.
-  std::map<cmStdString, cmComputeLinkInformation*>::iterator
-    i = this->LinkInformation.find(config?config:"");
+  TargetConfigPair key(headTarget,
+                                  cmSystemTools::UpperCase(config?config:""));
+  cmTargetLinkInformationMap::iterator
+    i = this->LinkInformation.find(key);
   if(i == this->LinkInformation.end())
     {
     // Compute information for this configuration.
     cmComputeLinkInformation* info =
-      new cmComputeLinkInformation(this, config);
+      new cmComputeLinkInformation(this, config, headTarget);
     if(!info || !info->Compute())
       {
       delete info;
@@ -4994,8 +5112,7 @@ cmTarget::GetLinkInformation(const char* config)
       }
 
     // Store the information for this configuration.
-    std::map<cmStdString, cmComputeLinkInformation*>::value_type
-      entry(config?config:"", info);
+    cmTargetLinkInformationMap::value_type entry(key, info);
     i = this->LinkInformation.insert(entry).first;
     }
   return i->second;

+ 26 - 12
Source/cmTarget.h

@@ -25,11 +25,13 @@ class cmSourceFile;
 class cmGlobalGenerator;
 class cmComputeLinkInformation;
 class cmListFileBacktrace;
+class cmTarget;
 
 struct cmTargetLinkInformationMap:
-  public std::map<cmStdString, cmComputeLinkInformation*>
+  public std::map<std::pair<cmTarget*, std::string>, cmComputeLinkInformation*>
 {
-  typedef std::map<cmStdString, cmComputeLinkInformation*> derived;
+  typedef std::map<std::pair<cmTarget*, std::string>,
+                   cmComputeLinkInformation*> derived;
   cmTargetLinkInformationMap() {}
   cmTargetLinkInformationMap(cmTargetLinkInformationMap const& r);
   ~cmTargetLinkInformationMap();
@@ -166,6 +168,9 @@ public:
   return this->LinkLibraries;}
   const LinkLibraryVectorType &GetOriginalLinkLibraries() const
     {return this->OriginalLinkLibraries;}
+  void GetDirectLinkLibraries(const char *config,
+                              std::vector<std::string> &,
+                              cmTarget *head);
 
   /** Compute the link type to use for the given configuration.  */
   LinkLibraryType ComputeLinkType(const char* config);
@@ -258,7 +263,8 @@ public:
 
   /** Get the link interface for the given configuration.  Returns 0
       if the target cannot be linked.  */
-  LinkInterface const* GetLinkInterface(const char* config);
+  LinkInterface const* GetLinkInterface(const char* config,
+                                        cmTarget *headTarget);
 
   /** The link implementation specifies the direct library
       dependencies needed by the object files of the target.  */
@@ -274,7 +280,8 @@ public:
     // Needed only for OLD behavior of CMP0003.
     std::vector<std::string> WrongConfigLibraries;
   };
-  LinkImplementation const* GetLinkImplementation(const char* config);
+  LinkImplementation const* GetLinkImplementation(const char* config,
+                                                  cmTarget *head);
 
   /** Link information from the transitive closure of the link
       implementation and the interfaces of its dependencies.  */
@@ -286,7 +293,7 @@ public:
     // Languages whose runtime libraries must be linked.
     std::vector<std::string> Languages;
   };
-  LinkClosure const* GetLinkClosure(const char* config);
+  LinkClosure const* GetLinkClosure(const char* config, cmTarget *head);
 
   /** Strip off leading and trailing whitespace from an item named in
       the link dependencies of this target.  */
@@ -331,7 +338,7 @@ public:
   bool FindSourceFiles();
 
   ///! Return the preferred linker language for this target
-  const char* GetLinkerLanguage(const char* config = 0);
+  const char* GetLinkerLanguage(const char* config = 0, cmTarget *head = 0);
 
   /** Get the full name of the target according to the settings in its
       makefile.  */
@@ -399,7 +406,8 @@ public:
   std::string GetInstallNameDirForInstallTree(const char* config,
                                               bool for_xcode = false);
 
-  cmComputeLinkInformation* GetLinkInformation(const char* config);
+  cmComputeLinkInformation* GetLinkInformation(const char* config,
+                                               cmTarget *head = 0);
 
   // Get the properties
   cmPropertyMap &GetProperties() { return this->Properties; };
@@ -597,16 +605,19 @@ private:
 
   // Cache import information from properties for each configuration.
   struct ImportInfo;
-  ImportInfo const* GetImportInfo(const char* config);
-  void ComputeImportInfo(std::string const& desired_config, ImportInfo& info);
+  ImportInfo const* GetImportInfo(const char* config,
+                                        cmTarget *workingTarget);
+  void ComputeImportInfo(std::string const& desired_config, ImportInfo& info,
+                                        cmTarget *head);
 
   cmTargetLinkInformationMap LinkInformation;
 
-  bool ComputeLinkInterface(const char* config, LinkInterface& iface);
+  bool ComputeLinkInterface(const char* config, LinkInterface& iface,
+                                        cmTarget *head);
 
   void ComputeLinkImplementation(const char* config,
-                                 LinkImplementation& impl);
-  void ComputeLinkClosure(const char* config, LinkClosure& lc);
+                                 LinkImplementation& impl, cmTarget *head);
+  void ComputeLinkClosure(const char* config, LinkClosure& lc, cmTarget *head);
 
   void ClearLinkMaps();
 
@@ -614,6 +625,9 @@ private:
 
   void ProcessSourceExpression(std::string const& expr);
 
+  std::string GetDebugGeneratorExpressions(const std::string &value,
+                                  cmTarget::LinkLibraryType llt);
+
   // The cmMakefile instance that owns this target.  This should
   // always be set.
   cmMakefile* Makefile;

+ 7 - 0
Tests/CMakeCommands/target_link_libraries/CMakeLists.txt

@@ -34,6 +34,13 @@ generate_export_header(depB)
 
 target_link_libraries(depB LINK_PRIVATE depA)
 
+add_library(libgenex SHARED libgenex.cpp)
+generate_export_header(libgenex)
+
+set_property(TARGET depB APPEND PROPERTY
+  LINK_LIBRARIES $<1:libgenex>
+)
+
 add_library(depC SHARED depC.cpp)
 generate_export_header(depC)
 

+ 5 - 1
Tests/CMakeCommands/target_link_libraries/depB.cpp

@@ -3,9 +3,13 @@
 
 #include "depA.h"
 
+#include "libgenex.h"
+
 int DepB::foo()
 {
   DepA a;
 
-  return a.foo();
+  LibGenex lg;
+
+  return a.foo() + lg.foo();
 }

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

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

+ 12 - 0
Tests/CMakeCommands/target_link_libraries/libgenex.h

@@ -0,0 +1,12 @@
+
+#include "libgenex_export.h"
+
+#ifndef LIBGENEX_H
+#define LIBGENEX_H
+
+struct LIBGENEX_EXPORT LibGenex
+{
+  int foo();
+};
+
+#endif