ソースを参照

Merge topic 'tll-includes-defines'

e48d842 Cache context-independent includes on evaluation.
089fe1c Optimize genex evaluation for includes and defines.
179f495 find_package: Reword <package>_NO_INTERFACES documentation
e7b579b Test workaround of bad interface include directories from depends.
77cecb7 Add includes and compile definitions with target_link_libraries.
0b92602 Add the $<LINKED:...> generator expression.
0fa7f69 Add API to check if we're reading a includes or defines property.
2c3654c Add a way to exclude INTERFACE properties from exported targets.
d4297d5 Export targets to a targets file, not a Config file.
df4d2b2 Make it an error for INSTALL_PREFIX to be evaluated.
7ceeba9 Advance more when preprocessing exported strings.
30268b4 Handle reading empty properties defined by the link interface.
Brad King 12 年 前
コミット
ec85306025
41 ファイル変更633 行追加94 行削除
  1. 8 0
      Source/cmDocumentGeneratorExpressions.h
  2. 65 10
      Source/cmExportFileGenerator.cxx
  3. 2 2
      Source/cmExportFileGenerator.h
  4. 20 0
      Source/cmFindPackageCommand.cxx
  5. 7 1
      Source/cmGeneratorExpression.cxx
  6. 5 0
      Source/cmGeneratorExpression.h
  7. 42 0
      Source/cmGeneratorExpressionDAGChecker.cxx
  8. 5 1
      Source/cmGeneratorExpressionDAGChecker.h
  9. 122 5
      Source/cmGeneratorExpressionEvaluator.cxx
  10. 1 0
      Source/cmGeneratorExpressionEvaluator.h
  11. 30 11
      Source/cmTarget.cxx
  12. 3 3
      Source/cmTarget.h
  13. 53 0
      Source/cmTargetLinkLibrariesCommand.cxx
  14. 9 0
      Source/cmTargetLinkLibrariesCommand.h
  15. 6 0
      Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt
  16. 4 0
      Tests/CMakeCommands/target_compile_definitions/consumer.cpp
  17. 10 1
      Tests/CMakeCommands/target_include_directories/CMakeLists.txt
  18. 5 0
      Tests/CMakeCommands/target_include_directories/consumer.cpp
  19. 21 4
      Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
  20. 7 0
      Tests/CMakeCommands/target_link_libraries/depG.cpp
  21. 7 0
      Tests/CMakeCommands/target_link_libraries/depG.h
  22. 16 0
      Tests/CMakeCommands/target_link_libraries/targetC.cpp
  23. 13 1
      Tests/CompatibleInterface/CMakeLists.txt
  24. 22 19
      Tests/ExportImport/Export/CMakeLists.txt
  25. 3 15
      Tests/ExportImport/Import/A/CMakeLists.txt
  26. 5 0
      Tests/ExportImport/Import/CMakeLists.txt
  27. 23 0
      Tests/ExportImport/Import/package_new_new/CMakeLists.txt
  28. 24 0
      Tests/ExportImport/Import/package_new_old/CMakeLists.txt
  29. 24 0
      Tests/ExportImport/Import/package_old_old/CMakeLists.txt
  30. 0 1
      Tests/GeneratorExpression/CMakeLists.txt
  31. 0 1
      Tests/GeneratorExpression/check-part2.cmake
  32. 41 0
      Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
  33. 0 19
      Tests/Qt4Targets/CMakeLists.txt
  34. 1 0
      Tests/RunCMake/GeneratorExpression/BadInstallPrefix-result.txt
  35. 9 0
      Tests/RunCMake/GeneratorExpression/BadInstallPrefix-stderr.txt
  36. 3 0
      Tests/RunCMake/GeneratorExpression/BadInstallPrefix.cmake
  37. 1 0
      Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
  38. 1 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadLinked-result.txt
  39. 7 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadLinked-stderr.txt
  40. 7 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/BadLinked.cmake
  41. 1 0
      Tests/RunCMake/TargetPropertyGeneratorExpressions/RunCMakeTest.cmake

+ 8 - 0
Source/cmDocumentGeneratorExpressions.h

@@ -51,6 +51,14 @@
   "on the target tgt.\n"                                                \
   "Note that tgt is not added as a dependency of the target this "      \
   "expression is evaluated on.\n"                                       \
+  "  $<LINKED:item>            = An empty string if item is not a "     \
+  "target.  If item is a target then the "                              \
+  "INTERFACE_INCLUDE_DIRECTORIES or INTERFACE_COMPILE_DEFINITIONS "     \
+  "content is read from the target.  "                                  \
+  "This generator expression can only be used in evaluation of the "    \
+  "INCLUDE_DIRECTORIES or COMPILE_DEFINITIONS property.  Note that "    \
+  "this expression is for internal use and may be changed or removed "  \
+  "in the future.\n"                                                    \
   "  $<TARGET_POLICY:pol>          = '1' if the policy was NEW when "   \
   "the 'head' target was created, else '0'.  If the policy was not "    \
   "set, the warning message for the policy will be emitted.  This "     \

+ 65 - 10
Source/cmExportFileGenerator.cxx

@@ -25,6 +25,8 @@
 
 #include <cmsys/auto_ptr.hxx>
 
