[Cmake-commits] CMake branch, next, updated. v2.8.10.1-1015-g7ef3378

Stephen Kelly steveire at gmail.com
Sat Nov 24 09:38:25 EST 2012


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "CMake".

The branch, next has been updated
       via  7ef33783f7008ee963f91f9a33f32e85c5cdcd9f (commit)
       via  ae6deb421e8793285e436b51ff8fdcdf6cf1204b (commit)
       via  e3ebe1f806c03ede2cd6b5da2006f8d1a77cad61 (commit)
       via  a341626bb56f825752b8acc5c223e87cecf89bdd (commit)
       via  05984459f649bf584c7776add4e7902d328a8871 (commit)
       via  9c72d037d3194360c1f403d9174da0023bbe6882 (commit)
       via  16ea52790d99e4c511f39e77bd804b6dd8c2f853 (commit)
       via  9737cec6fed6c5b5a04d9dbc4894d8afe4e3a893 (commit)
      from  5e7567dd588dd1005b6469f64bf61e43010949c4 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7ef33783f7008ee963f91f9a33f32e85c5cdcd9f
commit 7ef33783f7008ee963f91f9a33f32e85c5cdcd9f
Merge: 5e7567d ae6deb4
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Sat Nov 24 09:38:21 2012 -0500
Commit:     CMake Topic Stage <kwrobot at kitware.com>
CommitDate: Sat Nov 24 09:38:21 2012 -0500

    Merge topic 'tll-set-include-and-defines-requirements' into next
    
    ae6deb4 Add includes and compile definitions with target_link_libraries.
    e3ebe1f Add the TARGET_DEFINED generator expression
    a341626 Handle INTERFACE properties transitively for includes and defines.
    0598445 Keep track of INCLUDE_DIRECTORIES as a vector of structs.
    9c72d03 Use cmsys::auto_ptr to manage cmCompiledGeneratorExpressions
    16ea527 Genex: Add INTERFACE_LINK_LIBRARIES property
    9737cec Add expressions for separating build-location from install-location.


http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ae6deb421e8793285e436b51ff8fdcdf6cf1204b
commit ae6deb421e8793285e436b51ff8fdcdf6cf1204b
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Mon Nov 5 12:43:28 2012 +0100
Commit:     Stephen Kelly <steveire at gmail.com>
CommitDate: Sat Nov 24 15:33:59 2012 +0100

    Add includes and compile definitions with target_link_libraries.
    
    The compile-related properties are required for linking so it makes
    sense to add the interface includes for dependencies.
    
    This requires adding a policy to handle the change in behavior of
    code such as:
    
     add_executable(foo ...)
     target_link_libraries(foo bar bat)
     include_directories(${bat_INCLUDE_DIRS} ${bar_INCLUDE_DIRS})
    
    which will change order of generated includes after this patch if
    bar or bat are TARGETS with an INTERFACE_INCLUDE_DIRECTORIES
    property.
    
    This includes a workaround for broken std::remove on some Borland
    compilers.
    
    I don't have enough information about which versions of Borland
    are affected, but if this workaround works, then it could be
    put elsewhere such as cmsys.
    
     http://qc.embarcadero.com/wc/qcmain.aspx?d=4957
     http://www.gamedev.net/topic/366171-stdremove/
     http://www.delphigroups.info/3/5/7456.html
     http://bytes.com/topic/c/answers/59791-std-remove-syntax
     http://forums.devx.com/showthread.php?94489-About-std-remove

diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 8498d72..5fa10f2 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -1665,8 +1665,14 @@ void cmMakefile::AddIncludeDirectory(const char* inc, bool before)
        l != this->Targets.end(); ++l)
     {
     cmTarget &t = l->second;
-    prop = t.GetProperties().GetOrCreateProperty("INCLUDE_DIRECTORIES");
-    AddStringToProperty(prop, "INCLUDE_DIRECTORIES", inc, before);
+    if (before)
+      {
+      t.PrependTLLIncludeDirectories(inc);
+      }
+    else
+      {
+      t.AppendTLLIncludeDirectories(inc);
+      }
     }
 }
 
diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx
index 4c89dd6..13e36c8 100644
--- a/Source/cmPolicies.cxx
+++ b/Source/cmPolicies.cxx
@@ -511,6 +511,23 @@ cmPolicies::cmPolicies()
     "the value of the (IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)? target "
     "property",
     2,8,11,0, cmPolicies::WARN);
+
+    this->DefinePolicy(
+    CMP0020, "CMP0020",
+    "Use INCLUDE_DIRECTORIES order implied by target_link_libraries.",
+    "CMake 2.8.11 introduced a feature where using target_link_libraries "
+    "can read the INTERFACE_INCLUDE_DIRECTORIES property of a target and "
+    "use the value as include directories when compiling.  Because the "
+    "target_link_libraries call might occur before the include_directories "
+    "call, this could change the order of includes in the compile step."
+    "\n"
+    "The OLD behavior for this policy is to let the include_directories call "
+    "determine the order of includes."
+    "\n"
+    "The NEW behavior for this policy is to use the order of includes "
+    "determined by the order of all calls to target_link_libraries and "
+    "include_directories",
+    2,8,11,0, cmPolicies::WARN);
 }
 
 cmPolicies::~cmPolicies()
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index b6b8e39..94154ee 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -69,6 +69,7 @@ public:
     /// POSITION_INDEPENDENT_CODE property and *_COMPILE_OPTIONS_PI{E,C}
     /// instead.
     CMP0019, ///< Use new-style INTERFACE_LINK_LIBRARIES
+    CMP0020, ///< Use INCLUDE_DIRECTORIES order from target_link_libraries
 
     /** \brief Always the last entry.
      *
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 451b84b..55c47c8 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -121,10 +121,13 @@ public:
   SourceEntriesType SourceEntries;
 
   struct IncludeDirectoriesEntry {
-    IncludeDirectoriesEntry(cmsys::auto_ptr<cmCompiledGeneratorExpression> cge)
-      : ge(cge)
+    IncludeDirectoriesEntry(
+                          cmsys::auto_ptr<cmCompiledGeneratorExpression> cge,
+                          bool tllEntry = false)
+      : ge(cge), ImpliedByTargetLinkLibraries(tllEntry)
     {}
     const cmsys::auto_ptr<cmCompiledGeneratorExpression> ge;
+    const bool ImpliedByTargetLinkLibraries;
   };
   std::vector<IncludeDirectoriesEntry*> IncludeDirectoriesEntries;
   std::string IncludeDirectoriesString;
@@ -2522,6 +2525,50 @@ void cmTarget::AppendProperty(const char* prop, const char* value,
 }
 
 //----------------------------------------------------------------------------
+void cmTarget::AppendTLLIncludeDirectories(const std::string &includes)
+{
+  cmListFileBacktrace lfbt;
+  cmGeneratorExpression ge(lfbt);
+  this->Internal->IncludeDirectoriesEntries.push_back(
+          new cmTargetInternals::IncludeDirectoriesEntry(ge.Parse(includes),
+                                                         true)
+                                                     );
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::PrependTLLIncludeDirectories(const std::string &includes)
+{
+  cmListFileBacktrace lfbt;
+  cmGeneratorExpression ge(lfbt);
+  this->Internal->IncludeDirectoriesEntries.insert(
+      this->Internal->IncludeDirectoriesEntries.begin(),
+      new cmTargetInternals::IncludeDirectoriesEntry(ge.Parse(includes),
+                                                    true)
+                                                  );
+}
+
+// A Borland machine on the dashboard has a faulty std::remove.
+template <typename ForwardIterator, typename T>
+ForwardIterator cmStdRemove(ForwardIterator first,
+                            ForwardIterator last,
+                            const T& value)
+{
+#ifdef __BORLANDC__
+  ForwardIterator result = first;
+  for ( ; first != last; ++first)
+    {
+    if (!(*first == value))
+      {
+      *result++ = *first;
+      }
+    }
+  return result;
+#else
+  return std::remove<ForwardIterator, T>(first, last, value);
+#endif
+}
+
+//----------------------------------------------------------------------------
 std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config)
 {
   std::set<std::string> fromTll;
@@ -2554,8 +2601,44 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config)
         cmSystemTools::ConvertToUnixSlashes(inc);
         }
 
+      if (!(*it)->ImpliedByTargetLinkLibraries)
+        {
+        if (fromTll.find(*li) != fromTll.end())
+          {
+          switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0020))
+            {
+            case cmPolicies::WARN:
+              {
+              cmOStringStream e;
+              e << "The include directory " << *li << " was specified "
+                  "implicitly by an earlier call to target_link_libraries. "
+                  "Preserving the order of includes as if the earlier use of "
+                  "target_link_libraries had not added it."
+                << this->Makefile->GetPolicies()->GetPolicyWarning(
+                                                          cmPolicies::CMP0020);
+              this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, e.str());
+              }
+              // Fall through to OLD behavior
+            case cmPolicies::OLD:
+              includes.erase(cmStdRemove(includes.begin(),
+                                         includes.end(), *li),
+                             includes.end());
+              fromTll.erase(*li);
+              includes.push_back(*li);
+              break;
+            case cmPolicies::REQUIRED_ALWAYS:
+            case cmPolicies::REQUIRED_IF_USED:
+            case cmPolicies::NEW:
+              break;
+            }
+          }
+        }
       if(uniqueIncludes.insert(inc).second)
         {
+        if ((*it)->ImpliedByTargetLinkLibraries)
+          {
+          fromTll.insert(*li);
+          }
         includes.push_back(*li);
         }
       }
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 60a105e..a6090e5 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -478,6 +478,9 @@ public:
   /** @return the Mac framework directory without the base. */
   std::string GetFrameworkDirectory(const char* config = 0);
 
+  void AppendTLLIncludeDirectories(const std::string &includes);
+  void PrependTLLIncludeDirectories(const std::string &includes);
+
   std::vector<std::string> GetIncludeDirectories(const char *config);
 
 private:
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index d7a1443..2ccdc01 100644
--- a/Source/cmTargetLinkLibrariesCommand.cxx
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -273,10 +273,52 @@ static std::string generatorIface(const std::string &value,
 }
 
 //----------------------------------------------------------------------------
