Browse Source

Merge topic 'refactor-link-internals'

c45dd669 cmTarget: Cache compatible interface property sets
89095514 cmTarget: Refactor GetLinkImplementationClosure internals
9d72df45 Genex: Adjust code layout slightly
d5f0743d Genex: Refactor empty element strip
60bafeb6 Genex: Avoid repeated search of transitive property whitelist
8cb91054 Genex: Simplify TARGET_PROPERTY transitive lookup
0a8fbac1 cmTarget: Drop GetTransitivePropertyTargets method
fb3518dc Refactor system include annotation propagation
535fd6ce cmTarget: Make GetLink*Libraries methods safer to use
Brad King 11 years ago
parent
commit
e4510941a3
4 changed files with 165 additions and 229 deletions
  1. 64 97
      Source/cmGeneratorExpressionEvaluator.cxx
  2. 7 34
      Source/cmGeneratorTarget.cxx
  3. 62 79
      Source/cmTarget.cxx
  4. 32 19
      Source/cmTarget.h

+ 64 - 97
Source/cmGeneratorExpressionEvaluator.cxx

@@ -799,70 +799,51 @@ static const char* targetPropertyTransitiveWhitelist[] = {
 
 #undef TRANSITIVE_PROPERTY_NAME
 
+template <typename T>
 std::string
 getLinkedTargetsContent(
-  std::vector<cmTarget const*> &targets,
+  std::vector<T> const &libraries,
   cmTarget const* target,
   cmTarget const* headTarget,
   cmGeneratorExpressionContext *context,
   cmGeneratorExpressionDAGChecker *dagChecker,
   const std::string &interfacePropertyName)
 {
-  cmGeneratorExpression ge(&context->Backtrace);
-
+  std::string linkedTargetsContent;
   std::string sep;
   std::string depString;
-  for (std::vector<cmTarget const*>::const_iterator
-      it = targets.begin();
-      it != targets.end(); ++it)
+  for (typename std::vector<T>::const_iterator it = libraries.begin();
+       it != libraries.end(); ++it)
     {
-    if (*it == target)
-      {
-      // Broken code can have a target in its own link interface.
-      // Don't follow such link interface entries so as not to create a
-      // self-referencing loop.
-      continue;
+    // Broken code can have a target in its own link interface.
+    // Don't follow such link interface entries so as not to create a
+    // self-referencing loop.
+    if (it->Target && it->Target != target)
+      {
+      depString +=
+        sep + "$<TARGET_PROPERTY:" +
+        it->Target->GetName() + "," + interfacePropertyName + ">";
+      sep = ";";
       }
-    depString +=
-      sep + "$<TARGET_PROPERTY:" +
-        (*it)->GetName() + "," + interfacePropertyName + ">";
-    sep = ";";
     }
-  cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(depString);
-  std::string linkedTargetsContent = cge->Evaluate(target->GetMakefile(),
-                      context->Config,
-                      context->Quiet,
-                      headTarget,
-                      target,
-                      dagChecker);
-  if (cge->GetHadContextSensitiveCondition())
+  if(!depString.empty())
     {
-    context->HadContextSensitiveCondition = true;
-    }
-  return linkedTargetsContent;
-}
-
-std::string
-getLinkedTargetsContent(
-  std::vector<cmLinkImplItem> const &libraries,
-  cmTarget const* target,
-  cmTarget const* headTarget,
-  cmGeneratorExpressionContext *context,
-  cmGeneratorExpressionDAGChecker *dagChecker,
-  const std::string &interfacePropertyName)
-{
-  std::vector<cmTarget const*> tgts;
-  for (std::vector<cmLinkImplItem>::const_iterator
-      it = libraries.begin();
-      it != libraries.end(); ++it)
-    {
-    if (it->Target)
-      {
-      tgts.push_back(it->Target);
+    cmGeneratorExpression ge(&context->Backtrace);
+    cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(depString);
+    linkedTargetsContent = cge->Evaluate(target->GetMakefile(),
+                                         context->Config,
+                                         context->Quiet,
+                                         headTarget,
+                                         target,
+                                         dagChecker);
+    if (cge->GetHadContextSensitiveCondition())
+      {
+      context->HadContextSensitiveCondition = true;
       }
     }
-  return getLinkedTargetsContent(tgts, target, headTarget, context,
-                                 dagChecker, interfacePropertyName);
+  linkedTargetsContent =
+    cmGeneratorExpression::StripEmptyListElements(linkedTargetsContent);
+  return linkedTargetsContent;
 }
 
 //----------------------------------------------------------------------------
@@ -1058,18 +1039,24 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
           CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
                                             ASSERT_TRANSITIVE_PROPERTY_METHOD)
           false);
-        }
 #undef ASSERT_TRANSITIVE_PROPERTY_METHOD