+#include "assert.h"
+
 //----------------------------------------------------------------------------
 cmExportFileGenerator::cmExportFileGenerator()
 {
@@ -160,7 +162,7 @@ void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName,
                                                            preprocessRule);
     if (!prepro.empty())
       {
-      this->ResolveTargetsInGeneratorExpressions(prepro, target,
+      this->ResolveTargetsInGeneratorExpressions(prepro, target, propName,
                                                  missingTargets);
       properties[outputName] = prepro;
       }
@@ -264,15 +266,16 @@ void cmExportFileGenerator::GenerateInterfaceProperties(cmTarget *target,
 {
   if (!properties.empty())
     {
+    os << "if(NOT ${CMAKE_FIND_PACKAGE_NAME}_NO_INTERFACES)\n";
     std::string targetName = this->Namespace;
     targetName += target->GetName();
-    os << "set_target_properties(" << targetName << " PROPERTIES\n";
+    os << "  set_target_properties(" << targetName << " PROPERTIES\n";
     for(ImportPropertyMap::const_iterator pi = properties.begin();
         pi != properties.end(); ++pi)
       {
-      os << "  " << pi->first << " \"" << pi->second << "\"\n";
+      os << "    " << pi->first << " \"" << pi->second << "\"\n";
       }
-    os << ")\n\n";
+    os << "  )\nendif()\n\n";
     }
 }
 
@@ -323,13 +326,14 @@ static bool isGeneratorExpression(const std::string &lib)
 void
 cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
                                     std::string &input,
-                                    cmTarget* target,
+                                    cmTarget* target, const char *propName,
                                     std::vector<std::string> &missingTargets,
                                     FreeTargetsReplace replace)
 {
   if (replace == NoReplaceFreeTargets)
     {
-    this->ResolveTargetsInGeneratorExpression(input, target, missingTargets);
+    this->ResolveTargetsInGeneratorExpression(input, target, propName,
+                                              missingTargets);
     return;
     }
   std::vector<std::string> parts;
@@ -348,7 +352,7 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
       {
       this->ResolveTargetsInGeneratorExpression(
                                     *li,
-                                    target,
+                                    target, propName,
                                     missingTargets);
       }
     input += sep + *li;
@@ -360,7 +364,7 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
 void
 cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
                                     std::string &input,
-                                    cmTarget* target,
+                                    cmTarget* target, const char *propName,
                                     std::vector<std::string> &missingTargets)
 {
   std::string::size_type pos = 0;
@@ -391,10 +395,61 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
       {
       input.replace(nameStartPos, commaPos - nameStartPos, targetName);
       }
-    lastPos = pos + targetName.size();
+    lastPos = nameStartPos + targetName.size() + 1;
     }
 
   std::string errorString;
+  pos = 0;
+  lastPos = pos;
+  while((pos = input.find("$<LINKED:", lastPos)) != input.npos)
+    {
+    std::string::size_type nameStartPos = pos + sizeof("$<LINKED:") - 1;
+    std::string::size_type endPos = input.find(">", nameStartPos);
+    if (endPos == input.npos)
+      {
+      errorString = "$<LINKED:...> expression incomplete";
+      break;
+      }
+    std::string targetName = input.substr(nameStartPos,
+                                                endPos - nameStartPos);
+    if(targetName.find("$<") != input.npos)
+      {
+      errorString = "$<LINKED:...> requires its parameter to be a "
+                    "literal.";
+      break;
+      }
+    if (this->AddTargetNamespace(targetName, target, missingTargets))
+      {
+      assert(propName); // The link libraries strings will
+                        // never contain $<LINKED>
+      std::string replacement = "$<TARGET_PROPERTY:"
+                              + targetName + "," + propName;
+      input.replace(pos, endPos - pos, replacement);
+      lastPos = pos + replacement.size() + 1;
+      }
+    else
+      {
+      if (pos != 0)
+        {
+        if (input[pos - 1] == ';')
+          {
+          --pos;
+          }
+        }
+      else if (input[endPos + 1] == ';')
+        {
+        ++endPos;
+        }
+      input.replace(pos, endPos - pos + 1, "");
+      lastPos = pos;
+      }
+    }
+  if (!errorString.empty())
+    {
+    mf->IssueMessage(cmake::FATAL_ERROR, errorString);
+    return;
+    }
+
   pos = 0;
   lastPos = pos;
   while((pos = input.find("$<TARGET_NAME:", lastPos)) != input.npos)
@@ -490,7 +545,7 @@ cmExportFileGenerator
                                                          preprocessRule);
   if (!prepro.empty())
     {
-    this->ResolveTargetsInGeneratorExpressions(prepro, target,
+    this->ResolveTargetsInGeneratorExpressions(prepro, target, 0,
                                                missingTargets,
                                                ReplaceFreeTargets);
     properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = prepro;

+ 2 - 2
Source/cmExportFileGenerator.h

@@ -119,7 +119,7 @@ protected:
   };
 
   void ResolveTargetsInGeneratorExpressions(std::string &input,
-                          cmTarget* target,
+                          cmTarget* target, const char *propName,
                           std::vector<std::string> &missingTargets,
                           FreeTargetsReplace replace = NoReplaceFreeTargets);
 
@@ -150,7 +150,7 @@ private:
                           std::vector<std::string> &missingTargets);
 
   void ResolveTargetsInGeneratorExpression(std::string &input,
-                                    cmTarget* target,
+                                    cmTarget* target, const char *propName,
                                     std::vector<std::string> &missingTargets);
 
   virtual void ReplaceInstallPrefix(std::string &input);

+ 20 - 0
Source/cmFindPackageCommand.cxx

@@ -376,6 +376,26 @@ void cmFindPackageCommand::GenerateDocumentation()
     "The package configuration file may set <package>_FOUND to false "
     "to tell find_package that component requirements are not satisfied."
     "\n"
+    "A package configuration file may include() a <package>Targets.cmake "
+    "file, created by install(EXPORT) in the upstream source, to import "
+    "targets into the downstream consumer.  "
+    "When a new version of the upstream adds INTERFACE properties not "
+    "present in a previous version it can change behavior for existing "
+    "downstreams.  "
+    "In order to remain source compatible the upstream package configuration "
+    "file may set <package>_NO_INTERFACES to disable INTERFACE properties.  "
+    "For example, code of the form:\n"
+    "  if(<package>_FIND_VERSION VERSION_LESS <new-version>\n"
+    "      AND NOT <package>_INTERFACES)\n"
+    "    set(<package>_NO_INTERFACES 1)\n"
+    "  endif()\n"
+    "  include(\"${CMAKE_CURRENT_LIST_DIR}/<package>Targets.cmake\")\n"
+    "tells <package>Targets.cmake not to provide the INTERFACE properties "
+    "unless the downstream requests at least <new-version> or sets "
+    "<package>_INTERFACES to explicitly request them.  "
+    "This allows consumers to decide when to enable the new interfaces when "
+    "upgrading."
+    "\n"
     "See the cmake_policy() command documentation for discussion of the "
     "NO_POLICY_SCOPE option."
     ;

+ 7 - 1
Source/cmGeneratorExpression.cxx

@@ -88,6 +88,7 @@ const char *cmCompiledGeneratorExpression::Evaluate(
   context.Config = config;
   context.Quiet = quiet;
   context.HadError = false;
+  context.HadContextSensitiveCondition = false;
   context.HeadTarget = headTarget;
   context.CurrentTarget = currentTarget ? currentTarget : headTarget;
   context.Backtrace = this->Backtrace;
@@ -109,6 +110,10 @@ const char *cmCompiledGeneratorExpression::Evaluate(
       break;
       }
     }
+  if (!context.HadError)
+    {
+    this->HadContextSensitiveCondition = context.HadContextSensitiveCondition;
+    }
 
   this->Targets = context.Targets;
   // TODO: Return a std::string from here instead?
