From 77cecb778ff1882d87401c1055ec06585462f787 Mon Sep 17 00:00:00 2001
From: Stephen Kelly <steveire@gmail.com>
Date: Mon, 5 Nov 2012 12:43:28 +0100
Subject: Add includes and compile definitions with target_link_libraries.

This establishes that linking is used to propagate usage-requirements
between targets in CMake code. The use of the target_link_libraries
command as the API for this is chosen because introducing a new command
would introduce confusion due to multiple commands which differ only in
a subtle way.
---
 Source/cmTarget.h                                  |  6 +--
 Source/cmTargetLinkLibrariesCommand.cxx            | 53 ++++++++++++++++++++++
 Source/cmTargetLinkLibrariesCommand.h              |  9 ++++
 .../target_link_libraries/CMakeLists.txt           | 25 ++++++++--
 Tests/CMakeCommands/target_link_libraries/depG.cpp |  7 +++
 Tests/CMakeCommands/target_link_libraries/depG.h   |  7 +++
 .../target_link_libraries/targetC.cpp              | 16 +++++++
 Tests/ExportImport/Export/CMakeLists.txt           | 37 ++++++++-------
 Tests/ExportImport/Import/A/CMakeLists.txt         | 14 +-----
 Tests/ExportImport/Import/CMakeLists.txt           |  5 ++
 .../Import/package_new_new/CMakeLists.txt          | 23 ++++++++++
 .../Import/package_new_old/CMakeLists.txt          | 24 ++++++++++
 .../Import/package_old_old/CMakeLists.txt          | 24 ++++++++++
 Tests/Qt4Targets/CMakeLists.txt                    | 19 --------
 14 files changed, 213 insertions(+), 56 deletions(-)
 create mode 100644 Tests/CMakeCommands/target_link_libraries/depG.cpp
 create mode 100644 Tests/CMakeCommands/target_link_libraries/depG.h
 create mode 100644 Tests/CMakeCommands/target_link_libraries/targetC.cpp
 create mode 100644 Tests/ExportImport/Import/package_new_new/CMakeLists.txt
 create mode 100644 Tests/ExportImport/Import/package_new_old/CMakeLists.txt
 create mode 100644 Tests/ExportImport/Import/package_old_old/CMakeLists.txt

diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index cf2d4c4..7577a59 100644
--- a/Source/cmTarget.h
+++ b/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;
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index f42b0f6..cb913f5 100644
--- a/Source/cmTargetLinkLibrariesCommand.cxx
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -250,10 +250,51 @@ cmTargetLinkLibrariesCommand
 }
 
 //----------------------------------------------------------------------------
+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();
diff --git a/Source/cmTargetLinkLibrariesCommand.h b/Source/cmTargetLinkLibrariesCommand.h
index 3da3950..aaabdfa 100644
--- a/Source/cmTargetLinkLibrariesCommand.h
+++ b/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 "
diff --git a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
index 1d0e342..cd0fe11 100644
--- a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
+++ b/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)
diff --git a/Tests/CMakeCommands/target_link_libraries/depG.cpp b/Tests/CMakeCommands/target_link_libraries/depG.cpp
new file mode 100644
index 0000000..65b9655
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depG.cpp
@@ -0,0 +1,7 @@
+
+#include "depG.h"
+
+int DepG::foo()
+{
+  return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/depG.h b/Tests/CMakeCommands/target_link_libraries/depG.h
new file mode 100644
index 0000000..1a36589
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/depG.h
@@ -0,0 +1,7 @@
+
+#include "depg_export.h"
+
+struct DEPG_EXPORT DepG
+{
+  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..ff6ba66
--- /dev/null
+++ b/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();
+}
diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt
index ae44c28..ae938cd 100644
--- a/Tests/ExportImport/Export/CMakeLists.txt
+++ b/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")
@@ -239,6 +223,25 @@ install(EXPORT RequiredExp NAMESPACE Req:: FILE testLibRequiredTargets.cmake DES
 install(TARGETS testLibDepends testSharedLibDepends EXPORT DependsExp DESTINATION lib )
 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(
diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt
index 0675594..0337130 100644
--- a/Tests/ExportImport/Import/A/CMakeLists.txt
+++ b/Tests/ExportImport/Import/A/CMakeLists.txt
@@ -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>
diff --git a/Tests/ExportImport/Import/CMakeLists.txt b/Tests/ExportImport/Import/CMakeLists.txt
index 3fc78a2..237f8fa 100644
--- a/Tests/ExportImport/Import/CMakeLists.txt
+++ b/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)
diff --git a/Tests/ExportImport/Import/package_new_new/CMakeLists.txt b/Tests/ExportImport/Import/package_new_new/CMakeLists.txt
new file mode 100644
index 0000000..4e6f642
--- /dev/null
+++ b/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)
diff --git a/Tests/ExportImport/Import/package_new_old/CMakeLists.txt b/Tests/ExportImport/Import/package_new_old/CMakeLists.txt
new file mode 100644
index 0000000..e675d64
--- /dev/null
+++ b/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})
diff --git a/Tests/ExportImport/Import/package_old_old/CMakeLists.txt b/Tests/ExportImport/Import/package_old_old/CMakeLists.txt
new file mode 100644
index 0000000..3b27330
--- /dev/null
+++ b/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})
diff --git a/Tests/Qt4Targets/CMakeLists.txt b/Tests/Qt4Targets/CMakeLists.txt
index d3aba74..d0c9c66 100644
--- a/Tests/Qt4Targets/CMakeLists.txt
+++ b/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()
-- 
cgit v0.12