+static std::string compileProperty(const std::string &lib,
+                                   const std::string &property,
+                                   cmTarget::LinkLibraryType llt)
+{
+  return generatorIface(std::string("$<$<TARGET_DEFINED:" + lib + ">"
+                          ":$<TARGET_PROPERTY:")
+                          + lib
+                          + ",INTERFACE_" + property + ">>", 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);
+}
+
+//----------------------------------------------------------------------------
+static bool isList(const char *lib)
+{
+  std::vector<std::string> result;
+  cmSystemTools::ExpandListArgument(lib, result);
+  return result.size() > 1;
+}
+
+//----------------------------------------------------------------------------
 void
 cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
                                             cmTarget::LinkLibraryType llt)
 {
+  cmTarget *tgt = this->Makefile->FindTargetToUse(lib);
+  const bool isNonImportedTarget = tgt && !tgt->IsImported();
+  const bool isGenex = isGeneratorExpression(lib);
+  const std::string nsLib =
+                            std::string(isNonImportedTarget && !isList(lib)
+                                        ? "$<EXPORT_NAMESPACE>" : "") + lib;
+  if (tgt || isGenex)
+    {
+    this->Target->AppendTLLIncludeDirectories(compileProperty(nsLib,
+                                      "INCLUDE_DIRECTORIES", llt));
+    this->Target->AppendProperty("COMPILE_DEFINITIONS",
+                      compileProperty(nsLib,
+                                      "COMPILE_DEFINITIONS", llt).c_str());
+    }
+
   // Handle normal case first.
   if(this->CurrentProcessingState != ProcessingLinkInterface)
     {
@@ -290,7 +332,13 @@ cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
     }
 
   this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES",
-                               generatorIface(lib, llt).c_str());
+                               generatorIface(nsLib, llt).c_str());
+  this->Target->AppendProperty("INTERFACE_COMPILE_DEFINITIONS",
+                               compileProperty(nsLib,
+                                      "COMPILE_DEFINITIONS", llt).c_str());
+  this->Target->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
+                               compileProperty(nsLib,
+                                      "INCLUDE_DIRECTORIES", llt).c_str());
 
   // Get the list of configurations considered to be DEBUG.
   std::vector<std::string> const& debugConfigs =
diff --git a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
index 95cfd15..92c9338 100644
--- a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
+++ b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
@@ -74,3 +74,27 @@ add_executable(targetB targetB.cpp)
 target_link_libraries(targetB depD depE)
 
 # cmake_policy(POP)
+
+
+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(depF SHARED depF.cpp)
+generate_export_header(depF)
+set_property(TARGET depF PROPERTY
+  INTERFACE_INCLUDE_DIRECTORIES
+    ${CMAKE_CURRENT_BINARY_DIR}/foo
+    ${CMAKE_CURRENT_BINARY_DIR}/bar
+)
+set_property(TARGET depF PROPERTY
+  INTERFACE_COMPILE_DEFINITIONS
+    TEST_DEF
+)
+
+add_library(targetC targetC.cpp)
+target_link_libraries(targetC depF)
diff --git a/Tests/CMakeCommands/target_link_libraries/depF.cpp b/Tests/CMakeCommands/target_link_libraries/depF.cpp
new file mode 100644
index 0000000..1fd29c4
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depF.cpp
@@ -0,0 +1,7 @@
+
+#include "depF.h"
+
+int DepF::foo()
+{
+  return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/depF.h b/Tests/CMakeCommands/target_link_libraries/depF.h
new file mode 100644
index 0000000..95d6b14
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depF.h
@@ -0,0 +1,7 @@
+
+#include "depf_export.h"
+
+struct DEPF_EXPORT DepF
+{
+  int foo();
+};
diff --git a/Tests/CMakeCommands/target_link_libraries/targetC.cpp b/Tests/CMakeCommands/target_link_libraries/targetC.cpp
new file mode 100644
index 0000000..ac33c67
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/targetC.cpp
@@ -0,0 +1,16 @@
+
+#include "depF.h"
+
+#include "foo.h"
+#include "bar.h"
+
+#ifndef TEST_DEF
+#error Expected TEST_DEF definition
+#endif
+
+int main(int argc, char **argv)
+{
+  DepF f;
+
+  return f.foo();
+}

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e3ebe1f806c03ede2cd6b5da2006f8d1a77cad61
commit e3ebe1f806c03ede2cd6b5da2006f8d1a77cad61
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Mon Nov 19 23:56:12 2012 +0100
Commit:     Stephen Kelly <steveire at gmail.com>
CommitDate: Sat Nov 24 15:31:58 2012 +0100

    Add the TARGET_DEFINED generator expression
    
    This tests whether the parameter is a usable target.

diff --git a/Source/cmDocumentGeneratorExpressions.h b/Source/cmDocumentGeneratorExpressions.h
index 445fd0e..4866f0d 100644
--- a/Source/cmDocumentGeneratorExpressions.h
+++ b/Source/cmDocumentGeneratorExpressions.h
@@ -27,6 +27,7 @@
   "  $<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_DEFINED:tgt>     = '1' if tgt is a target, else '0'\n"    \
   "  $<TARGET_LINKER_FILE:tgt> = file used to link (.a, .lib, .so)\n"   \
   "  $<TARGET_SONAME_FILE:tgt> = file with soname (.so.3)\n"            \
   "where \"tgt\" is the name of a target.  "                            \
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx
index 57d75e0..9c6ea23 100644
--- a/Source/cmGeneratorExpressionEvaluator.cxx
+++ b/Source/cmGeneratorExpressionEvaluator.cxx
@@ -286,6 +286,23 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
 } configurationTestNode;
 
 //----------------------------------------------------------------------------
+static const struct TargetTestNode : public cmGeneratorExpressionNode
+{
+  TargetTestNode() {}
+
+  virtual int NumExpectedParameters() const { return 1; }
+
+  std::string Evaluate(const std::vector<std::string> &parameters,
+                       cmGeneratorExpressionContext *context,
+                       const GeneratorExpressionContent *,
+                       cmGeneratorExpressionDAGChecker *) const
+  {
+    return context->Makefile->FindTargetToUse(parameters.front().c_str())
+      ? "1" : "0";
+  }
+} targetTestNode;
+
+//----------------------------------------------------------------------------
 static const char* targetPropertyTransitiveWhitelist[] = {
     "INTERFACE_INCLUDE_DIRECTORIES"
   , "INTERFACE_COMPILE_DEFINITIONS"
@@ -648,6 +665,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
     return &installInterfaceNode;
   else if (identifier == "EXPORT_NAMESPACE")
     return &nullNode;
+  else if (identifier == "TARGET_DEFINED")
+    return &targetTestNode;
   return 0;
 
 }

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a341626bb56f825752b8acc5c223e87cecf89bdd
commit a341626bb56f825752b8acc5c223e87cecf89bdd
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Sun Sep 23 13:45:17 2012 +0200
Commit:     Stephen Kelly <steveire at gmail.com>
CommitDate: Sat Nov 24 15:31:58 2012 +0100

    Handle INTERFACE properties transitively for includes and defines.
    
    Contextually, the behavior is as if the properties content from another
    target is included in the string and then the result is evaluated.

diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index f8f412a..f943584 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -51,6 +51,12 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
         {
         ImportPropertyMap properties;
 
+        this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", te,
+                                        cmGeneratorExpression::BuildInterface,
+                                        properties);
+        this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", te,
+                                        cmGeneratorExpression::BuildInterface,
+                                        properties);
         this->PopulateInterfaceProperty("INTERFACE_LINK_LIBRARIES", te,
                                         cmGeneratorExpression::BuildInterface,
                                         properties);
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index 4d99866..40606be 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -68,6 +68,14 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
         {
         ImportPropertyMap properties;
 
+        this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES",
+                                      te->Target,
+                                      cmGeneratorExpression::InstallInterface,
+                                      properties);
+        this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS",
+                                      te->Target,
+                                      cmGeneratorExpression::InstallInterface,
+                                      properties);
         this->PopulateInterfaceProperty("INTERFACE_LINK_LIBRARIES",
                                       te->Target,
                                       cmGeneratorExpression::InstallInterface,
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx
index 07f46be..57d75e0 100644
--- a/Source/cmGeneratorExpressionEvaluator.cxx
+++ b/Source/cmGeneratorExpressionEvaluator.cxx
@@ -286,6 +286,12 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
 } configurationTestNode;
 
 //----------------------------------------------------------------------------
+static const char* targetPropertyTransitiveWhitelist[] = {
+    "INTERFACE_INCLUDE_DIRECTORIES"
+  , "INTERFACE_COMPILE_DEFINITIONS"
+};
+
+//----------------------------------------------------------------------------
 static const struct TargetPropertyNode : public cmGeneratorExpressionNode
 {
   TargetPropertyNode() {}
@@ -387,7 +393,27 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
       }
 
     const char *prop = target->GetProperty(propertyName.c_str());
-    return prop ? prop : "";
+    if (!prop)
+      {
+      return std::string();
+      }
+
+    for (size_t i = 0;
+         i < (sizeof(targetPropertyTransitiveWhitelist) /
+              sizeof(*targetPropertyTransitiveWhitelist));
+         ++i)
+      {
+      if (targetPropertyTransitiveWhitelist[i] == propertyName)
+        {
+        cmGeneratorExpression ge(context->Backtrace);
+        return ge.Parse(prop)->Evaluate(context->Makefile,
+                            context->Config,
+                            context->Quiet,
+                            context->Target,
+                            &dagChecker);
+        }
+      }
+    return prop;
   }
 } targetPropertyNode;
 
diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
index 7cb1b42..2a0d1a8 100644
--- a/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
+++ b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
@@ -45,3 +45,23 @@ set_property(TARGET TargetIncludeDirectories
   APPEND PROPERTY INCLUDE_DIRECTORIES
   "$<TARGET_PROPERTY:somelib::withcolons,INTERFACE_INCLUDE_DIRECTORIES>"
 )