+        }
       }
 
     std::string linkedTargetsContent;
 
     std::string interfacePropertyName;
+    bool isInterfaceProperty = false;
 
 #define POPULATE_INTERFACE_PROPERTY_NAME(prop) \
-    if (propertyName == #prop || propertyName == "INTERFACE_" #prop) \
+    if (propertyName == #prop) \
+      { \
+      interfacePropertyName = "INTERFACE_" #prop; \
+      } \
+    else if (propertyName == "INTERFACE_" #prop) \
       { \
       interfacePropertyName = "INTERFACE_" #prop; \
+      isInterfaceProperty = true; \
       } \
     else
 
@@ -1086,49 +1073,34 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
         }
       }
 #undef POPULATE_INTERFACE_PROPERTY_NAME
-
     cmTarget const* headTarget = context->HeadTarget
                                ? context->HeadTarget : target;
 
-    const char * const *transBegin =
-                        cmArrayBegin(targetPropertyTransitiveWhitelist) + 1;
-    const char * const *transEnd =
-                        cmArrayEnd(targetPropertyTransitiveWhitelist);
-
-    if (std::find_if(transBegin, transEnd,
-                     cmStrCmp(propertyName)) != transEnd)
+    if(isInterfaceProperty)
       {
-
-      std::vector<cmTarget const*> tgts;
-      target->GetTransitivePropertyTargets(context->Config,
-                                                 headTarget, tgts);
-      if (!tgts.empty())
+      if(cmTarget::LinkInterfaceLibraries const* iface =
+         target->GetLinkInterfaceLibraries(context->Config, headTarget, true))
         {
         linkedTargetsContent =
-                  getLinkedTargetsContent(tgts, target,
-                                          headTarget,
-                                          context, &dagChecker,
-                                          interfacePropertyName);
+          getLinkedTargetsContent(iface->Libraries, target,
+                                  headTarget,
+                                  context, &dagChecker,
+                                  interfacePropertyName);
         }
       }
-    else if (std::find_if(transBegin, transEnd,
-                          cmStrCmp(interfacePropertyName)) != transEnd)
+    else if(!interfacePropertyName.empty())
       {
-      const cmTarget::LinkImplementation *impl
-        = target->GetLinkImplementationLibraries(context->Config);
-      if(impl)
+      if(cmTarget::LinkImplementationLibraries const* impl =
+         target->GetLinkImplementationLibraries(context->Config))
         {
         linkedTargetsContent =
-                  getLinkedTargetsContent(impl->Libraries, target,
-                                          headTarget,
-                                          context, &dagChecker,
-                                          interfacePropertyName);
+          getLinkedTargetsContent(impl->Libraries, target,
+                                  headTarget,
+                                  context, &dagChecker,
+                                  interfacePropertyName);
         }
       }
 
-    linkedTargetsContent =
-          cmGeneratorExpression::StripEmptyListElements(linkedTargetsContent);
-
     if (!prop)
       {
       if (target->IsImported()
@@ -1202,32 +1174,27 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
         return propContent ? propContent : "";
         }
       }
-    for (size_t i = 1;
-         i < cmArraySize(targetPropertyTransitiveWhitelist);
-         ++i)
+    if(!interfacePropertyName.empty())
       {
-      if (targetPropertyTransitiveWhitelist[i] == interfacePropertyName)
-        {
-        cmGeneratorExpression ge(&context->Backtrace);
-        cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
-        cge->SetEvaluateForBuildsystem(context->EvaluateForBuildsystem);
-        std::string result = cge->Evaluate(context->Makefile,
+      cmGeneratorExpression ge(&context->Backtrace);
+      cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
+      cge->SetEvaluateForBuildsystem(context->EvaluateForBuildsystem);
+      std::string result = cge->Evaluate(context->Makefile,
                             context->Config,
                             context->Quiet,
                             headTarget,
                             target,
                             &dagChecker);
 
-        if (cge->GetHadContextSensitiveCondition())
-          {
-          context->HadContextSensitiveCondition = true;
-          }
-        if (!linkedTargetsContent.empty())
-          {
-          result += (result.empty() ? "" : ";") + linkedTargetsContent;
-          }
-        return result;
+      if (cge->GetHadContextSensitiveCondition())
+        {
+        context->HadContextSensitiveCondition = true;
+        }
+      if (!linkedTargetsContent.empty())
+        {
+        result += (result.empty() ? "" : ";") + linkedTargetsContent;
         }
+      return result;
       }
     return prop;
   }

+ 7 - 34
Source/cmGeneratorTarget.cxx

@@ -445,13 +445,6 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(const std::string& dir,
 
   if (iter == this->SystemIncludesCache.end())
     {
-    cmTarget::LinkImplementation const* impl
-      = this->Target->GetLinkImplementation(config);
-    if(!impl)
-      {
-      return false;
-      }
-
     cmGeneratorExpressionDAGChecker dagChecker(
                                         this->GetName(),
                                         "SYSTEM_INCLUDE_DIRECTORIES", 0, 0);
@@ -471,35 +464,15 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(const std::string& dir,
                                           &dagChecker), result);
       }
 
-    std::set<cmTarget const*> uniqueDeps;
-    for(std::vector<cmLinkImplItem>::const_iterator
-          li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li)
+    std::vector<cmTarget const*> const& deps =
+      this->Target->GetLinkImplementationClosure(config);
+    for(std::vector<cmTarget const*>::const_iterator
+          li = deps.begin(), le = deps.end(); li != le; ++li)
       {
-      cmTarget const* tgt = li->Target;
-      if (!tgt)
-        {
-        continue;
-        }
-
-      if (uniqueDeps.insert(tgt).second)
-        {
-        handleSystemIncludesDep(this->Makefile, tgt, config, this->Target,
-                                &dagChecker, result, excludeImported);
-
-        std::vector<cmTarget const*> deps;
-        tgt->GetTransitivePropertyTargets(config, this->Target, deps);
-
-        for(std::vector<cmTarget const*>::const_iterator di = deps.begin();
-            di != deps.end(); ++di)
-          {
-          if (uniqueDeps.insert(*di).second)
-            {
-            handleSystemIncludesDep(this->Makefile, *di, config, this->Target,
-                                    &dagChecker, result, excludeImported);
-            }
-          }
-        }
+      handleSystemIncludesDep(this->Makefile, *li, config, this->Target,
+                              &dagChecker, result, excludeImported);
       }
+
     std::set<std::string> unique;
     for(std::vector<std::string>::iterator li = result.begin();
         li != result.end(); ++li)

+ 62 - 79
Source/cmTarget.cxx

@@ -164,6 +164,20 @@ public:
   typedef std::map<std::string, cmTarget::LinkClosure> LinkClosureMapType;
   LinkClosureMapType LinkClosureMap;
 
+  struct LinkImplClosure: public std::vector<cmTarget const*>
+  {
+    LinkImplClosure(): Done(false) {}
+    bool Done;
+  };
+  std::map<std::string, LinkImplClosure> LinkImplClosureMap;
+
+  struct CompatibleInterfaces: public cmTarget::CompatibleInterfaces
+  {
+    CompatibleInterfaces(): Done(false) {}
+    bool Done;
+  };
+  std::map<std::string, CompatibleInterfaces> CompatibleInterfacesMap;
+
   typedef std::map<std::string, std::vector<cmSourceFile*> >
                                                        SourceFilesMapType;
   SourceFilesMapType SourceFilesMap;
@@ -203,15 +217,12 @@ public:
                         CachedLinkInterfaceSourcesEntries;
   std::map<std::string, std::vector<TargetPropertyEntry*> >
                         CachedLinkInterfaceCompileFeaturesEntries;
-  std::map<std::string, std::vector<cmTarget const*> >
-                        CachedLinkImplementationClosure;
 
   std::map<std::string, bool> CacheLinkInterfaceIncludeDirectoriesDone;
   std::map<std::string, bool> CacheLinkInterfaceCompileDefinitionsDone;
   std::map<std::string, bool> CacheLinkInterfaceCompileOptionsDone;
   std::map<std::string, bool> CacheLinkInterfaceSourcesDone;
   std::map<std::string, bool> CacheLinkInterfaceCompileFeaturesDone;
-  std::map<std::string, bool> CacheLinkImplementationClosureDone;
 };
 
 cmLinkImplItem cmTargetInternals::TargetPropertyEntry::NoLinkImplItem;
@@ -4379,7 +4390,7 @@ bool cmTarget::HaveBuildTreeRPATH(const std::string& config) const
     {
     return false;
     }
-  if(LinkImplementation const* impl =
+  if(LinkImplementationLibraries const* impl =
      this->GetLinkImplementationLibraries(config))
     {
     return !impl->Libraries.empty();
@@ -5298,44 +5309,6 @@ const char * cmTarget::GetLinkInterfaceDependentNumberMaxProperty(
                                                            NumberMaxType, 0);
 }
 
-//----------------------------------------------------------------------------
-bool isLinkDependentProperty(cmTarget const* tgt, const std::string &p,
-                             const std::string& interfaceProperty,
-                             const std::string& config)
-{
-  std::vector<cmTarget const*> const& deps =
-    tgt->GetLinkImplementationClosure(config);
-
-  if(deps.empty())
-    {
-    return false;
-    }
-
-  for(std::vector<cmTarget const*>::const_iterator li = deps.begin();
-      li != deps.end(); ++li)
-    {
-    const char *prop = (*li)->GetProperty(interfaceProperty);
-    if (!prop)
-      {
-      continue;
-      }
-
-    std::vector<std::string> props;
-    cmSystemTools::ExpandListArgument(prop, props);
-
-    for(std::vector<std::string>::iterator pi = props.begin();
-        pi != props.end(); ++pi)
-      {
-      if (*pi == p)
-        {
-        return true;
-        }
-      }
-    }
-
-  return false;
-}
-
 //----------------------------------------------------------------------------
 bool cmTarget::IsLinkInterfaceDependentBoolProperty(const std::string &p,
                                            const std::string& config) const
@@ -5345,9 +5318,7 @@ bool cmTarget::IsLinkInterfaceDependentBoolProperty(const std::string &p,
     {
     return false;
     }
-  return (p == "POSITION_INDEPENDENT_CODE") ||
-    isLinkDependentProperty(this, p, "COMPATIBLE_INTERFACE_BOOL",
-                                 config);
+  return this->GetCompatibleInterfaces(config).PropsBool.count(p) > 0;
 }
 
 //----------------------------------------------------------------------------
@@ -5359,9 +5330,7 @@ bool cmTarget::IsLinkInterfaceDependentStringProperty(const std::string &p,
     {
     return false;
     }
-  return (p == "AUTOUIC_OPTIONS") ||
-    isLinkDependentProperty(this, p, "COMPATIBLE_INTERFACE_STRING",
-                                 config);
+  return this->GetCompatibleInterfaces(config).PropsString.count(p) > 0;
 }
 
 //----------------------------------------------------------------------------
@@ -5373,8 +5342,7 @@ bool cmTarget::IsLinkInterfaceDependentNumberMinProperty(const std::string &p,
     {
     return false;
     }
-  return isLinkDependentProperty(this, p, "COMPATIBLE_INTERFACE_NUMBER_MIN",
-                                 config);
+  return this->GetCompatibleInterfaces(config).PropsNumberMin.count(p) > 0;
 }
 
 //----------------------------------------------------------------------------
@@ -5386,8 +5354,7 @@ bool cmTarget::IsLinkInterfaceDependentNumberMaxProperty(const std::string &p,
     {
     return false;
     }
-  return isLinkDependentProperty(this, p, "COMPATIBLE_INTERFACE_NUMBER_MAX",
-                                 config);
+  return this->GetCompatibleInterfaces(config).PropsNumberMax.count(p) > 0;
 }
 
 //----------------------------------------------------------------------------
@@ -5935,7 +5902,7 @@ cmTarget::LinkInterface const* cmTarget::GetLinkInterface(
 }
 
 //----------------------------------------------------------------------------
-cmTarget::LinkInterface const*
+cmTarget::LinkInterfaceLibraries const*
 cmTarget::GetLinkInterfaceLibraries(const std::string& config,
                                     cmTarget const* head,
                                     bool usage_requirements_only) const
@@ -6017,7 +5984,7 @@ void processILibs(const std::string& config,
   if (item.Target && emitted.insert(item.Target).second)
     {
     tgts.push_back(item.Target);
-    if(cmTarget::LinkInterface const* iface =
+    if(cmTarget::LinkInterfaceLibraries const* iface =
        item.Target->GetLinkInterfaceLibraries(config, headTarget, true))
       {
       for(std::vector<cmLinkItem>::const_iterator
@@ -6034,14 +6001,14 @@ void processILibs(const std::string& config,
 std::vector<cmTarget const*> const&
 cmTarget::GetLinkImplementationClosure(const std::string& config) const
 {
-  std::vector<cmTarget const*>& tgts =
-    this->Internal->CachedLinkImplementationClosure[config];
-  if(!this->Internal->CacheLinkImplementationClosureDone[config])
+  cmTargetInternals::LinkImplClosure& tgts =
+    this->Internal->LinkImplClosureMap[config];
+  if(!tgts.Done)
     {
-    this->Internal->CacheLinkImplementationClosureDone[config] = true;
+    tgts.Done = true;
     std::set<cmTarget const*> emitted;
 
-    cmTarget::LinkImplementation const* impl
+    cmTarget::LinkImplementationLibraries const* impl
       = this->GetLinkImplementationLibraries(config);
 
     for(std::vector<cmLinkImplItem>::const_iterator
@@ -6055,22 +6022,37 @@ cmTarget::GetLinkImplementationClosure(const std::string& config) const
 }
 
 //----------------------------------------------------------------------------
-void cmTarget::GetTransitivePropertyTargets(const std::string& config,
-                                      cmTarget const* headTarget,
-                                      std::vector<cmTarget const*> &tgts) const
+cmTarget::CompatibleInterfaces const&
+cmTarget::GetCompatibleInterfaces(std::string const& config) const
 {
-  if(cmTarget::LinkInterface const* iface =
-     this->GetLinkInterfaceLibraries(config, headTarget, true))
+  cmTargetInternals::CompatibleInterfaces& compat =
+    this->Internal->CompatibleInterfacesMap[config];
+  if(!compat.Done)
     {
-    for(std::vector<cmLinkItem>::const_iterator it = iface->Libraries.begin();
-        it != iface->Libraries.end(); ++it)
+    compat.Done = true;
+    compat.PropsBool.insert("POSITION_INDEPENDENT_CODE");
+    compat.PropsString.insert("AUTOUIC_OPTIONS");
+    std::vector<cmTarget const*> const& deps =
+      this->GetLinkImplementationClosure(config);
+    for(std::vector<cmTarget const*>::const_iterator li = deps.begin();
+        li != deps.end(); ++li)
       {
-      if (it->Target)
-        {
-        tgts.push_back(it->Target);
+#define CM_READ_COMPATIBLE_INTERFACE(X, x) \
+      if(const char* prop = (*li)->GetProperty("COMPATIBLE_INTERFACE_" #X)) \
+        { \
+        std::vector<std::string> props; \
+        cmSystemTools::ExpandListArgument(prop, props); \
+        std::copy(props.begin(), props.end(), \
+                  std::inserter(compat.Props##x, compat.Props##x.begin())); \
         }
+      CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool)
+      CM_READ_COMPATIBLE_INTERFACE(STRING, String)
+      CM_READ_COMPATIBLE_INTERFACE(NUMBER_MIN, NumberMin)
+      CM_READ_COMPATIBLE_INTERFACE(NUMBER_MAX, NumberMax)
+#undef CM_READ_COMPATIBLE_INTERFACE
       }
     }
+  return compat;
 }
 
 //----------------------------------------------------------------------------
@@ -6177,7 +6159,7 @@ cmTargetInternals::ComputeLinkInterfaceLibraries(
     // to the link implementation.
     {
     // The link implementation is the default link interface.
-    cmTarget::LinkImplementation const* impl =
+    cmTarget::LinkImplementationLibraries const* impl =
       thisTarget->GetLinkImplementationLibrariesInternal(config, headTarget);
     std::copy(impl->Libraries.begin(), impl->Libraries.end(),
               std::back_inserter(iface.Libraries));
@@ -6294,7 +6276,7 @@ void cmTargetInternals::ComputeLinkInterface(cmTarget const* thisTarget,
         || thisTarget->PolicyStatusCMP0022 == cmPolicies::OLD)
     {
     // The link implementation is the default link interface.
-    cmTarget::LinkImplementation const*
+    cmTarget::LinkImplementationLibraries const*
       impl = thisTarget->GetLinkImplementationLibrariesInternal(config,
                                                                 headTarget);
     iface.ImplementationIsInterface = true;
@@ -6345,7 +6327,7 @@ void cmTargetInternals::AddInterfaceEntries(
   cmTarget const* thisTarget, std::string const& config,
   std::string const& prop, std::vector<TargetPropertyEntry*>& entries)
 {
-  if(cmTarget::LinkImplementation const* impl =
+  if(cmTarget::LinkImplementationLibraries const* impl =
      thisTarget->GetLinkImplementationLibraries(config))
     {
     for (std::vector<cmLinkImplItem>::const_iterator
@@ -6383,7 +6365,7 @@ cmTarget::GetLinkImplementation(const std::string& config) const
   if(!impl.LibrariesDone)
     {
     impl.LibrariesDone = true;
-    this->ComputeLinkImplementation(config, impl, this);
+    this->ComputeLinkImplementationLibraries(config, impl, this);
     }
   if(!impl.LanguagesDone)
     {
@@ -6394,14 +6376,14 @@ cmTarget::GetLinkImplementation(const std::string& config) const
 }
 
 //----------------------------------------------------------------------------
-cmTarget::LinkImplementation const*
+cmTarget::LinkImplementationLibraries const*
 cmTarget::GetLinkImplementationLibraries(const std::string& config) const
 {
   return this->GetLinkImplementationLibrariesInternal(config, this);
 }
 
 //----------------------------------------------------------------------------
-cmTarget::LinkImplementation const*
+cmTarget::LinkImplementationLibraries const*
 cmTarget::GetLinkImplementationLibrariesInternal(const std::string& config,
                                                  cmTarget const* head) const
 {
@@ -6418,15 +6400,16 @@ cmTarget::GetLinkImplementationLibrariesInternal(const std::string& config,
   if(!impl.LibrariesDone)
     {
     impl.LibrariesDone = true;
-    this->ComputeLinkImplementation(config, impl, head);
+    this->ComputeLinkImplementationLibraries(config, impl, head);
     }
   return &impl;
 }
 
 //----------------------------------------------------------------------------
-void cmTarget::ComputeLinkImplementation(const std::string& config,
-                                         LinkImplementation& impl,
-                                         cmTarget const* head) const
+void
+cmTarget::ComputeLinkImplementationLibraries(const std::string& config,
+                                             LinkImplementation& impl,
+                                             cmTarget const* head) const
 {
   // Collect libraries directly linked in this configuration.
   for (std::vector<cmValueWithOrigin>::const_iterator

+ 32 - 19
Source/cmTarget.h

@@ -262,13 +262,15 @@ public:
 
   /** The link interface specifies transitive library dependencies and
       other information needed by targets that link to this target.  */
-  struct LinkInterface
+  struct LinkInterfaceLibraries
   {
-    // Languages whose runtime libraries must be linked.
-    std::vector<std::string> Languages;
-
     // Libraries listed in the interface.
     std::vector<cmLinkItem> Libraries;
+  };
+  struct LinkInterface: public LinkInterfaceLibraries
+  {
+    // Languages whose runtime libraries must be linked.
+    std::vector<std::string> Languages;
 
     // Shared library dependencies needed for linking on some platforms.
     std::vector<cmLinkItem> SharedDeps;
@@ -290,22 +292,28 @@ public:
       if the target cannot be linked.  */
   LinkInterface const* GetLinkInterface(const std::string& config,
                                         cmTarget const* headTarget) const;
-  LinkInterface const* GetLinkInterfaceLibraries(const std::string& config,
-                                        cmTarget const* headTarget,
-                                        bool usage_requirements_only) const;
-  void GetTransitivePropertyTargets(const std::string& config,
-                                    cmTarget const* headTarget,
-                                    std::vector<cmTarget const*> &libs) const;
+  LinkInterfaceLibraries const*
+    GetLinkInterfaceLibraries(const std::string& config,
+                              cmTarget const* headTarget,
+                              bool usage_requirements_only) const;
+
   std::vector<cmTarget const*> const&
     GetLinkImplementationClosure(const std::string& config) const;
 
+  struct CompatibleInterfaces
+  {
+    std::set<std::string> PropsBool;
+    std::set<std::string> PropsString;
+    std::set<std::string> PropsNumberMax;
+    std::set<std::string> PropsNumberMin;
+  };
+  CompatibleInterfaces const&
+    GetCompatibleInterfaces(std::string const& config) const;
+
   /** The link implementation specifies the direct library
       dependencies needed by the object files of the target.  */
-  struct LinkImplementation
+  struct LinkImplementationLibraries
   {
-    // Languages whose runtime libraries must be linked.
-    std::vector<std::string> Languages;
-
     // Libraries linked directly in this configuration.
     std::vector<cmLinkImplItem> Libraries;
 
@@ -313,10 +321,15 @@ public:
     // Needed only for OLD behavior of CMP0003.
     std::vector<cmLinkItem> WrongConfigLibraries;
   };
+  struct LinkImplementation: public LinkImplementationLibraries
+  {
+    // Languages whose runtime libraries must be linked.
+    std::vector<std::string> Languages;
+  };
   LinkImplementation const*
     GetLinkImplementation(const std::string& config) const;
 
-  LinkImplementation const*
+  LinkImplementationLibraries const*
     GetLinkImplementationLibraries(const std::string& config) const;
 
   /** Link information from the transitive closure of the link
@@ -778,12 +791,12 @@ private:
     GetImportLinkInterface(const std::string& config, cmTarget const* head,
                            bool usage_requirements_only) const;
 
-  LinkImplementation const*
+  LinkImplementationLibraries const*
     GetLinkImplementationLibrariesInternal(const std::string& config,
                                            cmTarget const* head) const;
-  void ComputeLinkImplementation(const std::string& config,
-                                 LinkImplementation& impl,
-                                 cmTarget const* head) const;
+  void ComputeLinkImplementationLibraries(const std::string& config,
+                                          LinkImplementation& impl,
+                                          cmTarget const* head) const;
   void ComputeLinkImplementationLanguages(const std::string& config,
                                           LinkImplementation& impl) const;
   void ComputeLinkClosure(const std::string& config, LinkClosure& lc) const;