summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2013-02-05 19:46:43 (GMT)
committerCMake Topic Stage <kwrobot@kitware.com>2013-02-05 19:46:43 (GMT)
commitec85306025ae787e08d4ce097fde966f1809c74f (patch)
treeb583e726d1ab08212554cf299bb653604c72ff2a /Source
parent020525845a3999078e4f7897d293c5aeab20af87 (diff)
parente48d84209cde93b43fcfb305897b4f52cd18a55f (diff)
downloadCMake-ec85306025ae787e08d4ce097fde966f1809c74f.zip
CMake-ec85306025ae787e08d4ce097fde966f1809c74f.tar.gz
CMake-ec85306025ae787e08d4ce097fde966f1809c74f.tar.bz2
Merge topic 'tll-includes-defines'
e48d842 Cache context-independent includes on evaluation. 089fe1c Optimize genex evaluation for includes and defines. 179f495 find_package: Reword <package>_NO_INTERFACES documentation e7b579b Test workaround of bad interface include directories from depends. 77cecb7 Add includes and compile definitions with target_link_libraries. 0b92602 Add the $<LINKED:...> generator expression. 0fa7f69 Add API to check if we're reading a includes or defines property. 2c3654c Add a way to exclude INTERFACE properties from exported targets. d4297d5 Export targets to a targets file, not a Config file. df4d2b2 Make it an error for INSTALL_PREFIX to be evaluated. 7ceeba9 Advance more when preprocessing exported strings. 30268b4 Handle reading empty properties defined by the link interface.
Diffstat (limited to 'Source')
-rw-r--r--Source/cmDocumentGeneratorExpressions.h8
-rw-r--r--Source/cmExportFileGenerator.cxx75
-rw-r--r--Source/cmExportFileGenerator.h4
-rw-r--r--Source/cmFindPackageCommand.cxx20
-rw-r--r--Source/cmGeneratorExpression.cxx8
-rw-r--r--Source/cmGeneratorExpression.h5
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.cxx42
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.h6
-rw-r--r--Source/cmGeneratorExpressionEvaluator.cxx127
-rw-r--r--Source/cmGeneratorExpressionEvaluator.h1
-rw-r--r--Source/cmTarget.cxx41
-rw-r--r--Source/cmTarget.h6
-rw-r--r--Source/cmTargetLinkLibrariesCommand.cxx53
-rw-r--r--Source/cmTargetLinkLibrariesCommand.h9
14 files changed, 372 insertions, 33 deletions
diff --git a/Source/cmDocumentGeneratorExpressions.h b/Source/cmDocumentGeneratorExpressions.h
index 8b80a8a..3993f7d 100644
--- a/Source/cmDocumentGeneratorExpressions.h
+++ b/Source/cmDocumentGeneratorExpressions.h
@@ -51,6 +51,14 @@
"on the target tgt.\n" \
"Note that tgt is not added as a dependency of the target this " \
"expression is evaluated on.\n" \
+ " $<LINKED:item> = An empty string if item is not a " \
+ "target. If item is a target then the " \
+ "INTERFACE_INCLUDE_DIRECTORIES or INTERFACE_COMPILE_DEFINITIONS " \
+ "content is read from the target. " \
+ "This generator expression can only be used in evaluation of the " \
+ "INCLUDE_DIRECTORIES or COMPILE_DEFINITIONS property. Note that " \
+ "this expression is for internal use and may be changed or removed " \
+ "in the future.\n" \
" $<TARGET_POLICY:pol> = '1' if the policy was NEW when " \
"the 'head' target was created, else '0'. If the policy was not " \
"set, the warning message for the policy will be emitted. This " \
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index dbe64e9..7e4c3df 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -25,6 +25,8 @@
#include <cmsys/auto_ptr.hxx>
+#include "assert.h"
+
//----------------------------------------------------------------------------
cmExportFileGenerator::cmExportFileGenerator()
{
@@ -160,7 +162,7 @@ void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName,
preprocessRule);
if (!prepro.empty())
{
- this->ResolveTargetsInGeneratorExpressions(prepro, target,
+ this->ResolveTargetsInGeneratorExpressions(prepro, target, propName,
missingTargets);
properties[outputName] = prepro;
}
@@ -264,15 +266,16 @@ void cmExportFileGenerator::GenerateInterfaceProperties(cmTarget *target,
{
if (!properties.empty())
{
+ os << "if(NOT ${CMAKE_FIND_PACKAGE_NAME}_NO_INTERFACES)\n";
std::string targetName = this->Namespace;
targetName += target->GetName();
- os << "set_target_properties(" << targetName << " PROPERTIES\n";
+ os << " set_target_properties(" << targetName << " PROPERTIES\n";
for(ImportPropertyMap::const_iterator pi = properties.begin();
pi != properties.end(); ++pi)
{
- os << " " << pi->first << " \"" << pi->second << "\"\n";
+ os << " " << pi->first << " \"" << pi->second << "\"\n";
}
- os << ")\n\n";
+ os << " )\nendif()\n\n";
}
}
@@ -323,13 +326,14 @@ static bool isGeneratorExpression(const std::string &lib)
void
cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
std::string &input,
- cmTarget* target,
+ cmTarget* target, const char *propName,
std::vector<std::string> &missingTargets,
FreeTargetsReplace replace)
{
if (replace == NoReplaceFreeTargets)
{
- this->ResolveTargetsInGeneratorExpression(input, target, missingTargets);
+ this->ResolveTargetsInGeneratorExpression(input, target, propName,
+ missingTargets);
return;
}
std::vector<std::string> parts;
@@ -348,7 +352,7 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
{
this->ResolveTargetsInGeneratorExpression(
*li,
- target,
+ target, propName,
missingTargets);
}
input += sep + *li;
@@ -360,7 +364,7 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
void
cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
std::string &input,
- cmTarget* target,
+ cmTarget* target, const char *propName,
std::vector<std::string> &missingTargets)
{
std::string::size_type pos = 0;
@@ -391,12 +395,63 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
{
input.replace(nameStartPos, commaPos - nameStartPos, targetName);
}
- lastPos = pos + targetName.size();
+ lastPos = nameStartPos + targetName.size() + 1;
}
std::string errorString;
pos = 0;
lastPos = pos;
+ while((pos = input.find("$<LINKED:", lastPos)) != input.npos)
+ {
+ std::string::size_type nameStartPos = pos + sizeof("$<LINKED:") - 1;
+ std::string::size_type endPos = input.find(">", nameStartPos);
+ if (endPos == input.npos)
+ {
+ errorString = "$<LINKED:...> expression incomplete";
+ break;
+ }
+ std::string targetName = input.substr(nameStartPos,
+ endPos - nameStartPos);
+ if(targetName.find("$<") != input.npos)
+ {
+ errorString = "$<LINKED:...> requires its parameter to be a "
+ "literal.";
+ break;
+ }
+ if (this->AddTargetNamespace(targetName, target, missingTargets))
+ {
+ assert(propName); // The link libraries strings will
+ // never contain $<LINKED>
+ std::string replacement = "$<TARGET_PROPERTY:"
+ + targetName + "," + propName;
+ input.replace(pos, endPos - pos, replacement);
+ lastPos = pos + replacement.size() + 1;
+ }
+ else
+ {
+ if (pos != 0)
+ {
+ if (input[pos - 1] == ';')
+ {
+ --pos;
+ }
+ }
+ else if (input[endPos + 1] == ';')
+ {
+ ++endPos;
+ }
+ input.replace(pos, endPos - pos + 1, "");
+ lastPos = pos;
+ }
+ }
+ if (!errorString.empty())
+ {
+ mf->IssueMessage(cmake::FATAL_ERROR, errorString);
+ return;
+ }
+
+ pos = 0;
+ lastPos = pos;
while((pos = input.find("$<TARGET_NAME:", lastPos)) != input.npos)
{
std::string::size_type nameStartPos = pos + sizeof("$<TARGET_NAME:") - 1;
@@ -490,7 +545,7 @@ cmExportFileGenerator
preprocessRule);
if (!prepro.empty())
{
- this->ResolveTargetsInGeneratorExpressions(prepro, target,
+ this->ResolveTargetsInGeneratorExpressions(prepro, target, 0,
missingTargets,
ReplaceFreeTargets);
properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = prepro;
diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h
index 776be61..5ad27bf 100644
--- a/Source/cmExportFileGenerator.h
+++ b/Source/cmExportFileGenerator.h
@@ -119,7 +119,7 @@ protected:
};
void ResolveTargetsInGeneratorExpressions(std::string &input,
- cmTarget* target,
+ cmTarget* target, const char *propName,
std::vector<std::string> &missingTargets,
FreeTargetsReplace replace = NoReplaceFreeTargets);
@@ -150,7 +150,7 @@ private:
std::vector<std::string> &missingTargets);
void ResolveTargetsInGeneratorExpression(std::string &input,
- cmTarget* target,
+ cmTarget* target, const char *propName,
std::vector<std::string> &missingTargets);
virtual void ReplaceInstallPrefix(std::string &input);
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index 470ceca..6e78bd7 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -376,6 +376,26 @@ void cmFindPackageCommand::GenerateDocumentation()
"The package configuration file may set <package>_FOUND to false "
"to tell find_package that component requirements are not satisfied."
"\n"
+ "A package configuration file may include() a <package>Targets.cmake "
+ "file, created by install(EXPORT) in the upstream source, to import "
+ "targets into the downstream consumer. "
+ "When a new version of the upstream adds INTERFACE properties not "
+ "present in a previous version it can change behavior for existing "
+ "downstreams. "
+ "In order to remain source compatible the upstream package configuration "
+ "file may set <package>_NO_INTERFACES to disable INTERFACE properties. "
+ "For example, code of the form:\n"
+ " if(<package>_FIND_VERSION VERSION_LESS <new-version>\n"
+ " AND NOT <package>_INTERFACES)\n"
+ " set(<package>_NO_INTERFACES 1)\n"
+ " endif()\n"
+ " include(\"${CMAKE_CURRENT_LIST_DIR}/<package>Targets.cmake\")\n"
+ "tells <package>Targets.cmake not to provide the INTERFACE properties "
+ "unless the downstream requests at least <new-version> or sets "
+ "<package>_INTERFACES to explicitly request them. "
+ "This allows consumers to decide when to enable the new interfaces when "
+ "upgrading."
+ "\n"
"See the cmake_policy() command documentation for discussion of the "
"NO_POLICY_SCOPE option."
;
diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx
index 78ae8f2..7add1bf 100644
--- a/Source/cmGeneratorExpression.cxx
+++ b/Source/cmGeneratorExpression.cxx
@@ -88,6 +88,7 @@ const char *cmCompiledGeneratorExpression::Evaluate(
context.Config = config;
context.Quiet = quiet;
context.HadError = false;
+ context.HadContextSensitiveCondition = false;
context.HeadTarget = headTarget;
context.CurrentTarget = currentTarget ? currentTarget : headTarget;
context.Backtrace = this->Backtrace;
@@ -109,6 +110,10 @@ const char *cmCompiledGeneratorExpression::Evaluate(
break;
}
}
+ if (!context.HadError)
+ {
+ this->HadContextSensitiveCondition = context.HadContextSensitiveCondition;
+ }
this->Targets = context.Targets;
// TODO: Return a std::string from here instead?
@@ -118,7 +123,8 @@ const char *cmCompiledGeneratorExpression::Evaluate(
cmCompiledGeneratorExpression::cmCompiledGeneratorExpression(
cmListFileBacktrace const& backtrace,
const char *input)
- : Backtrace(backtrace), Input(input ? input : "")
+ : Backtrace(backtrace), Input(input ? input : ""),
+ HadContextSensitiveCondition(false)
{
cmGeneratorExpressionLexer l;
std::vector<cmGeneratorExpressionToken> tokens =
diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h
index 8f1aef6..700fe03 100644
--- a/Source/cmGeneratorExpression.h
+++ b/Source/cmGeneratorExpression.h
@@ -100,6 +100,10 @@ public:
{
return this->Backtrace;
}
+ bool GetHadContextSensitiveCondition() const
+ {
+ return this->HadContextSensitiveCondition;
+ }
private:
cmCompiledGeneratorExpression(cmListFileBacktrace const& backtrace,
@@ -118,6 +122,7 @@ private:
mutable std::set<cmTarget*> Targets;
mutable std::map<cmStdString, cmStdString> SeenTargetProperties;
mutable std::string Output;
+ mutable bool HadContextSensitiveCondition;
};
#endif
diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx
index 269211b..b9069ef 100644
--- a/Source/cmGeneratorExpressionDAGChecker.cxx
+++ b/Source/cmGeneratorExpressionDAGChecker.cxx
@@ -24,7 +24,33 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
: Parent(parent), Target(target), Property(property),
Content(content), Backtrace(backtrace)
{
+ const cmGeneratorExpressionDAGChecker *top = this;
+ const cmGeneratorExpressionDAGChecker *p = this->Parent;
+ while (p)
+ {
+ top = p;
+ p = p->Parent;
+ }
this->CheckResult = this->checkGraph();
+
+ if (CheckResult == DAG && (top->Property == "INCLUDE_DIRECTORIES"
+ || top->Property == "COMPILE_DEFINITIONS") )
+ {
+ std::map<cmStdString, std::set<cmStdString> >::const_iterator it
+ = top->Seen.find(target);
+ if (it != top->Seen.end())
+ {
+ const std::set<cmStdString> &propSet = it->second;
+ const std::set<cmStdString>::const_iterator i = propSet.find(property);
+ if (i != propSet.end())
+ {
+ this->CheckResult = ALREADY_SEEN;
+ return;
+ }
+ }
+ const_cast<cmGeneratorExpressionDAGChecker *>(top)
+ ->Seen[target].insert(property);
+ }
}
//----------------------------------------------------------------------------
@@ -125,3 +151,19 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries()
|| strncmp(prop, "LINK_INTERFACE_LIBRARIES_", 26) == 0
|| strncmp(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_", 35) == 0);
}
+
+//----------------------------------------------------------------------------
+bool cmGeneratorExpressionDAGChecker::EvaluatingIncludeDirectories()
+{
+ const char *prop = this->Property.c_str();
+ return (strcmp(prop, "INCLUDE_DIRECTORIES") == 0
+ || strcmp(prop, "INTERFACE_INCLUDE_DIRECTORIES") == 0 );
+}
+
+//----------------------------------------------------------------------------
+bool cmGeneratorExpressionDAGChecker::EvaluatingCompileDefinitions()
+{
+ const char *prop = this->Property.c_str();
+ return (strcmp(prop, "COMPILE_DEFINITIONS") == 0
+ || strcmp(prop, "INTERFACE_COMPILE_DEFINITIONS") == 0 );
+}
diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h
index 3169291..a2e5ce4 100644
--- a/Source/cmGeneratorExpressionDAGChecker.h
+++ b/Source/cmGeneratorExpressionDAGChecker.h
@@ -28,7 +28,8 @@ struct cmGeneratorExpressionDAGChecker
enum Result {
DAG,
SELF_REFERENCE,
- CYCLIC_REFERENCE
+ CYCLIC_REFERENCE,
+ ALREADY_SEEN
};
Result check() const;
@@ -37,6 +38,8 @@ struct cmGeneratorExpressionDAGChecker
const std::string &expr);
bool EvaluatingLinkLibraries();
+ bool EvaluatingIncludeDirectories();
+ bool EvaluatingCompileDefinitions();
private:
Result checkGraph() const;
@@ -45,6 +48,7 @@ private:
const cmGeneratorExpressionDAGChecker * const Parent;
const std::string Target;
const std::string Property;
+ std::map<cmStdString, std::set<cmStdString> > Seen;
const GeneratorExpressionContent * const Content;
const cmListFileBacktrace Backtrace;
Result CheckResult;
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx
index f74b69e..5d94718 100644
--- a/Source/cmGeneratorExpressionEvaluator.cxx
+++ b/Source/cmGeneratorExpressionEvaluator.cxx
@@ -238,6 +238,7 @@ static const struct ConfigurationNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent *,
cmGeneratorExpressionDAGChecker *) const
{
+ context->HadContextSensitiveCondition = true;
return context->Config ? context->Config : "";
}
} configurationNode;
@@ -262,6 +263,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
"Expression syntax not recognized.");
return std::string();
}
+ context->HadContextSensitiveCondition = true;
if (!context->Config)
{
return parameters.front().empty() ? "1" : "0";
@@ -435,6 +437,9 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
// No error. We just skip cyclic references.
return std::string();
+ case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
+ // No error. We're not going to find anything new here.
+ return std::string();
case cmGeneratorExpressionDAGChecker::DAG:
break;
}
@@ -452,12 +457,14 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
}
if (propertyName == "POSITION_INDEPENDENT_CODE")
{
+ context->HadContextSensitiveCondition = true;
return target->GetLinkInterfaceDependentBoolProperty(
"POSITION_INDEPENDENT_CODE", context->Config) ? "1" : "0";
}
if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
context->Config))
{
+ context->HadContextSensitiveCondition = true;
return target->GetLinkInterfaceDependentBoolProperty(
propertyName,
context->Config) ? "1" : "0";
@@ -465,9 +472,12 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
if (target->IsLinkInterfaceDependentStringProperty(propertyName,
context->Config))
{
- return target->GetLinkInterfaceDependentStringProperty(
+ context->HadContextSensitiveCondition = true;
+ const char *propContent =
+ target->GetLinkInterfaceDependentStringProperty(
propertyName,
context->Config);
+ return propContent ? propContent : "";
}
return std::string();
@@ -481,12 +491,19 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
if (targetPropertyTransitiveWhitelist[i] == propertyName)
{
cmGeneratorExpression ge(context->Backtrace);
- return ge.Parse(prop)->Evaluate(context->Makefile,
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
+ std::string result = cge->Evaluate(context->Makefile,
context->Config,
context->Quiet,
context->HeadTarget,
target,
&dagChecker);
+
+ if (cge->GetHadContextSensitiveCondition())
+ {
+ context->HadContextSensitiveCondition = true;
+ }
+ return result;
}
}
return prop;
@@ -580,6 +597,9 @@ static const struct TargetPolicyNode : public cmGeneratorExpressionNode
"be used with add_custom_command.");
return std::string();
}
+
+ context->HadContextSensitiveCondition = true;
+
for (size_t i = 0;
i < (sizeof(targetPolicyWhitelist) /
sizeof(*targetPolicyWhitelist));
@@ -619,20 +639,115 @@ static const struct InstallPrefixNode : public cmGeneratorExpressionNode
{
InstallPrefixNode() {}
- virtual bool GeneratesContent() const { return false; }
+ virtual bool GeneratesContent() const { return true; }
virtual int NumExpectedParameters() const { return 0; }
std::string Evaluate(const std::vector<std::string> &,
- cmGeneratorExpressionContext *,
- const GeneratorExpressionContent *,
+ cmGeneratorExpressionContext *context,
+ const GeneratorExpressionContent *content,
cmGeneratorExpressionDAGChecker *) const
{
+ reportError(context, content->GetOriginalExpression(),
+ "INSTALL_PREFIX is a marker for install(EXPORT) only. It "
+ "should never be evaluated.");
return std::string();
}
} installPrefixNode;
//----------------------------------------------------------------------------
+static const struct LinkedNode : public cmGeneratorExpressionNode
+{
+ LinkedNode() {}
+
+ virtual bool GeneratesContent() const { return true; }
+ virtual int NumExpectedParameters() const { return 1; }
+ virtual bool RequiresLiteralInput() const { return true; }
+
+ std::string Evaluate(const std::vector<std::string> &parameters,
+ cmGeneratorExpressionContext *context,
+ const GeneratorExpressionContent *content,
+ cmGeneratorExpressionDAGChecker *dagChecker) const
+ {
+ if (dagChecker->EvaluatingIncludeDirectories())
+ {
+ return this->GetInterfaceProperty(parameters.front(),
+ "INCLUDE_DIRECTORIES",
+ context, content, dagChecker);
+ }
+ if (dagChecker->EvaluatingCompileDefinitions())
+ {
+ return this->GetInterfaceProperty(parameters.front(),
+ "COMPILE_DEFINITIONS",
+ context, content, dagChecker);
+ }
+
+ reportError(context, content->GetOriginalExpression(),
+ "$<LINKED:...> may only be used in INCLUDE_DIRECTORIES and "
+ "COMPILE_DEFINITIONS properties.");
+
+ return std::string();
+ }
+
+private:
+ std::string GetInterfaceProperty(const std::string &item,
+ const std::string &prop,
+ cmGeneratorExpressionContext *context,
+ const GeneratorExpressionContent *content,
+ cmGeneratorExpressionDAGChecker *dagCheckerParent) const
+ {
+ cmTarget *target = context->CurrentTarget
+ ->GetMakefile()->FindTargetToUse(item.c_str());
+ if (!target)
+ {
+ return std::string();
+ }
+ std::string propertyName = "INTERFACE_" + prop;
+ const char *propContent = target->GetProperty(propertyName.c_str());
+ if (!propContent)
+ {
+ return std::string();
+ }
+
+ cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
+ target->GetName(),
+ propertyName,
+ content,
+ dagCheckerParent);
+
+ switch (dagChecker.check())
+ {
+ case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
+ dagChecker.reportError(context, content->GetOriginalExpression());
+ return std::string();
+ case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
+ // No error. We just skip cyclic references.
+ return std::string();
+ case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
+ // No error. We're not going to find anything new here.
+ return std::string();
+ case cmGeneratorExpressionDAGChecker::DAG:
+ break;
+ }
+
+ cmGeneratorExpression ge(context->Backtrace);
+ cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(propContent);
+ std::string result = cge->Evaluate(context->Makefile,
+ context->Config,
+ context->Quiet,
+ context->HeadTarget,
+ target,
+ &dagChecker);
+ if (cge->GetHadContextSensitiveCondition())
+ {
+ context->HadContextSensitiveCondition = true;
+ }
+ return result;
+ }
+
+} linkedNode;
+
+//----------------------------------------------------------------------------
template<bool linker, bool soname>
struct TargetFilesystemArtifactResultCreator
{
@@ -869,6 +984,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
return &targetDefinedNode;
else if (identifier == "INSTALL_PREFIX")
return &installPrefixNode;
+ else if (identifier == "LINKED")
+ return &linkedNode;
return 0;
}
diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h
index fb6c7ee..37d5c86 100644
--- a/Source/cmGeneratorExpressionEvaluator.h
+++ b/Source/cmGeneratorExpressionEvaluator.h
@@ -32,6 +32,7 @@ struct cmGeneratorExpressionContext
// directly or indirectly in the property.
bool Quiet;
bool HadError;
+ bool HadContextSensitiveCondition;
};
struct cmGeneratorExpressionDAGChecker;
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 132154c..ca0e24b 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -134,6 +134,7 @@ public:
: ge(cge)
{}
const cmsys::auto_ptr<cmCompiledGeneratorExpression> ge;
+ std::vector<std::string> CachedIncludes;
};
std::vector<IncludeDirectoriesEntry*> IncludeDirectoriesEntries;
};
@@ -2778,22 +2779,36 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config)
end = this->Internal->IncludeDirectoriesEntries.end();
it != end; ++it)
{
- std::vector<std::string> entryIncludes;
- cmSystemTools::ExpandListArgument((*it)->ge->Evaluate(this->Makefile,
- config,
- false,
- this,
- &dagChecker),
- entryIncludes);
+
+ bool testIsOff = true;
+ bool cacheIncludes = false;
+ std::vector<std::string> entryIncludes = (*it)->CachedIncludes;
+ if(!entryIncludes.empty())
+ {
+ testIsOff = false;
+ }
+ else
+ {
+ cmSystemTools::ExpandListArgument((*it)->ge->Evaluate(this->Makefile,
+ config,
+ false,
+ this,
+ &dagChecker),
+ entryIncludes);
+ if (!(*it)->ge->GetHadContextSensitiveCondition())
+ {
+ cacheIncludes = true;
+ }
+ }
std::string usedIncludes;
- for(std::vector<std::string>::const_iterator
+ for(std::vector<std::string>::iterator
li = entryIncludes.begin(); li != entryIncludes.end(); ++li)
{
- std::string inc = *li;
- if (!cmSystemTools::IsOff(inc.c_str()))
+ if (testIsOff && !cmSystemTools::IsOff(li->c_str()))
{
- cmSystemTools::ConvertToUnixSlashes(inc);
+ cmSystemTools::ConvertToUnixSlashes(*li);
}
+ std::string inc = *li;
if(uniqueIncludes.insert(inc).second)
{
@@ -2804,6 +2819,10 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config)
}
}
}
+ if (cacheIncludes)
+ {
+ (*it)->CachedIncludes = entryIncludes;
+ }
if (!usedIncludes.empty())
{
this->Makefile->GetCMakeInstance()->IssueMessage(cmake::LOG,
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index cf2d4c4..7577a59 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -514,6 +514,9 @@ public:
const char *GetLinkInterfaceDependentStringProperty(const std::string &p,
const char *config);
+
+ std::string GetDebugGeneratorExpressions(const std::string &value,
+ cmTarget::LinkLibraryType llt);
private:
/**
* A list of direct dependencies. Use in conjunction with DependencyMap.
@@ -659,9 +662,6 @@ 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;
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index f42b0f6..cb913f5 100644
--- a/Source/cmTargetLinkLibrariesCommand.cxx
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -250,10 +250,51 @@ cmTargetLinkLibrariesCommand
}
//----------------------------------------------------------------------------
+static std::string compileProperty(cmTarget *tgt, const std::string &lib,
+ bool isGenex,
+ const std::string &property,
+ cmTarget::LinkLibraryType llt)
+{
+ std::string value = !isGenex ? "$<LINKED:" + lib + ">"
+ : "$<$<TARGET_DEFINED:" + lib + ">:" +
+ "$<TARGET_PROPERTY:" + lib +
+ ",INTERFACE_" + property + ">"
+ ">";
+
+ return tgt->GetDebugGeneratorExpressions(value, llt);
+}
+
+//----------------------------------------------------------------------------
+static bool isGeneratorExpression(const std::string &lib)
+{
+ const std::string::size_type openpos = lib.find("$<");
+ return (openpos != std::string::npos)
+ && (lib.find(">", openpos) != std::string::npos);
+}
+
+//----------------------------------------------------------------------------
void
cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
cmTarget::LinkLibraryType llt)
{
+ const bool isGenex = isGeneratorExpression(lib);
+
+ cmsys::RegularExpression targetNameValidator;
+ targetNameValidator.compile("^[A-Za-z0-9_.:-]+$");
+ const bool potentialTargetName = targetNameValidator.find(lib);
+
+ if (potentialTargetName || isGenex)
+ {
+ this->Target->AppendProperty("INCLUDE_DIRECTORIES",
+ compileProperty(this->Target, lib,
+ isGenex,
+ "INCLUDE_DIRECTORIES", llt).c_str());
+ this->Target->AppendProperty("COMPILE_DEFINITIONS",
+ compileProperty(this->Target, lib,
+ isGenex,
+ "COMPILE_DEFINITIONS", llt).c_str());
+ }
+
// Handle normal case first.
if(this->CurrentProcessingState != ProcessingLinkInterface)
{
@@ -266,6 +307,18 @@ cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
}
}
+ if (potentialTargetName || isGenex)
+ {
+ this->Target->AppendProperty("INTERFACE_COMPILE_DEFINITIONS",
+ compileProperty(this->Target, lib,
+ isGenex,
+ "COMPILE_DEFINITIONS", llt).c_str());
+ this->Target->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
+ compileProperty(this->Target, lib,
+ isGenex,
+ "INCLUDE_DIRECTORIES", llt).c_str());
+ }
+
// Get the list of configurations considered to be DEBUG.
std::vector<std::string> const& debugConfigs =
this->Makefile->GetCMakeInstance()->GetDebugConfigs();
diff --git a/Source/cmTargetLinkLibrariesCommand.h b/Source/cmTargetLinkLibrariesCommand.h
index 3da3950..aaabdfa 100644
--- a/Source/cmTargetLinkLibrariesCommand.h
+++ b/Source/cmTargetLinkLibrariesCommand.h
@@ -97,6 +97,15 @@ public:
"Calls to other signatures of this command may set the property "
"making any libraries linked exclusively by this signature private."
"\n"
+ "Target usage requirements are also consumed by this command. If the "
+ "<target> is linked to another target which has "
+ "a populated INTERFACE_INCLUDE_DIRECTORIES, the content of it is "
+ "appended to the INCLUDE_DIRECTORIES of <target>. Similarly, the "
+ "INTERFACE_COMPILE_DEFINITONS of a dependee are added to the "
+ "COMPILE_DEFINITONS of <target>, and the "
+ "INTERFACE_POSITION_INDEPENDENT_CODE property is used to determine the "
+ "POSITION_INDEPENDENT_CODE property of <target>."
+ "\n"
" target_link_libraries(<target> LINK_INTERFACE_LIBRARIES\n"
" [[debug|optimized|general] <lib>] ...)\n"
"The LINK_INTERFACE_LIBRARIES mode appends the libraries "