+
+create_header(fee)
+create_header(fiy)
+create_header(foh)
+create_header(fum)
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib1.cpp" "#include \"fee.h\"\n")
+add_library(lib1 "${CMAKE_CURRENT_BINARY_DIR}/lib1.cpp")
+set_property(TARGET lib1 APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/fee")
+set_property(TARGET lib1 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/fiy")
+set_property(TARGET lib1 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:${CMAKE_CURRENT_BINARY_DIR}/foh>")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/lib2.cpp" "#include \"fiy.h\"\n")
+add_library(lib2 "${CMAKE_CURRENT_BINARY_DIR}/lib2.cpp")
+set_property(TARGET lib2 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/fum;$<TARGET_PROPERTY:lib1,INTERFACE_INCLUDE_DIRECTORIES>")
+set_property(TARGET lib2 APPEND PROPERTY INCLUDE_DIRECTORIES "$<TARGET_PROPERTY:lib1,INTERFACE_INCLUDE_DIRECTORIES>")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main3.cpp" "#include \"fiy.h\"\n#include \"foh.h\"\n#include \"fum.h\"\nint main(int,char**) { return 0; }\n")
+add_executable(exe3 "${CMAKE_CURRENT_BINARY_DIR}/main3.cpp")
+set_property(TARGET exe3 APPEND PROPERTY INCLUDE_DIRECTORIES "$<TARGET_PROPERTY:lib2,INTERFACE_INCLUDE_DIRECTORIES>")

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=05984459f649bf584c7776add4e7902d328a8871
commit 05984459f649bf584c7776add4e7902d328a8871
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Mon Nov 19 22:47:30 2012 +0100
Commit:     Stephen Kelly <steveire at gmail.com>
CommitDate: Sat Nov 24 15:31:13 2012 +0100

    Keep track of INCLUDE_DIRECTORIES as a vector of structs.
    
    The struct can keep track of where the include came from, which gives
    us proper backtraces, and will allow us to implement a policy later
    relating to order of include directories.

diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 55507dd..62ee26a 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -252,45 +252,7 @@ const char* cmGeneratorTarget::GetCreateRuleVariable()
 std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories(
                                                           const char *config)
 {
-  std::vector<std::string> includes;
-  const char *prop = this->Target->GetProperty("INCLUDE_DIRECTORIES");
-  if(!prop)
-    {
-    return includes;
-    }
-
-  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->Target,
-                                              &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)
-    {
-    std::string inc = *li;
-    if (!cmSystemTools::IsOff(inc.c_str()))
-      {
-      cmSystemTools::ConvertToUnixSlashes(inc);
-      }
-    if(uniqueIncludes.insert(inc).second)
-      {
-      orderedAndUniqueIncludes.push_back(inc);
-      }
-    }
-
-  return orderedAndUniqueIncludes;
+  return this->Target->GetIncludeDirectories(config);
 }
 
 //----------------------------------------------------------------------------
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 0e83878..451b84b 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -119,6 +119,15 @@ public:
   struct SourceEntry { std::vector<cmSourceFile*> Depends; };
   typedef std::map<cmSourceFile*, SourceEntry> SourceEntriesType;
   SourceEntriesType SourceEntries;
+
+  struct IncludeDirectoriesEntry {
+    IncludeDirectoriesEntry(cmsys::auto_ptr<cmCompiledGeneratorExpression> cge)
+      : ge(cge)
+    {}
+    const cmsys::auto_ptr<cmCompiledGeneratorExpression> ge;
+  };
+  std::vector<IncludeDirectoriesEntry*> IncludeDirectoriesEntries;
+  std::string IncludeDirectoriesString;
 };
 
 //----------------------------------------------------------------------------
@@ -2478,6 +2487,16 @@ void cmTarget::SetProperty(const char* prop, const char* value)
     return;
     }
 
+  if(strcmp(prop,"INCLUDE_DIRECTORIES") == 0)
+    {
+    cmListFileBacktrace lfbt;
+    cmGeneratorExpression ge(lfbt);
+    this->Internal->IncludeDirectoriesEntries.clear();
+    cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value);
+    this->Internal->IncludeDirectoriesEntries.push_back(
+                          new cmTargetInternals::IncludeDirectoriesEntry(cge));
+    return;
+    }
   this->Properties.SetProperty(prop, value, cmProperty::TARGET);
   this->MaybeInvalidatePropertyCache(prop);
 }
@@ -2490,11 +2509,61 @@ void cmTarget::AppendProperty(const char* prop, const char* value,
     {
     return;
     }
+  if(strcmp(prop,"INCLUDE_DIRECTORIES") == 0)
+    {
+    cmListFileBacktrace lfbt;
+    cmGeneratorExpression ge(lfbt);
+    this->Internal->IncludeDirectoriesEntries.push_back(
+              new cmTargetInternals::IncludeDirectoriesEntry(ge.Parse(value)));
+    return;
+    }
   this->Properties.AppendProperty(prop, value, cmProperty::TARGET, asString);
   this->MaybeInvalidatePropertyCache(prop);
 }
 
 //----------------------------------------------------------------------------
+std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config)
+{
+  std::set<std::string> fromTll;
+  std::vector<std::string> includes;
+  std::set<std::string> uniqueIncludes;
+  cmListFileBacktrace lfbt;
+
+  cmGeneratorExpressionDAGChecker dagChecker(lfbt,
+                                              this->GetName(),
+                                              "INCLUDE_DIRECTORIES", 0, 0);
+
+  for (std::vector<cmTargetInternals::IncludeDirectoriesEntry*>::const_iterator
+      it = this->Internal->IncludeDirectoriesEntries.begin(),
+      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);
+    for(std::vector<std::string>::const_iterator
+          li = entryIncludes.begin(); li != entryIncludes.end(); ++li)
+      {
+      std::string inc = *li;
+      if (!cmSystemTools::IsOff(inc.c_str()))
+        {
+        cmSystemTools::ConvertToUnixSlashes(inc);
+        }
+
+      if(uniqueIncludes.insert(inc).second)
+        {
+        includes.push_back(*li);
+        }
+      }
+    }
+  return includes;
+}
+
+//----------------------------------------------------------------------------
 void cmTarget::MaybeInvalidatePropertyCache(const char* prop)
 {
   // Wipe out maps caching information affected by this property.
@@ -2820,6 +2889,23 @@ const char *cmTarget::GetProperty(const char* prop,
           }
         }
       }
+    if(strcmp(prop,"INCLUDE_DIRECTORIES") == 0)
+      {
+      this->Internal->IncludeDirectoriesString = "";
+      std::string sep;
+      typedef cmTargetInternals::IncludeDirectoriesEntry
+                                 IncludeDirectoriesEntry;
+      for (std::vector<IncludeDirectoriesEntry*>::const_iterator
+          it = this->Internal->IncludeDirectoriesEntries.begin(),
+          end = this->Internal->IncludeDirectoriesEntries.end();
+          it != end; ++it)
+        {
+        this->Internal->IncludeDirectoriesString += sep;
+        this->Internal->IncludeDirectoriesString += (*it)->ge->GetInput();
+        sep = ";";
+        }
+      return this->Internal->IncludeDirectoriesString.c_str();
+      }
     }
 
   if (strcmp(prop,"IMPORTED") == 0)
@@ -5086,6 +5172,13 @@ cmTargetInternalPointer
 //----------------------------------------------------------------------------
 cmTargetInternalPointer::~cmTargetInternalPointer()
 {
+  for (std::vector<cmTargetInternals::IncludeDirectoriesEntry*>::const_iterator
+      it = this->Pointer->IncludeDirectoriesEntries.begin(),
+      end = this->Pointer->IncludeDirectoriesEntries.end();
+      it != end; ++it)
+    {
+    delete *it;
+    }
   delete this->Pointer;
 }
 
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 7c55933..60a105e 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -478,6 +478,8 @@ public:
   /** @return the Mac framework directory without the base. */
   std::string GetFrameworkDirectory(const char* config = 0);
 
