summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/cmAddTestCommand.h2
-rw-r--r--Source/cmDocumentGeneratorExpressions.h17
-rw-r--r--Source/cmExtraCodeBlocksGenerator.cxx93
-rw-r--r--Source/cmGeneratorExpression.cxx8
-rw-r--r--Source/cmGeneratorExpression.h12
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.cxx106
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.h44
-rw-r--r--Source/cmGeneratorExpressionEvaluator.cxx169
-rw-r--r--Source/cmGeneratorExpressionEvaluator.h19
-rw-r--r--Source/cmGeneratorTarget.cxx60
-rw-r--r--Source/cmGeneratorTarget.h2
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx17
-rw-r--r--Source/cmIncludeDirectoryCommand.cxx16
-rw-r--r--Source/cmLocalGenerator.cxx11
-rw-r--r--Source/cmLocalGenerator.h5
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx15
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx13
-rw-r--r--Tests/CompileDefinitions/compiletest.cpp9
-rw-r--r--Tests/CompileDefinitions/target_prop/CMakeLists.txt6
-rw-r--r--Tests/GeneratorExpression/CMakeLists.txt17
-rw-r--r--Tests/GeneratorExpression/check.cmake17
-rw-r--r--Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt8
-rw-r--r--Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp4
-rw-r--r--Tests/IncludeDirectories/TargetIncludeDirectories/sing/ting/ting.h1
-rw-r--r--Tests/RunCMake/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1-result.txt1
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1-stderr.txt6
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1.cmake7
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2-result.txt1
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2-stderr.txt6
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2.cmake9
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3-result.txt1
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3-stderr.txt6
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3.cmake8
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4-result.txt1
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4-stderr.txt6
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4.cmake10
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5-result.txt1
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5-stderr.txt6
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5.cmake10
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6-result.txt1
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6-stderr.txt6
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6.cmake10
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/CMakeLists.txt8
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/RunCMakeTest.cmake8
-rwxr-xr-xbootstrap1
47 files changed, 666 insertions, 121 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 354f123..5a3e7d1 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -183,6 +183,8 @@ set(SRCS
cmFileTimeComparison.cxx
cmFileTimeComparison.h
cmGeneratedFileStream.cxx
+ cmGeneratorExpressionDAGChecker.cxx
+ cmGeneratorExpressionDAGChecker.h
cmGeneratorExpressionEvaluator.cxx
cmGeneratorExpressionEvaluator.h
cmGeneratorExpressionLexer.cxx
diff --git a/Source/cmAddTestCommand.h b/Source/cmAddTestCommand.h
index b11bff9..6a0cd9d 100644
--- a/Source/cmAddTestCommand.h
+++ b/Source/cmAddTestCommand.h
@@ -81,7 +81,7 @@ public:
"\n"
"Arguments after COMMAND may use \"generator expressions\" with the "
"syntax \"$<...>\". "
- CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS
+ CM_DOCUMENT_ADD_TEST_GENERATOR_EXPRESSIONS
"Example usage:\n"
" add_test(NAME mytest\n"
" COMMAND testDriver --config $<CONFIGURATION>\n"
diff --git a/Source/cmDocumentGeneratorExpressions.h b/Source/cmDocumentGeneratorExpressions.h
index 74c673a..6b0cf49 100644
--- a/Source/cmDocumentGeneratorExpressions.h
+++ b/Source/cmDocumentGeneratorExpressions.h
@@ -12,7 +12,7 @@
#ifndef cmDocumentGeneratorExpressions_h
#define cmDocumentGeneratorExpressions_h
-#define CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS \
+#define CM_DOCUMENT_ADD_TEST_GENERATOR_EXPRESSIONS \
"Generator expressions are evaluted during build system generation " \
"to produce information specific to each build configuration. " \
"Valid expressions are:\n" \
@@ -20,6 +20,12 @@
" $<1:...> = content of \"...\"\n" \
" $<CONFIG:cfg> = '1' if config is \"cfg\", else '0'\n" \
" $<CONFIGURATION> = configuration name\n" \
+ " $<BOOL:...> = '1' if the '...' is true, else '0'\n" \
+ " $<STREQUAL:a,b> = '1' if a is STREQUAL b, else '0'\n" \
+ " $<ANGLE-R> = A literal '>'. Used to compare " \
+ "strings which contain a '>' for example.\n" \
+ " $<COMMA> = A literal ','. Used to compare " \
+ "strings which contain a ',' for example.\n" \
" $<TARGET_FILE:tgt> = main file (.exe, .so.1.2, .a)\n" \
" $<TARGET_LINKER_FILE:tgt> = file used to link (.a, .lib, .so)\n" \
" $<TARGET_SONAME_FILE:tgt> = file with soname (.so.3)\n" \
@@ -29,11 +35,20 @@
" $<TARGET_FILE_DIR:tgt>/$<TARGET_FILE_NAME:tgt>\n" \
" $<TARGET_LINKER_FILE_DIR:tgt>/$<TARGET_LINKER_FILE_NAME:tgt>\n" \
" $<TARGET_SONAME_FILE_DIR:tgt>/$<TARGET_SONAME_FILE_NAME:tgt>\n" \
+ " $<TARGET_PROPERTY:tgt,prop> = The value of the property prop\n" \
+ "the target tgt. Note that tgt is not added as a dependency of the " \
+ "target this expression is evaluated on.\n" \
"Boolean expressions:\n" \
" $<AND:?[,?]...> = '1' if all '?' are '1', else '0'\n" \
" $<OR:?[,?]...> = '0' if all '?' are '0', else '1'\n" \
" $<NOT:?> = '0' if '?' is '1', else '1'\n" \
"where '?' is always either '0' or '1'.\n" \
+
+#define CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS \
+ CM_DOCUMENT_ADD_TEST_GENERATOR_EXPRESSIONS \
+ "Expressions with an implicit 'this' target:" \
+ " $<TARGET_PROPERTY:prop> = The value of the property prop on\n" \
+ "the target on which the generator expression is evaluated.\n" \
""
#endif
diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx
index b1bbd90..8b2daba 100644
--- a/Source/cmExtraCodeBlocksGenerator.cxx
+++ b/Source/cmExtraCodeBlocksGenerator.cxx
@@ -617,14 +617,17 @@ void cmExtraCodeBlocksGenerator::AppendTarget(cmGeneratedFileStream& fout,
" <Option compiler=\"" << compiler << "\" />\n"
" <Compiler>\n";
+ cmGeneratorTarget *gtgt = this->GlobalGenerator
+ ->GetGeneratorTarget(target);
+
// the compilerdefines for this target
- const char* cdefs = target->GetMakefile()->GetProperty(
- "COMPILE_DEFINITIONS");
- if(cdefs)
+ std::string cdefs = gtgt->GetCompileDefinitions();
+
+ if(cdefs.empty())
{
// Expand the list.
std::vector<std::string> defs;
- cmSystemTools::ExpandListArgument(cdefs, defs);
+ cmSystemTools::ExpandListArgument(cdefs.c_str(), defs);
for(std::vector<std::string>::const_iterator di = defs.begin();
di != defs.end(); ++di)
{
@@ -633,59 +636,57 @@ void cmExtraCodeBlocksGenerator::AppendTarget(cmGeneratedFileStream& fout,
}
}
- // the include directories for this target
- std::set<std::string> uniqIncludeDirs;
+ // the include directories for this target
+ std::set<std::string> uniqIncludeDirs;
+
+ std::vector<std::string> includes;
+ target->GetMakefile()->GetLocalGenerator()->
+ GetIncludeDirectories(includes, gtgt);
+ for(std::vector<std::string>::const_iterator dirIt=includes.begin();
+ dirIt != includes.end();
+ ++dirIt)
+ {
+ uniqIncludeDirs.insert(*dirIt);
+ }
- cmGeneratorTarget *gtgt = this->GlobalGenerator
- ->GetGeneratorTarget(target);
- std::vector<std::string> includes;
- target->GetMakefile()->GetLocalGenerator()->
- GetIncludeDirectories(includes, gtgt);
- for(std::vector<std::string>::const_iterator dirIt=includes.begin();
- dirIt != includes.end();
+ std::string systemIncludeDirs = makefile->GetSafeDefinition(
+ "CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS");
+ if (!systemIncludeDirs.empty())
+ {
+ std::vector<std::string> dirs;
+ cmSystemTools::ExpandListArgument(systemIncludeDirs.c_str(), dirs);
+ for(std::vector<std::string>::const_iterator dirIt=dirs.begin();
+ dirIt != dirs.end();
++dirIt)
{
uniqIncludeDirs.insert(*dirIt);
}
+ }
- std::string systemIncludeDirs = makefile->GetSafeDefinition(
- "CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS");
- if (!systemIncludeDirs.empty())
- {
- std::vector<std::string> dirs;
- cmSystemTools::ExpandListArgument(systemIncludeDirs.c_str(), dirs);
- for(std::vector<std::string>::const_iterator dirIt=dirs.begin();
- dirIt != dirs.end();
- ++dirIt)
- {
- uniqIncludeDirs.insert(*dirIt);
- }
- }
-
- systemIncludeDirs = makefile->GetSafeDefinition(
- "CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS");
- if (!systemIncludeDirs.empty())
- {
- std::vector<std::string> dirs;
- cmSystemTools::ExpandListArgument(systemIncludeDirs.c_str(), dirs);
- for(std::vector<std::string>::const_iterator dirIt=dirs.begin();
- dirIt != dirs.end();
- ++dirIt)
- {
- uniqIncludeDirs.insert(*dirIt);
- }
- }
-
- for(std::set<std::string>::const_iterator dirIt=uniqIncludeDirs.begin();
- dirIt != uniqIncludeDirs.end();
+ systemIncludeDirs = makefile->GetSafeDefinition(
+ "CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS");
+ if (!systemIncludeDirs.empty())
+ {
+ std::vector<std::string> dirs;
+ cmSystemTools::ExpandListArgument(systemIncludeDirs.c_str(), dirs);
+ for(std::vector<std::string>::const_iterator dirIt=dirs.begin();
+ dirIt != dirs.end();
++dirIt)
{
- fout <<" <Add directory=\"" << dirIt->c_str() << "\" />\n";
+ uniqIncludeDirs.insert(*dirIt);
}
+ }
- fout<<" </Compiler>\n";
+ for(std::set<std::string>::const_iterator dirIt=uniqIncludeDirs.begin();
+ dirIt != uniqIncludeDirs.end();
+ ++dirIt)
+ {
+ fout <<" <Add directory=\"" << dirIt->c_str() << "\" />\n";
}
- else // e.g. all and the GLOBAL and UTILITY targets
+
+ fout<<" </Compiler>\n";
+ }
+ else // e.g. all and the GLOBAL and UTILITY targets
{
fout<<" <Option working_dir=\""
<< makefile->GetStartOutputDirectory() << "\" />\n"
diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx
index 0885616..3f8e962 100644
--- a/Source/cmGeneratorExpression.cxx
+++ b/Source/cmGeneratorExpression.cxx
@@ -19,6 +19,7 @@
#include "cmGeneratorExpressionEvaluator.h"
#include "cmGeneratorExpressionLexer.h"
#include "cmGeneratorExpressionParser.h"
+#include "cmGeneratorExpressionDAGChecker.h"
//----------------------------------------------------------------------------
cmGeneratorExpression::cmGeneratorExpression(
@@ -65,7 +66,9 @@ cmGeneratorExpression::~cmGeneratorExpression()
//----------------------------------------------------------------------------
const char *cmCompiledGeneratorExpression::Evaluate(
- cmMakefile* mf, const char* config, bool quiet) const
+ cmMakefile* mf, const char* config, bool quiet,
+ cmGeneratorTarget *target,
+ cmGeneratorExpressionDAGChecker *dagChecker) const
{
if (!this->NeedsParsing)
{
@@ -84,11 +87,12 @@ const char *cmCompiledGeneratorExpression::Evaluate(
context.Config = config;
context.Quiet = quiet;
context.HadError = false;
+ context.Target = target;
context.Backtrace = this->Backtrace;
for ( ; it != end; ++it)
{
- this->Output += (*it)->Evaluate(&context);
+ this->Output += (*it)->Evaluate(&context, dagChecker);
if (context.HadError)
{
this->Output = "";
diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h
index b8467c2..d37ce97 100644
--- a/Source/cmGeneratorExpression.h
+++ b/Source/cmGeneratorExpression.h
@@ -9,6 +9,10 @@
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the License for more information.
============================================================================*/
+
+#ifndef cmGeneratorExpression_h
+#define cmGeneratorExpression_h
+
#include "cmStandardIncludes.h"
#include <stack>
@@ -16,10 +20,12 @@
#include <cmsys/RegularExpression.hxx>
class cmTarget;
+class cmGeneratorTarget;
class cmMakefile;
class cmListFileBacktrace;
struct cmGeneratorExpressionEvaluator;
+struct cmGeneratorExpressionDAGChecker;
class cmCompiledGeneratorExpression;
@@ -54,7 +60,9 @@ class cmCompiledGeneratorExpression
{
public:
const char* Evaluate(cmMakefile* mf, const char* config,
- bool quiet = false) const;
+ bool quiet = false,
+ cmGeneratorTarget *target = 0,
+ cmGeneratorExpressionDAGChecker *dagChecker = 0) const;
/** Get set of targets found during evaluations. */
std::set<cmTarget*> const& GetTargets() const
@@ -80,3 +88,5 @@ private:
mutable std::set<cmTarget*> Targets;
mutable std::string Output;
};
+
+#endif
diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx
new file mode 100644
index 0000000..bfb0ddf
--- /dev/null
+++ b/Source/cmGeneratorExpressionDAGChecker.cxx
@@ -0,0 +1,106 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmGeneratorExpressionDAGChecker.h"
+
+#include "cmMakefile.h"
+
+//----------------------------------------------------------------------------
+cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
+ const cmListFileBacktrace &backtrace,
+ const std::string &target,
+ const std::string &property,
+ const GeneratorExpressionContent *content,
+ cmGeneratorExpressionDAGChecker *parent)
+ : Parent(parent), Target(target), Property(property),
+ Content(content), Backtrace(backtrace)
+{
+ this->IsDAG = this->isDAG();
+}
+
+//----------------------------------------------------------------------------
+bool cmGeneratorExpressionDAGChecker::check() const
+{
+ return this->IsDAG;
+}
+
+//----------------------------------------------------------------------------
+void cmGeneratorExpressionDAGChecker::reportError(
+ cmGeneratorExpressionContext *context,
+ const std::string &expr)
+{
+ if (this->IsDAG)
+ {
+ return;
+ }
+
+ context->HadError = true;
+ if (context->Quiet)
+ {
+ return;
+ }
+
+ const cmGeneratorExpressionDAGChecker *parent = this->Parent;
+
+ if (parent && !parent->Parent)
+ {
+ cmOStringStream e;
+ e << "Error evaluating generator expression:\n"
+ << " " << expr << "\n"
+ << "Self reference on target \""
+ << context->Target->GetName() << "\".\n";
+ context->Makefile->GetCMakeInstance()
+ ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
+ parent->Backtrace);
+ return;
+ }
+
+ {
+ cmOStringStream e;
+ e << "Error evaluating generator expression:\n"
+ << " " << expr << "\n"
+ << "Dependency loop found.";
+ context->Makefile->GetCMakeInstance()
+ ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
+ context->Backtrace);
+ }
+
+ int loopStep = 1;
+ while (parent)
+ {
+ cmOStringStream e;
+ e << "Loop step " << loopStep << "\n"
+ << " "
+ << (parent->Content ? parent->Content->GetOriginalExpression() : expr)
+ << "\n";
+ context->Makefile->GetCMakeInstance()
+ ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(),
+ parent->Backtrace);
+ parent = parent->Parent;
+ ++loopStep;
+ }
+}
+
+//----------------------------------------------------------------------------
+bool cmGeneratorExpressionDAGChecker::isDAG() const
+{
+ const cmGeneratorExpressionDAGChecker *parent = this->Parent;
+ while (parent)
+ {
+ if (this->Target == parent->Target && this->Property == parent->Property)
+ {
+ return false;
+ }
+ parent = parent->Parent;
+ }
+ return true;
+}
diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h
new file mode 100644
index 0000000..ffc84f8
--- /dev/null
+++ b/Source/cmGeneratorExpressionDAGChecker.h
@@ -0,0 +1,44 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Stephen Kelly <steveire@gmail.com>
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef cmGeneratorExpressionDAGChecker_h
+#define cmGeneratorExpressionDAGChecker_h
+
+#include "cmStandardIncludes.h"
+
+#include "cmGeneratorExpressionEvaluator.h"
+
+//----------------------------------------------------------------------------
+struct cmGeneratorExpressionDAGChecker
+{
+ cmGeneratorExpressionDAGChecker(const cmListFileBacktrace &backtrace,
+ const std::string &target,
+ const std::string &property,
+ const GeneratorExpressionContent *content,
+ cmGeneratorExpressionDAGChecker *parent);
+
+ bool check() const;
+
+ void reportError(cmGeneratorExpressionContext *context,
+ const std::string &expr);
+private:
+ bool isDAG() const;
+
+private:
+ const cmGeneratorExpressionDAGChecker * const Parent;
+ const std::string Target;
+ const std::string Property;
+ const GeneratorExpressionContent * const Content;
+ const cmListFileBacktrace Backtrace;
+ bool IsDAG;
+};
+
+#endif
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx
index 9f84ed2..22f60d4 100644
--- a/Source/cmGeneratorExpressionEvaluator.cxx
+++ b/Source/cmGeneratorExpressionEvaluator.cxx
@@ -13,6 +13,8 @@
#include "cmGeneratorExpressionEvaluator.h"
#include "cmGeneratorExpressionParser.h"
+#include "cmGeneratorExpressionDAGChecker.h"
+#include "cmGeneratorExpression.h"
//----------------------------------------------------------------------------
static void reportError(cmGeneratorExpressionContext *context,
@@ -47,7 +49,8 @@ struct cmGeneratorExpressionNode
virtual std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
- const GeneratorExpressionContent *content
+ const GeneratorExpressionContent *content,
+ cmGeneratorExpressionDAGChecker *dagChecker
) const = 0;
};
@@ -60,7 +63,8 @@ static const struct ZeroNode : public cmGeneratorExpressionNode
std::string Evaluate(const std::vector<std::string> &,
cmGeneratorExpressionContext *,
- const GeneratorExpressionContent *) const
+ const GeneratorExpressionContent *,
+ cmGeneratorExpressionDAGChecker *) const
{
// Unreachable
return std::string();
@@ -76,7 +80,8 @@ static const struct OneNode : public cmGeneratorExpressionNode
std::string Evaluate(const std::vector<std::string> &,
cmGeneratorExpressionContext *,
- const GeneratorExpressionContent *) const
+ const GeneratorExpressionContent *,
+ cmGeneratorExpressionDAGChecker *) const
{
// Unreachable
return std::string();
@@ -93,7 +98,8 @@ static const struct OP ## Node : public cmGeneratorExpressionNode \
\
std::string Evaluate(const std::vector<std::string> &parameters, \
cmGeneratorExpressionContext *context, \
- const GeneratorExpressionContent *content) const \
+ const GeneratorExpressionContent *content, \
+ cmGeneratorExpressionDAGChecker *) const \
{ \
std::vector<std::string>::const_iterator it = parameters.begin(); \
const std::vector<std::string>::const_iterator end = parameters.end(); \
@@ -123,9 +129,11 @@ BOOLEAN_OP_NODE(orNode, OR, 0, 1)
static const struct NotNode : public cmGeneratorExpressionNode
{
NotNode() {}
+
std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
- const GeneratorExpressionContent *content) const
+ const GeneratorExpressionContent *content,
+ cmGeneratorExpressionDAGChecker *) const
{
if (*parameters.begin() != "0" && *parameters.begin() != "1")
{
@@ -138,14 +146,80 @@ static const struct NotNode : public cmGeneratorExpressionNode
} notNode;
//----------------------------------------------------------------------------
+static const struct BoolNode : public cmGeneratorExpressionNode
+{
+ BoolNode() {}
+
+ virtual int NumExpectedParameters() const { return 1; }
+
+ std::string Evaluate(const std::vector<std::string> &parameters,
+ cmGeneratorExpressionContext *,
+ const GeneratorExpressionContent *,
+ cmGeneratorExpressionDAGChecker *) const
+ {
+ return !cmSystemTools::IsOff(parameters.begin()->c_str()) ? "1" : "0";
+ }
+} boolNode;
+
+//----------------------------------------------------------------------------
+static const struct StrEqualNode : public cmGeneratorExpressionNode
+{
+ StrEqualNode() {}
+
+ virtual int NumExpectedParameters() const { return 2; }
+
+ std::string Evaluate(const std::vector<std::string> &parameters,
+ cmGeneratorExpressionContext *,
+ const GeneratorExpressionContent *,
+ cmGeneratorExpressionDAGChecker *) const
+ {
+ return *parameters.begin() == parameters.at(1) ? "1" : "0";
+ }
+} strEqualNode;
+
+//----------------------------------------------------------------------------
+static const struct Angle_RNode : public cmGeneratorExpressionNode
+{
+ Angle_RNode() {}
+
+ virtual int NumExpectedParameters() const { return 0; }
+
+ std::string Evaluate(const std::vector<std::string> &,
+ cmGeneratorExpressionContext *,
+ const GeneratorExpressionContent *,
+ cmGeneratorExpressionDAGChecker *) const
+ {
+ return ">";
+ }
+} angle_rNode;
+
+//----------------------------------------------------------------------------
+static const struct CommaNode : public cmGeneratorExpressionNode
+{
+ CommaNode() {}
+
+ virtual int NumExpectedParameters() const { return 0; }
+
+ std::string Evaluate(const std::vector<std::string> &,
+ cmGeneratorExpressionContext *,
+ const GeneratorExpressionContent *,
+ cmGeneratorExpressionDAGChecker *) const
+ {
+ return ",";
+ }
+} commaNode;
+
+//----------------------------------------------------------------------------
static const struct ConfigurationNode : public cmGeneratorExpressionNode
{
ConfigurationNode() {}
+
virtual int NumExpectedParameters() const { return 0; }
std::string Evaluate(const std::vector<std::string> &,
cmGeneratorExpressionContext *context,
- const GeneratorExpressionContent *) const
+ const GeneratorExpressionContent *,
+ cmGeneratorExpressionDAGChecker *) const
{
return context->Config ? context->Config : "";
}
@@ -160,7 +234,8 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
- const GeneratorExpressionContent *content) const
+ const GeneratorExpressionContent *content,
+ cmGeneratorExpressionDAGChecker *) const
{
if (!context->Config)
{
@@ -180,6 +255,61 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
} configurationTestNode;
//----------------------------------------------------------------------------
+static const struct TargetPropertyNode : public cmGeneratorExpressionNode
+{
+ TargetPropertyNode() {}
+
+ // This node handles errors on parameter count itself.
+ virtual int NumExpectedParameters() const { return -1; }
+
+ std::string Evaluate(const std::vector<std::string> &parameters,
+ cmGeneratorExpressionContext *context,
+ const GeneratorExpressionContent *content,
+ cmGeneratorExpressionDAGChecker *dagCheckerParent
+ ) const
+ {
+ if (parameters.size() != 1 && parameters.size() != 2)
+ {
+ reportError(context, content->GetOriginalExpression(),
+ "$<TARGET_PROPERTY:...> expression requires one or two parameters");
+ return std::string();
+ }
+ cmGeneratorTarget* target = context->Target;
+ std::string propertyName = *parameters.begin();
+ if (parameters.size() == 2)
+ {
+ target = context->Makefile->FindGeneratorTargetToUse(
+ parameters.begin()->c_str());
+
+ if (!target)
+ {
+ cmOStringStream e;
+ e << "Target \""
+ << target
+ << "\" not found.";
+ reportError(context, content->GetOriginalExpression(), e.str());
+ }
+ propertyName = parameters.at(1);
+ }
+
+ cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
+ target->GetName(),
+ propertyName,
+ content,
+ dagCheckerParent);
+
+ if (!dagChecker.check())
+ {
+ dagChecker.reportError(context, content->GetOriginalExpression());
+ return std::string();
+ }
+
+ const char *prop = target->GetProperty(propertyName.c_str());
+ return prop ? prop : "";
+ }
+} targetPropertyNode;
+
+//----------------------------------------------------------------------------
template<bool linker, bool soname>
struct TargetFilesystemArtifactResultCreator
{
@@ -293,7 +423,8 @@ struct TargetFilesystemArtifact : public cmGeneratorExpressionNode
std::string Evaluate(const std::vector<std::string> &parameters,
cmGeneratorExpressionContext *context,
- const GeneratorExpressionContent *content) const
+ const GeneratorExpressionContent *content,
+ cmGeneratorExpressionDAGChecker *) const
{
// Lookup the referenced target.
std::string name = *parameters.begin();
@@ -392,7 +523,18 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
return &targetLinkerFileDirNode;
else if (identifier == "TARGET_SONAME_FILE_DIR")
return &targetSoNameFileDirNode;
+ else if (identifier == "STREQUAL")
+ return &strEqualNode;
+ else if (identifier == "BOOL")
+ return &boolNode;
+ else if (identifier == "ANGLE-R")
+ return &angle_rNode;
+ else if (identifier == "COMMA")
+ return &commaNode;
+ else if (identifier == "TARGET_PROPERTY")
+ return &targetPropertyNode;
return 0;
+
}
//----------------------------------------------------------------------------
@@ -412,7 +554,8 @@ std::string GeneratorExpressionContent::GetOriginalExpression() const
//----------------------------------------------------------------------------
std::string GeneratorExpressionContent::Evaluate(
- cmGeneratorExpressionContext *context) const
+ cmGeneratorExpressionContext *context,
+ cmGeneratorExpressionDAGChecker *dagChecker) const
{
std::string identifier;
{
@@ -422,7 +565,7 @@ std::string GeneratorExpressionContent::Evaluate(
= this->IdentifierChildren.end();
for ( ; it != end; ++it)
{
- identifier += (*it)->Evaluate(context);
+ identifier += (*it)->Evaluate(context, dagChecker);
if (context->HadError)
{
return std::string();
@@ -465,7 +608,7 @@ std::string GeneratorExpressionContent::Evaluate(
= pit->end();
for ( ; it != end; ++it)
{
- result += (*it)->Evaluate(context);
+ result += (*it)->Evaluate(context, dagChecker);
if (context->HadError)
{
return std::string();
@@ -491,7 +634,7 @@ std::string GeneratorExpressionContent::Evaluate(
pit->end();
for ( ; it != end; ++it)
{
- parameter += (*it)->Evaluate(context);
+ parameter += (*it)->Evaluate(context, dagChecker);
if (context->HadError)
{
return std::string();
@@ -534,7 +677,7 @@ std::string GeneratorExpressionContent::Evaluate(
return std::string();
}
- return node->Evaluate(parameters, context, this);
+ return node->Evaluate(parameters, context, this, dagChecker);
}
//----------------------------------------------------------------------------
diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h
index 5163ca0..04a2acd 100644
--- a/Source/cmGeneratorExpressionEvaluator.h
+++ b/Source/cmGeneratorExpressionEvaluator.h
@@ -15,6 +15,11 @@
#include <vector>
#include <string>
+#include "cmListFileCache.h"
+
+class cmTarget;
+class cmGeneratorTarget;
+
//----------------------------------------------------------------------------
struct cmGeneratorExpressionContext
{
@@ -22,11 +27,13 @@ struct cmGeneratorExpressionContext
std::set<cmTarget*> Targets;
cmMakefile *Makefile;
const char *Config;
- cmTarget *Target;
+ cmGeneratorTarget *Target;
bool Quiet;
bool HadError;
};
+struct cmGeneratorExpressionDAGChecker;
+
//----------------------------------------------------------------------------
struct cmGeneratorExpressionEvaluator
{
@@ -41,8 +48,8 @@ struct cmGeneratorExpressionEvaluator
virtual Type GetType() const = 0;
- virtual std::string Evaluate(cmGeneratorExpressionContext *context
- ) const = 0;
+ virtual std::string Evaluate(cmGeneratorExpressionContext *context,
+ cmGeneratorExpressionDAGChecker *) const = 0;
private:
cmGeneratorExpressionEvaluator(const cmGeneratorExpressionEvaluator &);
@@ -57,7 +64,8 @@ struct TextContent : public cmGeneratorExpressionEvaluator
}
- std::string Evaluate(cmGeneratorExpressionContext *) const
+ std::string Evaluate(cmGeneratorExpressionContext *,
+ cmGeneratorExpressionDAGChecker *) const
{
return std::string(this->Content, this->Length);
}
@@ -102,7 +110,8 @@ struct GeneratorExpressionContent : public cmGeneratorExpressionEvaluator
return cmGeneratorExpressionEvaluator::Generator;
}
- std::string Evaluate(cmGeneratorExpressionContext *context) const;
+ std::string Evaluate(cmGeneratorExpressionContext *context,
+ cmGeneratorExpressionDAGChecker *) const;
std::string GetOriginalExpression() const;
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 91f16d1..d4b57f4 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -17,6 +17,8 @@
#include "cmComputeLinkInformation.h"
#include "cmGlobalGenerator.h"
#include "cmSourceFile.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionDAGChecker.h"
#include <assert.h>
@@ -289,19 +291,40 @@ std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories()
{
std::vector<std::string> includes;
const char *prop = this->Target->GetProperty("INCLUDE_DIRECTORIES");
- if(prop)
+ if(!prop)
{
- cmSystemTools::ExpandListArgument(prop, includes);
+ return includes;
}
+ const char *config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE");
+ cmListFileBacktrace lfbt;
+ cmGeneratorExpression ge(lfbt);
+
+ cmGeneratorExpressionDAGChecker dagChecker(lfbt,
+ this->GetName(),
+ "INCLUDE_DIRECTORIES", 0, 0);
+
+ cmSystemTools::ExpandListArgument(ge.Parse(prop)
+ .Evaluate(this->Makefile,
+ config,
+ false,
+ this,
+ &dagChecker),
+ includes);
+
std::set<std::string> uniqueIncludes;
std::vector<std::string> orderedAndUniqueIncludes;
for(std::vector<std::string>::const_iterator
li = includes.begin(); li != includes.end(); ++li)
{
- if(uniqueIncludes.insert(*li).second)
+ std::string inc = *li;
+ if (!cmSystemTools::IsOff(inc.c_str()))
+ {
+ cmSystemTools::ConvertToUnixSlashes(inc);
+ }
+ if(uniqueIncludes.insert(inc).second)
{
- orderedAndUniqueIncludes.push_back(*li);
+ orderedAndUniqueIncludes.push_back(inc);
}
}
@@ -309,15 +332,30 @@ std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories()
}
//----------------------------------------------------------------------------
-const char *cmGeneratorTarget::GetCompileDefinitions(const char *config)
+std::string cmGeneratorTarget::GetCompileDefinitions(const char *config)
{
- if (!config)
+ std::string defPropName = "COMPILE_DEFINITIONS";
+ if (config)
{
- return this->Target->GetProperty("COMPILE_DEFINITIONS");
+ defPropName += "_" + cmSystemTools::UpperCase(config);
}
- std::string defPropName = "COMPILE_DEFINITIONS_";
- defPropName +=
- cmSystemTools::UpperCase(config);
- return this->Target->GetProperty(defPropName.c_str());
+ const char *prop = this->Target->GetProperty(defPropName.c_str());
+
+ if (!prop)
+ {
+ return "";
+ }
+
+ cmListFileBacktrace lfbt;
+ cmGeneratorExpression ge(lfbt);
+
+ cmGeneratorExpressionDAGChecker dagChecker(lfbt,
+ this->GetName(),
+ defPropName, 0, 0);
+ return ge.Parse(prop).Evaluate(this->Makefile,
+ config,
+ false,
+ this,
+ &dagChecker);
}
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 4487c11..8ea17d7 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -74,7 +74,7 @@ public:
/** Get the include directories for this target. */
std::vector<std::string> GetIncludeDirectories();
- const char *GetCompileDefinitions(const char *config = 0);
+ std::string GetCompileDefinitions(const char *config = 0);
private:
void ClassifySources();
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 39b0ffe..95c6807 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -1647,16 +1647,12 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
// Add the export symbol definition for shared library objects.
this->AppendDefines(ppDefs, exportMacro);
}
- this->AppendDefines
- (ppDefs, this->CurrentMakefile->GetProperty("COMPILE_DEFINITIONS"));
- this->AppendDefines(ppDefs, target.GetProperty("COMPILE_DEFINITIONS"));
+ cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&target);
+ this->AppendDefines(ppDefs, gtgt->GetCompileDefinitions().c_str());
if(configName)
{
- std::string defVarName = "COMPILE_DEFINITIONS_";
- defVarName += cmSystemTools::UpperCase(configName);
- this->AppendDefines
- (ppDefs, this->CurrentMakefile->GetProperty(defVarName.c_str()));
- this->AppendDefines(ppDefs, target.GetProperty(defVarName.c_str()));
+ this->AppendDefines(ppDefs,
+ gtgt->GetCompileDefinitions(configName).c_str());
}
buildSettings->AddAttribute
("GCC_PREPROCESSOR_DEFINITIONS", ppDefs.CreateList());
@@ -1713,10 +1709,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
// Set target-specific architectures.
std::vector<std::string> archs;
- {
- cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&target);
gtgt->GetAppleArchs(configName, archs);
- }
+
if(!archs.empty())
{
// Enable ARCHS attribute.
@@ -1953,7 +1947,6 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
BuildObjectListOrString dirs(this, this->XcodeVersion >= 30);
BuildObjectListOrString fdirs(this, this->XcodeVersion >= 30);
std::vector<std::string> includes;
- cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&target);
this->CurrentLocalGenerator->GetIncludeDirectories(includes, gtgt);
std::set<cmStdString> emitted;
emitted.insert("/System/Library/Frameworks");
diff --git a/Source/cmIncludeDirectoryCommand.cxx b/Source/cmIncludeDirectoryCommand.cxx
index 4dd98a1..ba81849 100644
--- a/Source/cmIncludeDirectoryCommand.cxx
+++ b/Source/cmIncludeDirectoryCommand.cxx
@@ -55,6 +55,11 @@ bool cmIncludeDirectoryCommand
return true;
}
+static bool StartsWithGeneratorExpression(const std::string &input)
+{
+ return input[0] == '$' && input[1] == '<';
+}
+
// do a lot of cleanup on the arguments because this is one place where folks
// sometimes take the output of a program and pass it directly into this
// command not thinking that a single argument could be filled with spaces
@@ -105,10 +110,13 @@ void cmIncludeDirectoryCommand::AddDirectory(const char *i,
cmSystemTools::ConvertToUnixSlashes(ret);
if(!cmSystemTools::FileIsFullPath(ret.c_str()))
{
- std::string tmp = this->Makefile->GetStartDirectory();
- tmp += "/";
- tmp += ret;
- ret = tmp;
+ if(!StartsWithGeneratorExpression(ret))
+ {
+ std::string tmp = this->Makefile->GetStartDirectory();
+ tmp += "/";
+ tmp += ret;
+ ret = tmp;
+ }
}
}
this->Makefile->AddIncludeDirectory(ret.c_str(), before);
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index d452658..6079ba8 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -1390,6 +1390,11 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
}
}
+ if(!target)
+ {
+ return;
+ }
+
// Load implicit include directories for this language.
std::string impDirVar = "CMAKE_";
impDirVar += lang;
@@ -1407,10 +1412,8 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
// Get the target-specific include directories.
std::vector<std::string> includes;
- if(target)
- {
- includes = target->GetIncludeDirectories();
- }
+
+ includes = target->GetIncludeDirectories();
// Support putting all the in-project include directories first if
// it is requested by the project.
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 0916d44..9aaacf7 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -157,6 +157,11 @@ public:
*/
void AppendDefines(std::set<std::string>& defines,
const char* defines_list);
+ void AppendDefines(std::set<std::string>& defines,
+ std::string defines_list)
+ {
+ this->AppendDefines(defines, defines_list.c_str());
+ }
/**
* Join a set of defines into a definesString with a space separator.
*/
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 2ededfe..11d9d9c 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -724,10 +724,6 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
flags += targetFlags;
}
- std::string configUpper = cmSystemTools::UpperCase(configName);
- std::string defPropName = "COMPILE_DEFINITIONS_";
- defPropName += configUpper;
-
// Get preprocessor definitions for this directory.
std::string defineFlags = this->Makefile->GetDefineFlags();
Options::Tool t = Options::Compiler;
@@ -744,11 +740,10 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
targetOptions.Parse(flags.c_str());
targetOptions.Parse(defineFlags.c_str());
targetOptions.ParseFinish();
- targetOptions.AddDefines
- (this->Makefile->GetProperty("COMPILE_DEFINITIONS"));
- targetOptions.AddDefines(target.GetProperty("COMPILE_DEFINITIONS"));
- targetOptions.AddDefines(this->Makefile->GetProperty(defPropName.c_str()));
- targetOptions.AddDefines(target.GetProperty(defPropName.c_str()));
+ cmGeneratorTarget* gt =
+ this->GlobalGenerator->GetGeneratorTarget(&target);
+ targetOptions.AddDefines(gt->GetCompileDefinitions().c_str());
+ targetOptions.AddDefines(gt->GetCompileDefinitions(configName).c_str());
targetOptions.SetVerboseMakefile(
this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
@@ -819,8 +814,6 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
targetOptions.OutputAdditionalOptions(fout, "\t\t\t\t", "\n");
fout << "\t\t\t\tAdditionalIncludeDirectories=\"";
std::vector<std::string> includes;
- cmGeneratorTarget* gt =
- this->GlobalGenerator->GetGeneratorTarget(&target);
this->GetIncludeDirectories(includes, gt);
std::vector<std::string>::iterator i = includes.begin();
for(;i != includes.end(); ++i)
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index fea117a..90718ab 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -1225,21 +1225,16 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
flags += " ";
flags += targetFlags;
}
- std::string configUpper = cmSystemTools::UpperCase(configName);
- std::string defPropName = "COMPILE_DEFINITIONS_";
- defPropName += configUpper;
-
// Get preprocessor definitions for this directory.
std::string defineFlags = this->Target->GetMakefile()->GetDefineFlags();
clOptions.FixExceptionHandlingDefault();
clOptions.AddFlag("PrecompiledHeader", "NotUsing");
clOptions.Parse(flags.c_str());
clOptions.Parse(defineFlags.c_str());
- clOptions.AddDefines
- (this->Makefile->GetProperty("COMPILE_DEFINITIONS"));
- clOptions.AddDefines(this->Target->GetProperty("COMPILE_DEFINITIONS"));
- clOptions.AddDefines(this->Makefile->GetProperty(defPropName.c_str()));
- clOptions.AddDefines(this->Target->GetProperty(defPropName.c_str()));
+ clOptions.AddDefines(
+ this->GeneratorTarget->GetCompileDefinitions().c_str());
+ clOptions.AddDefines(this->GeneratorTarget->GetCompileDefinitions(
+ configName.c_str()).c_str());
clOptions.SetVerboseMakefile(
this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
diff --git a/Tests/CompileDefinitions/compiletest.cpp b/Tests/CompileDefinitions/compiletest.cpp
index 6db6f3f..4a68a07 100644
--- a/Tests/CompileDefinitions/compiletest.cpp
+++ b/Tests/CompileDefinitions/compiletest.cpp
@@ -27,6 +27,15 @@ enum {
#endif
};
+#ifdef TEST_GENERATOR_EXPRESSIONS
+#ifndef CMAKE_IS_DECLARATIVE
+#error Expect declarative definition
+#endif
+#ifdef GE_NOT_DEFINED
+#error Expect not defined generator expression
+#endif
+#endif
+
int main(int argc, char **argv)
{
return 0;
diff --git a/Tests/CompileDefinitions/target_prop/CMakeLists.txt b/Tests/CompileDefinitions/target_prop/CMakeLists.txt
index e2b6ba9..fcb22b0 100644
--- a/Tests/CompileDefinitions/target_prop/CMakeLists.txt
+++ b/Tests/CompileDefinitions/target_prop/CMakeLists.txt
@@ -7,3 +7,9 @@ set_target_properties(target_prop_executable PROPERTIES COMPILE_DEFINITIONS CMAK
set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS CMAKE_IS_REALLY="Very Fun" CMAKE_IS=Fun)
set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS CMAKE_IS_FUN CMAKE_IS_="Fun")
+
+set_property(TARGET target_prop_executable APPEND PROPERTY COMPILE_DEFINITIONS
+ TEST_GENERATOR_EXPRESSIONS
+ "$<1:CMAKE_IS_DECLARATIVE>"
+ "$<0:GE_NOT_DEFINED>"
+)
diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt
index 2b135dc..79a8abb 100644
--- a/Tests/GeneratorExpression/CMakeLists.txt
+++ b/Tests/GeneratorExpression/CMakeLists.txt
@@ -22,6 +22,23 @@ add_custom_target(check ALL
-Dtest_or_1=$<OR:1>
-Dtest_or_1_0=$<OR:1,0>
-Dtest_or_1_1=$<OR:1,1>
+ -Dtest_bool_notfound=$<BOOL:NOTFOUND>
+ -Dtest_bool_foo_notfound=$<BOOL:Foo-NOTFOUND>
+ -Dtest_bool_true=$<BOOL:True>
+ -Dtest_bool_false=$<BOOL:False>
+ -Dtest_bool_on=$<BOOL:On>
+ -Dtest_bool_off=$<BOOL:Off>
+ -Dtest_bool_no=$<BOOL:No>
+ -Dtest_bool_n=$<BOOL:N>
+ -Dtest_strequal_yes_yes=$<STREQUAL:Yes,Yes>
+ -Dtest_strequal_yes_yes_cs=$<STREQUAL:Yes,yes>
+ -Dtest_strequal_yes_no=$<STREQUAL:Yes,No>
+ -Dtest_strequal_no_yes=$<STREQUAL:No,Yes>
+ -Dtest_strequal_angle_r=$<STREQUAL:$<ANGLE-R>,$<ANGLE-R>>
+ -Dtest_strequal_comma=$<STREQUAL:$<COMMA>,$<COMMA>>
+ -Dtest_strequal_angle_r_comma=$<STREQUAL:$<ANGLE-R>,$<COMMA>>
+ -Dtest_angle_r=$<ANGLE-R>
+ -Dtest_comma=$<COMMA>
-P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake
COMMAND ${CMAKE_COMMAND} -E echo "check done"
VERBATIM
diff --git a/Tests/GeneratorExpression/check.cmake b/Tests/GeneratorExpression/check.cmake
index e243d85..6fb87a2 100644
--- a/Tests/GeneratorExpression/check.cmake
+++ b/Tests/GeneratorExpression/check.cmake
@@ -23,3 +23,20 @@ check(test_or_0_1 "1")
check(test_or_1 "1")
check(test_or_1_0 "1")
check(test_or_1_1 "1")
+check(test_bool_notfound "0")
+check(test_bool_foo_notfound "0")
+check(test_bool_true "1")
+check(test_bool_false "0")
+check(test_bool_on "1")
+check(test_bool_off "0")
+check(test_bool_no "0")
+check(test_bool_n "0")
+check(test_strequal_yes_yes "1")
+check(test_strequal_yes_yes_cs "0")
+check(test_strequal_yes_no "0")
+check(test_strequal_no_yes "0")
+check(test_strequal_angle_r "1")
+check(test_strequal_comma "1")
+check(test_strequal_angle_r_comma "0")
+check(test_angle_r ">")
+check(test_comma ",")
diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
index 334b8be..4b6f682 100644
--- a/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
+++ b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
@@ -12,13 +12,21 @@ create_header(bar)
create_header(bat)
create_header(foo)
create_header(baz)
+create_header(bang)
+create_header(bing)
+create_header(bung)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories("${CMAKE_CURRENT_BINARY_DIR}/bar")
+include_directories("$<1:${CMAKE_CURRENT_BINARY_DIR}/bang>")
add_executable(TargetIncludeDirectories main.cpp)
set_property(TARGET TargetIncludeDirectories APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/bat")
set_property(TARGET TargetIncludeDirectories APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/foo")
+set_property(TARGET TargetIncludeDirectories APPEND PROPERTY
+ INCLUDE_DIRECTORIES "$<1:${CMAKE_CURRENT_BINARY_DIR}/bing>")
include_directories("${CMAKE_CURRENT_BINARY_DIR}/baz")
+include_directories("$<1:${CMAKE_CURRENT_BINARY_DIR}/bung>")
+include_directories("sing$<1:/ting>")
diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp b/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp
index 8aa3532..63217f4 100644
--- a/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp
+++ b/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp
@@ -3,6 +3,10 @@
#include "bat.h"
#include "foo.h"
#include "baz.h"
+#include "bang.h"
+#include "bing.h"
+#include "bung.h"
+#include "ting.h"
int main(int, char**)
{
diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/sing/ting/ting.h b/Tests/IncludeDirectories/TargetIncludeDirectories/sing/ting/ting.h
new file mode 100644
index 0000000..4fe01dd
--- /dev/null
+++ b/Tests/IncludeDirectories/TargetIncludeDirectories/sing/ting/ting.h
@@ -0,0 +1 @@
+//ting.h
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 3ea54f1..2fa7141 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -46,6 +46,7 @@ macro(add_RunCMake_test test)
endmacro()
add_RunCMake_test(GeneratorExpression)
+add_RunCMake_test(TargetPropertyGeneratorExpressions)
add_RunCMake_test(Languages)
add_RunCMake_test(ObjectLibrary)
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1-result.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1-stderr.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1-stderr.txt
new file mode 100644
index 0000000..791c4a9
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error:
+ Error evaluating generator expression:
+
+ \$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>
+
+ Self reference on target "TargetPropertyGeneratorExpressions".$
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1.cmake b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1.cmake
new file mode 100644
index 0000000..a85731e
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1.cmake
@@ -0,0 +1,7 @@
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+ "int main(int, char **) { return 0; }\n")
+
+add_executable(TargetPropertyGeneratorExpressions
+ "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+include_directories("$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>")
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2-result.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2-stderr.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2-stderr.txt
new file mode 100644
index 0000000..791c4a9
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error:
+ Error evaluating generator expression:
+
+ \$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>
+
+ Self reference on target "TargetPropertyGeneratorExpressions".$
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2.cmake b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2.cmake
new file mode 100644
index 0000000..f1459b8
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2.cmake
@@ -0,0 +1,9 @@
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+ "int main(int, char **) { return 0; }\n")
+
+add_executable(TargetPropertyGeneratorExpressions
+ "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+set_property(TARGET TargetPropertyGeneratorExpressions PROPERTY
+ INCLUDE_DIRECTORIES "$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>"
+)
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3-result.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3-stderr.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3-stderr.txt
new file mode 100644
index 0000000..f60d726
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error:
+ Error evaluating generator expression:
+
+ \$<TARGET_PROPERTY:TargetPropertyGeneratorExpressions,INCLUDE_DIRECTORIES>
+
+ Self reference on target "TargetPropertyGeneratorExpressions".$
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3.cmake b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3.cmake
new file mode 100644
index 0000000..433b730
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3.cmake
@@ -0,0 +1,8 @@
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+ "int main(int, char **) { return 0; }\n")
+
+add_executable(TargetPropertyGeneratorExpressions
+ "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+include_directories(
+ "$<TARGET_PROPERTY:TargetPropertyGeneratorExpressions,INCLUDE_DIRECTORIES>")
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4-result.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4-stderr.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4-stderr.txt
new file mode 100644
index 0000000..f60d726
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error:
+ Error evaluating generator expression:
+
+ \$<TARGET_PROPERTY:TargetPropertyGeneratorExpressions,INCLUDE_DIRECTORIES>
+
+ Self reference on target "TargetPropertyGeneratorExpressions".$
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4.cmake b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4.cmake
new file mode 100644
index 0000000..4b64459
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4.cmake
@@ -0,0 +1,10 @@
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+ "int main(int, char **) { return 0; }\n")
+
+add_executable(TargetPropertyGeneratorExpressions
+ "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+set_property(TARGET TargetPropertyGeneratorExpressions PROPERTY
+INCLUDE_DIRECTORIES
+ "$<TARGET_PROPERTY:TargetPropertyGeneratorExpressions,INCLUDE_DIRECTORIES>"
+)
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5-result.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5-stderr.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5-stderr.txt
new file mode 100644
index 0000000..2b22d0f
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error:
+ Error evaluating generator expression:
+
+ \$<TARGET_PROPERTY:COMPILE_DEFINITIONS>
+
+ Self reference on target "TargetPropertyGeneratorExpressions".$
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5.cmake b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5.cmake
new file mode 100644
index 0000000..74fff67
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5.cmake
@@ -0,0 +1,10 @@
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+ "int main(int, char **) { return 0; }\n")
+
+add_executable(TargetPropertyGeneratorExpressions
+ "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+set_property(TARGET TargetPropertyGeneratorExpressions
+PROPERTY
+ COMPILE_DEFINITIONS "$<TARGET_PROPERTY:COMPILE_DEFINITIONS>"
+)
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6-result.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6-stderr.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6-stderr.txt
new file mode 100644
index 0000000..fe7caa3
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error:
+ Error evaluating generator expression:
+
+ \$<TARGET_PROPERTY:TargetPropertyGeneratorExpressions,COMPILE_DEFINITIONS>
+
+ Self reference on target "TargetPropertyGeneratorExpressions".$
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6.cmake b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6.cmake
new file mode 100644
index 0000000..d6650d3
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6.cmake
@@ -0,0 +1,10 @@
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+ "int main(int, char **) { return 0; }\n")
+
+add_executable(TargetPropertyGeneratorExpressions
+ "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+set_property(TARGET TargetPropertyGeneratorExpressions PROPERTY
+COMPILE_DEFINITIONS
+ "$<TARGET_PROPERTY:TargetPropertyGeneratorExpressions,COMPILE_DEFINITIONS>"
+)
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/CMakeLists.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/CMakeLists.txt
new file mode 100644
index 0000000..22577da
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/CMakeLists.txt
@@ -0,0 +1,8 @@
+
+cmake_minimum_required(VERSION 2.8)
+project(${RunCMake_TEST} CXX)
+
+# MSVC creates extra targets which pollute the stderr unless we set this.
+set(CMAKE_SUPPRESS_REGENERATION TRUE)
+
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/RunCMakeTest.cmake b/Tests/RunCMake/TargetPropertyGeneratorExpressions/RunCMakeTest.cmake
new file mode 100644
index 0000000..f2ff05b
--- /dev/null
+++ b/Tests/RunCMake/TargetPropertyGeneratorExpressions/RunCMakeTest.cmake
@@ -0,0 +1,8 @@
+include(RunCMake)
+
+run_cmake(BadSelfReference1)
+run_cmake(BadSelfReference2)
+run_cmake(BadSelfReference3)
+run_cmake(BadSelfReference4)
+run_cmake(BadSelfReference5)
+run_cmake(BadSelfReference6)
diff --git a/bootstrap b/bootstrap
index ceddfdc..1466a40 100755
--- a/bootstrap
+++ b/bootstrap
@@ -202,6 +202,7 @@ CMAKE_CXX_SOURCES="\
cmInstallDirectoryGenerator \
cmGeneratedFileStream \
cmGeneratorTarget \
+ cmGeneratorExpressionDAGChecker \
cmGeneratorExpressionEvaluator \
cmGeneratorExpressionLexer \
cmGeneratorExpressionParser \