Use the link information as a source of compile definitions and includes.

After evaluating the INTERFACE_INCLUDE_DIRECTORIES, of a target in a
generator expression, also read the INTERFACE_INCLUDE_DIRECTORIES of
its link interface dependencies.

That means that code such as this will result in the 'user' target
using /bar/include and /foo/include:

 add_library(foo ...)
 target_include_directories(foo INTERFACE /foo/include)
 add_library(bar ...)
 target_include_directories(bar INTERFACE /bar/include)
 target_link_libraries(bar LINK_PUBLIC foo)

 add_executable(user ...)
 target_include_directories(user PRIVATE
    $<TARGET_PROPERTY:bar,INTERFACE_INCLUDE_DIRECTORIES>)

Also process the interface include directories from direct link
dependencies for in-build targets.

The situation is similar for the INTERFACE_COMPILE_DEFINITIONS. The
include directories related code is currently more complex because
we also need to store a backtrace at configure-time for the purpose
of debugging includes. The compile definitions related code will use
the same pattern in the future.

This is not a change in behavior, as existing code has the same effect,
but that existing code will be removed in follow-up commits.
This commit is contained in:
Stephen Kelly 2013-02-12 11:29:09 +01:00
parent 5c9f5e313f
commit a1c4905f72
4 changed files with 231 additions and 70 deletions

View File

@ -451,15 +451,68 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
} }
const char *prop = target->GetProperty(propertyName.c_str()); const char *prop = target->GetProperty(propertyName.c_str());
std::string linkedTargetsContent;
if (dagCheckerParent)
{
if (dagCheckerParent->EvaluatingLinkLibraries())
{
if(!prop)
{
return std::string();
}
}
else
{
assert(dagCheckerParent->EvaluatingIncludeDirectories()
|| dagCheckerParent->EvaluatingCompileDefinitions());
if (propertyName == "INTERFACE_INCLUDE_DIRECTORIES"
|| propertyName == "INTERFACE_COMPILE_DEFINITIONS")
{
const cmTarget::LinkInterface *iface = target->GetLinkInterface(
context->Config,
context->HeadTarget);
if(iface)
{
cmGeneratorExpression ge(context->Backtrace);
std::string sep;
std::string depString;
for (std::vector<std::string>::const_iterator
it = iface->Libraries.begin();
it != iface->Libraries.end(); ++it)
{
if (context->Makefile->FindTargetToUse(it->c_str()))
{
depString +=
sep + "$<TARGET_PROPERTY:" + *it + "," + propertyName + ">";
sep = ";";
}
}
cmsys::auto_ptr<cmCompiledGeneratorExpression> cge =
ge.Parse(depString);
linkedTargetsContent = cge->Evaluate(context->Makefile,
context->Config,
context->Quiet,
context->HeadTarget,
target,
&dagChecker);
if (cge->GetHadContextSensitiveCondition())
{
context->HadContextSensitiveCondition = true;
}
}
}
}
}
if (!prop) if (!prop)
{ {
if (target->IsImported()) if (target->IsImported())
{ {
return std::string(); return linkedTargetsContent;
}
if (dagCheckerParent && dagCheckerParent->EvaluatingLinkLibraries())
{
return std::string();
} }
if (target->IsLinkInterfaceDependentBoolProperty(propertyName, if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
context->Config)) context->Config))
@ -480,7 +533,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
return propContent ? propContent : ""; return propContent ? propContent : "";
} }
return std::string(); return linkedTargetsContent;
} }
for (size_t i = 0; for (size_t i = 0;
@ -503,6 +556,10 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
{ {
context->HadContextSensitiveCondition = true; context->HadContextSensitiveCondition = true;
} }
if (!linkedTargetsContent.empty())
{
result += (result.empty() ? "" : ";") + linkedTargetsContent;
}
return result; return result;
} }
} }

View File

