1
0
Эх сурвалжийг харах

Merge topic 'generator-expression-target-properties'

083de7e Process generator expressions in the COMPILE_DEFINITIONS target property.
08cb4fa Process generator expressions in the INCLUDE_DIRECTORIES property.
0ef091d Early return if there is no target.
eb250cd Add a self-reference check for target properties.
7e80747 Add API to check that dependent target properties form a DAG.
239ac84 Add a generator expression for target properties.
e028381 Extend the generator expression language with more logic.
b8e61d6 Refactor GetCompileDefinitions a bit.
2c2b25b Return a std::string from GetCompileDefinitions.
b7e48e0 Add an AppendDefines std::string overload.
9a16087 Convert paths in INCLUDE_DIRECTORIES property to Unix slashes.
4557c8d Don't prepend a path before generator expressions in include_directories.
c6abc41 Add include guard for cmGeneratorExpression.
0ff4e3f Port remaining code to GetCompileDefinitions().
f178d53 Fix indentation in the code blocks generator.
Brad King 13 жил өмнө
parent
commit
103d99338a
47 өөрчлөгдсөн 666 нэмэгдсэн , 121 устгасан
  1. 2 0
      Source/CMakeLists.txt
  2. 1 1
      Source/cmAddTestCommand.h
  3. 16 1
      Source/cmDocumentGeneratorExpressions.h
  4. 47 46
      Source/cmExtraCodeBlocksGenerator.cxx
  5. 6 2
      Source/cmGeneratorExpression.cxx
  6. 11 1
      Source/cmGeneratorExpression.h
  7. 106 0
      Source/cmGeneratorExpressionDAGChecker.cxx
  8. 44 0
      Source/cmGeneratorExpressionDAGChecker.h
  9. 156 13
      Source/cmGeneratorExpressionEvaluator.cxx
  10. 14 5
      Source/cmGeneratorExpressionEvaluator.h
  11. 49 11
      Source/cmGeneratorTarget.cxx
  12. 1 1
      Source/cmGeneratorTarget.h
  13. 5 12
      Source/cmGlobalXCodeGenerator.cxx
  14. 12 4
      Source/cmIncludeDirectoryCommand.cxx
  15. 7 4
      Source/cmLocalGenerator.cxx
  16. 5 0
      Source/cmLocalGenerator.h
  17. 4 11
      Source/cmLocalVisualStudio7Generator.cxx
  18. 4 9
      Source/cmVisualStudio10TargetGenerator.cxx
  19. 9 0
      Tests/CompileDefinitions/compiletest.cpp
  20. 6 0
      Tests/CompileDefinitions/target_prop/CMakeLists.txt
  21. 17 0
      Tests/GeneratorExpression/CMakeLists.txt
  22. 17 0
      Tests/GeneratorExpression/check.cmake
  23. 8 0
      Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
  24. 4 0
      Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp
  25. 1 0
      Tests/IncludeDirectories/TargetIncludeDirectories/sing/ting/ting.h
  26. 1 0
      Tests/RunCMake/CMakeLists.txt
  27. 1 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1-result.txt
  28. 6 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1-stderr.txt
  29. 7 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1.cmake
  30. 1 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2-result.txt
  31. 6 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2-stderr.txt
  32. 9 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2.cmake
  33. 1 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3-result.txt
  34. 6 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3-stderr.txt
  35. 8 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3.cmake
  36. 1 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4-result.txt
  37. 6 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4-stderr.txt
  38. 10 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4.cmake
  39. 1 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5-result.txt
  40. 6 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5-stderr.txt
  41. 10 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5.cmake
  42. 1 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6-result.txt
  43. 6 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6-stderr.txt
  44. 10 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6.cmake
  45. 8 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/CMakeLists.txt
  46. 8 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/RunCMakeTest.cmake
  47. 1 0
      bootstrap

+ 2 - 0
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

+ 1 - 1
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"

+ 16 - 1
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

+ 47 - 46
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"

+ 6 - 2
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 = "";

+ 11 - 1
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

+ 106 - 0
Source/cmGeneratorExpressionDAGChecker.cxx

@@ -0,0 +1,106 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2012 Stephen Kelly <[email protected]>
+
+  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;
+}

+ 44 - 0
Source/cmGeneratorExpressionDAGChecker.h

@@ -0,0 +1,44 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2012 Stephen Kelly <[email protected]>
+
+  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

+ 156 - 13
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")
       {
@@ -137,15 +145,81 @@ 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)
       {
@@ -179,6 +254,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);
 }
 
 //----------------------------------------------------------------------------

+ 14 - 5
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;
 

+ 49 - 11
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);
 }

+ 1 - 1
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();

+ 5 - 12
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");

+ 12 - 4
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);

+ 7 - 4
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.

+ 5 - 0
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.
    */

+ 4 - 11
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)

+ 4 - 9
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"));
 

+ 9 - 0
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;

+ 6 - 0
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>"
+)

+ 17 - 0
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

+ 17 - 0
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 ",")

+ 8 - 0
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>")

+ 4 - 0
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**)
 {

+ 1 - 0
Tests/IncludeDirectories/TargetIncludeDirectories/sing/ting/ting.h

@@ -0,0 +1 @@
+//ting.h

+ 1 - 0
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)
 

+ 1 - 0
Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1-result.txt

@@ -0,0 +1 @@
+1

+ 6 - 0
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".$

+ 7 - 0
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>")

+ 1 - 0
Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2-result.txt

@@ -0,0 +1 @@
+1

+ 6 - 0
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".$

+ 9 - 0
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>"
+)

+ 1 - 0
Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3-result.txt

@@ -0,0 +1 @@
+1

+ 6 - 0
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".$

+ 8 - 0
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>")

+ 1 - 0
Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4-result.txt

@@ -0,0 +1 @@
+1

+ 6 - 0
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".$

+ 10 - 0
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>"
+)

+ 1 - 0
Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5-result.txt

@@ -0,0 +1 @@
+1

+ 6 - 0
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".$

+ 10 - 0
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>"
+)

+ 1 - 0
Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6-result.txt

@@ -0,0 +1 @@
+1

+ 6 - 0
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".$

+ 10 - 0
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>"
+)

+ 8 - 0
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)

+ 8 - 0
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)

+ 1 - 0
bootstrap

@@ -202,6 +202,7 @@ CMAKE_CXX_SOURCES="\
   cmInstallDirectoryGenerator \
   cmGeneratedFileStream \
   cmGeneratorTarget \
+  cmGeneratorExpressionDAGChecker \
   cmGeneratorExpressionEvaluator \
   cmGeneratorExpressionLexer \
   cmGeneratorExpressionParser \