summaryrefslogtreecommitdiffstats
path: root/Source/cmGeneratorExpressionEvaluator.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmGeneratorExpressionEvaluator.cxx')
-rw-r--r--Source/cmGeneratorExpressionEvaluator.cxx160
1 files changed, 151 insertions, 9 deletions
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx
index 102927e..8e40815a 100644
--- a/Source/cmGeneratorExpressionEvaluator.cxx
+++ b/Source/cmGeneratorExpressionEvaluator.cxx
@@ -18,6 +18,8 @@
#include <cmsys/String.h>
+#include <assert.h>
+
//----------------------------------------------------------------------------
#if !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x510
static
@@ -47,6 +49,8 @@ struct cmGeneratorExpressionNode
virtual bool GeneratesContent() const { return true; }
+ virtual bool RequiresLiteralInput() const { return false; }
+
virtual bool AcceptsSingleArbitraryContentParameter() const
{ return false; }
@@ -96,6 +100,12 @@ static const struct OneNode : public cmGeneratorExpressionNode
} oneNode;
//----------------------------------------------------------------------------
+static const struct OneNode buildInterfaceNode;
+
+//----------------------------------------------------------------------------
+static const struct ZeroNode installInterfaceNode;
+
+//----------------------------------------------------------------------------
#define BOOLEAN_OP_NODE(OPNAME, OP, SUCCESS_VALUE, FAILURE_VALUE) \
static const struct OP ## Node : public cmGeneratorExpressionNode \
{ \
@@ -257,11 +267,50 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
return parameters.front().empty() ? "1" : "0";
}
- return cmsysString_strcasecmp(parameters.begin()->c_str(),
- context->Config) == 0 ? "1" : "0";
+ if (cmsysString_strcasecmp(parameters.begin()->c_str(),
+ context->Config) == 0)
+ {
+ return "1";
+ }
+
+ if (context->CurrentTarget
+ && context->CurrentTarget->IsImported())
+ {
+ const char* loc = 0;
+ const char* imp = 0;
+ std::string suffix;
+ return context->CurrentTarget->GetMappedConfig(context->Config,
+ &loc,
+ &imp,
+ suffix) ? "1" : "0";
+ }
+ return "0";
}
} configurationTestNode;
+
+static const struct TargetDefinedNode : public cmGeneratorExpressionNode
+{
+ TargetDefinedNode() {}
+
+ virtual int NumExpectedParameters() const { return 1; }
+
+ std::string Evaluate(const std::vector<std::string> &parameters,
+ cmGeneratorExpressionContext *context,
+ const GeneratorExpressionContent *,
+ cmGeneratorExpressionDAGChecker *) const
+ {
+ return context->Makefile->FindTargetToUse(parameters.front().c_str())
+ ? "1" : "0";
+ }
+} targetDefinedNode;
+
+//----------------------------------------------------------------------------
+static const char* targetPropertyTransitiveWhitelist[] = {
+ "INTERFACE_INCLUDE_DIRECTORIES"
+ , "INTERFACE_COMPILE_DEFINITIONS"
+};
+
//----------------------------------------------------------------------------
static const struct TargetPropertyNode : public cmGeneratorExpressionNode
{
@@ -289,8 +338,19 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
cmsys::RegularExpression propertyNameValidator;
propertyNameValidator.compile("^[A-Za-z0-9_]+$");
- cmTarget* target = context->Target;
+ cmTarget* target = context->HeadTarget;
std::string propertyName = *parameters.begin();
+
+ if (!target && parameters.size() == 1)
+ {
+ reportError(context, content->GetOriginalExpression(),
+ "$<TARGET_PROPERTY:prop> may only be used with targets. It may not "
+ "be used with add_custom_command. Specify the target to read a "
+ "property from using the $<TARGET_PROPERTY:tgt,prop> signature "
+ "instead.");
+ return std::string();
+ }
+
if (parameters.size() == 2)
{
if (parameters.begin()->empty() && parameters[1].empty())
@@ -336,6 +396,14 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
}
}
+ if (target == context->HeadTarget)
+ {
+ // Keep track of the properties seen while processing.
+ // The evaluation of the LINK_LIBRARIES generator expressions
+ // will check this to ensure that properties form a DAG.
+ context->SeenTargetProperties.insert(propertyName);
+ }
+
if (propertyName.empty())
{
reportError(context, content->GetOriginalExpression(),
@@ -351,24 +419,75 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
return std::string();
}
+ assert(target);
+
cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
target->GetName(),
propertyName,
content,
dagCheckerParent);
- if (!dagChecker.check())
+ 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::DAG:
+ break;
}
const char *prop = target->GetProperty(propertyName.c_str());
- return prop ? prop : "";
+ if (!prop)
+ {
+ return std::string();
+ }
+
+ for (size_t i = 0;
+ i < (sizeof(targetPropertyTransitiveWhitelist) /
+ sizeof(*targetPropertyTransitiveWhitelist));
+ ++i)
+ {
+ if (targetPropertyTransitiveWhitelist[i] == propertyName)
+ {
+ cmGeneratorExpression ge(context->Backtrace);
+ return ge.Parse(prop)->Evaluate(context->Makefile,
+ context->Config,
+ context->Quiet,
+ context->HeadTarget,
+ target,
+ &dagChecker);
+ }
+ }
+ return prop;
}
} targetPropertyNode;
//----------------------------------------------------------------------------
+static const struct TargetNameNode : public cmGeneratorExpressionNode
+{
+ TargetNameNode() {}
+
+ virtual bool GeneratesContent() const { return true; }
+
+ virtual bool AcceptsSingleArbitraryContentParameter() const { return true; }
+ virtual bool RequiresLiteralInput() const { return true; }
+
+ std::string Evaluate(const std::vector<std::string> &parameters,
+ cmGeneratorExpressionContext *,
+ const GeneratorExpressionContent *,
+ cmGeneratorExpressionDAGChecker *) const
+ {
+ return parameters.front();
+ }
+
+ virtual int NumExpectedParameters() const { return 1; }
+
+} targetNameNode;
+
+//----------------------------------------------------------------------------
template<bool linker, bool soname>
struct TargetFilesystemArtifactResultCreator
{
@@ -553,13 +672,13 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
{
if (identifier == "0")
return &zeroNode;
- if (identifier == "1")
+ else if (identifier == "1")
return &oneNode;
- if (identifier == "AND")
+ else if (identifier == "AND")
return &andNode;
- if (identifier == "OR")
+ else if (identifier == "OR")
return &orNode;
- if (identifier == "NOT")
+ else if (identifier == "NOT")
return &notNode;
else if (identifier == "CONFIGURATION")
return &configurationNode;
@@ -593,6 +712,14 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
return &commaNode;
else if (identifier == "TARGET_PROPERTY")
return &targetPropertyNode;
+ else if (identifier == "TARGET_NAME")
+ return &targetNameNode;
+ else if (identifier == "BUILD_INTERFACE")
+ return &buildInterfaceNode;
+ else if (identifier == "INSTALL_INTERFACE")
+ return &installInterfaceNode;
+ else if (identifier == "TARGET_DEFINED")
+ return &targetDefinedNode;
return 0;
}
@@ -682,6 +809,15 @@ std::string GeneratorExpressionContent::Evaluate(
= pit->end();
for ( ; it != end; ++it)
{
+ if (node->RequiresLiteralInput())
+ {
+ if ((*it)->GetType() != cmGeneratorExpressionEvaluator::Text)
+ {
+ reportError(context, this->GetOriginalExpression(),
+ "$<" + identifier + "> expression requires literal input.");
+ return std::string();
+ }
+ }
result += (*it)->Evaluate(context, dagChecker);
if (context->HadError)
{
@@ -689,6 +825,12 @@ std::string GeneratorExpressionContent::Evaluate(
}
}
}
+ if (node->RequiresLiteralInput())
+ {
+ std::vector<std::string> parameters;
+ parameters.push_back(result);
+ return node->Evaluate(parameters, context, this, dagChecker);
+ }
return result;
}