Commit e4510941 authored by Brad King's avatar Brad King Committed by Kitware Robot
Browse files

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
parents bb4c1588 c45dd669
......@@ -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;
}
......
......@@ -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)
......
......@@ -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
......
......@@ -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,