@@ -118,7 +123,8 @@ const char *cmCompiledGeneratorExpression::Evaluate(
 cmCompiledGeneratorExpression::cmCompiledGeneratorExpression(
               cmListFileBacktrace const& backtrace,
               const char *input)
-  : Backtrace(backtrace), Input(input ? input : "")
+  : Backtrace(backtrace), Input(input ? input : ""),
+    HadContextSensitiveCondition(false)
 {
   cmGeneratorExpressionLexer l;
   std::vector<cmGeneratorExpressionToken> tokens =

+ 5 - 0
Source/cmGeneratorExpression.h

@@ -100,6 +100,10 @@ public:
   {
     return this->Backtrace;
   }
+  bool GetHadContextSensitiveCondition() const
+  {
+    return this->HadContextSensitiveCondition;
+  }
 
 private:
   cmCompiledGeneratorExpression(cmListFileBacktrace const& backtrace,
@@ -118,6 +122,7 @@ private:
   mutable std::set<cmTarget*> Targets;
   mutable std::map<cmStdString, cmStdString> SeenTargetProperties;
   mutable std::string Output;
+  mutable bool HadContextSensitiveCondition;
 };
 
 #endif

+ 42 - 0
Source/cmGeneratorExpressionDAGChecker.cxx

@@ -24,7 +24,33 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
   : Parent(parent), Target(target), Property(property),
     Content(content), Backtrace(backtrace)
 {
+  const cmGeneratorExpressionDAGChecker *top = this;
+  const cmGeneratorExpressionDAGChecker *p = this->Parent;
+  while (p)
+    {
+    top = p;
+    p = p->Parent;
+    }
   this->CheckResult = this->checkGraph();
+
+  if (CheckResult == DAG && (top->Property == "INCLUDE_DIRECTORIES"
+      || top->Property == "COMPILE_DEFINITIONS") )
+    {
+    std::map<cmStdString, std::set<cmStdString> >::const_iterator it
+                                                    = top->Seen.find(target);
+    if (it != top->Seen.end())
+      {
+      const std::set<cmStdString> &propSet = it->second;
+      const std::set<cmStdString>::const_iterator i = propSet.find(property);
+      if (i != propSet.end())
+        {
+        this->CheckResult = ALREADY_SEEN;
+        return;
+        }
+      }
+    const_cast<cmGeneratorExpressionDAGChecker *>(top)
+                                            ->Seen[target].insert(property);
+    }
 }
 
 //----------------------------------------------------------------------------
@@ -125,3 +151,19 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries()
        || strncmp(prop, "LINK_INTERFACE_LIBRARIES_", 26) == 0
        || strncmp(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_", 35) == 0);
 }
+
+//----------------------------------------------------------------------------
+bool cmGeneratorExpressionDAGChecker::EvaluatingIncludeDirectories()
+{
+  const char *prop = this->Property.c_str();
+  return (strcmp(prop, "INCLUDE_DIRECTORIES") == 0
+       || strcmp(prop, "INTERFACE_INCLUDE_DIRECTORIES") == 0 );
+}
+
+//----------------------------------------------------------------------------
+bool cmGeneratorExpressionDAGChecker::EvaluatingCompileDefinitions()
+{
+  const char *prop = this->Property.c_str();
+  return (strcmp(prop, "COMPILE_DEFINITIONS") == 0
+       || strcmp(prop, "INTERFACE_COMPILE_DEFINITIONS") == 0 );
+}

+ 5 - 1
Source/cmGeneratorExpressionDAGChecker.h

@@ -28,7 +28,8 @@ struct cmGeneratorExpressionDAGChecker
   enum Result {
     DAG,
     SELF_REFERENCE,
-    CYCLIC_REFERENCE
+    CYCLIC_REFERENCE,
+    ALREADY_SEEN
   };
 
   Result check() const;
@@ -37,6 +38,8 @@ struct cmGeneratorExpressionDAGChecker
                    const std::string &expr);
 
   bool EvaluatingLinkLibraries();
+  bool EvaluatingIncludeDirectories();
+  bool EvaluatingCompileDefinitions();
 
 private:
   Result checkGraph() const;
@@ -45,6 +48,7 @@ private:
   const cmGeneratorExpressionDAGChecker * const Parent;
   const std::string Target;
   const std::string Property;
+  std::map<cmStdString, std::set<cmStdString> > Seen;
   const GeneratorExpressionContent * const Content;
   const cmListFileBacktrace Backtrace;
   Result CheckResult;

+ 122 - 5
Source/cmGeneratorExpressionEvaluator.cxx

@@ -238,6 +238,7 @@ static const struct ConfigurationNode : public cmGeneratorExpressionNode
                        const GeneratorExpressionContent *,
                        cmGeneratorExpressionDAGChecker *) const
   {
+    context->HadContextSensitiveCondition = true;
     return context->Config ? context->Config : "";
   }
 } configurationNode;
@@ -262,6 +263,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
                   "Expression syntax not recognized.");
       return std::string();
       }
+    context->HadContextSensitiveCondition = true;
     if (!context->Config)
       {
       return parameters.front().empty() ? "1" : "0";
@@ -435,6 +437,9 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
     case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
       // No error. We just skip cyclic references.
       return std::string();
+    case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
+      // No error. We're not going to find anything new here.
+      return std::string();
     case cmGeneratorExpressionDAGChecker::DAG:
       break;
       }
@@ -452,12 +457,14 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
         }
       if (propertyName == "POSITION_INDEPENDENT_CODE")
         {
+        context->HadContextSensitiveCondition = true;
         return target->GetLinkInterfaceDependentBoolProperty(
                     "POSITION_INDEPENDENT_CODE", context->Config) ? "1" : "0";
         }
       if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
                                                        context->Config))
         {
+        context->HadContextSensitiveCondition = true;
         return target->GetLinkInterfaceDependentBoolProperty(
                                                 propertyName,
                                                 context->Config) ? "1" : "0";
@@ -465,9 +472,12 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
       if (target->IsLinkInterfaceDependentStringProperty(propertyName,
                                                          context->Config))
         {
-        return target->GetLinkInterfaceDependentStringProperty(
+        context->HadContextSensitiveCondition = true;
+        const char *propContent =
+                              target->GetLinkInterfaceDependentStringProperty(
                                                 propertyName,
                                                 context->Config);
+        return propContent ? propContent : "";
         }
 
       return std::string();
@@ -481,12 +491,19 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
       if (targetPropertyTransitiveWhitelist[i] == propertyName)
         {
         cmGeneratorExpression ge(context->Backtrace);
-        return ge.Parse(prop)->Evaluate(context->Makefile,
+        cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
+        std::string result = cge->Evaluate(context->Makefile,
                             context->Config,
                             context->Quiet,
                             context->HeadTarget,
                             target,
                             &dagChecker);
+
+        if (cge->GetHadContextSensitiveCondition())
+          {
+          context->HadContextSensitiveCondition = true;
+          }
+        return result;
         }
       }
     return prop;
@@ -580,6 +597,9 @@ static const struct TargetPolicyNode : public cmGeneratorExpressionNode
           "be used with add_custom_command.");
       return std::string();
       }