+  std::vector<std::string> GetIncludeDirectories(const char *config);
+
 private:
   /**
    * A list of direct dependencies. Use in conjunction with DependencyMap.

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9c72d037d3194360c1f403d9174da0023bbe6882
commit 9c72d037d3194360c1f403d9174da0023bbe6882
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Mon Nov 19 19:30:56 2012 +0100
Commit:     Stephen Kelly <steveire at gmail.com>
CommitDate: Sat Nov 24 15:31:13 2012 +0100

    Use cmsys::auto_ptr to manage cmCompiledGeneratorExpressions
    
    The compiled generator expressions need to outlive the creating
    type. For the same reason, store the input string in a std::string.

diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx
index 07df7d5..f2f77ee 100644
--- a/Source/cmCustomCommandGenerator.cxx
+++ b/Source/cmCustomCommandGenerator.cxx
@@ -47,7 +47,7 @@ std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const
     {
     return target->GetLocation(this->Config);
     }
-  return this->GE->Parse(argv0).Evaluate(this->Makefile, this->Config);
+  return this->GE->Parse(argv0)->Evaluate(this->Makefile, this->Config);
 }
 
 //----------------------------------------------------------------------------
@@ -58,7 +58,7 @@ cmCustomCommandGenerator
   cmCustomCommandLine const& commandLine = this->CC.GetCommandLines()[c];
   for(unsigned int j=1;j < commandLine.size(); ++j)
     {
-    std::string arg = this->GE->Parse(commandLine[j]).Evaluate(this->Makefile,
+    std::string arg = this->GE->Parse(commandLine[j])->Evaluate(this->Makefile,
                                                                this->Config);
     cmd += " ";
     if(this->OldStyle)
diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx
index 2bcced1..97a0581 100644
--- a/Source/cmGeneratorExpression.cxx
+++ b/Source/cmGeneratorExpression.cxx
@@ -25,44 +25,29 @@
 //----------------------------------------------------------------------------
 cmGeneratorExpression::cmGeneratorExpression(
   cmListFileBacktrace const& backtrace):
-  Backtrace(backtrace), CompiledExpression(0)
+  Backtrace(backtrace)
 {
 }
 
 //----------------------------------------------------------------------------
-const cmCompiledGeneratorExpression &
+cmsys::auto_ptr<cmCompiledGeneratorExpression>
 cmGeneratorExpression::Parse(std::string const& input)
 {
   return this->Parse(input.c_str());
 }
 
 //----------------------------------------------------------------------------
-const cmCompiledGeneratorExpression &
+cmsys::auto_ptr<cmCompiledGeneratorExpression>
 cmGeneratorExpression::Parse(const char* input)
 {
-  cmGeneratorExpressionLexer l;
-  std::vector<cmGeneratorExpressionToken> tokens = l.Tokenize(input);
-  bool needsParsing = l.GetSawGeneratorExpression();
-  std::vector<cmGeneratorExpressionEvaluator*> evaluators;
-
-  if (needsParsing)
-    {
-    cmGeneratorExpressionParser p(tokens);
-    p.Parse(evaluators);
-    }
-
-  delete this->CompiledExpression;
-  this->CompiledExpression = new cmCompiledGeneratorExpression(
-                                      this->Backtrace,
-                                      evaluators,
-                                      input,
-                                      needsParsing);
-  return *this->CompiledExpression;
+  return cmsys::auto_ptr<cmCompiledGeneratorExpression>(
+                                      new cmCompiledGeneratorExpression(
+                                        this->Backtrace,
+                                        input));
 }
 
 cmGeneratorExpression::~cmGeneratorExpression()
 {
-  delete this->CompiledExpression;
 }
 
 //----------------------------------------------------------------------------
@@ -73,7 +58,7 @@ const char *cmCompiledGeneratorExpression::Evaluate(
 {
   if (!this->NeedsParsing)
     {
-    return this->Input;
+    return this->Input.c_str();
     }
 
   this->Output = "";
@@ -108,12 +93,19 @@ const char *cmCompiledGeneratorExpression::Evaluate(
 
 cmCompiledGeneratorExpression::cmCompiledGeneratorExpression(
               cmListFileBacktrace const& backtrace,
-              const std::vector<cmGeneratorExpressionEvaluator*> &evaluators,
-              const char *input, bool needsParsing)
-  : Backtrace(backtrace), Evaluators(evaluators), Input(input),
-    NeedsParsing(needsParsing)
+              const char *input)
+  : Backtrace(backtrace), Input(input ? input : "")
 {
+  cmGeneratorExpressionLexer l;
+  std::vector<cmGeneratorExpressionToken> tokens =
+                                              l.Tokenize(this->Input.c_str());
+  this->NeedsParsing = l.GetSawGeneratorExpression();
 
+  if (this->NeedsParsing)
+    {
+    cmGeneratorExpressionParser p(tokens);
+    p.Parse(this->Evaluators);
+    }
 }
 
 
diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h
index 5e3352b..c3daf84 100644
--- a/Source/cmGeneratorExpression.h
+++ b/Source/cmGeneratorExpression.h
@@ -14,10 +14,12 @@
 #define cmGeneratorExpression_h
 
 #include "cmStandardIncludes.h"
+#include "cmListFileCache.h"
 
 #include <stack>
 
 #include <cmsys/RegularExpression.hxx>
+#include <cmsys/auto_ptr.hxx>
 
 class cmTarget;
 class cmMakefile;
@@ -44,8 +46,9 @@ public:
   cmGeneratorExpression(cmListFileBacktrace const& backtrace);
   ~cmGeneratorExpression();
 
-  const cmCompiledGeneratorExpression& Parse(std::string const& input);
-  const cmCompiledGeneratorExpression& Parse(const char* input);
+  cmsys::auto_ptr<cmCompiledGeneratorExpression> Parse(
+                                                std::string const& input);
+  cmsys::auto_ptr<cmCompiledGeneratorExpression> Parse(const char* input);
 
   enum PreprocessContext {
     StripAllGeneratorExpressions,
@@ -62,7 +65,6 @@ private:
   void operator=(const cmGeneratorExpression &);
 
   cmListFileBacktrace const& Backtrace;
-  cmCompiledGeneratorExpression *CompiledExpression;
 };
 
 class cmCompiledGeneratorExpression
@@ -79,20 +81,24 @@ public:
 
   ~cmCompiledGeneratorExpression();
 
+  std::string GetInput() const
+  {
+    return this->Input;
+  }
+
 private:
   cmCompiledGeneratorExpression(cmListFileBacktrace const& backtrace,
-              const std::vector<cmGeneratorExpressionEvaluator*> &evaluators,
-              const char *input, bool needsParsing);
+              const char *input);
 
   friend class cmGeneratorExpression;
 
   cmCompiledGeneratorExpression(const cmCompiledGeneratorExpression &);
   void operator=(const cmCompiledGeneratorExpression &);
 
-  cmListFileBacktrace const& Backtrace;
-  const std::vector<cmGeneratorExpressionEvaluator*> Evaluators;
-  const char* const Input;
-  const bool NeedsParsing;
+  cmListFileBacktrace Backtrace;
+  std::vector<cmGeneratorExpressionEvaluator*> Evaluators;
+  const std::string Input;
+  bool NeedsParsing;
 
   mutable std::set<cmTarget*> Targets;
   mutable std::string Output;
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index de8b5e3..55507dd 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -267,7 +267,7 @@ std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories(
                                               "INCLUDE_DIRECTORIES", 0, 0);
 
   cmSystemTools::ExpandListArgument(ge.Parse(prop)
-                                    .Evaluate(this->Makefile,
+                                    ->Evaluate(this->Makefile,
                                               config,
                                               false,
                                               this->Target,
@@ -315,7 +315,7 @@ std::string cmGeneratorTarget::GetCompileDefinitions(const char *config)
   cmGeneratorExpressionDAGChecker dagChecker(lfbt,
                                              this->GetName(),
                                              defPropName, 0, 0);
-  return ge.Parse(prop).Evaluate(this->Makefile,
+  return ge.Parse(prop)->Evaluate(this->Makefile,
                                  config,
                                  false,
                                  this->Target,
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 59b8f0a..0e83878 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -1732,9 +1732,10 @@ cmTargetTraceDependencies
     for(cmCustomCommandLine::const_iterator cli = cit->begin();
         cli != cit->end(); ++cli)
       {
-      const cmCompiledGeneratorExpression &cge = ge.Parse(*cli);
-      cge.Evaluate(this->Makefile, 0, true);
-      std::set<cmTarget*> geTargets = cge.GetTargets();
+      const cmsys::auto_ptr<cmCompiledGeneratorExpression> cge
+                                                              = ge.Parse(*cli);
+      cge->Evaluate(this->Makefile, 0, true);
+      std::set<cmTarget*> geTargets = cge->GetTargets();
       for(std::set<cmTarget*>::const_iterator it = geTargets.begin();
           it != geTargets.end(); ++it)
         {
@@ -4478,7 +4479,7 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config,
                                         this->GetName(),
                                         "INTERFACE_LINK_LIBRARIES", 0, 0);
     cmSystemTools::ExpandListArgument(ge.Parse(newStyleLibsProp)
-                                        .Evaluate(this->Makefile,
+                                       ->Evaluate(this->Makefile,
                                                   desired_config.c_str(),
                                                   false,
                                                   this,
@@ -4666,7 +4667,7 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface)
                                           this->GetName(),
                                           "INTERFACE_LINK_LIBRARIES", 0, 0);
 
-      cmSystemTools::ExpandListArgument(ge.Parse(newLibrariesProp).Evaluate(
+      cmSystemTools::ExpandListArgument(ge.Parse(newLibrariesProp)->Evaluate(
                                       this->Makefile,
                                       config,
                                       false,
diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx
index 2f650e7..42f511e 100644
--- a/Source/cmTestGenerator.cxx
+++ b/Source/cmTestGenerator.cxx
@@ -112,7 +112,7 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
   else
     {
     // Use the command name given.
-    exe = ge.Parse(exe.c_str()).Evaluate(mf, config);
+    exe = ge.Parse(exe.c_str())->Evaluate(mf, config);
     cmSystemTools::ConvertToUnixSlashes(exe);
     }
 
@@ -122,7 +122,7 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
   for(std::vector<std::string>::const_iterator ci = command.begin()+1;
       ci != command.end(); ++ci)
     {
-    os << " " << lg->EscapeForCMake(ge.Parse(*ci).Evaluate(mf, config));
+    os << " " << lg->EscapeForCMake(ge.Parse(*ci)->Evaluate(mf, config));
     }
 
   // Finish the test command.

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=16ea52790d99e4c511f39e77bd804b6dd8c2f853
commit 16ea52790d99e4c511f39e77bd804b6dd8c2f853
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Thu Nov 1 00:32:10 2012 +0100
Commit:     Stephen Kelly <steveire at gmail.com>
CommitDate: Sat Nov 24 15:31:13 2012 +0100

    Genex: Add INTERFACE_LINK_LIBRARIES property
    
    This new property is a replacement for
    the (IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)? properties as
    it can contain generator expressions. It is also part of the generated
    IMPORTED targets generated by the export() and install(EXPORT) commands.
    
    User code may already populate
    the (IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)? properties, so
    policy CMP0019 is added to handle that.
    
    If the policy is NEW, the old properties are ignored and
    the INTERFACE_LINK_LIBRARIES property is used.
    
    Otherwise if the policy is OLD the old properties are used and the
    new INTERFACE_LINK_LIBRARIES is ignored.
    
    The policy emits a warning if the old-style property and new-style
    property differ in their content.
    
    The policy also affects the IMPORTED targets generated by export()
    and install(EXPORT). If the policy is NEW, that means that the user
    has bumped their cmake requirement to 2.8.11. As we'll therefore be
    generating INTERFACE_LINK_LIBRARIES properties in the IMPORTED
    targets, we need to ensure that consumers can use the new property,
    so 2.8.11 will be required for the consumers too.

diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index fb3f39f..f8f412a 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -12,6 +12,7 @@
 #include "cmExportBuildFileGenerator.h"
 
 #include "cmExportCommand.h"
+#include "cmGeneratorExpression.h"
 
 //----------------------------------------------------------------------------
 cmExportBuildFileGenerator::cmExportBuildFileGenerator()
@@ -27,10 +28,35 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
         tei = this->Exports->begin();
       tei != this->Exports->end(); ++tei)
     {
+    if ((*tei)->GetPolicyStatusCMP0019() == cmPolicies::NEW)
+      {
+      os << "IF(NOT POLICY CMP0019)\n"
+        << "   MESSAGE(FATAL_ERROR \"CMake >= 2.8.11 required to use "
+           "IMPORTED targets containing generator expressions\")\n"
+        << "ENDIF(NOT POLICY CMP0019)\n";
+      break;
+      }
+    }
+
+  for(std::vector<cmTarget*>::const_iterator
+        tei = this->Exports->begin();
+      tei != this->Exports->end(); ++tei)
+    {
     cmTarget* te = *tei;
     if(this->ExportedTargets.insert(te).second)
       {
       this->GenerateImportTargetCode(os, te);
+
+      if ((*tei)->GetPolicyStatusCMP0019() == cmPolicies::NEW)
+        {
+        ImportPropertyMap properties;
+
+        this->PopulateInterfaceProperty("INTERFACE_LINK_LIBRARIES", te,
+                                        cmGeneratorExpression::BuildInterface,
+                                        properties);
+
+        this->GenerateInterfaceProperties(te, os, properties);
+        }
       }
     else
       {
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 8dffae4..50db180 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -125,6 +125,50 @@ void cmExportFileGenerator::GenerateImportConfig(std::ostream& os,
 }
 
 //----------------------------------------------------------------------------
+void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName,
+                      cmTarget *target,
+                      cmGeneratorExpression::PreprocessContext preprocessRule,
+                      ImportPropertyMap &properties)
+{
+  const char *input = target->GetProperty(propName);
+  if (input)
+    {
+    if (!*input)
+      {
+      // Set to empty
+      properties[propName] = "";
+      return;
+      }
+    std::string prepro = cmGeneratorExpression::Preprocess(input,
+                                                    preprocessRule,
+                                                    this->Namespace.c_str());
+    if (!prepro.empty())
+      {
+      properties[propName] = prepro;
+      }
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmExportFileGenerator::GenerateInterfaceProperties(cmTarget *target,
+                                        std::ostream& os,
+                                        const ImportPropertyMap &properties)
+{
+  if (!properties.empty())
+    {
+    std::string targetName = this->Namespace;
+    targetName += target->GetName();
+    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 << ")\n\n";
+    }
+}
+
+//----------------------------------------------------------------------------
 void
 cmExportFileGenerator
 ::SetImportDetailProperties(const char* config, std::string const& suffix,
@@ -167,9 +211,13 @@ cmExportFileGenerator
     this->SetImportLinkProperty(suffix, target,
                                 "IMPORTED_LINK_INTERFACE_LANGUAGES",
                                 iface->Languages, properties, missingTargets);
-    this->SetImportLinkProperty(suffix, target,
+
+    if(target->GetPolicyStatusCMP0019() != cmPolicies::NEW)
+      {
+      this->SetImportLinkProperty(suffix, target,
                                 "IMPORTED_LINK_INTERFACE_LIBRARIES",
                                 iface->Libraries, properties, missingTargets);
+      }
     this->SetImportLinkProperty(suffix, target,
                                 "IMPORTED_LINK_DEPENDENT_LIBRARIES",
                                 iface->SharedDeps, properties, missingTargets);
diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h
index 70bc65d..3aee1b8 100644
--- a/Source/cmExportFileGenerator.h
+++ b/Source/cmExportFileGenerator.h
@@ -13,6 +13,7 @@
 #define cmExportFileGenerator_h
 
 #include "cmCommand.h"
+#include "cmGeneratorExpression.h"
 
 /** \class cmExportFileGenerator
  * \brief Generate a file exporting targets from a build or install tree.
@@ -91,6 +92,12 @@ protected:
                                    cmMakefile* mf,
                                    cmTarget* depender,
                                    cmTarget* dependee) = 0;
+  void PopulateInterfaceProperty(const char *,
+                                 cmTarget *target,
+                                 cmGeneratorExpression::PreprocessContext,
+                                 ImportPropertyMap &properties);
+  void GenerateInterfaceProperties(cmTarget *target, std::ostream& os,
+                                   const ImportPropertyMap &properties);
 
   // The namespace in which the exports are placed in the generated file.
   std::string Namespace;
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index 7841731..4d99866 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -19,6 +19,7 @@
 #include "cmInstallExportGenerator.h"
 #include "cmInstallTargetGenerator.h"
 #include "cmTargetExport.h"
+#include "cmGeneratorExpression.h"
 
 //----------------------------------------------------------------------------
 cmExportInstallFileGenerator
@@ -39,6 +40,20 @@ std::string cmExportInstallFileGenerator::GetConfigImportFileGlob()
 //----------------------------------------------------------------------------
 bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
 {
+  for(std::vector<cmTargetExport*>::const_iterator
+        tei = this->IEGen->GetExportSet()->GetTargetExports()->begin();
+      tei != this->IEGen->GetExportSet()->GetTargetExports()->end(); ++tei)
+    {
+    if ((*tei)->Target->GetPolicyStatusCMP0019() == cmPolicies::NEW)
+      {
+      os << "IF(NOT POLICY CMP0019)\n"
+        << "   MESSAGE(FATAL_ERROR \"CMake >= 2.8.11 required to use "
+           "IMPORTED targets containing generator expressions\")\n"
+        << "ENDIF(NOT POLICY CMP0019)\n";
+      break;
+      }
+    }
+
   // Create all the imported targets.
   for(std::vector<cmTargetExport*>::const_iterator
         tei = this->IEGen->GetExportSet()->GetTargetExports()->begin();
@@ -48,6 +63,18 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
     if(this->ExportedTargets.insert(te->Target).second)
       {
       this->GenerateImportTargetCode(os, te->Target);
+
+      if ((*tei)->Target->GetPolicyStatusCMP0019() == cmPolicies::NEW)
+        {
+        ImportPropertyMap properties;
+
+        this->PopulateInterfaceProperty("INTERFACE_LINK_LIBRARIES",
+                                      te->Target,
+                                      cmGeneratorExpression::InstallInterface,
+                                      properties);
+
+        this->GenerateInterfaceProperties(te->Target, os, properties);
+        }
       }
     else
       {
diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx
index 6aef502..4c89dd6 100644
--- a/Source/cmPolicies.cxx
+++ b/Source/cmPolicies.cxx
@@ -491,6 +491,26 @@ cmPolicies::cmPolicies()
     "CMAKE_SHARED_LIBRARY_<Lang>_FLAGS whether it is modified or not and "
     "honor the POSITION_INDEPENDENT_CODE target property.",
     2,8,9,0, cmPolicies::WARN);
+
+    this->DefinePolicy(
+    CMP0019, "CMP0019",
+    "Use INTERFACE_LINK_LIBRARIES instead of LINK_INTERFACE_LIBRARIES.",
+    "CMake 2.8.10 used the (IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)? "
+    "properties to determine the link interface.  CMake 2.8.11 and higher "
+    "prefer instead to use the INTERFACE_LINK_LIBRARIES target property to "
+    "determine the link interface, while ignoring "
+    "(IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)? completely. The new "
+    "INTERFACE_LINK_LIBRARIES target property can use generator expressions "
+    "to specify config-specific link libraries."
+    "\n"
+    "The OLD behavior for this policy is to ignore the "
+    "INTERFACE_LINK_LIBRARIES property for all targets and use the "
+    "value of (IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)? instead."
+    "\n"
+    "The NEW behavior for this policy is to ignore "
+    "the value of the (IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)? target "
+    "property",
+    2,8,11,0, cmPolicies::WARN);
 }
 
 cmPolicies::~cmPolicies()
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 6932565..b6b8e39 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -68,6 +68,7 @@ public:
     CMP0018, ///< Ignore language flags for shared libs, and adhere to
     /// POSITION_INDEPENDENT_CODE property and *_COMPILE_OPTIONS_PI{E,C}
     /// instead.
+    CMP0019, ///< Use new-style INTERFACE_LINK_LIBRARIES
 
     /** \brief Always the last entry.
      *
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index be20464..59b8f0a 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -21,6 +21,7 @@
 #include "cmDocumentLocationUndefined.h"
 #include "cmListFileCache.h"
 #include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionDAGChecker.h"
 #include <cmsys/RegularExpression.hxx>
 #include <map>
 #include <set>
@@ -127,6 +128,7 @@ cmTarget::cmTarget()
   this->PolicyStatusCMP0003 = cmPolicies::WARN;
   this->PolicyStatusCMP0004 = cmPolicies::WARN;
   this->PolicyStatusCMP0008 = cmPolicies::WARN;
+  this->PolicyStatusCMP0019 = cmPolicies::WARN;
   this->LinkLibrariesAnalyzed = false;
   this->HaveInstallRule = false;
   this->DLLPlatform = false;
@@ -1409,6 +1411,8 @@ void cmTarget::SetMakefile(cmMakefile* mf)
     this->Makefile->GetPolicyStatus(cmPolicies::CMP0004);
   this->PolicyStatusCMP0008 =
     this->Makefile->GetPolicyStatus(cmPolicies::CMP0008);
+  this->PolicyStatusCMP0019 =
+    this->Makefile->GetPolicyStatus(cmPolicies::CMP0019);
 }
 
 //----------------------------------------------------------------------------
@@ -4238,6 +4242,28 @@ cmTarget::GetImportInfo(const char* config)
   return &i->second;
 }
 
+
+bool handleCMP0019(const std::vector<std::string> &newLinkLibraries,
+  const std::vector<std::string> &oldLinkLibraries)
+{
+  if (newLinkLibraries.size() != oldLinkLibraries.size())
+    {
+    return false;
+    }
+  for(std::vector<std::string>::const_iterator
+      oll = oldLinkLibraries.begin(), nll = newLinkLibraries.begin();
+      oll != oldLinkLibraries.end() && nll != newLinkLibraries.end();
+      ++oll, ++nll)
+    {
+    if (*oll != *nll)
+      {
+      return false;
+      }
+    }
+  return true;
+}
+
+
 //----------------------------------------------------------------------------
 void cmTarget::ComputeImportInfo(std::string const& desired_config,
                                  ImportInfo& info)
@@ -4441,21 +4467,79 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config,
 
   // Get the link interface.
   {
+  std::vector<std::string> newInterfaceLibs;
+  const char* newStyleLibsProp = this->GetProperty("INTERFACE_LINK_LIBRARIES");
+  if(newStyleLibsProp)
+    {
+    cmListFileBacktrace lfbt;
+    cmGeneratorExpression ge(lfbt);
+
+    cmGeneratorExpressionDAGChecker dagChecker(lfbt,
+                                        this->GetName(),
+                                        "INTERFACE_LINK_LIBRARIES", 0, 0);
+    cmSystemTools::ExpandListArgument(ge.Parse(newStyleLibsProp)
+                                        .Evaluate(this->Makefile,
+                                                  desired_config.c_str(),
+                                                  false,
+                                                  this,
+                                                  &dagChecker),
+                                      newInterfaceLibs);
+    }
+
   std::string linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
-  linkProp += suffix;
-  if(const char* config_libs = this->GetProperty(linkProp.c_str()))
+  std::vector<std::string> oldInterfaceLibs;
+  const char *oldProp = this->GetProperty((linkProp + suffix).c_str());
+  if(oldProp)
     {
-    cmSystemTools::ExpandListArgument(config_libs,
-                                      info.LinkInterface.Libraries);
+    linkProp += suffix;
+    cmSystemTools::ExpandListArgument(oldProp,
+                                      oldInterfaceLibs);
     }
-  else if(const char* libs =
-          this->GetProperty("IMPORTED_LINK_INTERFACE_LIBRARIES"))
+  else
+    {
+    oldProp = this->GetProperty("IMPORTED_LINK_INTERFACE_LIBRARIES");
+    if(oldProp)
+      {
+      cmSystemTools::ExpandListArgument(oldProp,
+                                        oldInterfaceLibs);
+      }
+    }
+
+  std::vector<std::string> usedLinkLibraries;
+  switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0019))
     {
-    cmSystemTools::ExpandListArgument(libs,
-                                      info.LinkInterface.Libraries);
+    case cmPolicies::WARN:
+      {
+      if (newStyleLibsProp && oldProp
+          && !handleCMP0019(newInterfaceLibs, oldInterfaceLibs))
+        {
+        cmOStringStream e;
+        e << "The " << linkProp << " and "
+             "LINK_INTERFACE_LIBRARIES are not the same for target \""
+          << this->GetName() << "\". NEW content is \""
+          << (newStyleLibsProp ? newStyleLibsProp : "(unset)") << "\"\n"
+          "OLD content is \""
+          << (oldProp ? oldProp : "(unset)") << "\"\n"
+          << this->Makefile->GetPolicies()->GetPolicyWarning(
+                                                    cmPolicies::CMP0019);
+        this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, e.str());
+        }
+        // fall through to OLD behaviour
+      }
+      case cmPolicies::OLD:
+        usedLinkLibraries = oldInterfaceLibs;
+        break;
+      case cmPolicies::REQUIRED_IF_USED:
+      case cmPolicies::REQUIRED_ALWAYS:
+      case cmPolicies::NEW:
+      default:
+        usedLinkLibraries = newInterfaceLibs;
     }
+  info.LinkInterface.Libraries.insert(info.LinkInterface.Libraries.end(),
+                      usedLinkLibraries.begin(), usedLinkLibraries.end());
   }
 
+
   // Get the link dependencies.
   {
   std::string linkProp = "IMPORTED_LINK_DEPENDENT_LIBRARIES";
@@ -4562,21 +4646,82 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface)
 
   // An explicit list of interface libraries may be set for shared
   // libraries and executables that export symbols.
-  const char* explicitLibraries = 0;
+  bool explicitLibraries = false;
+  std::vector<std::string> usedLinkLibraries;
   if(this->GetType() == cmTarget::SHARED_LIBRARY ||
      this->IsExecutableWithExports())
     {
+    const char *newLibrariesProp =
+                                 this->GetProperty("INTERFACE_LINK_LIBRARIES");
+
+    std::vector<std::string> newInterfaceLibs;
+    std::vector<std::string> oldInterfaceLibs;
+
+    if(newLibrariesProp)
+      {
+      cmListFileBacktrace lfbt;
+      cmGeneratorExpression ge(lfbt);
+
+      cmGeneratorExpressionDAGChecker dagChecker(lfbt,
+                                          this->GetName(),
+                                          "INTERFACE_LINK_LIBRARIES", 0, 0);
+
+      cmSystemTools::ExpandListArgument(ge.Parse(newLibrariesProp).Evaluate(
+                                      this->Makefile,
+                                      config,
+                                      false,
+                                      this,
+                                      &dagChecker), newInterfaceLibs);
+      }
     // Lookup the per-configuration property.
     std::string propName = "LINK_INTERFACE_LIBRARIES";
     propName += suffix;
-    explicitLibraries = this->GetProperty(propName.c_str());
+    const char *oldLibrariesProp = this->GetProperty(propName.c_str());
 
     // If not set, try the generic property.
-    if(!explicitLibraries)
+    if(!oldLibrariesProp)
+      {
+      oldLibrariesProp = this->GetProperty("LINK_INTERFACE_LIBRARIES");
+      }
+    if(oldLibrariesProp)
+      {
+      cmSystemTools::ExpandListArgument(oldLibrariesProp, oldInterfaceLibs);
+      }
+
+    {
+    switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0019))
       {
-      explicitLibraries = this->GetProperty("LINK_INTERFACE_LIBRARIES");
+      case cmPolicies::WARN:
+        {
+        if (newLibrariesProp && oldLibrariesProp
+            && !handleCMP0019(newInterfaceLibs, oldInterfaceLibs))
+          {
+          cmOStringStream e;
+          e << "The INTERFACE_LINK_LIBRARIES and LINK_INTERFACE_LIBRARIES are "
+               "not the same for target \"" << this->GetName() << "\".\n"
+               "NEW content is \""
+            << (newLibrariesProp ? newLibrariesProp : "(unset)") << "\"\n"
+               "OLD content is \""
+            << (oldLibrariesProp ? oldLibrariesProp : "(unset)") << "\"\n"
+            << this->Makefile->GetPolicies()->GetPolicyWarning(
+                                                      cmPolicies::CMP0019);
+          this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, e.str());
+          }
+          // fall through to OLD behaviour
+        }
+        case cmPolicies::OLD:
+          explicitLibraries = oldLibrariesProp ? true : false;
+          usedLinkLibraries = oldInterfaceLibs;
+          break;
+        case cmPolicies::REQUIRED_IF_USED:
+        case cmPolicies::REQUIRED_ALWAYS:
+        case cmPolicies::NEW:
+        default:
+          usedLinkLibraries = newInterfaceLibs;
+          explicitLibraries = newLibrariesProp ? true : false;
       }
     }
+    }
 
   // There is no implicit link interface for executables or modules
   // so if none was explicitly set then there is no link interface.
@@ -4592,7 +4737,8 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface)
   if(explicitLibraries)
     {
     // The interface libraries have been explicitly set.
-    cmSystemTools::ExpandListArgument(explicitLibraries, iface.Libraries);
+    iface.Libraries.insert(iface.Libraries.end(),
+                          usedLinkLibraries.begin(), usedLinkLibraries.end());
 
     if(this->GetType() == cmTarget::SHARED_LIBRARY)
       {
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 9efd638..7c55933 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -99,6 +99,10 @@ public:
   cmPolicies::PolicyStatus GetPolicyStatusCMP0008() const
     { return this->PolicyStatusCMP0008; }
 
+  /** Get the status of policy CMP0019 when the target was created.  */
+  cmPolicies::PolicyStatus GetPolicyStatusCMP0019() const
+    { return this->PolicyStatusCMP0019; }
+
   /**
    * Get the list of the custom commands for this target
    */