@ -137,6 +137,7 @@ public:
std::vector<std::string> CachedIncludes; std::vector<std::string> CachedIncludes;
}; };
std::vector<IncludeDirectoriesEntry*> IncludeDirectoriesEntries; std::vector<IncludeDirectoriesEntry*> IncludeDirectoriesEntries;
std::vector<cmValueWithOrigin> LinkInterfaceIncludeDirectoriesEntries;
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -2742,6 +2743,12 @@ void cmTarget::AppendBuildInterfaceIncludes()
} }
} }
//----------------------------------------------------------------------------
void cmTarget::AppendTllInclude(const cmValueWithOrigin &entry)
{
this->Internal->LinkInterfaceIncludeDirectoriesEntries.push_back(entry);
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmTarget::InsertInclude(const cmValueWithOrigin &entry, void cmTarget::InsertInclude(const cmValueWithOrigin &entry,
bool before) bool before)
@ -2756,6 +2763,73 @@ void cmTarget::InsertInclude(const cmValueWithOrigin &entry,
new cmTargetInternals::IncludeDirectoriesEntry(ge.Parse(entry.Value))); new cmTargetInternals::IncludeDirectoriesEntry(ge.Parse(entry.Value)));
} }
//----------------------------------------------------------------------------
static void processIncludeDirectories(cmTarget *tgt,
const std::vector<cmTargetInternals::IncludeDirectoriesEntry*> &entries,
std::vector<std::string> &includes,
std::set<std::string> &uniqueIncludes,
cmGeneratorExpressionDAGChecker *dagChecker,
const char *config, bool debugIncludes)
{
cmMakefile *mf = tgt->GetMakefile();
for (std::vector<cmTargetInternals::IncludeDirectoriesEntry*>::const_iterator
it = entries.begin(), end = entries.end(); it != end; ++it)
{
bool testIsOff = true;
bool cacheIncludes = false;
std::vector<std::string> entryIncludes = (*it)->CachedIncludes;
if(!entryIncludes.empty())
{
testIsOff = false;
}
else
{
cmSystemTools::ExpandListArgument((*it)->ge->Evaluate(mf,
config,
false,
tgt,
dagChecker),
entryIncludes);
if (mf->IsGeneratingBuildSystem()
&& !(*it)->ge->GetHadContextSensitiveCondition())
{
cacheIncludes = true;
}
}
std::string usedIncludes;
for(std::vector<std::string>::iterator
li = entryIncludes.begin(); li != entryIncludes.end(); ++li)
{
if (testIsOff && !cmSystemTools::IsOff(li->c_str()))
{
cmSystemTools::ConvertToUnixSlashes(*li);
}
std::string inc = *li;
if(uniqueIncludes.insert(inc).second)
{
includes.push_back(inc);
if (debugIncludes)
{
usedIncludes += " * " + inc + "\n";
}
}
}
if (cacheIncludes)
{
(*it)->CachedIncludes = entryIncludes;
}
if (!usedIncludes.empty())
{
mf->GetCMakeInstance()->IssueMessage(cmake::LOG,
std::string("Used includes for target ")
+ tgt->GetName() + ":\n"
+ usedIncludes, (*it)->ge->GetBacktrace());
}
}
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config) std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config)
{ {
@ -2788,63 +2862,50 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config)
this->DebugIncludesDone = true; this->DebugIncludesDone = true;
} }
for (std::vector<cmTargetInternals::IncludeDirectoriesEntry*>::const_iterator processIncludeDirectories(this,
it = this->Internal->IncludeDirectoriesEntries.begin(), this->Internal->IncludeDirectoriesEntries,
end = this->Internal->IncludeDirectoriesEntries.end(); includes,
uniqueIncludes,
&dagChecker,
config,
debugIncludes);
std::vector<cmTargetInternals::IncludeDirectoriesEntry*>
linkInterfaceIncludeDirectoriesEntries;
for (std::vector<cmValueWithOrigin>::const_iterator
it = this->Internal->LinkInterfaceIncludeDirectoriesEntries.begin(),
end = this->Internal->LinkInterfaceIncludeDirectoriesEntries.end();
it != end; ++it) it != end; ++it)
{ {
{
bool testIsOff = true; cmGeneratorExpression ge(lfbt);
bool cacheIncludes = false; cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(it->Value);
std::vector<std::string> entryIncludes = (*it)->CachedIncludes; std::string result = cge->Evaluate(this->Makefile, config,
if(!entryIncludes.empty()) false, this, 0, 0);
if (!this->Makefile->FindTargetToUse(result.c_str()))
{ {
testIsOff = false; continue;
}
else
{
cmSystemTools::ExpandListArgument((*it)->ge->Evaluate(this->Makefile,
config,
false,
this,
&dagChecker),
entryIncludes);
if (this->Makefile->IsGeneratingBuildSystem()
&& !(*it)->ge->GetHadContextSensitiveCondition())
{
cacheIncludes = true;
}
}
std::string usedIncludes;
for(std::vector<std::string>::iterator
li = entryIncludes.begin(); li != entryIncludes.end(); ++li)
{
if (testIsOff && !cmSystemTools::IsOff(li->c_str()))
{
cmSystemTools::ConvertToUnixSlashes(*li);
}
std::string inc = *li;
if(uniqueIncludes.insert(inc).second)
{
includes.push_back(inc);
if (debugIncludes)
{
usedIncludes += " * " + inc + "\n";
}
}
}
if (cacheIncludes)
{
(*it)->CachedIncludes = entryIncludes;
}
if (!usedIncludes.empty())
{
this->Makefile->GetCMakeInstance()->IssueMessage(cmake::LOG,
"Used includes for target " + this->Name + ":\n"
+ usedIncludes, (*it)->ge->GetBacktrace());
} }
} }
cmGeneratorExpression ge(it->Backtrace);
cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(
"$<TARGET_PROPERTY:" + it->Value + ",INTERFACE_INCLUDE_DIRECTORIES>");
linkInterfaceIncludeDirectoriesEntries.push_back(
new cmTargetInternals::IncludeDirectoriesEntry(cge));
}
processIncludeDirectories(this,
linkInterfaceIncludeDirectoriesEntries,
includes,
uniqueIncludes,
&dagChecker,
config,
debugIncludes);
deleteAndClear(linkInterfaceIncludeDirectoriesEntries);
return includes; return includes;
} }
@ -2858,23 +2919,57 @@ std::string cmTarget::GetCompileDefinitions(const char *config)
} }
const char *prop = this->GetProperty(defPropName.c_str()); const char *prop = this->GetProperty(defPropName.c_str());
cmListFileBacktrace lfbt;
cmGeneratorExpressionDAGChecker dagChecker(lfbt,
this->GetName(),
defPropName, 0, 0);
if (!prop) std::string result;
if (prop)
{ {
return ""; cmGeneratorExpression ge(lfbt);
result = ge.Parse(prop)->Evaluate(this->Makefile,
config,
false,
this,
&dagChecker);
} }
cmListFileBacktrace lfbt; std::vector<std::string> libs;
cmGeneratorExpression ge(lfbt); this->GetDirectLinkLibraries(config, libs, this);
cmGeneratorExpressionDAGChecker dagChecker(lfbt, if (libs.empty())
this->GetName(), {
defPropName, 0, 0); return result;
return ge.Parse(prop)->Evaluate(this->Makefile, }
config,
false, std::string sep;
this, std::string depString;
&dagChecker); for (std::vector<std::string>::const_iterator it = libs.begin();
it != libs.end(); ++it)
{
if (this->Makefile->FindTargetToUse(it->c_str()))
{
depString += sep + "$<TARGET_PROPERTY:"
+ *it + ",INTERFACE_COMPILE_DEFINITIONS>";
sep = ";";
}
}
cmGeneratorExpression ge2(lfbt);
cmsys::auto_ptr<cmCompiledGeneratorExpression> cge2 = ge2.Parse(depString);
std::string depResult = cge2->Evaluate(this->Makefile,
config,
false,
this,
&dagChecker);
if (!depResult.empty())
{
result += (result.empty() ? "" : ";") + depResult;
}
return result;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------