+
+    context->HadContextSensitiveCondition = true;
+
     for (size_t i = 0;
          i < (sizeof(targetPolicyWhitelist) /
               sizeof(*targetPolicyWhitelist));
@@ -619,19 +639,114 @@ static const struct InstallPrefixNode : public cmGeneratorExpressionNode
 {
   InstallPrefixNode() {}
 
-  virtual bool GeneratesContent() const { return false; }
+  virtual bool GeneratesContent() const { return true; }
   virtual int NumExpectedParameters() const { return 0; }
 
   std::string Evaluate(const std::vector<std::string> &,
-                       cmGeneratorExpressionContext *,
-                       const GeneratorExpressionContent *,
+                       cmGeneratorExpressionContext *context,
+                       const GeneratorExpressionContent *content,
                        cmGeneratorExpressionDAGChecker *) const
   {
+    reportError(context, content->GetOriginalExpression(),
+                "INSTALL_PREFIX is a marker for install(EXPORT) only.  It "
+                "should never be evaluated.");
     return std::string();
   }
 
 } installPrefixNode;
 
+//----------------------------------------------------------------------------
+static const struct LinkedNode : public cmGeneratorExpressionNode
+{
+  LinkedNode() {}
+
+  virtual bool GeneratesContent() const { return true; }
+  virtual int NumExpectedParameters() const { return 1; }
+  virtual bool RequiresLiteralInput() const { return true; }
+
+  std::string Evaluate(const std::vector<std::string> &parameters,
+                       cmGeneratorExpressionContext *context,
+                       const GeneratorExpressionContent *content,
+                       cmGeneratorExpressionDAGChecker *dagChecker) const
+  {
+    if (dagChecker->EvaluatingIncludeDirectories())
+      {
+      return this->GetInterfaceProperty(parameters.front(),
+                                        "INCLUDE_DIRECTORIES",
+                                        context, content, dagChecker);
+      }
+    if (dagChecker->EvaluatingCompileDefinitions())
+      {
+      return this->GetInterfaceProperty(parameters.front(),
+                                        "COMPILE_DEFINITIONS",
+                                        context, content, dagChecker);
+      }
+
+    reportError(context, content->GetOriginalExpression(),
+                "$<LINKED:...> may only be used in INCLUDE_DIRECTORIES and "
+                "COMPILE_DEFINITIONS properties.");
+
+    return std::string();
+  }
+
+private:
+  std::string GetInterfaceProperty(const std::string &item,
+                      const std::string &prop,
+                      cmGeneratorExpressionContext *context,
+                      const GeneratorExpressionContent *content,
+                      cmGeneratorExpressionDAGChecker *dagCheckerParent) const
+  {
+    cmTarget *target = context->CurrentTarget
+                              ->GetMakefile()->FindTargetToUse(item.c_str());
+    if (!target)
+      {
+      return std::string();
+      }
+    std::string propertyName = "INTERFACE_" + prop;
+    const char *propContent = target->GetProperty(propertyName.c_str());
+    if (!propContent)
+      {
+      return std::string();
+      }
+
+    cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
+                                               target->GetName(),
+                                               propertyName,
+                                               content,
+                                               dagCheckerParent);
+
+    switch (dagChecker.check())
+      {
+    case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
+      dagChecker.reportError(context, content->GetOriginalExpression());
+      return std::string();
+    case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
+      // No error. We just skip cyclic references.
+      return std::string();
+    case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
+      // No error. We're not going to find anything new here.
+      return std::string();
+    case cmGeneratorExpressionDAGChecker::DAG:
+      break;
+      }
+
+    cmGeneratorExpression ge(context->Backtrace);
+    cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(propContent);
+    std::string result = cge->Evaluate(context->Makefile,
+                        context->Config,
+                        context->Quiet,
+                        context->HeadTarget,
+                        target,
+                        &dagChecker);
+    if (cge->GetHadContextSensitiveCondition())
+      {
+      context->HadContextSensitiveCondition = true;
+      }
+    return result;
+  }
+
+} linkedNode;
+
 //----------------------------------------------------------------------------
 template<bool linker, bool soname>
 struct TargetFilesystemArtifactResultCreator
@@ -869,6 +984,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
     return &targetDefinedNode;
   else if (identifier == "INSTALL_PREFIX")
     return &installPrefixNode;
+  else if (identifier == "LINKED")
+    return &linkedNode;
   return 0;
 
 }

+ 1 - 0
Source/cmGeneratorExpressionEvaluator.h

@@ -32,6 +32,7 @@ struct cmGeneratorExpressionContext
                            // directly or indirectly in the property.
   bool Quiet;
   bool HadError;
+  bool HadContextSensitiveCondition;
 };
 
 struct cmGeneratorExpressionDAGChecker;

+ 30 - 11
Source/cmTarget.cxx

@@ -134,6 +134,7 @@ public:
       : ge(cge)
     {}
     const cmsys::auto_ptr<cmCompiledGeneratorExpression> ge;
+    std::vector<std::string> CachedIncludes;
   };
   std::vector<IncludeDirectoriesEntry*> IncludeDirectoriesEntries;
 };
@@ -2778,22 +2779,36 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config)
       end = this->Internal->IncludeDirectoriesEntries.end();
       it != end; ++it)
     {
-    std::vector<std::string> entryIncludes;
-    cmSystemTools::ExpandListArgument((*it)->ge->Evaluate(this->Makefile,
-                                              config,
-                                              false,
-                                              this,
-                                              &dagChecker),
-                                    entryIncludes);
+
+    bool testIsOff = true;
+    bool cacheIncludes = false;
+    std::vector<std::string> entryIncludes = (*it)->CachedIncludes;
+    if(!entryIncludes.empty())
+      {
+      testIsOff = false;
+      }
+    else
+      {
+      cmSystemTools::ExpandListArgument((*it)->ge->Evaluate(this->Makefile,
+                                                config,
+                                                false,
+                                                this,
+                                                &dagChecker),
+                                      entryIncludes);
+      if (!(*it)->ge->GetHadContextSensitiveCondition())
+        {
+        cacheIncludes = true;
+        }
+      }
     std::string usedIncludes;
-    for(std::vector<std::string>::const_iterator
+    for(std::vector<std::string>::iterator
           li = entryIncludes.begin(); li != entryIncludes.end(); ++li)
       {
-      std::string inc = *li;
-      if (!cmSystemTools::IsOff(inc.c_str()))
+      if (testIsOff && !cmSystemTools::IsOff(li->c_str()))
         {
-        cmSystemTools::ConvertToUnixSlashes(inc);
+        cmSystemTools::ConvertToUnixSlashes(*li);
         }
+      std::string inc = *li;
 
       if(uniqueIncludes.insert(inc).second)
         {
@@ -2804,6 +2819,10 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config)
           }
         }
       }