@@ -618,6 +622,7 @@ private:
   cmPolicies::PolicyStatus PolicyStatusCMP0003;
   cmPolicies::PolicyStatus PolicyStatusCMP0004;
   cmPolicies::PolicyStatus PolicyStatusCMP0008;
+  cmPolicies::PolicyStatus PolicyStatusCMP0019;
 
   // Internal representation details.
   friend class cmTargetInternals;
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index f42b0f6..d7a1443 100644
--- a/Source/cmTargetLinkLibrariesCommand.cxx
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -232,7 +232,11 @@ bool cmTargetLinkLibrariesCommand
     {
     this->Target->SetProperty("LINK_INTERFACE_LIBRARIES", "");
     }
-
+  if(this->CurrentProcessingState != ProcessingLinkLibraries &&
+     !this->Target->GetProperty("INTERFACE_LINK_LIBRARIES"))
+    {
+    this->Target->SetProperty("INTERFACE_LINK_LIBRARIES", "");
+    }
   return true;
 }
 
@@ -250,6 +254,25 @@ cmTargetLinkLibrariesCommand
 }
 
 //----------------------------------------------------------------------------
+static std::string generatorIface(const std::string &value,
+                                  cmTarget::LinkLibraryType llt)
+{
+  if (llt == cmTarget::DEBUG)
+    {
+    return "$<$<CONFIG:Debug>:"
+                     + value
+                     + ">";
+    }
+  else if (llt == cmTarget::OPTIMIZED)
+    {
+    return "$<$<NOT:$<CONFIG:Debug>>:"
+                     + value
+                     + ">";
+    }
+  return value;
+}
+
+//----------------------------------------------------------------------------
 void
 cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
                                             cmTarget::LinkLibraryType llt)