View File

@ -495,6 +495,7 @@ public:
std::vector<std::string> GetIncludeDirectories(const char *config); std::vector<std::string> GetIncludeDirectories(const char *config);
void InsertInclude(const cmValueWithOrigin &entry, void InsertInclude(const cmValueWithOrigin &entry,
bool before = false); bool before = false);
void AppendTllInclude(const cmValueWithOrigin &entry);
void AppendBuildInterfaceIncludes(); void AppendBuildInterfaceIncludes();

View File

@ -291,6 +291,14 @@ cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
// Handle normal case first. // Handle normal case first.
if(this->CurrentProcessingState != ProcessingLinkInterface) if(this->CurrentProcessingState != ProcessingLinkInterface)
{ {
{
cmListFileBacktrace lfbt;
this->Makefile->GetBacktrace(lfbt);
cmValueWithOrigin entry(this->Target->GetDebugGeneratorExpressions(lib,
llt),
lfbt);
this->Target->AppendTllInclude(entry);
}
this->Makefile this->Makefile
->AddLinkLibraryForTarget(this->Target->GetName(), lib, llt); ->AddLinkLibraryForTarget(this->Target->GetName(), lib, llt);
if (this->CurrentProcessingState != ProcessingPublicInterface) if (this->CurrentProcessingState != ProcessingPublicInterface)