+    if (cacheIncludes)
+      {
+      (*it)->CachedIncludes = entryIncludes;
+      }
     if (!usedIncludes.empty())
       {
       this->Makefile->GetCMakeInstance()->IssueMessage(cmake::LOG,

+ 3 - 3
Source/cmTarget.h

@@ -514,6 +514,9 @@ public:
 
   const char *GetLinkInterfaceDependentStringProperty(const std::string &p,
                                                       const char *config);
+
+  std::string GetDebugGeneratorExpressions(const std::string &value,
+                                  cmTarget::LinkLibraryType llt);
 private:
   /**
    * A list of direct dependencies. Use in conjunction with DependencyMap.
@@ -659,9 +662,6 @@ private:
 
   void ProcessSourceExpression(std::string const& expr);
 
-  std::string GetDebugGeneratorExpressions(const std::string &value,
-                                  cmTarget::LinkLibraryType llt);
-
   // The cmMakefile instance that owns this target.  This should
   // always be set.
   cmMakefile* Makefile;

+ 53 - 0
Source/cmTargetLinkLibrariesCommand.cxx

@@ -249,11 +249,52 @@ cmTargetLinkLibrariesCommand
   this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
 }
 
+//----------------------------------------------------------------------------
+static std::string compileProperty(cmTarget *tgt, const std::string &lib,
+                                   bool isGenex,
+                                   const std::string &property,
+                                   cmTarget::LinkLibraryType llt)
+{
+  std::string value = !isGenex ? "$<LINKED:" + lib + ">"
+                               : "$<$<TARGET_DEFINED:" + lib + ">:" +
+                                   "$<TARGET_PROPERTY:" + lib +
+                                   ",INTERFACE_" + property + ">"
+                                 ">";
+
+  return tgt->GetDebugGeneratorExpressions(value, llt);
+}
+
+//----------------------------------------------------------------------------
+static bool isGeneratorExpression(const std::string &lib)
+{
+  const std::string::size_type openpos = lib.find("$<");
+  return (openpos != std::string::npos)
+      && (lib.find(">", openpos) != std::string::npos);
+}
+
 //----------------------------------------------------------------------------
 void
 cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
                                             cmTarget::LinkLibraryType llt)
 {
+  const bool isGenex = isGeneratorExpression(lib);
+
+  cmsys::RegularExpression targetNameValidator;
+  targetNameValidator.compile("^[A-Za-z0-9_.:-]+$");
+  const bool potentialTargetName = targetNameValidator.find(lib);
+
+  if (potentialTargetName || isGenex)
+    {
+    this->Target->AppendProperty("INCLUDE_DIRECTORIES",
+                                 compileProperty(this->Target, lib,
+                                                 isGenex,
+                                      "INCLUDE_DIRECTORIES", llt).c_str());
+    this->Target->AppendProperty("COMPILE_DEFINITIONS",
+                                 compileProperty(this->Target, lib,
+                                                 isGenex,
+                                      "COMPILE_DEFINITIONS", llt).c_str());
+    }
+
   // Handle normal case first.
   if(this->CurrentProcessingState != ProcessingLinkInterface)
     {
@@ -266,6 +307,18 @@ cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
       }
     }
 
+  if (potentialTargetName || isGenex)
+    {
+    this->Target->AppendProperty("INTERFACE_COMPILE_DEFINITIONS",
+                                compileProperty(this->Target, lib,
+                                                isGenex,
+                                        "COMPILE_DEFINITIONS", llt).c_str());
+    this->Target->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
+                                compileProperty(this->Target, lib,
+                                                isGenex,
+                                        "INCLUDE_DIRECTORIES", llt).c_str());
+    }
+
   // Get the list of configurations considered to be DEBUG.
   std::vector<std::string> const& debugConfigs =
     this->Makefile->GetCMakeInstance()->GetDebugConfigs();

+ 9 - 0
Source/cmTargetLinkLibrariesCommand.h

@@ -97,6 +97,15 @@ public:
       "Calls to other signatures of this command may set the property "
       "making any libraries linked exclusively by this signature private."
       "\n"
+      "Target usage requirements are also consumed by this command. If the "
+      "<target> is linked to another target which has "
+      "a populated INTERFACE_INCLUDE_DIRECTORIES, the content of it is "
+      "appended to the INCLUDE_DIRECTORIES of <target>.  Similarly, the "
+      "INTERFACE_COMPILE_DEFINITONS of a dependee are added to the "
+      "COMPILE_DEFINITONS of <target>, and the "
+      "INTERFACE_POSITION_INDEPENDENT_CODE property is used to determine the "
+      "POSITION_INDEPENDENT_CODE property of <target>."
+      "\n"
       "  target_link_libraries(<target> LINK_INTERFACE_LIBRARIES\n"
       "                        [[debug|optimized|general] <lib>] ...)\n"
       "The LINK_INTERFACE_LIBRARIES mode appends the libraries "

+ 6 - 0
Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt

@@ -16,9 +16,15 @@ add_executable(consumer
   "${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp"
 )
 
+add_library(linked UNKNOWN IMPORTED)
+set_property(TARGET linked PROPERTY
+  INTERFACE_COMPILE_DEFINITIONS "MY_LINKED_DEFINE")
+
+
 target_compile_definitions(consumer
   PRIVATE $<TARGET_PROPERTY:target_compile_definitions,INTERFACE_COMPILE_DEFINITIONS>
   $<$<TARGET_DEFINED:notdefined>:SHOULD_NOT_BE_DEFINED>
   $<$<TARGET_DEFINED:target_compile_definitions>:SHOULD_BE_DEFINED>
+  $<LINKED:linked>
   -DDASH_D_DEFINE
 )

+ 4 - 0
Tests/CMakeCommands/target_compile_definitions/consumer.cpp

@@ -23,4 +23,8 @@
 #error Expected DASH_D_DEFINE
 #endif
 
+#ifndef MY_LINKED_DEFINE
+#error Expected MY_LINKED_DEFINE
+#endif
+
 int main() { return 0; }

+ 10 - 1
Tests/CMakeCommands/target_include_directories/CMakeLists.txt

@@ -17,6 +17,9 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/poison/common.h" "#error Should not be i
 file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/cure")
 file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cure/common.h" "#define CURE_DEFINE\n")
 
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/linkedinclude")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/linkedinclude/linkedinclude.h" "#define LINKEDINCLUDE_DEFINE\n")
+
 add_executable(target_include_directories
   "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
 )
@@ -42,7 +45,13 @@ add_executable(consumer
   "${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp"
 )
 
+add_library(linked UNKNOWN IMPORTED)
+set_property(TARGET linked PROPERTY
+  INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/linkedinclude")
+
 target_include_directories(consumer
-  PRIVATE $<TARGET_PROPERTY:target_include_directories,INTERFACE_INCLUDE_DIRECTORIES>
+  PRIVATE
+    $<TARGET_PROPERTY:target_include_directories,INTERFACE_INCLUDE_DIRECTORIES>
+    $<LINKED:linked>
   relative_dir
 )

+ 5 - 0
Tests/CMakeCommands/target_include_directories/consumer.cpp

@@ -3,6 +3,7 @@
 #include "publicinclude.h"
 #include "interfaceinclude.h"
 #include "relative_dir.h"
+#include "linkedinclude.h"
 
 #ifdef PRIVATEINCLUDE_DEFINE
 #error Unexpected PRIVATEINCLUDE_DEFINE
@@ -24,4 +25,8 @@
 #error Expected RELATIVE_DIR_DEFINE
 #endif
 
+#ifndef LINKEDINCLUDE_DEFINE
+#error Expected LINKEDINCLUDE_DEFINE
+#endif
+
 int main() { return 0; }

+ 21 - 4
Tests/CMakeCommands/target_link_libraries/CMakeLists.txt

@@ -62,10 +62,6 @@ assert_property(targetA LINK_INTERFACE_LIBRARIES "")
 
 add_subdirectory(subdir)
 target_link_libraries(targetA subdirlib)
-set_property(TARGET targetA APPEND PROPERTY
-  INCLUDE_DIRECTORIES
-    $<TARGET_PROPERTY:subdirlib,INTERFACE_INCLUDE_DIRECTORIES>
-)
 
 target_link_libraries(targetA depB depC)
 
@@ -87,3 +83,24 @@ set_property(TARGET depD APPEND PROPERTY
 
 add_executable(targetB targetB.cpp)
 target_link_libraries(targetB depD)
+
+macro(create_header _name)
+  file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${_name}")
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_name}/${_name}.h" "//${_name}.h\n")
+endmacro()
+
+create_header(foo)
+create_header(bar)
+
+add_library(depG SHARED depG.cpp)
+generate_export_header(depG)
+target_include_directories(depG INTERFACE
+    "${CMAKE_CURRENT_BINARY_DIR}/foo"
+    "${CMAKE_CURRENT_BINARY_DIR}/bar"
+)
+target_compile_definitions(depG INTERFACE
+    TEST_DEF
+)
+
+add_executable(targetC targetC.cpp)
+target_link_libraries(targetC depG)

+ 7 - 0
Tests/CMakeCommands/target_link_libraries/depG.cpp

@@ -0,0 +1,7 @@
+
+#include "depG.h"
+
+int DepG::foo()
+{
+  return 0;
+}

+ 7 - 0
Tests/CMakeCommands/target_link_libraries/depG.h

@@ -0,0 +1,7 @@
+
+#include "depg_export.h"
+
+struct DEPG_EXPORT DepG
+{
+  int foo();
+};

+ 16 - 0
Tests/CMakeCommands/target_link_libraries/targetC.cpp

@@ -0,0 +1,16 @@
+
+#include "depG.h"
+
+#include "foo.h"
+#include "bar.h"
+
+#ifndef TEST_DEF
+#error Expected TEST_DEF definition
+#endif
+
+int main(int argc, char **argv)
+{
+  DepG g;
+
+  return g.foo();
+}

+ 13 - 1
Tests/CompatibleInterface/CMakeLists.txt

@@ -48,10 +48,22 @@ target_compile_definitions(CompatibleInterface
 add_library(iface2 SHARED iface2.cpp)
 generate_export_header(iface2)
 
+set_property(TARGET iface2 APPEND PROPERTY
+  COMPATIBLE_INTERFACE_STRING
+    Iface2_PROP
+)
+
 # For the LINK_LIBRARIES and related properties, we should not evaluate
 # properties defined only in the interface - they should be implicitly zero
 set_property(TARGET iface2
   APPEND PROPERTY
     LINK_INTERFACE_LIBRARIES $<$<BOOL:$<TARGET_PROPERTY:BOOL_PROP4>>:nonexistant>
 )
-target_link_libraries(CompatibleInterface iface2)
+target_link_libraries(CompatibleInterface iface2
+      $<$<BOOL:$<TARGET_PROPERTY:Iface2_PROP>>:nonexistant>
+)
+# Test that this does not segfault:
+target_compile_definitions(CompatibleInterface
+  PRIVATE
+    $<$<BOOL:$<TARGET_PROPERTY:Iface2_PROP>>:SOME_DEFINE>
+)

+ 22 - 19
Tests/ExportImport/Export/CMakeLists.txt

@@ -90,23 +90,7 @@ set_property(TARGET testLibCycleA PROPERTY LINK_INTERFACE_MULTIPLICITY 3)
 # Test exporting dependent libraries into different exports
 add_library(testLibRequired testLibRequired.c)
 add_library(testLibDepends testLibDepends.c)
-set_property(TARGET testLibDepends APPEND PROPERTY
-  INCLUDE_DIRECTORIES
-    $<TARGET_PROPERTY:testLibRequired,INTERFACE_INCLUDE_DIRECTORIES>
-)
-set_property(TARGET testLibDepends APPEND PROPERTY
-  COMPILE_DEFINITIONS
-    $<TARGET_PROPERTY:testLibRequired,INTERFACE_COMPILE_DEFINITIONS>
-)
-set_property(TARGET testLibDepends APPEND PROPERTY
-  INTERFACE_INCLUDE_DIRECTORIES
-    $<TARGET_PROPERTY:testLibRequired,INTERFACE_INCLUDE_DIRECTORIES>
-)
-set_property(TARGET testLibDepends APPEND PROPERTY
-  INTERFACE_COMPILE_DEFINITIONS
-    $<TARGET_PROPERTY:testLibRequired,INTERFACE_COMPILE_DEFINITIONS>
-)
-target_link_libraries(testLibDepends testLibRequired)
+target_link_libraries(testLibDepends LINK_PUBLIC testLibRequired)
 
 macro(add_include_lib _libName)
   file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_libName}.c" "// no content\n")
@@ -234,11 +218,30 @@ install(TARGETS testLibRequired
                 testLibIncludeRequired6
                 testSharedLibRequired
         EXPORT RequiredExp DESTINATION lib )
-install(EXPORT RequiredExp NAMESPACE Req:: FILE testLibRequiredConfig.cmake DESTINATION lib/cmake/testLibRequired)
+install(EXPORT RequiredExp NAMESPACE Req:: FILE testLibRequiredTargets.cmake DESTINATION lib/cmake/testLibRequired)
 
 install(TARGETS testLibDepends testSharedLibDepends EXPORT DependsExp DESTINATION lib )
-install(EXPORT DependsExp FILE testLibDependsConfig.cmake DESTINATION lib/cmake/testLibDepends)
+install(EXPORT DependsExp FILE testLibDependsTargets.cmake DESTINATION lib/cmake/testLibDepends)
 
+file(WRITE
+  "${CMAKE_CURRENT_BINARY_DIR}/testLibRequiredConfig.cmake"
+  "
+if(\${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION VERSION_LESS 2.3 AND NOT \${CMAKE_FIND_PACKAGE_NAME}_INTERFACES)
+  set(\${CMAKE_FIND_PACKAGE_NAME}_NO_INTERFACES 1)
+endif()
+include(\"\${CMAKE_CURRENT_LIST_DIR}/testLibRequiredTargets.cmake\")
+set(\${CMAKE_FIND_PACKAGE_NAME}_INCLUDE_DIRS \"${CMAKE_CURRENT_BINARY_DIR}\" \"${CMAKE_CURRENT_SOURCE_DIR}\" )
+"
+)
+
+include(CMakePackageConfigHelpers)
+write_basic_package_version_file( testLibRequiredConfigVersion.cmake VERSION 2.5 COMPATIBILITY AnyNewerVersion)
+
+install(FILES
+  "${CMAKE_CURRENT_BINARY_DIR}/testLibRequiredConfig.cmake"
+  "${CMAKE_CURRENT_BINARY_DIR}/testLibRequiredConfigVersion.cmake"
+  DESTINATION lib/cmake/testLibRequired
+)
 
 # Install and export from install tree.
 install(

+ 3 - 15
Tests/ExportImport/Import/A/CMakeLists.txt

@@ -5,8 +5,8 @@ include(${Import_BINARY_DIR}/../Export/ExportBuildTree.cmake)
 include(${CMAKE_INSTALL_PREFIX}/lib/exp/exp.cmake)
 
 # Import two exports, where the Depends one depends on an exported target from the Required one:
-include(${CMAKE_INSTALL_PREFIX}/lib/cmake/testLibRequired/testLibRequiredConfig.cmake)
-include(${CMAKE_INSTALL_PREFIX}/lib/cmake/testLibDepends/testLibDependsConfig.cmake)
+include(${CMAKE_INSTALL_PREFIX}/lib/cmake/testLibRequired/testLibRequiredTargets.cmake)
+include(${CMAKE_INSTALL_PREFIX}/lib/cmake/testLibDepends/testLibDependsTargets.cmake)
 
 # Try referencing an executable imported from the install tree.
 add_custom_command(
@@ -159,18 +159,11 @@ endif()
 
 add_executable(deps_iface deps_iface.c)
 target_link_libraries(deps_iface testLibDepends)
-target_include_directories(deps_iface PRIVATE $<TARGET_PROPERTY:testLibDepends,INTERFACE_INCLUDE_DIRECTORIES>)
-target_compile_definitions(deps_iface PRIVATE $<TARGET_PROPERTY:testLibDepends,INTERFACE_COMPILE_DEFINITIONS>)
 
 add_executable(deps_shared_iface deps_shared_iface.cpp)
 target_link_libraries(deps_shared_iface testSharedLibDepends)
-target_include_directories(deps_shared_iface
-  PRIVATE
-    $<TARGET_PROPERTY:testSharedLibDepends,INTERFACE_INCLUDE_DIRECTORIES>
-)
 target_compile_definitions(deps_shared_iface
   PRIVATE
-    $<TARGET_PROPERTY:testSharedLibDepends,INTERFACE_COMPILE_DEFINITIONS>
     $<$<BOOL:$<TARGET_PROPERTY:POSITION_INDEPENDENT_CODE>>:PIC_PROPERTY_IS_ON>
     $<$<BOOL:$<TARGET_PROPERTY:CUSTOM_PROP>>:CUSTOM_PROPERTY_IS_ON>
     $<$<STREQUAL:$<TARGET_PROPERTY:CUSTOM_STRING>,testcontent>:CUSTOM_STRING_IS_MATCH>
@@ -200,13 +193,8 @@ endif()
 
 add_executable(deps_shared_iface2 deps_shared_iface.cpp)
 target_link_libraries(deps_shared_iface2 bld_testSharedLibDepends bld_subdirlib)
-target_include_directories(deps_shared_iface2
-  PRIVATE
-    $<TARGET_PROPERTY:bld_testSharedLibDepends,INTERFACE_INCLUDE_DIRECTORIES>
-    $<TARGET_PROPERTY:bld_subdirlib,INTERFACE_INCLUDE_DIRECTORIES>
-)
 target_compile_definitions(deps_shared_iface2
-  PRIVATE $<TARGET_PROPERTY:bld_testSharedLibDepends,INTERFACE_COMPILE_DEFINITIONS> TEST_SUBDIR_LIB
+  PRIVATE TEST_SUBDIR_LIB
   $<$<BOOL:$<TARGET_PROPERTY:POSITION_INDEPENDENT_CODE>>:PIC_PROPERTY_IS_ON>
   $<$<BOOL:$<TARGET_PROPERTY:CUSTOM_PROP>>:CUSTOM_PROPERTY_IS_ON>
   $<$<STREQUAL:$<TARGET_PROPERTY:CUSTOM_STRING>,testcontent>:CUSTOM_STRING_IS_MATCH>

+ 5 - 0
Tests/ExportImport/Import/CMakeLists.txt

@@ -17,3 +17,8 @@ add_executable(imp_testTransExe1 imp_testTransExe1.c)
 target_link_libraries(imp_testTransExe1 imp_lib1)
 add_executable(imp_testTransExe1b imp_testTransExe1.c)
 target_link_libraries(imp_testTransExe1b imp_lib1b)
+
+# Test package INTERFACE controls
+add_subdirectory(package_old_old)
+add_subdirectory(package_new_old)
+add_subdirectory(package_new_new)

+ 23 - 0
Tests/ExportImport/Import/package_new_new/CMakeLists.txt

@@ -0,0 +1,23 @@
+
+cmake_minimum_required(VERSION 2.8)
+
+find_package(testLibRequired 2.5 REQUIRED)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+  "
+#include \"testSharedLibRequired.h\"
+int main(int argc, char **argv)
+{
+  TestSharedLibRequired req;
+  return req.foo();
+}
+"
+)
+
+get_target_property(prop Req::testSharedLibRequired INTERFACE_INCLUDE_DIRECTORIES)
+if (NOT prop)
+  message(SEND_ERROR "Interface of Req::testSharedLibRequired should not be empty")
+endif()
+
+add_executable(new_new_test "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+target_link_libraries(new_new_test Req::testSharedLibRequired)

+ 24 - 0
Tests/ExportImport/Import/package_new_old/CMakeLists.txt

@@ -0,0 +1,24 @@
+
+cmake_minimum_required(VERSION 2.8)
+
+find_package(testLibRequired 2.5 REQUIRED)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+  "
+#include \"testSharedLibRequired.h\"
+int main(int argc, char **argv)
+{
+  TestSharedLibRequired req;
+  return req.foo();
+}
+"
+)
+
+get_target_property(prop Req::testSharedLibRequired INTERFACE_INCLUDE_DIRECTORIES)
+if ("${prop}" STREQUAL "")
+  message(SEND_ERROR "Interface of Req::testSharedLibRequired should not be empty")
+endif()
+
+add_executable(new_old_test "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+target_link_libraries(new_old_test Req::testSharedLibRequired)
+include_directories(${testLibRequired_INCLUDE_DIRS})

+ 24 - 0
Tests/ExportImport/Import/package_old_old/CMakeLists.txt

@@ -0,0 +1,24 @@
+
+cmake_minimum_required(VERSION 2.8)
+
+find_package(testLibRequired 2.1 REQUIRED)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+  "
+#include \"testSharedLibRequired.h\"
+int main(int argc, char **argv)
+{
+  TestSharedLibRequired req;
+  return req.foo();
+}
+"
+)
+
+get_target_property(prop Req::testSharedLibRequired INTERFACE_INCLUDE_DIRECTORIES)
+if (prop)
+  message(SEND_ERROR "Interface of Req::testSharedLibRequired should be empty, but is ${prop}")
+endif()
+
+add_executable(old_old_test "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+target_link_libraries(old_old_test Req::testSharedLibRequired)
+include_directories(${testLibRequired_INCLUDE_DIRS})

+ 0 - 1
Tests/GeneratorExpression/CMakeLists.txt

@@ -89,7 +89,6 @@ add_custom_target(check-part2 ALL
     -Dtest_install_interface=$<INSTALL_INTERFACE:install>
     -Dtest_target_name_1=$<TARGET_NAME:tgt,ok>
     -Dtest_target_name_2=$<TARGET_NAME:tgt:ok>
-    -Dtest_install_prefix=$<INSTALL_PREFIX>
     -P ${CMAKE_CURRENT_SOURCE_DIR}/check-part2.cmake
   COMMAND ${CMAKE_COMMAND} -E echo "check done (part 2 of 2)"
   VERBATIM

+ 0 - 1
Tests/GeneratorExpression/check-part2.cmake

@@ -26,4 +26,3 @@ check(test_build_interface "build")
 check(test_install_interface "")
 check(test_target_name_1 "tgt,ok")
 check(test_target_name_2 "tgt:ok")
-check(test_install_prefix "")

+ 41 - 0
Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt

@@ -82,3 +82,44 @@ add_custom_target(test_custom_target
         $<TARGET_PROPERTY:TargetIncludeDirectories,COMPILE_DEFINITIONS>
         WORKING_DIRECTORY
         "${CMAKE_CURRENT_SOURCE_DIR}")
+
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bad")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/bad/common.h" "#error Should not be included\n")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/good")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/good/common.h" "#include \"othergood.h\"\n")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/othergood")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/othergood/othergood.h" "// No error\n")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/libothergood.cpp" "// No content \n")
+add_library(libothergood "${CMAKE_CURRENT_BINARY_DIR}/libothergood.cpp")
+set_property(TARGET libothergood APPEND PROPERTY
+  INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/othergood"
+)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/libgood.cpp" "// No content \n")
+add_library(libgood "${CMAKE_CURRENT_BINARY_DIR}/libgood.cpp")
+set_property(TARGET libgood APPEND PROPERTY
+  INTERFACE_INCLUDE_DIRECTORIES
+    "${CMAKE_CURRENT_BINARY_DIR}/good;$<TARGET_PROPERTY:libothergood,INTERFACE_INCLUDE_DIRECTORIES>"
+)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/libbad.cpp" "// No content \n")
+add_library(libbad "${CMAKE_CURRENT_BINARY_DIR}/libbad.cpp")
+set_property(TARGET libbad APPEND PROPERTY
+  INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/bad"
+)
+
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib5.cpp" "#include \"common.h\"\n")
+add_library(lib5 "${CMAKE_CURRENT_BINARY_DIR}/lib5.cpp")
+
+# Assuming the link order must be:
+target_link_libraries(lib5 libbad libgood)
+
+# Oops!.
+# As include directory order and link order are the same when using target_link_libraries, we have to
+# get the libgood includes in before the libbad includes.
+# We do that with this command:
+target_include_directories(lib5
+  BEFORE PRIVATE $<LINKED:libgood>
+)

+ 0 - 19
Tests/Qt4Targets/CMakeLists.txt

@@ -12,29 +12,10 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
 add_executable(Qt4Targets WIN32 main.cpp)
 target_link_libraries(Qt4Targets Qt4::QtGui)
 
-set_property(TARGET Qt4Targets APPEND PROPERTY
-  INCLUDE_DIRECTORIES
-    $<TARGET_PROPERTY:Qt4::QtGui,INTERFACE_INCLUDE_DIRECTORIES>
-)
-set_property(TARGET Qt4Targets APPEND PROPERTY
-  COMPILE_DEFINITIONS
-    $<TARGET_PROPERTY:Qt4::QtGui,INTERFACE_COMPILE_DEFINITIONS>
-)
-
 if (WIN32)
   if (TARGET Qt4::QAxServer)
     add_executable(activeqtexe WIN32 activeqtexe.cpp)
     set_property(TARGET activeqtexe PROPERTY QT4_NO_LINK_QTMAIN ON)
     target_link_libraries(activeqtexe Qt4::QAxServer Qt4::QtGui)
-    set_property(TARGET activeqtexe APPEND PROPERTY
-      INCLUDE_DIRECTORIES
-      $<TARGET_PROPERTY:Qt4::QAxServer,INTERFACE_INCLUDE_DIRECTORIES>
-      $<TARGET_PROPERTY:Qt4::QtGui,INTERFACE_INCLUDE_DIRECTORIES>
-    )
-    set_property(TARGET activeqtexe APPEND PROPERTY
-      COMPILE_DEFINITIONS
-      $<TARGET_PROPERTY:Qt4::QAxServer,INTERFACE_COMPILE_DEFINITIONS>
-      $<TARGET_PROPERTY:Qt4::QtGui,INTERFACE_COMPILE_DEFINITIONS>
-    )
   endif()
 endif()

+ 1 - 0
Tests/RunCMake/GeneratorExpression/BadInstallPrefix-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/BadInstallPrefix-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at BadInstallPrefix.cmake:1 \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<INSTALL_PREFIX>
+
+  INSTALL_PREFIX is a marker for install\(EXPORT\) only.  It should never be
+  evaluated.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 3 - 0
Tests/RunCMake/GeneratorExpression/BadInstallPrefix.cmake

@@ -0,0 +1,3 @@
+add_custom_target(check ALL COMMAND check
+  $<INSTALL_PREFIX>/include
+  VERBATIM)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake

@@ -7,3 +7,4 @@ run_cmake(BadNOT)
 run_cmake(BadStrEqual)
 run_cmake(BadZero)
 run_cmake(BadTargetName)
+run_cmake(BadInstallPrefix)

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

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

+ 7 - 0
Tests/RunCMake/TargetPropertyGeneratorExpressions/BadLinked-stderr.txt

@@ -0,0 +1,7 @@
+CMake Error:
+  Error evaluating generator expression:
+
+    \$<LINKED:something>
+
+  \$<LINKED:...> may only be used in INCLUDE_DIRECTORIES and
+  COMPILE_DEFINITIONS properties.$

+ 7 - 0
Tests/RunCMake/TargetPropertyGeneratorExpressions/BadLinked.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")
+target_link_libraries(TargetPropertyGeneratorExpressions "$<LINKED:something>")

+ 1 - 0
Tests/RunCMake/TargetPropertyGeneratorExpressions/RunCMakeTest.cmake

@@ -15,3 +15,4 @@ run_cmake(BadInvalidName5)
 run_cmake(BadInvalidName6)
 run_cmake(BadInvalidName7)
 run_cmake(BadInvalidName8)
+run_cmake(BadLinked)