@@ -266,6 +289,9 @@ cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
       }
     }
 
+  this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES",
+                               generatorIface(lib, llt).c_str());
+
   // Get the list of configurations considered to be DEBUG.
   std::vector<std::string> const& debugConfigs =
     this->Makefile->GetCMakeInstance()->GetDebugConfigs();
diff --git a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
index 1faa888..95cfd15 100644
--- a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
+++ b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
@@ -56,3 +56,21 @@ assert_property(targetA LINK_INTERFACE_LIBRARIES "")
 target_link_libraries(targetA depB depC)
 
 assert_property(targetA LINK_INTERFACE_LIBRARIES "")
+
+# cmake_policy(PUSH)
+
+cmake_policy(SET CMP0019 NEW)
+
+add_library(depD SHARED depD.cpp)
+generate_export_header(depD)
+set_property(TARGET depD APPEND PROPERTY INTERFACE_LINK_LIBRARIES $<1:depA>)
+
+add_library(depE SHARED depE.cpp)
+generate_export_header(depE)
+target_link_libraries(depE LINK_PRIVATE depB)
+target_link_libraries(depE LINK_INTERFACE_LIBRARIES $<1:depB>)
+
+add_executable(targetB targetB.cpp)
+target_link_libraries(targetB depD depE)
+
+# cmake_policy(POP)
diff --git a/Tests/CMakeCommands/target_link_libraries/depD.cpp b/Tests/CMakeCommands/target_link_libraries/depD.cpp
new file mode 100644
index 0000000..b02c76c
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depD.cpp
@@ -0,0 +1,13 @@
+
+#include "depD.h"
+
+int DepD::foo()
+{
+  return 0;
+}
+
+DepA DepD::getA()
+{
+  DepA a;
+  return a;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/depD.h b/Tests/CMakeCommands/target_link_libraries/depD.h
new file mode 100644
index 0000000..d24ff5f
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depD.h
@@ -0,0 +1,11 @@
+
+#include "depd_export.h"
+
+#include "depA.h"
+
+struct DEPD_EXPORT DepD
+{
+  int foo();
+
+  DepA getA();
+};
diff --git a/Tests/CMakeCommands/target_link_libraries/depE.cpp b/Tests/CMakeCommands/target_link_libraries/depE.cpp
new file mode 100644
index 0000000..1a3da4a
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depE.cpp
@@ -0,0 +1,13 @@
+
+#include "depE.h"
+
+int DepE::foo()
+{
+  return 0;
+}
+
+DepB DepE::getB()
+{
+  DepB a;
+  return a;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/depE.h b/Tests/CMakeCommands/target_link_libraries/depE.h
new file mode 100644
index 0000000..2273e17
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depE.h
@@ -0,0 +1,11 @@
+
+#include "depe_export.h"
+
+#include "depB.h"
+
+struct DEPE_EXPORT DepE
+{
+  int foo();
+
+  DepB getB();
+};
diff --git a/Tests/CMakeCommands/target_link_libraries/targetB.cpp b/Tests/CMakeCommands/target_link_libraries/targetB.cpp
new file mode 100644
index 0000000..c6a1264
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/targetB.cpp
@@ -0,0 +1,14 @@
+
+#include "depD.h"
+#include "depE.h"
+
+int main(int argc, char **argv)
+{
+  DepD d;
+  DepA a = d.getA();
+
+  DepE e;
+  DepB b = e.getB();
+
+  return d.foo() + a.foo() + e.foo() + b.foo();
+}

http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9737cec6fed6c5b5a04d9dbc4894d8afe4e3a893
commit 9737cec6fed6c5b5a04d9dbc4894d8afe4e3a893
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Sun Sep 23 13:16:44 2012 +0200
Commit:     Stephen Kelly <steveire at gmail.com>
CommitDate: Sat Nov 24 15:30:44 2012 +0100

    Add expressions for separating build-location from install-location.
    
    This is for specifying INCLUDE_DIRECTORIES relevant to the build-location
    or the install location for example:
    
      set_property(TARGET foo PROPERTY
        INTERFACE_INCLUDE_DIRECTORIES
        "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}>"
        "$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>"
      )
    
    A 'bar' target can then use:
    
      set_property(TARGET bar PROPERTY
        INCLUDE_DIRECTORIES
        "$<TARGET_PROPERTY:foo,INTERFACE_INCLUDE_DIRECTORIES>"
      )
    
    and it will work whether foo is in the same project, or an imported target
    from an installation location, or an imported target from a build location
    generated by the export() command.
    
    Because the generator expressions are only evaluated at build-time, these
    new expressions are equivalent to the ZeroNode and OneNode.
    
    Additionally, the EXPORT_NAMESPACE expression is added to expand to the
    namespace used when using export() or install(EXPORT). A full example of
    this would be:
    
      set_property(TARGET bar PROPERTY
        INCLUDE_DIRECTORIES
        "$<TARGET_PROPERTY:$<EXPORT_NAMESPACE>foo,INTERFACE_INCLUDE_DIRECTORIES>"
      )
    
    The GeneratorExpression test is split into parts. Some shells can't run
    the custom command as it is getting too long.

diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx
index 32bf941..2bcced1 100644
--- a/Source/cmGeneratorExpression.cxx
+++ b/Source/cmGeneratorExpression.cxx
@@ -131,15 +131,9 @@ cmCompiledGeneratorExpression::~cmCompiledGeneratorExpression()
     }
 }
 
-std::string cmGeneratorExpression::Preprocess(const std::string &input,
-                                              PreprocessContext context)
+//----------------------------------------------------------------------------
+static std::string stripAllGeneratorExpressions(const std::string &input)
 {
-  if (context != StripAllGeneratorExpressions)
-  {
-    assert(!"cmGeneratorExpression::Preprocess called with invalid args");
-    return std::string();
-  }
-
   std::string result;
   std::string::size_type pos = 0;
   std::string::size_type lastPos = pos;
@@ -178,3 +172,95 @@ std::string cmGeneratorExpression::Preprocess(const std::string &input,
   result += input.substr(lastPos);
   return result;
 }
+
+//----------------------------------------------------------------------------
+static std::string stripExportInterface(const std::string &input,
+                          cmGeneratorExpression::PreprocessContext context,
+                          const char *ns)
+{
+  std::string result;
+  {
+  std::string::size_type pos = 0;
+  std::string::size_type lastPos = pos;
+  while((pos = input.find("$<BUILD_INTERFACE:", lastPos)) != input.npos
+    || (pos = input.find("$<INSTALL_INTERFACE:", lastPos)) != input.npos)
+    {
+    result += input.substr(lastPos, pos - lastPos);
+    const bool gotInstallInterface = input[pos + 2] == 'I';
+    pos += gotInstallInterface ? sizeof("$<INSTALL_INTERFACE:") - 1
+                               : sizeof("$<BUILD_INTERFACE:") - 1;
+    int nestingLevel = 1;
+    const char *c = input.c_str() + pos;
+    const char * const cStart = c;
+    for ( ; *c; ++c)
+      {
+      if(c[0] == '$' && c[1] == '<')
+        {
+        ++nestingLevel;
+        ++c;
+        continue;
+        }
+      if(c[0] == '>')
+        {
+        --nestingLevel;
+        if (nestingLevel != 0)
+          {
+          continue;
+          }
+        if(context == cmGeneratorExpression::BuildInterface
+            && !gotInstallInterface)
+          {
+          result += input.substr(pos, c - cStart);
+          }
+        else if(context == cmGeneratorExpression::InstallInterface
+            && gotInstallInterface)
+          {
+          result += input.substr(pos, c - cStart);
+          }
+        break;
+        }
+      }
+    const std::string::size_type traversed = (c - cStart) + 1;
+    if (!*c)
+      {
+      result += std::string(gotInstallInterface ? "$<INSTALL_INTERFACE:"
+                                                : "$<BUILD_INTERFACE:")
+             + input.substr(pos, traversed);
+      }
+    pos += traversed;
+    lastPos = pos;
+    }
+  result += input.substr(lastPos);
+  }
+
+  {
+  std::string::size_type pos = 0;
+  std::string::size_type lastPos = pos;
+
+  std::string expNs = ns ? ns : "";
+  while((pos = result.find("$<EXPORT_NAMESPACE>", lastPos)) != input.npos)
+    {
+    result.replace(pos, sizeof("$<EXPORT_NAMESPACE>") - 1, expNs);
+    pos += sizeof("$<EXPORT_NAMESPACE>") - 1;
+    }
+  }
+  return result;
+}
+
+//----------------------------------------------------------------------------
+std::string cmGeneratorExpression::Preprocess(const std::string &input,
+                                              PreprocessContext context,
+                                              const char *ns)
+{
+  if (context == StripAllGeneratorExpressions)
+    {
+    return stripAllGeneratorExpressions(input);
+    }
+  else if (context == BuildInterface || context == InstallInterface)
+  {
+    return stripExportInterface(input, context, ns);
+  }
+
+  assert(!"cmGeneratorExpression::Preprocess called with invalid args");
+  return std::string();
+}
diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h
index ea3e7d0..5e3352b 100644
--- a/Source/cmGeneratorExpression.h
+++ b/Source/cmGeneratorExpression.h
@@ -48,11 +48,14 @@ public:
   const cmCompiledGeneratorExpression& Parse(const char* input);
 
   enum PreprocessContext {
-    StripAllGeneratorExpressions
+    StripAllGeneratorExpressions,
+    BuildInterface,
+    InstallInterface
   };
 
   static std::string Preprocess(const std::string &input,
-                                PreprocessContext context);
+                                PreprocessContext context,
+                                const char *ns = 0);
 
 private:
   cmGeneratorExpression(const cmGeneratorExpression &);
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx
index c609000..07f46be 100644
--- a/Source/cmGeneratorExpressionEvaluator.cxx
+++ b/Source/cmGeneratorExpressionEvaluator.cxx
@@ -94,6 +94,31 @@ static const struct OneNode : public cmGeneratorExpressionNode
 } oneNode;
 
 //----------------------------------------------------------------------------
+static const struct OneNode buildInterfaceNode;
+
+//----------------------------------------------------------------------------
+static const struct ZeroNode installInterfaceNode;
+
+//----------------------------------------------------------------------------
+static const struct NullNode : public cmGeneratorExpressionNode
+{
+  NullNode() {}
+
+  virtual bool GeneratesContent() const { return false; }
+
+  std::string Evaluate(const std::vector<std::string> &,
+                       cmGeneratorExpressionContext *,
+                       const GeneratorExpressionContent *,
+                       cmGeneratorExpressionDAGChecker *) const
+  {
+    return std::string();
+  }
+
+  virtual int NumExpectedParameters() const { return 0; }
+
+} nullNode;
+
+//----------------------------------------------------------------------------
 #define BOOLEAN_OP_NODE(OPNAME, OP, SUCCESS_VALUE, FAILURE_VALUE) \
 static const struct OP ## Node : public cmGeneratorExpressionNode \
 { \
@@ -591,6 +616,12 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
     return &commaNode;
   else if (identifier == "TARGET_PROPERTY")
     return &targetPropertyNode;
+  else if (identifier == "BUILD_INTERFACE")
+    return &buildInterfaceNode;
+  else if (identifier == "INSTALL_INTERFACE")
+    return &installInterfaceNode;
+  else if (identifier == "EXPORT_NAMESPACE")
+    return &nullNode;
   return 0;
 
 }
diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt
index 3a92d81..66c190a 100644
--- a/Tests/GeneratorExpression/CMakeLists.txt
+++ b/Tests/GeneratorExpression/CMakeLists.txt
@@ -1,7 +1,7 @@
 cmake_minimum_required (VERSION 2.8.8)
 project(GeneratorExpression NONE)
 
-add_custom_target(check ALL
+add_custom_target(check-part1 ALL
   COMMAND ${CMAKE_COMMAND}
     -Dtest_0=$<0:nothing>
     -Dtest_0_with_comma=$<0:-Wl,--no-undefined>
@@ -57,6 +57,13 @@ add_custom_target(check ALL
     -Dtest_colons_3=$<1:Qt5::Core>
     -Dtest_colons_4=$<1:C:\\CMake>
     -Dtest_colons_5=$<1:C:/CMake>
+    -P ${CMAKE_CURRENT_SOURCE_DIR}/check-part1.cmake
+  COMMAND ${CMAKE_COMMAND} -E echo "check done (part 1 of 2)"
+  VERBATIM
+  )
+
+add_custom_target(check-part2 ALL
+  COMMAND ${CMAKE_COMMAND}
     -Dtest_incomplete_1=$<
     -Dtest_incomplete_2=$<something
     -Dtest_incomplete_3=$<something:
@@ -78,7 +85,10 @@ add_custom_target(check ALL
     -Dtest_incomplete_19=$<1:some,thing$<ANGLE-R>
     -Dtest_incomplete_20=$<CONFIGURATION$<ANGLE-R>
     -Dtest_incomplete_21=$<BOOL:something$<ANGLE-R>
-    -P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake
-  COMMAND ${CMAKE_COMMAND} -E echo "check done"
+    -Dtest_build_interface=$<BUILD_INTERFACE:build>
+    -Dtest_install_interface=$<INSTALL_INTERFACE:install>
+    -Dtest_export_namespace=$<EXPORT_NAMESPACE>x
+    -P ${CMAKE_CURRENT_SOURCE_DIR}/check-part2.cmake
+  COMMAND ${CMAKE_COMMAND} -E echo "check done (part 2 of 2)"
   VERBATIM
   )
diff --git a/Tests/GeneratorExpression/check-common.cmake b/Tests/GeneratorExpression/check-common.cmake
new file mode 100644
index 0000000..8ffebd7
--- /dev/null
+++ b/Tests/GeneratorExpression/check-common.cmake
@@ -0,0 +1,5 @@
+macro(check var val)
+  if(NOT "${${var}}" STREQUAL "${val}")
+    message(SEND_ERROR "${var} is \"${${var}}\", not \"${val}\"")
+  endif()
+endmacro()
diff --git a/Tests/GeneratorExpression/check-part1.cmake b/Tests/GeneratorExpression/check-part1.cmake
new file mode 100644
index 0000000..7abfa82
--- /dev/null
+++ b/Tests/GeneratorExpression/check-part1.cmake
@@ -0,0 +1,56 @@
+
+include(${CMAKE_CURRENT_LIST_DIR}/check-common.cmake)
+
+message(STATUS "config=[${config}]")
+check(test_0 "")
+check(test_0_with_comma "")
+check(test_1 "content")
+check(test_1_with_comma "-Wl,--no-undefined")
+check(test_and_0 "0")
+check(test_and_0_0 "0")
+check(test_and_0_1 "0")
+check(test_and_1 "1")
+check(test_and_1_0 "0")
+check(test_and_1_1 "1")
+check(test_and_0_invalidcontent "0")
+check(test_config_0 "0")
+check(test_config_1 "1")
+foreach(c debug release relwithdebinfo minsizerel)
+  if(NOT "${test_config_${c}}" MATCHES "^(0+|1+)$")
+    message(SEND_ERROR "test_config_${c} is \"${test_config_${c}}\", not all 0 or all 1")
+  endif()
+endforeach()
+check(test_not_0 "1")
+check(test_not_1 "0")
+check(test_or_0 "0")
+check(test_or_0_0 "0")
+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_or_1_invalidcontent "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_bool_empty "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_strequal_both_empty "1")
+check(test_strequal_one_empty "0")
+check(test_angle_r ">")
+check(test_comma ",")
+check(test_colons_1 ":")
+check(test_colons_2 "::")
+check(test_colons_3 "Qt5::Core")
+check(test_colons_4 "C:\\\\CMake")
+check(test_colons_5 "C:/CMake")
diff --git a/Tests/GeneratorExpression/check-part2.cmake b/Tests/GeneratorExpression/check-part2.cmake
new file mode 100644
index 0000000..4201345
--- /dev/null
+++ b/Tests/GeneratorExpression/check-part2.cmake
@@ -0,0 +1,27 @@
+
+include(${CMAKE_CURRENT_LIST_DIR}/check-common.cmake)
+
+check(test_incomplete_1 "$<")
+check(test_incomplete_2 "$<something")
+check(test_incomplete_3 "$<something:")
+check(test_incomplete_4 "$<something:,")
+check(test_incomplete_5 "$something:,>")
+check(test_incomplete_6 "<something:,>")
+check(test_incomplete_7 "$<something::")
+check(test_incomplete_8 "$<something:,")
+check(test_incomplete_9 "$<something:,,")
+check(test_incomplete_10 "$<something:,:")
+check(test_incomplete_11 "$<something,,")
+check(test_incomplete_12 "$<,,")
+check(test_incomplete_13 "$<somespecialthing")
+check(test_incomplete_14 "$<>")
+check(test_incomplete_15 "$<some$<thing")
+check(test_incomplete_16 "$<BOOL:something")
+check(test_incomplete_17 "some$thing")
+check(test_incomplete_18 "$<1:some,thing")
+check(test_incomplete_19 "$<1:some,thing>")
+check(test_incomplete_20 "$<CONFIGURATION>")
+check(test_incomplete_21 "$<BOOL:something>")
+check(test_build_interface "build")
+check(test_install_interface "")
+check(test_export_namespace "x")
diff --git a/Tests/GeneratorExpression/check.cmake b/Tests/GeneratorExpression/check.cmake
deleted file mode 100644
index af436de..0000000
--- a/Tests/GeneratorExpression/check.cmake
+++ /dev/null
@@ -1,80 +0,0 @@
-macro(check var val)
-  if(NOT "${${var}}" STREQUAL "${val}")
-    message(SEND_ERROR "${var} is \"${${var}}\", not \"${val}\"")
-  endif()
-endmacro()
-
-message(STATUS "config=[${config}]")
-check(test_0 "")
-check(test_0_with_comma "")
-check(test_1 "content")
-check(test_1_with_comma "-Wl,--no-undefined")
-check(test_and_0 "0")
-check(test_and_0_0 "0")
-check(test_and_0_1 "0")
-check(test_and_1 "1")
-check(test_and_1_0 "0")
-check(test_and_1_1 "1")
-check(test_and_0_invalidcontent "0")
-check(test_config_0 "0")
-check(test_config_1 "1")
-foreach(c debug release relwithdebinfo minsizerel)
-  if(NOT "${test_config_${c}}" MATCHES "^(0+|1+)$")
-    message(SEND_ERROR "test_config_${c} is \"${test_config_${c}}\", not all 0 or all 1")
-  endif()
-endforeach()
-check(test_not_0 "1")
-check(test_not_1 "0")
-check(test_or_0 "0")
-check(test_or_0_0 "0")
-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_or_1_invalidcontent "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_bool_empty "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_strequal_both_empty "1")
-check(test_strequal_one_empty "0")
-check(test_angle_r ">")
-check(test_comma ",")
-check(test_colons_1 ":")
-check(test_colons_2 "::")
-check(test_colons_3 "Qt5::Core")
-check(test_colons_4 "C:\\\\CMake")
-check(test_colons_5 "C:/CMake")
-check(test_incomplete_1 "$<")
-check(test_incomplete_2 "$<something")
-check(test_incomplete_3 "$<something:")
-check(test_incomplete_4 "$<something:,")
-check(test_incomplete_5 "$something:,>")
-check(test_incomplete_6 "<something:,>")
-check(test_incomplete_7 "$<something::")
-check(test_incomplete_8 "$<something:,")
-check(test_incomplete_9 "$<something:,,")
-check(test_incomplete_10 "$<something:,:")
-check(test_incomplete_11 "$<something,,")
-check(test_incomplete_12 "$<,,")
-check(test_incomplete_13 "$<somespecialthing")
-check(test_incomplete_14 "$<>")
-check(test_incomplete_15 "$<some$<thing")
-check(test_incomplete_16 "$<BOOL:something")
-check(test_incomplete_17 "some$thing")
-check(test_incomplete_18 "$<1:some,thing")
-check(test_incomplete_19 "$<1:some,thing>")
-check(test_incomplete_20 "$<CONFIGURATION>")
-check(test_incomplete_21 "$<BOOL:something>")

-----------------------------------------------------------------------

Summary of changes:


hooks/post-receive
-- 
CMake


More information about the Cmake-commits mailing list