Преглед на файлове

Merge branch 'master' into generator-toolset

We need the latest Tests/CMakeLists.txt so we can refactor all tests.
Brad King преди 12 години
родител
ревизия
c0debb1f89
променени са 100 файла, в които са добавени 2866 реда и са изтрити 578 реда
  1. 22 4
      Modules/CMakePackageConfigHelpers.cmake
  2. 761 0
      Modules/ExternalData.cmake
  3. 4 0
      Modules/ExternalData_config.cmake.in
  4. 5 2
      Modules/ExternalProject.cmake
  5. 41 35
      Modules/FindGTK2.cmake
  6. 28 0
      Modules/FindQt4.cmake
  7. 3 2
      Modules/Platform/Windows-MSVC.cmake
  8. 1 1
      Source/CMakeVersion.cmake
  9. 19 4
      Source/cmDocumentGeneratorExpressions.h
  10. 1 0
      Source/cmExportBuildFileGenerator.cxx
  11. 212 75
      Source/cmExportFileGenerator.cxx
  12. 6 2
      Source/cmExportFileGenerator.h
  13. 52 37
      Source/cmExportInstallFileGenerator.cxx
  14. 2 0
      Source/cmExportInstallFileGenerator.h
  15. 1 1
      Source/cmExtraCodeBlocksGenerator.cxx
  16. 5 1
      Source/cmFLTKWrapUICommand.cxx
  17. 20 0
      Source/cmFindPackageCommand.cxx
  18. 7 1
      Source/cmGeneratorExpression.cxx
  19. 5 0
      Source/cmGeneratorExpression.h
  20. 61 0
      Source/cmGeneratorExpressionDAGChecker.cxx
  21. 8 1
      Source/cmGeneratorExpressionDAGChecker.h
  22. 267 1
      Source/cmGeneratorExpressionEvaluator.cxx
  23. 1 0
      Source/cmGeneratorExpressionEvaluator.h
  24. 0 29
      Source/cmGeneratorTarget.cxx
  25. 0 2
      Source/cmGeneratorTarget.h
  26. 3 1
      Source/cmGlobalGenerator.cxx
  27. 2 2
      Source/cmGlobalXCodeGenerator.cxx
  28. 58 34
      Source/cmIncludeDirectoryCommand.cxx
  29. 5 3
      Source/cmIncludeDirectoryCommand.h
  30. 2 4
      Source/cmLinkDirectoriesCommand.h
  31. 8 9
      Source/cmLocalVisualStudio6Generator.cxx
  32. 2 2
      Source/cmLocalVisualStudio7Generator.cxx
  33. 27 10
      Source/cmMakefile.cxx
  34. 9 2
      Source/cmMakefile.h
  35. 2 2
      Source/cmMakefileTargetGenerator.cxx
  36. 1 1
      Source/cmNinjaNormalTargetGenerator.cxx
  37. 2 2
      Source/cmNinjaTargetGenerator.cxx
  38. 21 0
      Source/cmPolicies.cxx
  39. 1 0
      Source/cmPolicies.h
  40. 5 1
      Source/cmQtAutomoc.cxx
  41. 20 31
      Source/cmSystemTools.cxx
  42. 320 69
      Source/cmTarget.cxx
  43. 18 3
      Source/cmTarget.h
  44. 25 14
      Source/cmTargetCompileDefinitionsCommand.cxx
  45. 6 10
      Source/cmTargetCompileDefinitionsCommand.h
  46. 31 21
      Source/cmTargetIncludeDirectoriesCommand.cxx
  47. 6 10
      Source/cmTargetIncludeDirectoriesCommand.h
  48. 53 14
      Source/cmTargetLinkLibrariesCommand.cxx
  49. 12 1
      Source/cmTargetLinkLibrariesCommand.h
  50. 8 17
      Source/cmTargetPropCommandBase.cxx
  51. 10 13
      Source/cmTargetPropCommandBase.h
  52. 2 2
      Source/cmVisualStudio10TargetGenerator.cxx
  53. 4 0
      Source/cmake.cxx
  54. 52 0
      Source/kwsys/DynamicLoader.cxx
  55. 1 1
      Source/kwsys/Glob.cxx
  56. 1 0
      Source/kwsys/IOStream.cxx
  57. 1 1
      Source/kwsys/ProcessUNIX.c
  58. 4 1
      Source/kwsys/SystemInformation.cxx
  59. 2 2
      Source/kwsys/SystemTools.cxx
  60. 8 8
      Source/kwsys/testCommandLineArguments.cxx
  61. 1 1
      Source/kwsys/testDynamicLoader.cxx
  62. 11 11
      Source/kwsys/testProcess.c
  63. 13 13
      Source/kwsys/testSystemTools.cxx
  64. 9 7
      Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt
  65. 8 4
      Tests/CMakeCommands/target_compile_definitions/consumer.cpp
  66. 15 8
      Tests/CMakeCommands/target_include_directories/CMakeLists.txt
  67. 10 5
      Tests/CMakeCommands/target_include_directories/consumer.cpp
  68. 2 0
      Tests/CMakeCommands/target_include_directories/relative_dir/relative_dir.h
  69. 21 7
      Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
  70. 7 0
      Tests/CMakeCommands/target_link_libraries/depG.cpp
  71. 7 0
      Tests/CMakeCommands/target_link_libraries/depG.h
  72. 16 0
      Tests/CMakeCommands/target_link_libraries/targetC.cpp
  73. 15 0
      Tests/CMakeLists.txt
  74. 3 2
      Tests/CMakeTests/CMakeLists.txt
  75. 9 2
      Tests/CMakeTests/ProcessorCountTest.cmake.in
  76. 69 0
      Tests/CompatibleInterface/CMakeLists.txt
  77. 1 0
      Tests/CompatibleInterface/empty.cpp
  78. 7 0
      Tests/CompatibleInterface/iface2.cpp
  79. 13 0
      Tests/CompatibleInterface/iface2.h
  80. 32 0
      Tests/CompatibleInterface/main.cpp
  81. 56 20
      Tests/ExportImport/Export/CMakeLists.txt
  82. 12 8
      Tests/ExportImport/Import/A/CMakeLists.txt
  83. 12 0
      Tests/ExportImport/Import/A/deps_shared_iface.cpp
  84. 5 0
      Tests/ExportImport/Import/CMakeLists.txt
  85. 23 0
      Tests/ExportImport/Import/package_new_new/CMakeLists.txt
  86. 24 0
      Tests/ExportImport/Import/package_new_old/CMakeLists.txt
  87. 24 0
      Tests/ExportImport/Import/package_old_old/CMakeLists.txt
  88. 3 1
      Tests/ExternalProject/CMakeLists.txt
  89. 41 0
      Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt
  90. 38 0
      Tests/Module/ExternalData/CMakeLists.txt
  91. 1 0
      Tests/Module/ExternalData/Data.dat.md5
  92. 52 0
      Tests/Module/ExternalData/Data1Check.cmake
  93. 1 0
      Tests/Module/ExternalData/Data2.dat.md5
  94. 11 0
      Tests/Module/ExternalData/Data2/CMakeLists.txt
  95. 12 0
      Tests/Module/ExternalData/Data2/Data2Check.cmake
  96. 1 0
      Tests/Module/ExternalData/Data2/SeriesC_1_.my.dat.md5
  97. 1 0
      Tests/Module/ExternalData/Data2/SeriesC_2_.my.dat.md5
  98. 1 0
      Tests/Module/ExternalData/Data2/SeriesC_3_.my.dat.md5
  99. 1 0
      Tests/Module/ExternalData/Data2b.dat.md5
  100. 14 0
      Tests/Module/ExternalData/Data3/CMakeLists.txt

+ 22 - 4
Modules/CMakePackageConfigHelpers.cmake

@@ -9,6 +9,8 @@
 # configure_file() command when creating the <Name>Config.cmake or <Name>-config.cmake
 # file for installing a project or library. It helps making the resulting package
 # relocatable by avoiding hardcoded paths in the installed Config.cmake file.
+# <Name>Config.cmake files installed under UNIX into /lib(64) or /usr/lib(64) are
+# considered system packages and are not relocatable.
 #
 # In a FooConfig.cmake file there may be code like this to make the
 # install destinations know to the using project:
@@ -173,17 +175,33 @@ function(CONFIGURE_PACKAGE_CONFIG_FILE _inputFile _outputFile)
   else()
     set(absInstallDir "${CMAKE_INSTALL_PREFIX}/${CCF_INSTALL_DESTINATION}")
   endif()
+
+  # with the /usr-move, /lib(64) is a symlink to /usr/lib on Fedora, ArchLinux, Mageira and others.
+  # If we are installed to such a location, force using absolute paths.
+  set(forceAbsolutePaths FALSE)
+  if("${absInstallDir}" MATCHES "^(/usr)?/lib(64)?/.+")
+    set(forceAbsolutePaths TRUE)
+  endif()
+
   file(RELATIVE_PATH PACKAGE_RELATIVE_PATH "${absInstallDir}" "${CMAKE_INSTALL_PREFIX}" )
 
   foreach(var ${CCF_PATH_VARS})
     if(NOT DEFINED ${var})
       message(FATAL_ERROR "Variable ${var} does not exist")
     else()
-      if(IS_ABSOLUTE "${${var}}")
-        string(REPLACE "${CMAKE_INSTALL_PREFIX}" "\${PACKAGE_PREFIX_DIR}"
-                        PACKAGE_${var} "${${var}}")
+      if(forceAbsolutePaths)
+        if(IS_ABSOLUTE "${${var}}")
+          set(PACKAGE_${var} "${${var}}")
+        else()
+          set(PACKAGE_${var} "${CMAKE_INSTALL_PREFIX}/${${var}}")
+        endif()
       else()
-        set(PACKAGE_${var} "\${PACKAGE_PREFIX_DIR}/${${var}}")
+        if(IS_ABSOLUTE "${${var}}")
+          string(REPLACE "${CMAKE_INSTALL_PREFIX}" "\${PACKAGE_PREFIX_DIR}"
+                          PACKAGE_${var} "${${var}}")
+        else()
+          set(PACKAGE_${var} "\${PACKAGE_PREFIX_DIR}/${${var}}")
+        endif()
       endif()
     endif()
   endforeach()

+ 761 - 0
Modules/ExternalData.cmake

@@ -0,0 +1,761 @@
+# - Manage data files stored outside source tree
+# Use this module to unambiguously reference data files stored outside the
+# source tree and fetch them at build time from arbitrary local and remote
+# content-addressed locations.  Functions provided by this module recognize
+# arguments with the syntax "DATA{<name>}" as references to external data,
+# replace them with full paths to local copies of those data, and create build
+# rules to fetch and update the local copies.
+#
+# The DATA{} syntax is literal and the <name> is a full or relative path
+# within the source tree.  The source tree must contain either a real data
+# file at <name> or a "content link" at <name><ext> containing a hash of the
+# real file using a hash algorithm corresponding to <ext>.  For example, the
+# argument "DATA{img.png}" may be satisfied by either a real "img.png" file in
+# the current source directory or a "img.png.md5" file containing its MD5 sum.
+#
+# The 'ExternalData_Expand_Arguments' function evaluates DATA{} references
+# in its arguments and constructs a new list of arguments:
+#  ExternalData_Expand_Arguments(
+#    <target>   # Name of data management target
+#    <outVar>   # Output variable
+#    [args...]  # Input arguments, DATA{} allowed
+#    )
+# It replaces each DATA{} reference in an argument with the full path of a
+# real data file on disk that will exist after the <target> builds.
+#
+# The 'ExternalData_Add_Test' function wraps around the CMake add_test()
+# command but supports DATA{} references in its arguments:
+#  ExternalData_Add_Test(
+#    <target>   # Name of data management target
+#    ...        # Arguments of add_test(), DATA{} allowed
+#    )
+# It passes its arguments through ExternalData_Expand_Arguments and then
+# invokes add_test() using the results.
+#
+# The 'ExternalData_Add_Target' function creates a custom target to manage
+# local instances of data files stored externally:
+#  ExternalData_Add_Target(
+#    <target>   # Name of data management target
+#    )
+# It creates custom commands in the target as necessary to make data files
+# available for each DATA{} reference previously evaluated by other functions
+# provided by this module.  A list of URL templates must be provided in the
+# variable ExternalData_URL_TEMPLATES using the placeholders "%(algo)" and
+# "%(hash)" in each template.  Data fetch rules try each URL template in order
+# by substituting the hash algorithm name for "%(algo)" and the hash value for
+# "%(hash)".
+#
+# The following hash algorithms are supported:
+#    %(algo)     <ext>     Description
+#    -------     -----     -----------
+#    MD5         .md5      Message-Digest Algorithm 5, RFC 1321
+#    SHA1        .sha1     US Secure Hash Algorithm 1, RFC 3174
+#    SHA224      .sha224   US Secure Hash Algorithms, RFC 4634
+#    SHA256      .sha256   US Secure Hash Algorithms, RFC 4634
+#    SHA384      .sha384   US Secure Hash Algorithms, RFC 4634
+#    SHA512      .sha512   US Secure Hash Algorithms, RFC 4634
+# Note that the hashes are used only for unique data identification and
+# download verification.  This is not security software.
+#
+# Example usage:
+#   include(ExternalData)
+#   set(ExternalData_URL_TEMPLATES "file:///local/%(algo)/%(hash)"
+#                                  "http://data.org/%(algo)/%(hash)")
+#   ExternalData_Add_Test(MyData
+#     NAME MyTest
+#     COMMAND MyExe DATA{MyInput.png}
+#     )
+#   ExternalData_Add_Target(MyData)
+# When test "MyTest" runs the "DATA{MyInput.png}" argument will be replaced by
+# the full path to a real instance of the data file "MyInput.png" on disk.  If
+# the source tree contains a content link such as "MyInput.png.md5" then the
+# "MyData" target creates a real "MyInput.png" in the build tree.
+#
+# The DATA{} syntax can be told to fetch a file series using the form
+# "DATA{<name>,:}", where the ":" is literal.  If the source tree contains a
+# group of files or content links named like a series then a reference to one
+# member adds rules to fetch all of them.  Although all members of a series
+# are fetched, only the file originally named by the DATA{} argument is
+# substituted for it.  The default configuration recognizes file series names
+# ending with "#.ext", "_#.ext", ".#.ext", or "-#.ext" where "#" is a sequence
+# of decimal digits and ".ext" is any single extension.  Configure it with a
+# regex that parses <number> and <suffix> parts from the end of <name>:
+#  ExternalData_SERIES_PARSE = regex of the form (<number>)(<suffix>)$
+# For more complicated cases set:
+#  ExternalData_SERIES_PARSE = regex with at least two () groups
+#  ExternalData_SERIES_PARSE_PREFIX = <prefix> regex group number, if any
+#  ExternalData_SERIES_PARSE_NUMBER = <number> regex group number
+#  ExternalData_SERIES_PARSE_SUFFIX = <suffix> regex group number
+# Configure series number matching with a regex that matches the
+# <number> part of series members named <prefix><number><suffix>:
+#  ExternalData_SERIES_MATCH = regex matching <number> in all series members
+# Note that the <suffix> of a series does not include a hash-algorithm
+# extension.
+#
+# The DATA{} syntax can alternatively match files associated with the named
+# file and contained in the same directory.  Associated files may be specified
+# by options using the syntax DATA{<name>,<opt1>,<opt2>,...}.  Each option may
+# specify one file by name or specify a regular expression to match file names
+# using the syntax REGEX:<regex>.  For example, the arguments
+#   DATA{MyData/MyInput.mhd,MyInput.img}                   # File pair
+#   DATA{MyData/MyFrames00.png,REGEX:MyFrames[0-9]+\\.png} # Series
+# will pass MyInput.mha and MyFrames00.png on the command line but ensure
+# that the associated files are present next to them.
+#
+# The DATA{} syntax may reference a directory using a trailing slash and a
+# list of associated files.  The form DATA{<name>/,<opt1>,<opt2>,...} adds
+# rules to fetch any files in the directory that match one of the associated
+# file options.  For example, the argument DATA{MyDataDir/,REGEX:.*} will pass
+# the full path to a MyDataDir directory on the command line and ensure that
+# the directory contains files corresponding to every file or content link in
+# the MyDataDir source directory.
+#
+# The variable ExternalData_LINK_CONTENT may be set to the name of a supported
+# hash algorithm to enable automatic conversion of real data files referenced
+# by the DATA{} syntax into content links.  For each such <file> a content
+# link named "<file><ext>" is created.  The original file is renamed to the
+# form ".ExternalData_<algo>_<hash>" to stage it for future transmission to
+# one of the locations in the list of URL templates (by means outside the
+# scope of this module).  The data fetch rule created for the content link
+# will use the staged object if it cannot be found using any URL template.
+#
+# The variable ExternalData_OBJECT_STORES may be set to a list of local
+# directories that store objects using the layout <dir>/%(algo)/%(hash).
+# These directories will be searched first for a needed object.  If the object
+# is not available in any store then it will be fetched remotely using the URL
+# templates and added to the first local store listed.  If no stores are
+# specified the default is a location inside the build tree.
+#
+# The variable ExternalData_SOURCE_ROOT may be set to the highest source
+# directory containing any path named by a DATA{} reference.  The default is
+# CMAKE_SOURCE_DIR.  ExternalData_SOURCE_ROOT and CMAKE_SOURCE_DIR must refer
+# to directories within a single source distribution (e.g. they come together
+# in one tarball).
+#
+# The variable ExternalData_BINARY_ROOT may be set to the directory to hold
+# the real data files named by expanded DATA{} references.  The default is
+# CMAKE_BINARY_DIR.  The directory layout will mirror that of content links
+# under ExternalData_SOURCE_ROOT.
+#
+# Variables ExternalData_TIMEOUT_INACTIVITY and ExternalData_TIMEOUT_ABSOLUTE
+# set the download inactivity and absolute timeouts, in seconds.  The defaults
+# are 60 seconds and 300 seconds, respectively.  Set either timeout to 0
+# seconds to disable enforcement.
+
+#=============================================================================
+# Copyright 2010-2013 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+function(ExternalData_add_test target)
+  ExternalData_expand_arguments("${target}" testArgs ${ARGN})
+  add_test(${testArgs})
+endfunction()
+
+function(ExternalData_add_target target)
+  if(NOT ExternalData_URL_TEMPLATES)
+    message(FATAL_ERROR "ExternalData_URL_TEMPLATES is not set!")
+  endif()
+  if(NOT ExternalData_OBJECT_STORES)
+    set(ExternalData_OBJECT_STORES ${CMAKE_BINARY_DIR}/ExternalData/Objects)
+  endif()
+  set(config ${CMAKE_CURRENT_BINARY_DIR}/${target}_config.cmake)
+  configure_file(${_ExternalData_SELF_DIR}/ExternalData_config.cmake.in ${config} @ONLY)
+
+  set(files "")
+
+  # Set "_ExternalData_FILE_${file}" for each output file to avoid duplicate
+  # rules.  Use local data first to prefer real files over content links.
+
+  # Custom commands to copy or link local data.
+  get_property(data_local GLOBAL PROPERTY _ExternalData_${target}_LOCAL)
+  foreach(entry IN LISTS data_local)
+    string(REPLACE "|" ";" tuple "${entry}")
+    list(GET tuple 0 file)
+    list(GET tuple 1 name)
+    if(NOT DEFINED "_ExternalData_FILE_${file}")
+      set("_ExternalData_FILE_${file}" 1)
+      add_custom_command(
+        COMMENT "Generating ${file}"
+        OUTPUT "${file}"
+        COMMAND ${CMAKE_COMMAND} -Drelative_top=${CMAKE_BINARY_DIR}
+                                 -Dfile=${file} -Dname=${name}
+                                 -DExternalData_ACTION=local
+                                 -DExternalData_CONFIG=${config}
+                                 -P ${_ExternalData_SELF}
+        MAIN_DEPENDENCY "${name}"
+        )
+      list(APPEND files "${file}")
+    endif()
+  endforeach()
+
+  # Custom commands to fetch remote data.
+  get_property(data_fetch GLOBAL PROPERTY _ExternalData_${target}_FETCH)
+  foreach(entry IN LISTS data_fetch)
+    string(REPLACE "|" ";" tuple "${entry}")
+    list(GET tuple 0 file)
+    list(GET tuple 1 name)
+    list(GET tuple 2 ext)
+    set(stamp "${ext}-stamp")
+    if(NOT DEFINED "_ExternalData_FILE_${file}")
+      set("_ExternalData_FILE_${file}" 1)
+      add_custom_command(
+        # Users care about the data file, so hide the hash/timestamp file.
+        COMMENT "Generating ${file}"
+        # The hash/timestamp file is the output from the build perspective.
+        # List the real file as a second output in case it is a broken link.
+        # The files must be listed in this order so CMake can hide from the
+        # make tool that a symlink target may not be newer than the input.
+        OUTPUT "${file}${stamp}" "${file}"
+        # Run the data fetch/update script.
+        COMMAND ${CMAKE_COMMAND} -Drelative_top=${CMAKE_BINARY_DIR}
+                                 -Dfile=${file} -Dname=${name} -Dext=${ext}
+                                 -DExternalData_ACTION=fetch
+                                 -DExternalData_CONFIG=${config}
+                                 -P ${_ExternalData_SELF}
+        # Update whenever the object hash changes.
+        MAIN_DEPENDENCY "${name}${ext}"
+        )
+      list(APPEND files "${file}${stamp}")
+    endif()
+  endforeach()
+
+  # Custom target to drive all update commands.
+  add_custom_target(${target} ALL DEPENDS ${files})
+endfunction()
+
+function(ExternalData_expand_arguments target outArgsVar)
+  # Replace DATA{} references with real arguments.
+  set(data_regex "DATA{([^{}\r\n]*)}")
+  set(other_regex "([^D]|D[^A]|DA[^T]|DAT[^A]|DATA[^{])+|.")
+  set(outArgs "")
+  foreach(arg IN LISTS ARGN)
+    if("x${arg}" MATCHES "${data_regex}")
+      # Split argument into DATA{}-pieces and other pieces.
+      string(REGEX MATCHALL "${data_regex}|${other_regex}" pieces "${arg}")
+      # Compose output argument with DATA{}-pieces replaced.
+      set(outArg "")
+      foreach(piece IN LISTS pieces)
+        if("x${piece}" MATCHES "^x${data_regex}$")
+          # Replace this DATA{}-piece with a file path.
+          string(REGEX REPLACE "${data_regex}" "\\1" data "${piece}")
+          _ExternalData_arg("${target}" "${piece}" "${data}" file)
+          set(outArg "${outArg}${file}")
+        else()
+          # No replacement needed for this piece.
+          set(outArg "${outArg}${piece}")
+        endif()
+      endforeach()
+      list(APPEND outArgs "${outArg}")
+    else()
+      # No replacements needed in this argument.
+      list(APPEND outArgs "${arg}")
+    endif()
+  endforeach()
+  set("${outArgsVar}" "${outArgs}" PARENT_SCOPE)
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Private helper interface
+
+set(_ExternalData_REGEX_ALGO "MD5|SHA1|SHA224|SHA256|SHA384|SHA512")
+set(_ExternalData_REGEX_EXT "md5|sha1|sha224|sha256|sha384|sha512")
+set(_ExternalData_SELF "${CMAKE_CURRENT_LIST_FILE}")
+get_filename_component(_ExternalData_SELF_DIR "${_ExternalData_SELF}" PATH)
+
+function(_ExternalData_compute_hash var_hash algo file)
+  if("${algo}" MATCHES "^${_ExternalData_REGEX_ALGO}$")
+    file("${algo}" "${file}" hash)
+    set("${var_hash}" "${hash}" PARENT_SCOPE)
+  else()
+    message(FATAL_ERROR "Hash algorithm ${algo} unimplemented.")
+  endif()
+endfunction()
+
+function(_ExternalData_random var)
+  string(RANDOM LENGTH 6 random)
+  set("${var}" "${random}" PARENT_SCOPE)
+endfunction()
+
+function(_ExternalData_exact_regex regex_var string)
+  string(REGEX REPLACE "([][+.*()^])" "\\\\\\1" regex "${string}")
+  set("${regex_var}" "${regex}" PARENT_SCOPE)
+endfunction()
+
+function(_ExternalData_atomic_write file content)
+  _ExternalData_random(random)
+  set(tmp "${file}.tmp${random}")
+  file(WRITE "${tmp}" "${content}")
+  file(RENAME "${tmp}" "${file}")
+endfunction()
+
+function(_ExternalData_link_content name var_ext)
+  if("${ExternalData_LINK_CONTENT}" MATCHES "^(${_ExternalData_REGEX_ALGO})$")
+    set(algo "${ExternalData_LINK_CONTENT}")
+  else()
+    message(FATAL_ERROR
+      "Unknown hash algorithm specified by ExternalData_LINK_CONTENT:\n"
+      "  ${ExternalData_LINK_CONTENT}")
+  endif()
+  _ExternalData_compute_hash(hash "${algo}" "${name}")
+  get_filename_component(dir "${name}" PATH)
+  set(staged "${dir}/.ExternalData_${algo}_${hash}")
+  string(TOLOWER ".${algo}" ext)
+  _ExternalData_atomic_write("${name}${ext}" "${hash}\n")
+  file(RENAME "${name}" "${staged}")
+  set("${var_ext}" "${ext}" PARENT_SCOPE)
+
+  file(RELATIVE_PATH relname "${ExternalData_SOURCE_ROOT}" "${name}${ext}")
+  message(STATUS "Linked ${relname} to ExternalData ${algo}/${hash}")
+endfunction()
+
+function(_ExternalData_arg target arg options var_file)
+  # Separate data path from the options.
+  string(REPLACE "," ";" options "${options}")
+  list(GET options 0 data)
+  list(REMOVE_AT options 0)
+
+  # Interpret trailing slashes as directories.
+  set(data_is_directory 0)
+  if("x${data}" MATCHES "^x(.*)([/\\])$")
+    set(data_is_directory 1)
+    set(data "${CMAKE_MATCH_1}")
+  endif()
+
+  # Convert to full path.
+  if(IS_ABSOLUTE "${data}")
+    set(absdata "${data}")
+  else()
+    set(absdata "${CMAKE_CURRENT_SOURCE_DIR}/${data}")
+  endif()
+  get_filename_component(absdata "${absdata}" ABSOLUTE)
+
+  # Convert to relative path under the source tree.
+  if(NOT ExternalData_SOURCE_ROOT)
+    set(ExternalData_SOURCE_ROOT "${CMAKE_SOURCE_DIR}")
+  endif()
+  set(top_src "${ExternalData_SOURCE_ROOT}")
+  file(RELATIVE_PATH reldata "${top_src}" "${absdata}")
+  if(IS_ABSOLUTE "${reldata}" OR "${reldata}" MATCHES "^\\.\\./")
+    message(FATAL_ERROR "Data file referenced by argument\n"
+      "  ${arg}\n"
+      "does not lie under the top-level source directory\n"
+      "  ${top_src}\n")
+  endif()
+  if(data_is_directory AND NOT IS_DIRECTORY "${top_src}/${reldata}")
+    message(FATAL_ERROR "Data directory referenced by argument\n"
+      "  ${arg}\n"
+      "corresponds to source tree path\n"
+      "  ${reldata}\n"
+      "that does not exist as a directory!")
+  endif()
+  if(NOT ExternalData_BINARY_ROOT)
+    set(ExternalData_BINARY_ROOT "${CMAKE_BINARY_DIR}")
+  endif()
+  set(top_bin "${ExternalData_BINARY_ROOT}")
+
+  # Handle in-source builds gracefully.
+  if("${top_src}" STREQUAL "${top_bin}")
+    if(ExternalData_LINK_CONTENT)
+      message(WARNING "ExternalData_LINK_CONTENT cannot be used in-source")
+      set(ExternalData_LINK_CONTENT 0)
+    endif()
+    set(top_same 1)
+  endif()
+
+  set(external "") # Entries external to the source tree.
+  set(internal "") # Entries internal to the source tree.
+  set(have_original ${data_is_directory})
+
+  # Process options.
+  set(series_option "")
+  set(associated_files "")
+  set(associated_regex "")
+  foreach(opt ${options})
+    if("x${opt}" MATCHES "^xREGEX:[^:/]+$")
+      # Regular expression to match associated files.
+      string(REGEX REPLACE "^REGEX:" "" regex "${opt}")
+      list(APPEND associated_regex "${regex}")
+    elseif("x${opt}" MATCHES "^x:$")
+      # Activate series matching.
+      set(series_option "${opt}")
+    elseif("x${opt}" MATCHES "^[^][:/*?]+$")
+      # Specific associated file.
+      list(APPEND associated_files "${opt}")
+    else()
+      message(FATAL_ERROR "Unknown option \"${opt}\" in argument\n"
+        "  ${arg}\n")
+    endif()
+  endforeach()
+
+  if(series_option)
+    if(data_is_directory)
+      message(FATAL_ERROR "Series option \"${series_option}\" not allowed with directories.")
+    endif()
+    if(associated_files OR associated_regex)
+      message(FATAL_ERROR "Series option \"${series_option}\" not allowed with associated files.")
+    endif()
+    # Load a whole file series.
+    _ExternalData_arg_series()
+  elseif(data_is_directory)
+    if(associated_files OR associated_regex)
+      # Load listed/matching associated files in the directory.
+      _ExternalData_arg_associated()
+    else()
+      message(FATAL_ERROR "Data directory referenced by argument\n"
+        "  ${arg}\n"
+        "must list associated files.")
+    endif()
+  else()
+    # Load the named data file.
+    _ExternalData_arg_single()
+    if(associated_files OR associated_regex)
+      # Load listed/matching associated files.
+      _ExternalData_arg_associated()
+    endif()
+  endif()
+
+  if(NOT have_original)
+    message(FATAL_ERROR "Data file referenced by argument\n"
+      "  ${arg}\n"
+      "corresponds to source tree path\n"
+      "  ${reldata}\n"
+      "that does not exist as a file (with or without an extension)!")
+  endif()
+
+  if(external)
+    # Make the series available in the build tree.
+    set_property(GLOBAL APPEND PROPERTY
+      _ExternalData_${target}_FETCH "${external}")
+    set_property(GLOBAL APPEND PROPERTY
+      _ExternalData_${target}_LOCAL "${internal}")
+    set("${var_file}" "${top_bin}/${reldata}" PARENT_SCOPE)
+  else()
+    # The whole series is in the source tree.
+    set("${var_file}" "${top_src}/${reldata}" PARENT_SCOPE)
+  endif()
+endfunction()
+
+macro(_ExternalData_arg_associated)
+  # Associated files lie in the same directory.
+  if(data_is_directory)
+    set(reldir "${reldata}")
+  else()
+    get_filename_component(reldir "${reldata}" PATH)
+  endif()
+  if(reldir)
+    set(reldir "${reldir}/")
+  endif()
+  _ExternalData_exact_regex(reldir_regex "${reldir}")
+
+  # Find files named explicitly.
+  foreach(file ${associated_files})
+    _ExternalData_exact_regex(file_regex "${file}")
+    _ExternalData_arg_find_files("${reldir}${file}" "${reldir_regex}${file_regex}")
+  endforeach()
+
+  # Find files matching the given regular expressions.
+  set(all "")
+  set(sep "")
+  foreach(regex ${associated_regex})
+    set(all "${all}${sep}${reldir_regex}${regex}")
+    set(sep "|")
+  endforeach()
+  _ExternalData_arg_find_files("${reldir}" "${all}")
+endmacro()
+
+macro(_ExternalData_arg_single)
+  # Match only the named data by itself.
+  _ExternalData_exact_regex(data_regex "${reldata}")
+  _ExternalData_arg_find_files("${reldata}" "${data_regex}")
+endmacro()
+
+macro(_ExternalData_arg_series)
+  # Configure series parsing and matching.
+  set(series_parse_prefix "")
+  set(series_parse_number "\\1")
+  set(series_parse_suffix "\\2")
+  if(ExternalData_SERIES_PARSE)
+    if(ExternalData_SERIES_PARSE_NUMBER AND ExternalData_SERIES_PARSE_SUFFIX)
+      if(ExternalData_SERIES_PARSE_PREFIX)
+        set(series_parse_prefix "\\${ExternalData_SERIES_PARSE_PREFIX}")
+      endif()
+      set(series_parse_number "\\${ExternalData_SERIES_PARSE_NUMBER}")
+      set(series_parse_suffix "\\${ExternalData_SERIES_PARSE_SUFFIX}")
+    elseif(NOT "x${ExternalData_SERIES_PARSE}" MATCHES "^x\\([^()]*\\)\\([^()]*\\)\\$$")
+      message(FATAL_ERROR
+        "ExternalData_SERIES_PARSE is set to\n"
+        "  ${ExternalData_SERIES_PARSE}\n"
+        "which is not of the form\n"
+        "  (<number>)(<suffix>)$\n"
+        "Fix the regular expression or set variables\n"
+        "  ExternalData_SERIES_PARSE_PREFIX = <prefix> regex group number, if any\n"
+        "  ExternalData_SERIES_PARSE_NUMBER = <number> regex group number\n"
+        "  ExternalData_SERIES_PARSE_SUFFIX = <suffix> regex group number\n"
+        )
+    endif()
+    set(series_parse "${ExternalData_SERIES_PARSE}")
+  else()
+    set(series_parse "([0-9]*)(\\.[^./]*)$")
+  endif()
+  if(ExternalData_SERIES_MATCH)
+    set(series_match "${ExternalData_SERIES_MATCH}")
+  else()
+    set(series_match "[_.-]?[0-9]*")
+  endif()
+
+  # Parse the base, number, and extension components of the series.
+  string(REGEX REPLACE "${series_parse}" "${series_parse_prefix};${series_parse_number};${series_parse_suffix}" tuple "${reldata}")
+  list(LENGTH tuple len)
+  if(NOT "${len}" EQUAL 3)
+    message(FATAL_ERROR "Data file referenced by argument\n"
+      "  ${arg}\n"
+      "corresponds to path\n"
+      "  ${reldata}\n"
+      "that does not match regular expression\n"
+      "  ${series_parse}")
+  endif()
+  list(GET tuple 0 relbase)
+  list(GET tuple 2 ext)
+
+  # Glob files that might match the series.
+  # Then match base, number, and extension.
+  _ExternalData_exact_regex(series_base "${relbase}")
+  _ExternalData_exact_regex(series_ext "${ext}")
+  _ExternalData_arg_find_files("${relbase}*${ext}"
+    "${series_base}${series_match}${series_ext}")
+endmacro()
+
+function(_ExternalData_arg_find_files pattern regex)
+  file(GLOB globbed RELATIVE "${top_src}" "${top_src}/${pattern}*")
+  foreach(entry IN LISTS globbed)
+    if("x${entry}" MATCHES "^x(.*)(\\.(${_ExternalData_REGEX_EXT}))$")
+      set(relname "${CMAKE_MATCH_1}")
+      set(alg "${CMAKE_MATCH_2}")
+    else()
+      set(relname "${entry}")
+      set(alg "")
+    endif()
+    if("x${relname}" MATCHES "^x${regex}$" AND NOT IS_DIRECTORY "${top_src}/${entry}")
+      set(name "${top_src}/${relname}")
+      set(file "${top_bin}/${relname}")
+      if(alg)
+        list(APPEND external "${file}|${name}|${alg}")
+      elseif(ExternalData_LINK_CONTENT)
+        _ExternalData_link_content("${name}" alg)
+        list(APPEND external "${file}|${name}|${alg}")
+      elseif(NOT top_same)
+        list(APPEND internal "${file}|${name}")
+      endif()
+      if("${relname}" STREQUAL "${reldata}")
+        set(have_original 1)
+      endif()
+    endif()
+  endforeach()
+  set(external "${external}" PARENT_SCOPE)
+  set(internal "${internal}" PARENT_SCOPE)
+  set(have_original "${have_original}" PARENT_SCOPE)
+endfunction()
+
+#-----------------------------------------------------------------------------
+# Private script mode interface
+
+if(CMAKE_GENERATOR OR NOT ExternalData_ACTION)
+  return()
+endif()
+
+if(ExternalData_CONFIG)
+  include(${ExternalData_CONFIG})
+endif()
+if(NOT ExternalData_URL_TEMPLATES)
+  message(FATAL_ERROR "No ExternalData_URL_TEMPLATES set!")
+endif()
+
+function(_ExternalData_link_or_copy src dst)
+  # Create a temporary file first.
+  get_filename_component(dst_dir "${dst}" PATH)
+  file(MAKE_DIRECTORY "${dst_dir}")
+  _ExternalData_random(random)
+  set(tmp "${dst}.tmp${random}")
+  if(UNIX)
+    # Create a symbolic link.
+    set(tgt "${src}")
+    if(relative_top)
+      # Use relative path if files are close enough.
+      file(RELATIVE_PATH relsrc "${relative_top}" "${src}")
+      file(RELATIVE_PATH relfile "${relative_top}" "${dst}")
+      if(NOT IS_ABSOLUTE "${relsrc}" AND NOT "${relsrc}" MATCHES "^\\.\\./" AND
+          NOT IS_ABSOLUTE "${reldst}" AND NOT "${reldst}" MATCHES "^\\.\\./")
+        file(RELATIVE_PATH tgt "${dst_dir}" "${src}")
+      endif()
+    endif()
+    execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink "${tgt}" "${tmp}" RESULT_VARIABLE result)
+  else()
+    # Create a copy.
+    execute_process(COMMAND "${CMAKE_COMMAND}" -E copy "${src}" "${tmp}" RESULT_VARIABLE result)
+  endif()
+  if(result)
+    file(REMOVE "${tmp}")
+    message(FATAL_ERROR "Failed to create\n  ${tmp}\nfrom\n  ${obj}")
+  endif()
+
+  # Atomically create/replace the real destination.
+  file(RENAME "${tmp}" "${dst}")
+endfunction()
+
+function(_ExternalData_download_file url file err_var msg_var)
+  set(retry 3)
+  while(retry)
+    math(EXPR retry "${retry} - 1")
+    if(ExternalData_TIMEOUT_INACTIVITY)
+      set(inactivity_timeout INACTIVITY_TIMEOUT ${ExternalData_TIMEOUT_INACTIVITY})
+    elseif(NOT "${ExternalData_TIMEOUT_INACTIVITY}" EQUAL 0)
+      set(inactivity_timeout INACTIVITY_TIMEOUT 60)
+    else()
+      set(inactivity_timeout "")
+    endif()
+    if(ExternalData_TIMEOUT_ABSOLUTE)
+      set(absolute_timeout TIMEOUT ${ExternalData_TIMEOUT_ABSOLUTE})
+    elseif(NOT "${ExternalData_TIMEOUT_ABSOLUTE}" EQUAL 0)
+      set(absolute_timeout TIMEOUT 300)
+    else()
+      set(absolute_timeout "")
+    endif()
+    file(DOWNLOAD "${url}" "${file}" STATUS status LOG log ${inactivity_timeout} ${absolute_timeout} SHOW_PROGRESS)
+    list(GET status 0 err)
+    list(GET status 1 msg)
+    if(err)
+      if("${msg}" MATCHES "HTTP response code said error" AND
+          "${log}" MATCHES "error: 503")
+        set(msg "temporarily unavailable")
+      endif()
+    elseif("${log}" MATCHES "\nHTTP[^\n]* 503")
+      set(err TRUE)
+      set(msg "temporarily unavailable")
+    endif()
+    if(NOT err OR NOT "${msg}" MATCHES "partial|timeout|temporarily")
+      break()
+    elseif(retry)
+      message(STATUS "[download terminated: ${msg}, retries left: ${retry}]")
+    endif()
+  endwhile()
+  set("${err_var}" "${err}" PARENT_SCOPE)
+  set("${msg_var}" "${msg}" PARENT_SCOPE)
+endfunction()
+
+function(_ExternalData_download_object name hash algo var_obj)
+  # Search all object stores for an existing object.
+  foreach(dir ${ExternalData_OBJECT_STORES})
+    set(obj "${dir}/${algo}/${hash}")
+    if(EXISTS "${obj}")
+      message(STATUS "Found object: \"${obj}\"")
+      set("${var_obj}" "${obj}" PARENT_SCOPE)
+      return()
+    endif()
+  endforeach()
+
+  # Download object to the first store.
+  list(GET ExternalData_OBJECT_STORES 0 store)
+  set(obj "${store}/${algo}/${hash}")
+
+  _ExternalData_random(random)
+  set(tmp "${obj}.tmp${random}")
+  set(found 0)
+  set(tried "")
+  foreach(url_template IN LISTS ExternalData_URL_TEMPLATES)
+    string(REPLACE "%(hash)" "${hash}" url_tmp "${url_template}")
+    string(REPLACE "%(algo)" "${algo}" url "${url_tmp}")
+    message(STATUS "Fetching \"${url}\"")
+    _ExternalData_download_file("${url}" "${tmp}" err errMsg)
+    set(tried "${tried}\n  ${url}")
+    if(err)
+      set(tried "${tried} (${errMsg})")
+    else()
+      # Verify downloaded object.
+      _ExternalData_compute_hash(dl_hash "${algo}" "${tmp}")
+      if("${dl_hash}" STREQUAL "${hash}")
+        set(found 1)
+        break()
+      else()
+        set(tried "${tried} (wrong hash ${algo}=${dl_hash})")
+        if("$ENV{ExternalData_DEBUG_DOWNLOAD}" MATCHES ".")
+          file(RENAME "${tmp}" "${store}/${algo}/${dl_hash}")
+        endif()
+      endif()
+    endif()
+    file(REMOVE "${tmp}")
+  endforeach()
+
+  get_filename_component(dir "${name}" PATH)
+  set(staged "${dir}/.ExternalData_${algo}_${hash}")
+
+  if(found)
+    file(RENAME "${tmp}" "${obj}")
+    message(STATUS "Downloaded object: \"${obj}\"")
+  elseif(EXISTS "${staged}")
+    set(obj "${staged}")
+    message(STATUS "Staged object: \"${obj}\"")
+  else()
+    message(FATAL_ERROR "Object ${algo}=${hash} not found at:${tried}")
+  endif()
+
+  set("${var_obj}" "${obj}" PARENT_SCOPE)
+endfunction()
+
+if("${ExternalData_ACTION}" STREQUAL "fetch")
+  foreach(v ExternalData_OBJECT_STORES file name ext)
+    if(NOT DEFINED "${v}")
+      message(FATAL_ERROR "No \"-D${v}=\" value provided!")
+    endif()
+  endforeach()
+
+  file(READ "${name}${ext}" hash)
+  string(STRIP "${hash}" hash)
+
+  if("${ext}" MATCHES "^\\.(${_ExternalData_REGEX_EXT})$")
+    string(TOUPPER "${CMAKE_MATCH_1}" algo)
+  else()
+    message(FATAL_ERROR "Unknown hash algorithm extension \"${ext}\"")
+  endif()
+
+  _ExternalData_download_object("${name}" "${hash}" "${algo}" obj)
+
+  # Check if file already corresponds to the object.
+  set(stamp "${ext}-stamp")
+  set(file_up_to_date 0)
+  if(EXISTS "${file}" AND EXISTS "${file}${stamp}")
+    file(READ "${file}${stamp}" f_hash)
+    string(STRIP "${f_hash}" f_hash)
+    if("${f_hash}" STREQUAL "${hash}")
+      #message(STATUS "File already corresponds to object")
+      set(file_up_to_date 1)
+    endif()
+  endif()
+
+  if(file_up_to_date)
+    # Touch the file to convince the build system it is up to date.
+    execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${file}")
+  else()
+    _ExternalData_link_or_copy("${obj}" "${file}")
+  endif()
+
+  # Atomically update the hash/timestamp file to record the object referenced.
+  _ExternalData_atomic_write("${file}${stamp}" "${hash}\n")
+elseif("${ExternalData_ACTION}" STREQUAL "local")
+  foreach(v file name)
+    if(NOT DEFINED "${v}")
+      message(FATAL_ERROR "No \"-D${v}=\" value provided!")
+    endif()
+  endforeach()
+  _ExternalData_link_or_copy("${name}" "${file}")
+else()
+  message(FATAL_ERROR "Unknown ExternalData_ACTION=[${ExternalData_ACTION}]")
+endif()

+ 4 - 0
Modules/ExternalData_config.cmake.in

@@ -0,0 +1,4 @@
+set(ExternalData_OBJECT_STORES "@ExternalData_OBJECT_STORES@")
+set(ExternalData_URL_TEMPLATES "@ExternalData_URL_TEMPLATES@")
+set(ExternalData_TIMEOUT_INACTIVITY "@ExternalData_TIMEOUT_INACTIVITY@")
+set(ExternalData_TIMEOUT_ABSOLUTE "@ExternalData_TIMEOUT_ABSOLUTE@")

+ 5 - 2
Modules/ExternalProject.cmake

@@ -1559,8 +1559,11 @@ function(_ep_add_configure_command name)
   set(file_deps)
   get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
   foreach(dep IN LISTS deps)
-    _ep_get_step_stampfile(${dep} "done" done_stamp_file)
-    list(APPEND file_deps ${done_stamp_file})
+    get_property(is_ep TARGET ${dep} PROPERTY _EP_IS_EXTERNAL_PROJECT)
+    if(is_ep)
+      _ep_get_step_stampfile(${dep} "done" done_stamp_file)
+      list(APPEND file_deps ${done_stamp_file})
+    endif()
   endforeach()
 
   get_property(cmd_set TARGET ${name} PROPERTY _EP_CONFIGURE_COMMAND SET)

+ 41 - 35
Modules/FindGTK2.cmake

@@ -439,28 +439,19 @@ list(APPEND GTK2_LIBRARIES ${FREETYPE_LIBRARIES})
 
 foreach(_GTK2_component ${GTK2_FIND_COMPONENTS})
     if(_GTK2_component STREQUAL "gtk")
-        _GTK2_FIND_INCLUDE_DIR(GTK2_GLIB_INCLUDE_DIR glib.h)
-        _GTK2_FIND_INCLUDE_DIR(GTK2_GLIBCONFIG_INCLUDE_DIR glibconfig.h)
-        _GTK2_FIND_LIBRARY    (GTK2_GLIB_LIBRARY glib false true)
-
-        _GTK2_FIND_INCLUDE_DIR(GTK2_GOBJECT_INCLUDE_DIR gobject/gobject.h)
-        _GTK2_FIND_LIBRARY    (GTK2_GOBJECT_LIBRARY gobject false true)
-
-        _GTK2_FIND_INCLUDE_DIR(GTK2_GDK_PIXBUF_INCLUDE_DIR gdk-pixbuf/gdk-pixbuf.h)
-        _GTK2_FIND_LIBRARY    (GTK2_GDK_PIXBUF_LIBRARY gdk_pixbuf false true)
-
-        _GTK2_FIND_INCLUDE_DIR(GTK2_GDK_INCLUDE_DIR gdk/gdk.h)
-        _GTK2_FIND_INCLUDE_DIR(GTK2_GDKCONFIG_INCLUDE_DIR gdkconfig.h)
         _GTK2_FIND_INCLUDE_DIR(GTK2_GTK_INCLUDE_DIR gtk/gtk.h)
 
         if(UNIX)
-            _GTK2_FIND_LIBRARY    (GTK2_GDK_LIBRARY gdk-x11 false true)
             _GTK2_FIND_LIBRARY    (GTK2_GTK_LIBRARY gtk-x11 false true)
+            _GTK2_FIND_LIBRARY    (GTK2_GDK_LIBRARY gdk-x11 false true)
         else()
-            _GTK2_FIND_LIBRARY    (GTK2_GDK_LIBRARY gdk-win32 false true)
             _GTK2_FIND_LIBRARY    (GTK2_GTK_LIBRARY gtk-win32 false true)
+            _GTK2_FIND_LIBRARY    (GTK2_GDK_LIBRARY gdk-win32 false true)
         endif()
 
+        _GTK2_FIND_INCLUDE_DIR(GTK2_GDK_INCLUDE_DIR gdk/gdk.h)
+        _GTK2_FIND_INCLUDE_DIR(GTK2_GDKCONFIG_INCLUDE_DIR gdkconfig.h)
+
         _GTK2_FIND_INCLUDE_DIR(GTK2_CAIRO_INCLUDE_DIR cairo.h)
         _GTK2_FIND_LIBRARY    (GTK2_CAIRO_LIBRARY cairo false false)
 
@@ -469,35 +460,40 @@ foreach(_GTK2_component ${GTK2_FIND_COMPONENTS})
         _GTK2_FIND_INCLUDE_DIR(GTK2_PANGO_INCLUDE_DIR pango/pango.h)
         _GTK2_FIND_LIBRARY    (GTK2_PANGO_LIBRARY pango false true)
 
+        _GTK2_FIND_INCLUDE_DIR(GTK2_GDK_PIXBUF_INCLUDE_DIR gdk-pixbuf/gdk-pixbuf.h)
+        _GTK2_FIND_LIBRARY    (GTK2_GDK_PIXBUF_LIBRARY gdk_pixbuf false true)
+
+        _GTK2_FIND_LIBRARY    (GTK2_GIO_LIBRARY gio false true)
+
         _GTK2_FIND_INCLUDE_DIR(GTK2_ATK_INCLUDE_DIR atk/atk.h)
         _GTK2_FIND_LIBRARY    (GTK2_ATK_LIBRARY atk false true)
 
+        _GTK2_FIND_INCLUDE_DIR(GTK2_GOBJECT_INCLUDE_DIR gobject/gobject.h)
+        _GTK2_FIND_LIBRARY    (GTK2_GOBJECT_LIBRARY gobject false true)
 
-    elseif(_GTK2_component STREQUAL "gtkmm")
-
-        _GTK2_FIND_INCLUDE_DIR(GTK2_GLIBMM_INCLUDE_DIR glibmm.h)
-        _GTK2_FIND_INCLUDE_DIR(GTK2_GLIBMMCONFIG_INCLUDE_DIR glibmmconfig.h)
-        _GTK2_FIND_LIBRARY    (GTK2_GLIBMM_LIBRARY glibmm true true)
+        _GTK2_FIND_INCLUDE_DIR(GTK2_GLIB_INCLUDE_DIR glib.h)
+        _GTK2_FIND_INCLUDE_DIR(GTK2_GLIBCONFIG_INCLUDE_DIR glibconfig.h)
+        _GTK2_FIND_LIBRARY    (GTK2_GLIB_LIBRARY glib false true)
 
-        _GTK2_FIND_INCLUDE_DIR(GTK2_GDKMM_INCLUDE_DIR gdkmm.h)
-        _GTK2_FIND_INCLUDE_DIR(GTK2_GDKMMCONFIG_INCLUDE_DIR gdkmmconfig.h)
-        _GTK2_FIND_LIBRARY    (GTK2_GDKMM_LIBRARY gdkmm true true)
+    elseif(_GTK2_component STREQUAL "gtkmm")
 
         _GTK2_FIND_INCLUDE_DIR(GTK2_GTKMM_INCLUDE_DIR gtkmm.h)
         _GTK2_FIND_INCLUDE_DIR(GTK2_GTKMMCONFIG_INCLUDE_DIR gtkmmconfig.h)
         _GTK2_FIND_LIBRARY    (GTK2_GTKMM_LIBRARY gtkmm true true)
 
-        _GTK2_FIND_INCLUDE_DIR(GTK2_CAIROMM_INCLUDE_DIR cairomm/cairomm.h)
-        _GTK2_FIND_INCLUDE_DIR(GTK2_CAIROMMCONFIG_INCLUDE_DIR cairommconfig.h)
-        _GTK2_FIND_LIBRARY    (GTK2_CAIROMM_LIBRARY cairomm true true)
+        _GTK2_FIND_INCLUDE_DIR(GTK2_GDKMM_INCLUDE_DIR gdkmm.h)
+        _GTK2_FIND_INCLUDE_DIR(GTK2_GDKMMCONFIG_INCLUDE_DIR gdkmmconfig.h)
+        _GTK2_FIND_LIBRARY    (GTK2_GDKMM_LIBRARY gdkmm true true)
 
         _GTK2_FIND_INCLUDE_DIR(GTK2_PANGOMM_INCLUDE_DIR pangomm.h)
         _GTK2_FIND_INCLUDE_DIR(GTK2_PANGOMMCONFIG_INCLUDE_DIR pangommconfig.h)
         _GTK2_FIND_LIBRARY    (GTK2_PANGOMM_LIBRARY pangomm true true)
 
-        _GTK2_FIND_INCLUDE_DIR(GTK2_SIGC++_INCLUDE_DIR sigc++/sigc++.h)
-        _GTK2_FIND_INCLUDE_DIR(GTK2_SIGC++CONFIG_INCLUDE_DIR sigc++config.h)
-        _GTK2_FIND_LIBRARY    (GTK2_SIGC++_LIBRARY sigc true true)
+        _GTK2_FIND_LIBRARY    (GTK2_PANGOCAIRO_LIBRARY pangocairo true true)
+
+        _GTK2_FIND_INCLUDE_DIR(GTK2_CAIROMM_INCLUDE_DIR cairomm/cairomm.h)
+        _GTK2_FIND_INCLUDE_DIR(GTK2_CAIROMMCONFIG_INCLUDE_DIR cairommconfig.h)
+        _GTK2_FIND_LIBRARY    (GTK2_CAIROMM_LIBRARY cairomm true true)
 
         _GTK2_FIND_INCLUDE_DIR(GTK2_GIOMM_INCLUDE_DIR giomm.h)
         _GTK2_FIND_INCLUDE_DIR(GTK2_GIOMMCONFIG_INCLUDE_DIR giommconfig.h)
@@ -506,6 +502,15 @@ foreach(_GTK2_component ${GTK2_FIND_COMPONENTS})
         _GTK2_FIND_INCLUDE_DIR(GTK2_ATKMM_INCLUDE_DIR atkmm.h)
         _GTK2_FIND_LIBRARY    (GTK2_ATKMM_LIBRARY atkmm true true)
 
+        _GTK2_FIND_INCLUDE_DIR(GTK2_GLIBMM_INCLUDE_DIR glibmm.h)
+        _GTK2_FIND_INCLUDE_DIR(GTK2_GLIBMMCONFIG_INCLUDE_DIR glibmmconfig.h)
+        _GTK2_FIND_LIBRARY    (GTK2_GLIBMM_LIBRARY glibmm true true)
+
+        _GTK2_FIND_INCLUDE_DIR(GTK2_SIGC++_INCLUDE_DIR sigc++/sigc++.h)
+        _GTK2_FIND_INCLUDE_DIR(GTK2_SIGC++CONFIG_INCLUDE_DIR sigc++config.h)
+        _GTK2_FIND_LIBRARY    (GTK2_SIGC++_LIBRARY sigc true true)
+
+
     elseif(_GTK2_component STREQUAL "glade")
 
         _GTK2_FIND_INCLUDE_DIR(GTK2_GLADE_INCLUDE_DIR glade/glade.h)
@@ -549,13 +554,13 @@ foreach(_GTK2_component ${GTK2_FIND_COMPONENTS})
             GTK2_GTK_LIBRARY
             GTK2_GTK_INCLUDE_DIR
 
-            GTK2_GLIB_INCLUDE_DIR
-            GTK2_GLIBCONFIG_INCLUDE_DIR
-            GTK2_GLIB_LIBRARY
-
             GTK2_GDK_INCLUDE_DIR
             GTK2_GDKCONFIG_INCLUDE_DIR
             GTK2_GDK_LIBRARY
+
+            GTK2_GLIB_INCLUDE_DIR
+            GTK2_GLIBCONFIG_INCLUDE_DIR
+            GTK2_GLIB_LIBRARY
         )
     elseif(_GTK2_component STREQUAL "gtkmm")
         FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTK2_${_COMPONENT_UPPER} "Some or all of the gtkmm libraries were not found."
@@ -563,13 +568,14 @@ foreach(_GTK2_component ${GTK2_FIND_COMPONENTS})
             GTK2_GTKMM_INCLUDE_DIR
             GTK2_GTKMMCONFIG_INCLUDE_DIR
 
+            GTK2_GDKMM_INCLUDE_DIR
+            GTK2_GDKMMCONFIG_INCLUDE_DIR
+            GTK2_GDKMM_LIBRARY
+
             GTK2_GLIBMM_INCLUDE_DIR
             GTK2_GLIBMMCONFIG_INCLUDE_DIR
             GTK2_GLIBMM_LIBRARY
 
-            GTK2_GDKMM_INCLUDE_DIR
-            GTK2_GDKMMCONFIG_INCLUDE_DIR
-            GTK2_GDKMM_LIBRARY
         )
     elseif(_GTK2_component STREQUAL "glade")
         FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTK2_${_COMPONENT_UPPER} "The glade library was not found."

+ 28 - 0
Modules/FindQt4.cmake

@@ -65,6 +65,12 @@
 #       is much more flexible, but requires that FindQt4.cmake is executed before
 #       such an exported dependency file is processed.
 #
+#       Note that if using IMPORTED targets, the qtmain.lib static library is
+#       automatically linked on Windows. To disable that globally, set the
+#       QT4_NO_LINK_QTMAIN variable before finding Qt4. To disable that for a
+#       particular executable, set the QT4_NO_LINK_QTMAIN target property to
+#       True on the executable.
+#
 #  QT_INCLUDE_DIRS_NO_SYSTEM
 #        If this variable is set to TRUE, the Qt include directories
 #        in the QT_USE_FILE will NOT have the SYSTEM keyword set.
@@ -1009,7 +1015,14 @@ if (QT_QMAKE_EXECUTABLE AND QTVERSION)
   # platform dependent libraries
   if(Q_WS_WIN)
     _QT4_ADJUST_LIB_VARS(qtmain)
+
     _QT4_ADJUST_LIB_VARS(QAxServer)
+    set_property(TARGET Qt4::QAxServer PROPERTY
+      INTERFACE_QT4_NO_LINK_QTMAIN ON
+    )
+    set_property(TARGET Qt4::QAxServer APPEND PROPERTY
+      COMPATIBLE_INTERFACE_BOOL QT4_NO_LINK_QTMAIN)
+
     _QT4_ADJUST_LIB_VARS(QAxContainer)
   endif()
 
@@ -1049,6 +1062,21 @@ if (QT_QMAKE_EXECUTABLE AND QTVERSION)
     _qt4_add_target_private_depends(phonon DBus)
   endif()
 
+  if (WIN32 AND NOT QT4_NO_LINK_QTMAIN)
+    set(_isExe $<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>)
+    set(_isWin32 $<BOOL:$<TARGET_PROPERTY:WIN32_EXECUTABLE>>)
+    set(_isNotExcluded $<NOT:$<BOOL:$<TARGET_PROPERTY:QT4_NO_LINK_QTMAIN>>>)
+    set(_isPolicyNEW $<TARGET_POLICY:CMP0020>)
+    set_property(TARGET Qt4::QtCore APPEND PROPERTY
+      IMPORTED_LINK_INTERFACE_LIBRARIES
+        $<$<AND:${_isExe},${_isWin32},${_isNotExcluded},${_isPolicyNEW}>:Qt4::qtmain>
+    )
+    unset(_isExe)
+    unset(_isWin32)
+    unset(_isNotExcluded)
+    unset(_isPolicyNEW)
+  endif()
+
   #######################################
   #
   #       Check the executables of Qt

+ 3 - 2
Modules/Platform/Windows-MSVC.cmake

@@ -41,6 +41,7 @@ set(WIN32 1)
 if(CMAKE_SYSTEM_NAME MATCHES "WindowsCE")
   set(CMAKE_CREATE_WIN32_EXE "/subsystem:windowsce /entry:WinMainCRTStartup")
   set(CMAKE_CREATE_CONSOLE_EXE "/subsystem:windowsce /entry:mainACRTStartup")
+  set(WINCE 1)
 else()
   set(CMAKE_CREATE_WIN32_EXE "/subsystem:windows")
   set(CMAKE_CREATE_CONSOLE_EXE "/subsystem:console")
@@ -122,7 +123,7 @@ endif()
 # default to Debug builds
 set(CMAKE_BUILD_TYPE_INIT Debug)
 
-if(CMAKE_SYSTEM_NAME MATCHES "WindowsCE")
+if(WINCE)
   string(TOUPPER "${MSVC_C_ARCHITECTURE_ID}" _MSVC_C_ARCHITECTURE_ID_UPPER)
   string(TOUPPER "${MSVC_CXX_ARCHITECTURE_ID}" _MSVC_CXX_ARCHITECTURE_ID_UPPER)
 
@@ -170,7 +171,7 @@ set(_MACHINE_ARCH_FLAG ${MSVC_C_ARCHITECTURE_ID})
 if(NOT _MACHINE_ARCH_FLAG)
   set(_MACHINE_ARCH_FLAG ${MSVC_CXX_ARCHITECTURE_ID})
 endif()
-if(CMAKE_SYSTEM_NAME MATCHES "WindowsCE")
+if(WINCE)
   if(_MACHINE_ARCH_FLAG MATCHES "ARM")
     set(_MACHINE_ARCH_FLAG "THUMB")
   elseif(_MACHINE_ARCH_FLAG MATCHES "SH")

+ 1 - 1
Source/CMakeVersion.cmake

@@ -2,5 +2,5 @@
 set(CMake_VERSION_MAJOR 2)
 set(CMake_VERSION_MINOR 8)
 set(CMake_VERSION_PATCH 10)
-set(CMake_VERSION_TWEAK 20130118)
+set(CMake_VERSION_TWEAK 20130205)
 #set(CMake_VERSION_RC 1)

+ 19 - 4
Source/cmDocumentGeneratorExpressions.h

@@ -47,9 +47,24 @@
   "  $<TARGET_LINKER_FILE_DIR:tgt>/$<TARGET_LINKER_FILE_NAME:tgt>\n"    \
   "  $<TARGET_SONAME_FILE_DIR:tgt>/$<TARGET_SONAME_FILE_NAME:tgt>\n"    \
   "\n"                                                                  \
-  "  $<TARGET_PROPERTY:tgt,prop>   = The value of the property prop\n"  \
-  "on the target tgt. Note that tgt is not added as a dependency of\n"  \
-  "the target this expression is evaluated on.\n"                       \
+  "  $<TARGET_PROPERTY:tgt,prop>   = The value of the property prop "   \
+  "on the target tgt.\n"                                                \
+  "Note that tgt is not added as a dependency of the target this "      \
+  "expression is evaluated on.\n"                                       \
+  "  $<LINKED:item>            = An empty string if item is not a "     \
+  "target.  If item is a target then the "                              \
+  "INTERFACE_INCLUDE_DIRECTORIES or INTERFACE_COMPILE_DEFINITIONS "     \
+  "content is read from the target.  "                                  \
+  "This generator expression can only be used in evaluation of the "    \
+  "INCLUDE_DIRECTORIES or COMPILE_DEFINITIONS property.  Note that "    \
+  "this expression is for internal use and may be changed or removed "  \
+  "in the future.\n"                                                    \
+  "  $<TARGET_POLICY:pol>          = '1' if the policy was NEW when "   \
+  "the 'head' target was created, else '0'.  If the policy was not "    \
+  "set, the warning message for the policy will be emitted.  This "     \
+  "generator expression only works for a subset of policies.\n"         \
+  "  $<INSTALL_PREFIX>         = Content of the install prefix when "   \
+  "the target is exported via INSTALL(EXPORT) and empty otherwise.\n"   \
   "Boolean expressions:\n"                                              \
   "  $<AND:?[,?]...>           = '1' if all '?' are '1', else '0'\n"    \
   "  $<OR:?[,?]...>            = '0' if all '?' are '0', else '1'\n"    \
@@ -60,7 +75,7 @@
 #define CM_DOCUMENT_COMMAND_GENERATOR_EXPRESSIONS                       \
   CM_DOCUMENT_ADD_TEST_GENERATOR_EXPRESSIONS \
   "Expressions with an implicit 'this' target:\n"                       \
-  "  $<TARGET_PROPERTY:prop>   = The value of the property prop on\n"   \
+  "  $<TARGET_PROPERTY:prop>   = The value of the property prop on "    \
   "the target on which the generator expression is evaluated.\n"        \
   ""
 

+ 1 - 0
Source/cmExportBuildFileGenerator.cxx

@@ -74,6 +74,7 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
                                     properties, missingTargets);
     this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE",
                                   te, properties);
+    this->PopulateCompatibleInterfaceProperties(te, properties);
 
     this->GenerateInterfaceProperties(te, os, properties);
     }

+ 212 - 75
Source/cmExportFileGenerator.cxx

@@ -21,9 +21,12 @@
 #include "cmTarget.h"
 #include "cmTargetExport.h"
 #include "cmVersion.h"
+#include "cmComputeLinkInformation.h"
 
 #include <cmsys/auto_ptr.hxx>
 
+#include "assert.h"
+
 //----------------------------------------------------------------------------
 cmExportFileGenerator::cmExportFileGenerator()
 {
@@ -81,16 +84,16 @@ bool cmExportFileGenerator::GenerateImportFile()
 
   // Protect that file against use with older CMake versions.
   os << "# Generated by CMake " << cmVersion::GetCMakeVersion() << "\n\n";
-  os << "IF(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.5)\n"
-     << "   MESSAGE(FATAL_ERROR \"CMake >= 2.6.0 required\")\n"
-     << "ENDIF(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.5)\n";
+  os << "if(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.5)\n"
+     << "   message(FATAL_ERROR \"CMake >= 2.6.0 required\")\n"
+     << "endif()\n";
 
   // Isolate the file policy level.
   // We use 2.6 here instead of the current version because newer
   // versions of CMake should be able to export files imported by 2.6
   // until the import format changes.
-  os << "CMAKE_POLICY(PUSH)\n"
-     << "CMAKE_POLICY(VERSION 2.6)\n";
+  os << "cmake_policy(PUSH)\n"
+     << "cmake_policy(VERSION 2.6)\n";
 
   // Start with the import file header.
   this->GenerateImportHeaderCode(os);
@@ -100,7 +103,7 @@ bool cmExportFileGenerator::GenerateImportFile()
 
   // End with the import file footer.
   this->GenerateImportFooterCode(os);
-  os << "CMAKE_POLICY(POP)\n";
+  os << "cmake_policy(POP)\n";
 
   return result;
 }
@@ -159,7 +162,7 @@ void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName,
                                                            preprocessRule);
     if (!prepro.empty())
       {
-      this->ResolveTargetsInGeneratorExpressions(prepro, target,
+      this->ResolveTargetsInGeneratorExpressions(prepro, target, propName,
                                                  missingTargets);
       properties[outputName] = prepro;
       }
@@ -177,6 +180,85 @@ void cmExportFileGenerator::PopulateInterfaceProperty(const char *propName,
                             properties, missingTargets);
 }
 
+
+//----------------------------------------------------------------------------
+void getPropertyContents(cmTarget *tgt, const char *prop,
+         std::set<std::string> &ifaceProperties)
+{
+  const char *p = tgt->GetProperty(prop);
+  if (!p)
+    {
+    return;
+    }
+  std::vector<std::string> content;
+  cmSystemTools::ExpandListArgument(p, content);
+  for (std::vector<std::string>::const_iterator ci = content.begin();
+    ci != content.end(); ++ci)
+    {
+    ifaceProperties.insert(*ci);
+    }
+}
+
+//----------------------------------------------------------------------------
+void getCompatibleInterfaceProperties(cmTarget *target,
+                                      std::set<std::string> &ifaceProperties,
+                                      const char *config)
+{
+  cmComputeLinkInformation *info = target->GetLinkInformation(config);
+
+  const cmComputeLinkInformation::ItemVector &deps = info->GetItems();
+
+  for(cmComputeLinkInformation::ItemVector::const_iterator li =
+      deps.begin();
+      li != deps.end(); ++li)
+    {
+    if (!li->Target)
+      {
+      continue;
+      }
+    getPropertyContents(li->Target,
+                        "COMPATIBLE_INTERFACE_BOOL",
+                        ifaceProperties);
+    getPropertyContents(li->Target,
+                        "COMPATIBLE_INTERFACE_STRING",
+                        ifaceProperties);
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmExportFileGenerator::PopulateCompatibleInterfaceProperties(
+                                cmTarget *target,
+                                ImportPropertyMap &properties)
+{
+  this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_BOOL",
+                                target, properties);
+  this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_STRING",
+                                target, properties);
+
+  std::set<std::string> ifaceProperties;
+
+  getPropertyContents(target, "COMPATIBLE_INTERFACE_BOOL", ifaceProperties);
+  getPropertyContents(target, "COMPATIBLE_INTERFACE_STRING", ifaceProperties);
+
+  getCompatibleInterfaceProperties(target, ifaceProperties, 0);
+
+  std::vector<std::string> configNames;
+  target->GetMakefile()->GetConfigurations(configNames);
+
+  for (std::vector<std::string>::const_iterator ci = configNames.begin();
+    ci != configNames.end(); ++ci)
+    {
+    getCompatibleInterfaceProperties(target, ifaceProperties, ci->c_str());
+    }
+
+  for (std::set<std::string>::const_iterator it = ifaceProperties.begin();
+    it != ifaceProperties.end(); ++it)
+    {
+    this->PopulateInterfaceProperty(("INTERFACE_" + *it).c_str(),
+                                    target, properties);
+    }
+}
+
 //----------------------------------------------------------------------------
 void cmExportFileGenerator::GenerateInterfaceProperties(cmTarget *target,
                                         std::ostream& os,
@@ -184,15 +266,16 @@ void cmExportFileGenerator::GenerateInterfaceProperties(cmTarget *target,
 {
   if (!properties.empty())
     {
+    os << "if(NOT ${CMAKE_FIND_PACKAGE_NAME}_NO_INTERFACES)\n";
     std::string targetName = this->Namespace;
     targetName += target->GetName();
-    os << "SET_TARGET_PROPERTIES(" << targetName << " PROPERTIES\n";
+    os << "  set_target_properties(" << targetName << " PROPERTIES\n";
     for(ImportPropertyMap::const_iterator pi = properties.begin();
         pi != properties.end(); ++pi)
       {
-      os << "  " << pi->first << " \"" << pi->second << "\"\n";
+      os << "    " << pi->first << " \"" << pi->second << "\"\n";
       }
-    os << ")\n\n";
+    os << "  )\nendif()\n\n";
     }
 }
 
@@ -243,13 +326,14 @@ static bool isGeneratorExpression(const std::string &lib)
 void
 cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
                                     std::string &input,
-                                    cmTarget* target,
+                                    cmTarget* target, const char *propName,
                                     std::vector<std::string> &missingTargets,
                                     FreeTargetsReplace replace)
 {
   if (replace == NoReplaceFreeTargets)
     {
-    this->ResolveTargetsInGeneratorExpression(input, target, missingTargets);
+    this->ResolveTargetsInGeneratorExpression(input, target, propName,
+                                              missingTargets);
     return;
     }
   std::vector<std::string> parts;
@@ -268,7 +352,7 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
       {
       this->ResolveTargetsInGeneratorExpression(
                                     *li,
-                                    target,
+                                    target, propName,
                                     missingTargets);
       }
     input += sep + *li;
@@ -280,14 +364,13 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpressions(
 void
 cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
                                     std::string &input,
-                                    cmTarget* target,
+                                    cmTarget* target, const char *propName,
                                     std::vector<std::string> &missingTargets)
 {
   std::string::size_type pos = 0;
   std::string::size_type lastPos = pos;
 
   cmMakefile *mf = target->GetMakefile();
-  std::string errorString;
 
   while((pos = input.find("$<TARGET_PROPERTY:", lastPos)) != input.npos)
     {
@@ -308,14 +391,58 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
     std::string targetName = input.substr(nameStartPos,
                                                 commaPos - nameStartPos);
 
-    if (!this->AddTargetNamespace(targetName, target, missingTargets))
+    if (this->AddTargetNamespace(targetName, target, missingTargets))
+      {
+      input.replace(nameStartPos, commaPos - nameStartPos, targetName);
+      }
+    lastPos = nameStartPos + targetName.size() + 1;
+    }
+
+  std::string errorString;
+  pos = 0;
+  lastPos = pos;
+  while((pos = input.find("$<LINKED:", lastPos)) != input.npos)
+    {
+    std::string::size_type nameStartPos = pos + sizeof("$<LINKED:") - 1;
+    std::string::size_type endPos = input.find(">", nameStartPos);
+    if (endPos == input.npos)
+      {
+      errorString = "$<LINKED:...> expression incomplete";
+      break;
+      }
+    std::string targetName = input.substr(nameStartPos,
+                                                endPos - nameStartPos);
+    if(targetName.find("$<") != input.npos)
       {
-      errorString = "$<TARGET_PROPERTY:" + targetName + ",prop> requires "
-                    "its first parameter to be a reachable target.";
+      errorString = "$<LINKED:...> requires its parameter to be a "
+                    "literal.";
       break;
       }
-    input.replace(nameStartPos, commaPos - nameStartPos, targetName);
-    lastPos = pos + targetName.size();
+    if (this->AddTargetNamespace(targetName, target, missingTargets))
+      {
+      assert(propName); // The link libraries strings will
+                        // never contain $<LINKED>
+      std::string replacement = "$<TARGET_PROPERTY:"
+                              + targetName + "," + propName;
+      input.replace(pos, endPos - pos, replacement);
+      lastPos = pos + replacement.size() + 1;
+      }
+    else
+      {
+      if (pos != 0)
+        {
+        if (input[pos - 1] == ';')
+          {
+          --pos;
+          }
+        }
+      else if (input[endPos + 1] == ';')
+        {
+        ++endPos;
+        }
+      input.replace(pos, endPos - pos + 1, "");
+      lastPos = pos;
+      }
     }
   if (!errorString.empty())
     {
@@ -351,12 +478,22 @@ cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
     input.replace(pos, endPos - pos + 1, targetName);
     lastPos = endPos;
     }
+
+  this->ReplaceInstallPrefix(input);
+
   if (!errorString.empty())
     {
     mf->IssueMessage(cmake::FATAL_ERROR, errorString);
     }
 }
 
+//----------------------------------------------------------------------------
+void
+cmExportFileGenerator::ReplaceInstallPrefix(std::string &)
+{
+  // Do nothing
+}
+
 //----------------------------------------------------------------------------
 void
 cmExportFileGenerator
@@ -408,7 +545,7 @@ cmExportFileGenerator
                                                          preprocessRule);
   if (!prepro.empty())
     {
-    this->ResolveTargetsInGeneratorExpressions(prepro, target,
+    this->ResolveTargetsInGeneratorExpressions(prepro, target, 0,
                                                missingTargets,
                                                ReplaceFreeTargets);
     properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix] = prepro;
@@ -536,7 +673,7 @@ void cmExportFileGenerator::GenerateImportHeaderCode(std::ostream& os,
 void cmExportFileGenerator::GenerateImportFooterCode(std::ostream& os)
 {
   os << "# Commands beyond this point should not need to know the version.\n"
-     << "SET(CMAKE_IMPORT_FILE_VERSION)\n";
+     << "set(CMAKE_IMPORT_FILE_VERSION)\n";
 }
 
 //----------------------------------------------------------------------------
@@ -545,7 +682,7 @@ void cmExportFileGenerator::GenerateImportVersionCode(std::ostream& os)
   // Store an import file format version.  This will let us change the
   // format later while still allowing old import files to work.
   os << "# Commands may need to know the format version.\n"
-     << "SET(CMAKE_IMPORT_FILE_VERSION 1)\n"
+     << "set(CMAKE_IMPORT_FILE_VERSION 1)\n"
      << "\n";
 }
 
@@ -553,31 +690,31 @@ void cmExportFileGenerator::GenerateImportVersionCode(std::ostream& os)
 void cmExportFileGenerator::GenerateExpectedTargetsCode(std::ostream& os,
                                             const std::string &expectedTargets)
 {
-  os << "SET(_targetsDefined)\n"
-        "SET(_targetsNotDefined)\n"
-        "SET(_expectedTargets)\n"
-        "FOREACH(_expectedTarget " << expectedTargets << ")\n"
-        "  LIST(APPEND _expectedTargets ${_expectedTarget})\n"
-        "  IF(NOT TARGET ${_expectedTarget})\n"
-        "    LIST(APPEND _targetsNotDefined ${_expectedTarget})\n"
-        "  ENDIF(NOT TARGET ${_expectedTarget})\n"
-        "  IF(TARGET ${_expectedTarget})\n"
-        "    LIST(APPEND _targetsDefined ${_expectedTarget})\n"
-        "  ENDIF(TARGET ${_expectedTarget})\n"
-        "ENDFOREACH(_expectedTarget)\n"
-        "IF(\"${_targetsDefined}\" STREQUAL \"${_expectedTargets}\")\n"
-        "  SET(CMAKE_IMPORT_FILE_VERSION)\n"
-        "  CMAKE_POLICY(POP)\n"
-        "  RETURN()\n"
-        "ENDIF(\"${_targetsDefined}\" STREQUAL \"${_expectedTargets}\")\n"
-        "IF(NOT \"${_targetsDefined}\" STREQUAL \"\")\n"
-        "  MESSAGE(FATAL_ERROR \"Some (but not all) targets in this export "
+  os << "set(_targetsDefined)\n"
+        "set(_targetsNotDefined)\n"
+        "set(_expectedTargets)\n"
+        "foreach(_expectedTarget " << expectedTargets << ")\n"
+        "  list(APPEND _expectedTargets ${_expectedTarget})\n"
+        "  if(NOT TARGET ${_expectedTarget})\n"
+        "    list(APPEND _targetsNotDefined ${_expectedTarget})\n"
+        "  endif()\n"
+        "  if(TARGET ${_expectedTarget})\n"
+        "    list(APPEND _targetsDefined ${_expectedTarget})\n"
+        "  endif()\n"
+        "endforeach()\n"
+        "if(\"${_targetsDefined}\" STREQUAL \"${_expectedTargets}\")\n"
+        "  set(CMAKE_IMPORT_FILE_VERSION)\n"
+        "  cmake_policy(POP)\n"
+        "  return()\n"
+        "endif()\n"
+        "if(NOT \"${_targetsDefined}\" STREQUAL \"\")\n"
+        "  message(FATAL_ERROR \"Some (but not all) targets in this export "
         "set were already defined.\\nTargets Defined: ${_targetsDefined}\\n"
         "Targets not yet defined: ${_targetsNotDefined}\\n\")\n"
-        "ENDIF(NOT \"${_targetsDefined}\" STREQUAL \"\")\n"
-        "UNSET(_targetsDefined)\n"
-        "UNSET(_targetsNotDefined)\n"
-        "UNSET(_expectedTargets)\n"
+        "endif()\n"
+        "unset(_targetsDefined)\n"
+        "unset(_targetsNotDefined)\n"
+        "unset(_expectedTargets)\n"
         "\n\n";
 }
 //----------------------------------------------------------------------------
@@ -594,16 +731,16 @@ cmExportFileGenerator
   switch(target->GetType())
     {
     case cmTarget::EXECUTABLE:
-      os << "ADD_EXECUTABLE(" << targetName << " IMPORTED)\n";
+      os << "add_executable(" << targetName << " IMPORTED)\n";
       break;
     case cmTarget::STATIC_LIBRARY:
-      os << "ADD_LIBRARY(" << targetName << " STATIC IMPORTED)\n";
+      os << "add_library(" << targetName << " STATIC IMPORTED)\n";
       break;
     case cmTarget::SHARED_LIBRARY:
-      os << "ADD_LIBRARY(" << targetName << " SHARED IMPORTED)\n";
+      os << "add_library(" << targetName << " SHARED IMPORTED)\n";
       break;
     case cmTarget::MODULE_LIBRARY:
-      os << "ADD_LIBRARY(" << targetName << " MODULE IMPORTED)\n";
+      os << "add_library(" << targetName << " MODULE IMPORTED)\n";
       break;
     default:  // should never happen
       break;
@@ -612,27 +749,27 @@ cmExportFileGenerator
   // Mark the imported executable if it has exports.
   if(target->IsExecutableWithExports())
     {
-    os << "SET_PROPERTY(TARGET " << targetName
+    os << "set_property(TARGET " << targetName
        << " PROPERTY ENABLE_EXPORTS 1)\n";
     }
 
   // Mark the imported library if it is a framework.
   if(target->IsFrameworkOnApple())
     {
-    os << "SET_PROPERTY(TARGET " << targetName
+    os << "set_property(TARGET " << targetName
        << " PROPERTY FRAMEWORK 1)\n";
     }
 
   // Mark the imported executable if it is an application bundle.
   if(target->IsAppBundleOnApple())
     {
-    os << "SET_PROPERTY(TARGET " << targetName
+    os << "set_property(TARGET " << targetName
        << " PROPERTY MACOSX_BUNDLE 1)\n";
     }
 
   if (target->IsCFBundleOnApple())
     {
-    os << "SET_PROPERTY(TARGET " << targetName
+    os << "set_property(TARGET " << targetName
        << " PROPERTY BUNDLE 1)\n";
     }
   os << "\n";
@@ -652,7 +789,7 @@ cmExportFileGenerator
   // Set the import properties.
   os << "# Import target \"" << targetName << "\" for configuration \""
      << config << "\"\n";
-  os << "SET_PROPERTY(TARGET " << targetName
+  os << "set_property(TARGET " << targetName
      << " APPEND PROPERTY IMPORTED_CONFIGURATIONS ";
   if(config && *config)
     {
@@ -663,7 +800,7 @@ cmExportFileGenerator
     os << "NOCONFIG";
     }
   os << ")\n";
-  os << "SET_TARGET_PROPERTIES(" << targetName << " PROPERTIES\n";
+  os << "set_target_properties(" << targetName << " PROPERTIES\n";
   for(ImportPropertyMap::const_iterator pi = properties.begin();
       pi != properties.end(); ++pi)
     {
@@ -689,17 +826,17 @@ void cmExportFileGenerator::GenerateMissingTargetsCheckCode(std::ostream& os,
     {
     if (emitted.insert(missingTargets[i]).second)
       {
-      os << "IF(NOT TARGET \"" << missingTargets[i] << "\" )\n"
-        << "  IF(CMAKE_FIND_PACKAGE_NAME)\n"
-        << "    SET( ${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE)\n"
-        << "    SET( ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "
+      os << "if(NOT TARGET \"" << missingTargets[i] << "\" )\n"
+        << "  if(CMAKE_FIND_PACKAGE_NAME)\n"
+        << "    set( ${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE)\n"
+        << "    set( ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "
         << "\"Required imported target \\\"" << missingTargets[i]
         << "\\\" not found ! \")\n"
-        << "  ELSE()\n"
-        << "    MESSAGE(FATAL_ERROR \"Required imported target \\\""
+        << "  else()\n"
+        << "    message(FATAL_ERROR \"Required imported target \\\""
         << missingTargets[i] << "\\\" not found ! \")\n"
-        << "  ENDIF()\n"
-        << "ENDIF()\n";
+        << "  endif()\n"
+        << "endif()\n";
       }
     }
   os << "\n";
@@ -718,10 +855,10 @@ cmExportFileGenerator::GenerateImportedFileCheckLoop(std::ostream& os)
   // on SUSE with a mysql pkg-config file, which claimed everything is fine,
   // but the development package was not installed.).
   os << "# Loop over all imported files and verify that they actually exist\n"
-        "FOREACH(target ${_IMPORT_CHECK_TARGETS} )\n"
-        "  FOREACH(file ${_IMPORT_CHECK_FILES_FOR_${target}} )\n"
-        "    IF(NOT EXISTS \"${file}\" )\n"
-        "      MESSAGE(FATAL_ERROR \"The imported target \\\"${target}\\\""
+        "foreach(target ${_IMPORT_CHECK_TARGETS} )\n"
+        "  foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )\n"
+        "    if(NOT EXISTS \"${file}\" )\n"
+        "      message(FATAL_ERROR \"The imported target \\\"${target}\\\""
         " references the file\n"
         "   \\\"${file}\\\"\n"
         "but this file does not exist.  Possible reasons include:\n"
@@ -731,11 +868,11 @@ cmExportFileGenerator::GenerateImportedFileCheckLoop(std::ostream& os)
         "   \\\"${CMAKE_CURRENT_LIST_FILE}\\\"\n"
         "but not all the files it references.\n"
         "\")\n"
-        "    ENDIF()\n"
-        "  ENDFOREACH()\n"
-        "  UNSET(_IMPORT_CHECK_FILES_FOR_${target})\n"
-        "ENDFOREACH()\n"
-        "UNSET(_IMPORT_CHECK_TARGETS)\n"
+        "    endif()\n"
+        "  endforeach()\n"
+        "  unset(_IMPORT_CHECK_FILES_FOR_${target})\n"
+        "endforeach()\n"
+        "unset(_IMPORT_CHECK_TARGETS)\n"
         "\n";
 }
 
@@ -751,8 +888,8 @@ cmExportFileGenerator
   std::string targetName = this->Namespace;
   targetName += target->GetName();
 
-  os << "LIST(APPEND _IMPORT_CHECK_TARGETS " << targetName << " )\n"
-        "LIST(APPEND _IMPORT_CHECK_FILES_FOR_" << targetName << " ";
+  os << "list(APPEND _IMPORT_CHECK_TARGETS " << targetName << " )\n"
+        "list(APPEND _IMPORT_CHECK_FILES_FOR_" << targetName << " ";
 
   for(std::set<std::string>::const_iterator li = importedLocations.begin();
       li != importedLocations.end();

+ 6 - 2
Source/cmExportFileGenerator.h

@@ -103,6 +103,8 @@ protected:
                                  std::vector<std::string> &missingTargets);
   void PopulateInterfaceProperty(const char *propName, cmTarget *target,
                                  ImportPropertyMap &properties);
+  void PopulateCompatibleInterfaceProperties(cmTarget *target,
+                                 ImportPropertyMap &properties);
   void GenerateInterfaceProperties(cmTarget *target, std::ostream& os,
                                    const ImportPropertyMap &properties);
 
@@ -117,7 +119,7 @@ protected:
   };
 
   void ResolveTargetsInGeneratorExpressions(std::string &input,
-                          cmTarget* target,
+                          cmTarget* target, const char *propName,
                           std::vector<std::string> &missingTargets,
                           FreeTargetsReplace replace = NoReplaceFreeTargets);
 
@@ -148,8 +150,10 @@ private:
                           std::vector<std::string> &missingTargets);
 
   void ResolveTargetsInGeneratorExpression(std::string &input,
-                                    cmTarget* target,
+                                    cmTarget* target, const char *propName,
                                     std::vector<std::string> &missingTargets);
+
+  virtual void ReplaceInstallPrefix(std::string &input);
 };
 
 #endif

+ 52 - 37
Source/cmExportInstallFileGenerator.cxx

@@ -57,7 +57,7 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
     else
       {
       cmOStringStream e;
-      e << "INSTALL(EXPORT \""
+      e << "install(EXPORT \""
         << this->IEGen->GetExportSet()->GetName()
         << "\" ...) " << "includes target \"" << te->Target->GetName()
         << "\" more than once in the export set.";
@@ -69,6 +69,27 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
   this->GenerateExpectedTargetsCode(os, expectedTargets);
   }
 
+  // Add code to compute the installation prefix relative to the
+  // import file location.
+  const char* installDest = this->IEGen->GetDestination();
+  if(!cmSystemTools::FileIsFullPath(installDest))
+    {
+    std::string dest = installDest;
+    os << "# Compute the installation prefix relative to this file.\n"
+       << "get_filename_component(_IMPORT_PREFIX "
+       << "\"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n";
+    while(!dest.empty())
+      {
+      os <<
+        "get_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\n";
+      dest = cmSystemTools::GetFilenamePath(dest);
+      }
+    os << "\n";
+
+    // Import location properties may reference this variable.
+    this->ImportPrefix = "${_IMPORT_PREFIX}/";
+    }
+
   std::vector<std::string> missingTargets;
 
   // Create all the imported targets.
@@ -91,6 +112,7 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
                                   properties, missingTargets);
     this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE",
                                   te, properties);
+    this->PopulateCompatibleInterfaceProperties(te, properties);
 
     this->GenerateInterfaceProperties(te, os, properties);
     }
@@ -98,14 +120,21 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
 
   // Now load per-configuration properties for them.
   os << "# Load information for each installed configuration.\n"
-     << "GET_FILENAME_COMPONENT(_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"
-     << "FILE(GLOB CONFIG_FILES \"${_DIR}/"
+     << "get_filename_component(_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"
+     << "file(GLOB CONFIG_FILES \"${_DIR}/"
      << this->GetConfigImportFileGlob() << "\")\n"
-     << "FOREACH(f ${CONFIG_FILES})\n"
-     << "  INCLUDE(${f})\n"
-     << "ENDFOREACH(f)\n"
+     << "foreach(f ${CONFIG_FILES})\n"
+     << "  include(${f})\n"
+     << "endforeach()\n"
      << "\n";
 
+  // Cleanup the import prefix variable.
+  if(!this->ImportPrefix.empty())
+    {
+    os << "# Cleanup temporary variables.\n"
+       << "set(_IMPORT_PREFIX)\n"
+       << "\n";
+    }
   this->GenerateImportedFileCheckLoop(os);
 
   // Generate an import file for each configuration.
@@ -125,6 +154,21 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
   return result;
 }
 
+//----------------------------------------------------------------------------
+void
+cmExportInstallFileGenerator::ReplaceInstallPrefix(std::string &input)
+{
+  std::string::size_type pos = 0;
+  std::string::size_type lastPos = pos;
+
+  while((pos = input.find("$<INSTALL_PREFIX>", lastPos)) != input.npos)
+    {
+    std::string::size_type endPos = pos + sizeof("$<INSTALL_PREFIX>") - 1;
+    input.replace(pos, endPos - pos, "${_IMPORT_PREFIX}");
+    lastPos = endPos;
+    }
+}
+
 //----------------------------------------------------------------------------
 bool
 cmExportInstallFileGenerator::GenerateImportFileConfig(const char* config,
@@ -186,27 +230,6 @@ cmExportInstallFileGenerator
                               const char* config, std::string const& suffix,
                               std::vector<std::string> &missingTargets)
 {
-  // Add code to compute the installation prefix relative to the
-  // import file location.
-  const char* installDest = this->IEGen->GetDestination();
-  if(!cmSystemTools::FileIsFullPath(installDest))
-    {
-    std::string dest = installDest;
-    os << "# Compute the installation prefix relative to this file.\n"
-       << "GET_FILENAME_COMPONENT(_IMPORT_PREFIX "
-       << "\"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n";
-    while(!dest.empty())
-      {
-      os <<
-        "GET_FILENAME_COMPONENT(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" PATH)\n";
-      dest = cmSystemTools::GetFilenamePath(dest);
-      }
-    os << "\n";
-
-    // Import location properties may reference this variable.
-    this->ImportPrefix = "${_IMPORT_PREFIX}/";
-    }
-
   // Add each target in the set to the export.
   for(std::vector<cmTargetExport*>::const_iterator
         tei = this->IEGen->GetExportSet()->GetTargetExports()->begin();
@@ -252,14 +275,6 @@ cmExportInstallFileGenerator
                                            importedLocations);
       }
     }
-
-  // Cleanup the import prefix variable.
-  if(!this->ImportPrefix.empty())
-    {
-    os << "# Cleanup temporary variables.\n"
-       << "SET(_IMPORT_PREFIX)\n"
-       << "\n";
-    }
 }
 
 //----------------------------------------------------------------------------
@@ -427,7 +442,7 @@ cmExportInstallFileGenerator
 {
   const char* installDest = this->IEGen->GetDestination();
   cmOStringStream e;
-  e << "INSTALL(EXPORT \""
+  e << "install(EXPORT \""
     << this->IEGen->GetExportSet()->GetName()
     << "\") given absolute "
     << "DESTINATION \"" << installDest << "\" but the export "
@@ -445,7 +460,7 @@ cmExportInstallFileGenerator
                              int occurrences)
 {
   cmOStringStream e;
-  e << "INSTALL(EXPORT \""
+  e << "install(EXPORT \""
     << this->IEGen->GetExportSet()->GetName()
     << "\" ...) "
     << "includes target \"" << depender->GetName()

+ 2 - 0
Source/cmExportInstallFileGenerator.h

@@ -64,6 +64,8 @@ protected:
                                    cmTarget* depender,
                                    cmTarget* dependee);
 
+  virtual void ReplaceInstallPrefix(std::string &input);
+
   void ComplainAboutMissingTarget(cmTarget* depender,
                                   cmTarget* dependee,
                                   int occurrences);

+ 1 - 1
Source/cmExtraCodeBlocksGenerator.cxx

@@ -621,7 +621,7 @@ void cmExtraCodeBlocksGenerator::AppendTarget(cmGeneratedFileStream& fout,
                                   ->GetGeneratorTarget(target);
 
     // the compilerdefines for this target
-    std::string cdefs = gtgt->GetCompileDefinitions();
+    std::string cdefs = target->GetCompileDefinitions();
 
     if(!cdefs.empty())
       {

+ 5 - 1
Source/cmFLTKWrapUICommand.cxx

@@ -37,9 +37,13 @@ bool cmFLTKWrapUICommand
   // get the list of GUI files from which .cxx and .h will be generated
   std::string outputDirectory = this->Makefile->GetCurrentOutputDirectory();
 
+  {
   // Some of the generated files are *.h so the directory "GUI"
   // where they are created have to be added to the include path
-  this->Makefile->AddIncludeDirectory( outputDirectory.c_str() );
+  std::vector<std::string> outputDirectories;
+  outputDirectories.push_back(outputDirectory);
+  this->Makefile->AddIncludeDirectories( outputDirectories );
+  }
 
   for(std::vector<std::string>::iterator i = (newArgs.begin() + 1);
       i != newArgs.end(); i++)

+ 20 - 0
Source/cmFindPackageCommand.cxx

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

+ 7 - 1
Source/cmGeneratorExpression.cxx

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

+ 5 - 0
Source/cmGeneratorExpression.h

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

+ 61 - 0
Source/cmGeneratorExpressionDAGChecker.cxx

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

+ 8 - 1
Source/cmGeneratorExpressionDAGChecker.h

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

+ 267 - 1
Source/cmGeneratorExpressionEvaluator.cxx

@@ -238,6 +238,7 @@ static const struct ConfigurationNode : public cmGeneratorExpressionNode
                        const GeneratorExpressionContent *,
                        cmGeneratorExpressionDAGChecker *) const
   {
+    context->HadContextSensitiveCondition = true;
     return context->Config ? context->Config : "";
   }
 } configurationNode;
@@ -262,6 +263,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
                   "Expression syntax not recognized.");
       return std::string();
       }
+    context->HadContextSensitiveCondition = true;
     if (!context->Config)
       {
       return parameters.front().empty() ? "1" : "0";
@@ -435,6 +437,9 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
     case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
       // No error. We just skip cyclic references.
       return std::string();
+    case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
+      // No error. We're not going to find anything new here.
+      return std::string();
     case cmGeneratorExpressionDAGChecker::DAG:
       break;
       }
@@ -442,6 +447,39 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
     const char *prop = target->GetProperty(propertyName.c_str());
     if (!prop)
       {
+      if (target->IsImported())
+        {
+        return std::string();
+        }
+      if (dagCheckerParent && dagCheckerParent->EvaluatingLinkLibraries())
+        {
+        return std::string();
+        }
+      if (propertyName == "POSITION_INDEPENDENT_CODE")
+        {
+        context->HadContextSensitiveCondition = true;
+        return target->GetLinkInterfaceDependentBoolProperty(
+                    "POSITION_INDEPENDENT_CODE", context->Config) ? "1" : "0";
+        }
+      if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
+                                                       context->Config))
+        {
+        context->HadContextSensitiveCondition = true;
+        return target->GetLinkInterfaceDependentBoolProperty(
+                                                propertyName,
+                                                context->Config) ? "1" : "0";
+        }
+      if (target->IsLinkInterfaceDependentStringProperty(propertyName,
+                                                         context->Config))
+        {
+        context->HadContextSensitiveCondition = true;
+        const char *propContent =
+                              target->GetLinkInterfaceDependentStringProperty(
+                                                propertyName,
+                                                context->Config);
+        return propContent ? propContent : "";
+        }
+
       return std::string();
       }
 
@@ -453,12 +491,19 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
       if (targetPropertyTransitiveWhitelist[i] == propertyName)
         {
         cmGeneratorExpression ge(context->Backtrace);
-        return ge.Parse(prop)->Evaluate(context->Makefile,
+        cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
+        std::string result = cge->Evaluate(context->Makefile,
                             context->Config,
                             context->Quiet,
                             context->HeadTarget,
                             target,
                             &dagChecker);
+
+        if (cge->GetHadContextSensitiveCondition())
+          {
+          context->HadContextSensitiveCondition = true;
+          }
+        return result;
         }
       }
     return prop;
@@ -487,6 +532,221 @@ static const struct TargetNameNode : public cmGeneratorExpressionNode
 
 } targetNameNode;
 
+//----------------------------------------------------------------------------
+static const char* targetPolicyWhitelist[] = {
+    "CMP0003"
+  , "CMP0004"
+  , "CMP0008"
+  , "CMP0020"
+};
+
+cmPolicies::PolicyStatus statusForTarget(cmTarget *tgt, const char *policy)
+{
+#define RETURN_POLICY(POLICY) \
+  if (strcmp(policy, #POLICY) == 0) \
+  { \
+    return tgt->GetPolicyStatus ## POLICY (); \
+  } \
+
+  RETURN_POLICY(CMP0003)
+  RETURN_POLICY(CMP0004)
+  RETURN_POLICY(CMP0008)
+  RETURN_POLICY(CMP0020)
+
+#undef RETURN_POLICY
+
+  assert("!Unreachable code. Not a valid policy");
+  return cmPolicies::WARN;
+}
+
+cmPolicies::PolicyID policyForString(const char *policy_id)
+{
+#define RETURN_POLICY_ID(POLICY_ID) \
+  if (strcmp(policy_id, #POLICY_ID) == 0) \
+  { \
+    return cmPolicies:: POLICY_ID; \
+  } \
+
+  RETURN_POLICY_ID(CMP0003)
+  RETURN_POLICY_ID(CMP0004)
+  RETURN_POLICY_ID(CMP0008)
+  RETURN_POLICY_ID(CMP0020)
+
+#undef RETURN_POLICY_ID
+
+  assert("!Unreachable code. Not a valid policy");
+  return cmPolicies::CMP0002;
+}
+
+//----------------------------------------------------------------------------
+static const struct TargetPolicyNode : public cmGeneratorExpressionNode
+{
+  TargetPolicyNode() {}
+
+  virtual int NumExpectedParameters() const { return 1; }
+
+  std::string Evaluate(const std::vector<std::string> &parameters,
+                       cmGeneratorExpressionContext *context ,
+                       const GeneratorExpressionContent *content,
+                       cmGeneratorExpressionDAGChecker *) const
+  {
+    if (!context->HeadTarget)
+      {
+      reportError(context, content->GetOriginalExpression(),
+          "$<TARGET_POLICY:prop> may only be used with targets.  It may not "
+          "be used with add_custom_command.");
+      return std::string();
+      }
+
+    context->HadContextSensitiveCondition = true;
+
+    for (size_t i = 0;
+         i < (sizeof(targetPolicyWhitelist) /
+              sizeof(*targetPolicyWhitelist));
+         ++i)
+      {
+      const char *policy = targetPolicyWhitelist[i];
+      if (parameters.front() == policy)
+        {
+        cmMakefile *mf = context->HeadTarget->GetMakefile();
+        switch(statusForTarget(context->HeadTarget, policy))
+          {
+          case cmPolicies::WARN:
+            mf->IssueMessage(cmake::AUTHOR_WARNING,
+                             mf->GetPolicies()->
+                             GetPolicyWarning(policyForString(policy)));
+          case cmPolicies::REQUIRED_IF_USED:
+          case cmPolicies::REQUIRED_ALWAYS:
+          case cmPolicies::OLD:
+            return "0";
+          case cmPolicies::NEW:
+            return "1";
+          }
+        }
+      }
+    reportError(context, content->GetOriginalExpression(),
+      "$<TARGET_POLICY:prop> may only be used with a limited number of "
+      "policies.  Currently it may be used with policies CMP0003, CMP0004, "
+      "CMP0008 and CMP0020."
+      );
+    return std::string();
+  }
+
+} targetPolicyNode;
+
+//----------------------------------------------------------------------------
+static const struct InstallPrefixNode : public cmGeneratorExpressionNode
+{
+  InstallPrefixNode() {}
+
+  virtual bool GeneratesContent() const { return true; }
+  virtual int NumExpectedParameters() const { return 0; }
+
+  std::string Evaluate(const std::vector<std::string> &,
+                       cmGeneratorExpressionContext *context,
+                       const GeneratorExpressionContent *content,
+                       cmGeneratorExpressionDAGChecker *) const
+  {
+    reportError(context, content->GetOriginalExpression(),
+                "INSTALL_PREFIX is a marker for install(EXPORT) only.  It "
+                "should never be evaluated.");
+    return std::string();
+  }
+
+} installPrefixNode;
+
+//----------------------------------------------------------------------------
+static const struct LinkedNode : public cmGeneratorExpressionNode
+{
+  LinkedNode() {}
+
+  virtual bool GeneratesContent() const { return true; }
+  virtual int NumExpectedParameters() const { return 1; }
+  virtual bool RequiresLiteralInput() const { return true; }
+
+  std::string Evaluate(const std::vector<std::string> &parameters,
+                       cmGeneratorExpressionContext *context,
+                       const GeneratorExpressionContent *content,
+                       cmGeneratorExpressionDAGChecker *dagChecker) const
+  {
+    if (dagChecker->EvaluatingIncludeDirectories())
+      {
+      return this->GetInterfaceProperty(parameters.front(),
+                                        "INCLUDE_DIRECTORIES",
+                                        context, content, dagChecker);
+      }
+    if (dagChecker->EvaluatingCompileDefinitions())
+      {
+      return this->GetInterfaceProperty(parameters.front(),
+                                        "COMPILE_DEFINITIONS",
+                                        context, content, dagChecker);
+      }
+
+    reportError(context, content->GetOriginalExpression(),
+                "$<LINKED:...> may only be used in INCLUDE_DIRECTORIES and "
+                "COMPILE_DEFINITIONS properties.");
+
+    return std::string();
+  }
+
+private:
+  std::string GetInterfaceProperty(const std::string &item,
+                      const std::string &prop,
+                      cmGeneratorExpressionContext *context,
+                      const GeneratorExpressionContent *content,
+                      cmGeneratorExpressionDAGChecker *dagCheckerParent) const
+  {
+    cmTarget *target = context->CurrentTarget
+                              ->GetMakefile()->FindTargetToUse(item.c_str());
+    if (!target)
+      {
+      return std::string();
+      }
+    std::string propertyName = "INTERFACE_" + prop;
+    const char *propContent = target->GetProperty(propertyName.c_str());
+    if (!propContent)
+      {
+      return std::string();
+      }
+
+    cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace,
+                                               target->GetName(),
+                                               propertyName,
+                                               content,
+                                               dagCheckerParent);
+
+    switch (dagChecker.check())
+      {
+    case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
+      dagChecker.reportError(context, content->GetOriginalExpression());
+      return std::string();
+    case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
+      // No error. We just skip cyclic references.
+      return std::string();
+    case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
+      // No error. We're not going to find anything new here.
+      return std::string();
+    case cmGeneratorExpressionDAGChecker::DAG:
+      break;
+      }
+
+    cmGeneratorExpression ge(context->Backtrace);
+    cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(propContent);
+    std::string result = cge->Evaluate(context->Makefile,
+                        context->Config,
+                        context->Quiet,
+                        context->HeadTarget,
+                        target,
+                        &dagChecker);
+    if (cge->GetHadContextSensitiveCondition())
+      {
+      context->HadContextSensitiveCondition = true;
+      }
+    return result;
+  }
+
+} linkedNode;
+
 //----------------------------------------------------------------------------
 template<bool linker, bool soname>
 struct TargetFilesystemArtifactResultCreator
@@ -714,12 +974,18 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
     return &targetPropertyNode;
   else if (identifier == "TARGET_NAME")
     return &targetNameNode;
+  else if (identifier == "TARGET_POLICY")
+    return &targetPolicyNode;
   else if (identifier == "BUILD_INTERFACE")
     return &buildInterfaceNode;
   else if (identifier == "INSTALL_INTERFACE")
     return &installInterfaceNode;
   else if (identifier == "TARGET_DEFINED")
     return &targetDefinedNode;
+  else if (identifier == "INSTALL_PREFIX")
+    return &installPrefixNode;
+  else if (identifier == "LINKED")
+    return &linkedNode;
   return 0;
 
 }

+ 1 - 0
Source/cmGeneratorExpressionEvaluator.h

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

+ 0 - 29
Source/cmGeneratorTarget.cxx

@@ -254,32 +254,3 @@ std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories(
 {
   return this->Target->GetIncludeDirectories(config);
 }
-
-//----------------------------------------------------------------------------
-std::string cmGeneratorTarget::GetCompileDefinitions(const char *config)
-{
-  std::string defPropName = "COMPILE_DEFINITIONS";
-  if (config)
-    {
-    defPropName += "_" + cmSystemTools::UpperCase(config);
-    }
-
-  const char *prop = this->Target->GetProperty(defPropName.c_str());
-
-  if (!prop)
-    {
-    return "";
-    }
-
-  cmListFileBacktrace lfbt;
-  cmGeneratorExpression ge(lfbt);
-
-  cmGeneratorExpressionDAGChecker dagChecker(lfbt,
-                                             this->GetName(),
-                                             defPropName, 0, 0);
-  return ge.Parse(prop)->Evaluate(this->Makefile,
-                                 config,
-                                 false,
-                                 this->Target,
-                                 &dagChecker);
-}

+ 0 - 2
Source/cmGeneratorTarget.h

@@ -68,8 +68,6 @@ public:
   /** Get the include directories for this target.  */
   std::vector<std::string> GetIncludeDirectories(const char *config);
 
-  std::string GetCompileDefinitions(const char *config = 0);
-
 private:
   void ClassifySources();
   void LookupObjectLibraries();

+ 3 - 1
Source/cmGlobalGenerator.cxx

@@ -994,6 +994,7 @@ void cmGlobalGenerator::Generate()
   // Generate project files
   for (i = 0; i < this->LocalGenerators.size(); ++i)
     {
+    this->LocalGenerators[i]->GetMakefile()->SetGeneratingBuildSystem();
     this->SetCurrentLocalGenerator(this->LocalGenerators[i]);
     this->LocalGenerators[i]->Generate();
     this->LocalGenerators[i]->GenerateInstallRules();
@@ -1077,7 +1078,8 @@ void cmGlobalGenerator::CreateAutomocTargets()
       if(target.GetType() == cmTarget::EXECUTABLE ||
          target.GetType() == cmTarget::STATIC_LIBRARY ||
          target.GetType() == cmTarget::SHARED_LIBRARY ||
-         target.GetType() == cmTarget::MODULE_LIBRARY)
+         target.GetType() == cmTarget::MODULE_LIBRARY ||
+         target.GetType() == cmTarget::OBJECT_LIBRARY)
         {
         if(target.GetPropertyAsBool("AUTOMOC") && !target.IsImported())
           {

+ 2 - 2
Source/cmGlobalXCodeGenerator.cxx

@@ -1700,11 +1700,11 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
     this->AppendDefines(ppDefs, exportMacro);
     }
   cmGeneratorTarget *gtgt = this->GetGeneratorTarget(&target);
-  this->AppendDefines(ppDefs, gtgt->GetCompileDefinitions().c_str());
+  this->AppendDefines(ppDefs, target.GetCompileDefinitions().c_str());
   if(configName)
     {
     this->AppendDefines(ppDefs,
-                        gtgt->GetCompileDefinitions(configName).c_str());
+                        target.GetCompileDefinitions(configName).c_str());
     }
   buildSettings->AddAttribute
     ("GCC_PREPROCESSOR_DEFINITIONS", ppDefs.CreateList());

+ 58 - 34
Source/cmIncludeDirectoryCommand.cxx

@@ -36,6 +36,10 @@ bool cmIncludeDirectoryCommand
     ++i;
     }
 
+  std::vector<std::string> beforeIncludes;
+  std::vector<std::string> afterIncludes;
+  std::set<cmStdString> systemIncludes;
+
   for(; i != args.end(); ++i)
     {
     if(*i == "SYSTEM")
@@ -49,9 +53,37 @@ bool cmIncludeDirectoryCommand
       return false;
       }
 
-    this->AddDirectory(i->c_str(),before,system);
+    std::vector<std::string> includes;
+
+    GetIncludes(*i, includes);
 
+    if (before)
+      {
+      beforeIncludes.insert(beforeIncludes.end(),
+                            includes.begin(),
+                            includes.end());
+      }
+    else
+      {
+      afterIncludes.insert(afterIncludes.end(),
+                           includes.begin(),
+                           includes.end());
+      }
+    if (system)
+      {
+      for (std::vector<std::string>::const_iterator li = includes.begin();
+        li != includes.end(); ++li)
+        {
+        systemIncludes.insert(*li);
+        }
+      }
     }
+  std::reverse(beforeIncludes.begin(), beforeIncludes.end());
+
+  this->Makefile->AddIncludeDirectories(afterIncludes);
+  this->Makefile->AddIncludeDirectories(beforeIncludes, before);
+  this->Makefile->AddSystemIncludeDirectories(systemIncludes);
+
   return true;
 }
 
@@ -72,57 +104,49 @@ static bool StartsWithGeneratorExpression(const std::string &input)
 // output from a program and passing it into a command the cleanup doesn't
 // always happen
 //
-void cmIncludeDirectoryCommand::AddDirectory(const char *i,
-                                             bool before,
-                                             bool system)
+void cmIncludeDirectoryCommand::GetIncludes(const std::string &arg,
+                                            std::vector<std::string> &incs)
 {
   // break apart any line feed arguments
-  std::string ret = i;
   std::string::size_type pos = 0;
-  if((pos = ret.find('\n', pos)) != std::string::npos)
+  std::string::size_type lastPos = 0;
+  while((pos = arg.find('\n', lastPos)) != std::string::npos)
     {
     if (pos)
       {
-      this->AddDirectory(ret.substr(0,pos).c_str(), before, system);
-      }
-    if (ret.size()-pos-1)
-      {
-      this->AddDirectory(ret.substr(pos+1,ret.size()-pos-1).c_str(),
-                         before, system);
+      std::string inc = arg.substr(lastPos,pos);
+      NormalizeInclude(inc);
+      incs.push_back(inc);
       }
-    return;
+    lastPos = pos + 1;
     }
+  std::string inc = arg.substr(lastPos);
+  NormalizeInclude(inc);
+  incs.push_back(inc);
+}
 
-  // remove any leading or trailing spaces and \r
-  std::string::size_type b = ret.find_first_not_of(" \r");
-  std::string::size_type e = ret.find_last_not_of(" \r");
-  if ((b!=ret.npos) && (e!=ret.npos))
-    {
-    ret.assign(ret, b, 1+e-b);   // copy the remaining substring
-    }
-  else
+void cmIncludeDirectoryCommand::NormalizeInclude(std::string &inc)
+{
+  std::string::size_type b = inc.find_first_not_of(" \r");
+  std::string::size_type e = inc.find_last_not_of(" \r");
+  if ((b!=inc.npos) && (e!=inc.npos))
     {
-    return;         // if we get here, we had only whitespace in the string
+    inc.assign(inc, b, 1+e-b);   // copy the remaining substring
     }
 
-  if (!cmSystemTools::IsOff(ret.c_str()))
+  if (!cmSystemTools::IsOff(inc.c_str()))
     {
-    cmSystemTools::ConvertToUnixSlashes(ret);
-    if(!cmSystemTools::FileIsFullPath(ret.c_str()))
+    cmSystemTools::ConvertToUnixSlashes(inc);
+
+    if(!cmSystemTools::FileIsFullPath(inc.c_str()))
       {
-      if(!StartsWithGeneratorExpression(ret))
+      if(!StartsWithGeneratorExpression(inc))
         {
         std::string tmp = this->Makefile->GetStartDirectory();
         tmp += "/";
-        tmp += ret;
-        ret = tmp;
+        tmp += inc;
+        inc = tmp;
         }
       }
     }
-  this->Makefile->AddIncludeDirectory(ret.c_str(), before);
-  if(system)
-    {
-    this->Makefile->AddSystemIncludeDirectory(ret.c_str());
-    }
 }
-

+ 5 - 3
Source/cmIncludeDirectoryCommand.h

@@ -59,8 +59,9 @@ public:
     return
       "  include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)\n"
       "Add the given directories to those the compiler uses to search "
-      "for include files. "
-      "These directories are added to the directory property "
+      "for include files.  Relative paths are interpreted as relative to "
+      "the current source directory. \n"
+      "The include directories are added to the directory property "
       "INCLUDE_DIRECTORIES for the current CMakeLists file. "
       "They are also added to the target property INCLUDE_DIRECTORIES "
       "for each target in the current CMakeLists file. "
@@ -84,7 +85,8 @@ public:
 
 protected:
   // used internally
-  void AddDirectory(const char *arg, bool before, bool system);
+  void GetIncludes(const std::string &arg, std::vector<std::string> &incs);
+  void NormalizeInclude(std::string &inc);
 };
 
 

+ 2 - 4
Source/cmLinkDirectoriesCommand.h

@@ -62,10 +62,8 @@ public:
       "  link_directories(directory1 directory2 ...)\n"
       "Specify the paths in which the linker should search for libraries. "
       "The command will apply only to targets created after it is called. "
-      "For historical reasons, relative paths given to this command are "
-      "passed to the linker unchanged "
-      "(unlike many CMake commands which interpret them relative to the "
-      "current source directory).\n"
+      "Relative paths given to this command are interpreted as relative to "
+      "the current source directory, see CMP0015. \n"
       "Note that this command is rarely necessary.  Library locations "
       "returned by find_package() and find_library() are absolute paths.  "
       "Pass these absolute library file paths directly to the "

+ 8 - 9
Source/cmLocalVisualStudio6Generator.cxx

@@ -325,6 +325,9 @@ void cmLocalVisualStudio6Generator::WriteDSPFile(std::ostream& fout,
       if(!cmSystemTools::FileExists(source.c_str()))
         {
         cmSystemTools::ReplaceString(source, "$(IntDir)/", "");
+        // Make sure the path exists for the file
+        std::string path = cmSystemTools::GetFilenamePath(source);
+        cmSystemTools::MakeDirectory(path.c_str());
 #if defined(_WIN32) || defined(__CYGWIN__)
         std::ofstream sourceFout(source.c_str(),
                            std::ios::binary | std::ios::out
@@ -1697,25 +1700,21 @@ void cmLocalVisualStudio6Generator
     std::set<std::string> minsizeDefinesSet;
     std::set<std::string> debugrelDefinesSet;
 
-
-    cmGeneratorTarget* gt =
-      this->GlobalGenerator->GetGeneratorTarget(&target);
-
     this->AppendDefines(
       definesSet,
-      gt->GetCompileDefinitions());
+      target.GetCompileDefinitions());
     this->AppendDefines(
       debugDefinesSet,
-      gt->GetCompileDefinitions("DEBUG"));
+      target.GetCompileDefinitions("DEBUG"));
     this->AppendDefines(
       releaseDefinesSet,
-      gt->GetCompileDefinitions("RELEASE"));
+      target.GetCompileDefinitions("RELEASE"));
     this->AppendDefines(
       minsizeDefinesSet,
-      gt->GetCompileDefinitions("MINSIZEREL"));
+      target.GetCompileDefinitions("MINSIZEREL"));
     this->AppendDefines(
       debugrelDefinesSet,
-      gt->GetCompileDefinitions("RELWITHDEBINFO"));
+      target.GetCompileDefinitions("RELWITHDEBINFO"));
 
     std::string defines = " ";
     std::string debugDefines = " ";

+ 2 - 2
Source/cmLocalVisualStudio7Generator.cxx

@@ -745,8 +745,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout,
   targetOptions.ParseFinish();
   cmGeneratorTarget* gt =
     this->GlobalGenerator->GetGeneratorTarget(&target);
-  targetOptions.AddDefines(gt->GetCompileDefinitions().c_str());
-  targetOptions.AddDefines(gt->GetCompileDefinitions(configName).c_str());
+  targetOptions.AddDefines(target.GetCompileDefinitions().c_str());
+  targetOptions.AddDefines(target.GetCompileDefinitions(configName).c_str());
   targetOptions.SetVerboseMakefile(
     this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));
 

+ 27 - 10
Source/cmMakefile.cxx

@@ -99,6 +99,7 @@ cmMakefile::cmMakefile(): Internal(new Internals)
   this->AddDefaultDefinitions();
   this->Initialize();
   this->PreOrder = false;
+  this->GeneratingBuildSystem = false;
 }
 
 cmMakefile::cmMakefile(const cmMakefile& mf): Internal(new Internals)
@@ -1616,20 +1617,31 @@ void cmMakefile::AddSubDirectory(const char* srcPath, const char *binPath,
 }
 
 //----------------------------------------------------------------------------
-void cmMakefile::AddIncludeDirectory(const char* inc, bool before)
+void cmMakefile::AddIncludeDirectories(const std::vector<std::string> &incs,
+                                       bool before)
 {
-  if (!inc)
+  if (incs.empty())
     {
     return;
     }
 
+  std::string incString;
+  std::string sep;
+
+  for(std::vector<std::string>::const_iterator li = incs.begin();
+      li != incs.end(); ++li)
+    {
+    incString += sep + *li;
+    sep = ";";
+    }
+
   std::vector<IncludeDirectoriesEntry>::iterator position =
-                               before ? this->IncludeDirectoriesEntries.begin()
-                                      : this->IncludeDirectoriesEntries.end();
+                              before ? this->IncludeDirectoriesEntries.begin()
+                                    : this->IncludeDirectoriesEntries.end();
 
   cmListFileBacktrace lfbt;
   this->GetBacktrace(lfbt);
-  IncludeDirectoriesEntry entry(inc, lfbt);
+  IncludeDirectoriesEntry entry(incString, lfbt);
   this->IncludeDirectoriesEntries.insert(position, entry);
 
   // Property on each target:
@@ -1642,9 +1654,14 @@ void cmMakefile::AddIncludeDirectory(const char* inc, bool before)
 }
 
 //----------------------------------------------------------------------------
-void cmMakefile::AddSystemIncludeDirectory(const char* dir)
+void
+cmMakefile::AddSystemIncludeDirectories(const std::set<cmStdString> &incs)
 {
-  this->SystemIncludeDirectories.insert(dir);
+  for(std::set<cmStdString>::const_iterator li = incs.begin();
+      li != incs.end(); ++li)
+    {
+    this->SystemIncludeDirectories.insert(*li);
+    }
 }
 
 //----------------------------------------------------------------------------
@@ -2243,7 +2260,7 @@ bool cmMakefile::CanIWriteThisFile(const char* fileName)
     {
     return true;
     }
-  // If we are doing an in-source build, than the test will always fail
+  // If we are doing an in-source build, then the test will always fail
   if ( cmSystemTools::SameFile(this->GetHomeDirectory(),
                                this->GetHomeOutputDirectory()) )
     {
@@ -2254,8 +2271,8 @@ bool cmMakefile::CanIWriteThisFile(const char* fileName)
     return true;
     }
 
-  // Check if this is subdirectory of the source tree but not a
-  // subdirectory of a build tree
+  // Check if this is a subdirectory of the source tree but not a
+  // subdirectory of the build tree
   if ( cmSystemTools::IsSubDirectory(fileName,
       this->GetHomeDirectory()) &&
     !cmSystemTools::IsSubDirectory(fileName,

+ 9 - 2
Source/cmMakefile.h

@@ -287,7 +287,8 @@ public:
   /**
    * Add an include directory to the build.
    */
-  void AddIncludeDirectory(const char*, bool before = false);
+  void AddIncludeDirectories(const std::vector<std::string> &incs,
+                             bool before = false);
 
   /**
    * Add a variable definition to the build. This variable
@@ -545,7 +546,7 @@ public:
   /**
    * Mark include directories as system directories.
    */
-  void AddSystemIncludeDirectory(const char* dir);
+  void AddSystemIncludeDirectories(const std::set<cmStdString> &incs);
   bool IsSystemIncludeDirectory(const char* dir);
 
   /** Expand out any arguements in the vector that have ; separated
@@ -869,6 +870,9 @@ public:
     return this->IncludeDirectoriesEntries;
   }
 
+  bool IsGeneratingBuildSystem(){ return this->GeneratingBuildSystem; }
+  void SetGeneratingBuildSystem(){ this->GeneratingBuildSystem = true; }
+
 protected:
   // add link libraries and directories to the target
   void AddGlobalLinkInformation(const char* name, cmTarget& target);
@@ -1018,6 +1022,9 @@ private:
 
   // Enforce rules about CMakeLists.txt files.
   void EnforceDirectoryLevelRules();
+
+  bool GeneratingBuildSystem;
+
 };
 
 //----------------------------------------------------------------------------

+ 2 - 2
Source/cmMakefileTargetGenerator.cxx

@@ -303,10 +303,10 @@ std::string cmMakefileTargetGenerator::GetDefines(const std::string &l)
 
     // Add preprocessor definitions for this target and configuration.
     this->LocalGenerator->AppendDefines
-      (defines, this->GeneratorTarget->GetCompileDefinitions());
+      (defines, this->Target->GetCompileDefinitions());
 
     this->LocalGenerator->AppendDefines
-      (defines, this->GeneratorTarget->GetCompileDefinitions(
+      (defines, this->Target->GetCompileDefinitions(
                             this->LocalGenerator->ConfigurationName.c_str()));
 
     std::string definesString;

+ 1 - 1
Source/cmNinjaNormalTargetGenerator.cxx

@@ -190,7 +190,7 @@ cmNinjaNormalTargetGenerator
         linkOptionVar += cmTarget::GetTargetTypeName(targetType);
         const std::string linkOption =
                 GetMakefile()->GetSafeDefinition(linkOptionVar.c_str());
-        rspcontent = "$in " + linkOption + " $LINK_PATH $LINK_LIBRARIES";
+        rspcontent = "$in_newline "+linkOption+" $LINK_PATH $LINK_LIBRARIES";
         vars.Objects = responseFlag.c_str();
         vars.LinkLibraries = "";
     }

+ 2 - 2
Source/cmNinjaTargetGenerator.cxx

@@ -228,7 +228,7 @@ ComputeDefines(cmSourceFile *source, const std::string& language)
   // Add preprocessor definitions for this target and configuration.
   this->LocalGenerator->AppendDefines
     (defines,
-     this->GeneratorTarget->GetCompileDefinitions());
+     this->Target->GetCompileDefinitions());
   this->LocalGenerator->AppendDefines
     (defines,
      source->GetProperty("COMPILE_DEFINITIONS"));
@@ -237,7 +237,7 @@ ComputeDefines(cmSourceFile *source, const std::string& language)
   defPropName += cmSystemTools::UpperCase(this->GetConfigName());
   this->LocalGenerator->AppendDefines
     (defines,
-     this->GeneratorTarget->GetCompileDefinitions(this->GetConfigName()));
+     this->Target->GetCompileDefinitions(this->GetConfigName()));
   this->LocalGenerator->AppendDefines
     (defines,
      source->GetProperty(defPropName.c_str()));

+ 21 - 0
Source/cmPolicies.cxx

@@ -508,6 +508,27 @@ cmPolicies::cmPolicies()
     "for strict compatibility.  "
     "The NEW behavior for this policy is to leave the values untouched.",
     2,8,11,0, cmPolicies::WARN);
+
+  this->DefinePolicy(
+    CMP0020, "CMP0020",
+    "Automatically link Qt executables to qtmain target on Windows.",
+    "CMake 2.8.10 and lower required users of Qt to always specify a link "
+    "dependency to the qtmain.lib static library manually on Windows.  CMake "
+    "2.8.11 gained the ability to evaluate generator expressions while "
+    "determining the link dependencies from IMPORTED targets.  This allows "
+    "CMake itself to automatically link executables which link to Qt to the "
+    "qtmain.lib library when using IMPORTED Qt targets.  For applications "
+    "already linking to qtmain.lib, this should have little impact.  For "
+    "applications which supply their own alternative WinMain implementation "
+    "and for applications which use the QAxServer library, this automatic "
+    "linking will need to be disabled as per the documentation."
+    "\n"
+    "The OLD behavior for this policy is not to link executables to "
+    "qtmain.lib automatically when they link to the QtCore IMPORTED"
+    "target.  "
+    "The NEW behavior for this policy is to link executables to "
+    "qtmain.lib automatically when they link to QtCore IMPORTED target.",
+    2,8,11,0, cmPolicies::WARN);
 }
 
 cmPolicies::~cmPolicies()

+ 1 - 0
Source/cmPolicies.h

@@ -69,6 +69,7 @@ public:
     /// POSITION_INDEPENDENT_CODE property and *_COMPILE_OPTIONS_PI{E,C}
     /// instead.
     CMP0019, ///< No variable re-expansion in include and link info
+    CMP0020, ///< Automatically link Qt executables to qtmain target
 
     /** \brief Always the last entry.
      *

+ 5 - 1
Source/cmQtAutomoc.cxx

@@ -229,7 +229,11 @@ void cmQtAutomoc::SetupAutomocTarget(cmTarget* target)
     }
 
   const char* tmp = target->GetProperty("COMPILE_DEFINITIONS");
-  std::string _moc_compile_defs = (tmp!=0 ? tmp : "");
+  std::string _moc_compile_defs;
+  if (tmp)
+    {
+    _moc_compile_defs = target->GetCompileDefinitions();
+    }
   tmp = makefile->GetProperty("COMPILE_DEFINITIONS");
   if (tmp)
     {

+ 20 - 31
Source/cmSystemTools.cxx

@@ -1180,46 +1180,35 @@ bool cmSystemTools::CopyFileIfDifferent(const char* source,
 bool cmSystemTools::RenameFile(const char* oldname, const char* newname)
 {
 #ifdef _WIN32
-  /* On Windows the move functions will not replace existing files.
-     Check if the destination exists.  */
-  struct stat newFile;
-  if(stat(newname, &newFile) == 0)
+# ifndef INVALID_FILE_ATTRIBUTES
+#  define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+# endif
+  /* Windows MoveFileEx may not replace read-only or in-use files.  If it
+     fails then remove the read-only attribute from any existing destination.
+     Try multiple times since we may be racing against another process
+     creating/opening the destination file just before our MoveFileEx.  */
+  int tries = 5;
+  while(!MoveFileEx(oldname, newname, MOVEFILE_REPLACE_EXISTING) && --tries)
     {
-    /* The destination exists.  We have to replace it carefully.  The
-       MoveFileEx function does what we need but is not available on
-       Win9x.  */
-    OSVERSIONINFO osv;
-    DWORD attrs;
-
-    /* Make sure the destination is not read only.  */
-    attrs = GetFileAttributes(newname);
-    if(attrs & FILE_ATTRIBUTE_READONLY)
+    // Try again only if failure was due to access permissions.
+    if(GetLastError() != ERROR_ACCESS_DENIED)
       {
-      SetFileAttributes(newname, attrs & ~FILE_ATTRIBUTE_READONLY);
+      return false;
       }
-
-    /* Check the windows version number.  */
-    osv.dwOSVersionInfoSize = sizeof(osv);
-    GetVersionEx(&osv);
-    if(osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
+    DWORD attrs = GetFileAttributes(newname);
+    if((attrs != INVALID_FILE_ATTRIBUTES) &&
+       (attrs & FILE_ATTRIBUTE_READONLY))
       {
-      /* This is Win9x.  There is no MoveFileEx implementation.  We
-         cannot quite rename the file atomically.  Just delete the
-         destination and then move the file.  */
-      DeleteFile(newname);
-      return MoveFile(oldname, newname) != 0;
+      // Remove the read-only attribute from the destination file.
+      SetFileAttributes(newname, attrs & ~FILE_ATTRIBUTE_READONLY);
       }
     else
       {
-      /* This is not Win9x.  Use the MoveFileEx implementation.  */
-      return MoveFileEx(oldname, newname, MOVEFILE_REPLACE_EXISTING) != 0;
+      // The file may be temporarily in use so wait a bit.
+      cmSystemTools::Delay(100);
       }
     }
-  else
-    {
-    /* The destination does not exist.  Just move the file.  */
-    return MoveFile(oldname, newname) != 0;
-    }
+  return tries > 0;
 #else
   /* On UNIX we have an OS-provided call to do this atomically.  */
   return rename(oldname, newname) == 0;

+ 320 - 69
Source/cmTarget.cxx

@@ -134,6 +134,7 @@ public:
       : ge(cge)
     {}
     const cmsys::auto_ptr<cmCompiledGeneratorExpression> ge;
+    std::vector<std::string> CachedIncludes;
   };
   std::vector<IncludeDirectoriesEntry*> IncludeDirectoriesEntries;
 };
@@ -145,12 +146,14 @@ cmTarget::cmTarget()
   this->PolicyStatusCMP0003 = cmPolicies::WARN;
   this->PolicyStatusCMP0004 = cmPolicies::WARN;
   this->PolicyStatusCMP0008 = cmPolicies::WARN;
+  this->PolicyStatusCMP0020 = cmPolicies::WARN;
   this->LinkLibrariesAnalyzed = false;
   this->HaveInstallRule = false;
   this->DLLPlatform = false;
   this->IsApple = false;
   this->IsImportedTarget = false;
   this->BuildInterfaceIncludesAppended = false;
+  this->DebugIncludesDone = false;
 }
 
 //----------------------------------------------------------------------------
@@ -905,6 +908,17 @@ void cmTarget::DefineProperties(cmake *cm)
      "then it must have the same boolean value as all others, and if the "
      "property is not set, then it is ignored.");
 
+  cm->DefineProperty
+    ("COMPATIBLE_INTERFACE_STRING", cmProperty::TARGET,
+     "Properties which must be string-compatible with their link interface",
+     "The COMPATIBLE_INTERFACE_STRING property may contain a list of "
+     "properties for this target which must be the same when evaluated as "
+     "a string in the INTERFACE of all linked dependencies.  For example, "
+     "if a property \"FOO\" appears in the list, then the \"INTERFACE_FOO\" "
+     "property content in all dependencies must be equal with each "
+     "other, and with the \"FOO\" property in this target.  If the "
+     "property is not set, then it is ignored.");
+
   cm->DefineProperty
     ("POST_INSTALL_SCRIPT", cmProperty::TARGET,
      "Deprecated install support.",
@@ -1499,6 +1513,8 @@ void cmTarget::SetMakefile(cmMakefile* mf)
     this->Makefile->GetPolicyStatus(cmPolicies::CMP0004);
   this->PolicyStatusCMP0008 =
     this->Makefile->GetPolicyStatus(cmPolicies::CMP0008);
+  this->PolicyStatusCMP0020 =
+    this->Makefile->GetPolicyStatus(cmPolicies::CMP0020);
 }
 
 //----------------------------------------------------------------------------
@@ -1520,6 +1536,13 @@ void cmTarget::ClearLinkMaps()
   this->Internal->LinkImplMap.clear();
   this->Internal->LinkInterfaceMap.clear();
   this->Internal->LinkClosureMap.clear();
+  for (cmTargetLinkInformationMap::const_iterator it
+      = this->LinkInformation.begin();
+      it != this->LinkInformation.end(); ++it)
+    {
+    delete it->second;
+    }
+  this->LinkInformation.clear();
 }
 
 //----------------------------------------------------------------------------
@@ -2269,8 +2292,9 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf,
   cmTarget *tgt = this->Makefile->FindTargetToUse(lib);
   const bool isNonImportedTarget = tgt && !tgt->IsImported();
 
-  std::string libName = isNonImportedTarget ? targetNameGenex(lib)
-                                          : std::string(lib);
+  const std::string libName = (isNonImportedTarget && llt != GENERAL)
+                                                        ? targetNameGenex(lib)
+                                                        : std::string(lib);
   this->AppendProperty("LINK_LIBRARIES",
                        this->GetDebugGeneratorExpressions(libName,
                                                           llt).c_str());
@@ -2739,52 +2763,105 @@ std::vector<std::string> cmTarget::GetIncludeDirectories(const char *config)
     cmSystemTools::ExpandListArgument(debugProp, debugProperties);
     }
 
-  bool debugIncludes = std::find(debugProperties.begin(),
+  bool debugIncludes = !this->DebugIncludesDone
+                    && std::find(debugProperties.begin(),
                                  debugProperties.end(),
                                  "INCLUDE_DIRECTORIES")
                         != debugProperties.end();
 
+  if (this->Makefile->IsGeneratingBuildSystem())
+    {
+    this->DebugIncludesDone = true;
+    }
+
   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);
+
+    bool testIsOff = true;
+    bool cacheIncludes = false;
+    std::vector<std::string> entryIncludes = (*it)->CachedIncludes;
+    if(!entryIncludes.empty())
+      {
+      testIsOff = false;
+      }
+    else
+      {
+      cmSystemTools::ExpandListArgument((*it)->ge->Evaluate(this->Makefile,
+                                                config,
+                                                false,
+                                                this,
+                                                &dagChecker),
+                                      entryIncludes);
+      if (!(*it)->ge->GetHadContextSensitiveCondition())
+        {
+        cacheIncludes = true;
+        }
+      }
     std::string usedIncludes;
-    for(std::vector<std::string>::const_iterator
+    for(std::vector<std::string>::iterator
           li = entryIncludes.begin(); li != entryIncludes.end(); ++li)
       {
-      std::string inc = *li;
-      if (!cmSystemTools::IsOff(inc.c_str()))
+      if (testIsOff && !cmSystemTools::IsOff(li->c_str()))
         {
-        cmSystemTools::ConvertToUnixSlashes(inc);
+        cmSystemTools::ConvertToUnixSlashes(*li);
         }
+      std::string inc = *li;
 
       if(uniqueIncludes.insert(inc).second)
         {
-        includes.push_back(*li);
+        includes.push_back(inc);
         if (debugIncludes)
           {
-          usedIncludes += " * " + *li + "\n";
+          usedIncludes += " * " + inc + "\n";
           }
         }
       }
+    if (cacheIncludes)
+      {
+      (*it)->CachedIncludes = entryIncludes;
+      }
     if (!usedIncludes.empty())
       {
       this->Makefile->GetCMakeInstance()->IssueMessage(cmake::LOG,
-                            "Used includes:\n" + usedIncludes,
-                            (*it)->ge->GetBacktrace());
+                            "Used includes for target " + this->Name + ":\n"
+                            + usedIncludes, (*it)->ge->GetBacktrace());
       }
     }
   return includes;
 }
 
+//----------------------------------------------------------------------------
+std::string cmTarget::GetCompileDefinitions(const char *config)
+{
+  std::string defPropName = "COMPILE_DEFINITIONS";
+  if (config)
+    {
+    defPropName += "_" + cmSystemTools::UpperCase(config);
+    }
+
+  const char *prop = this->GetProperty(defPropName.c_str());
+
+  if (!prop)
+    {
+    return "";
+    }
+
+  cmListFileBacktrace lfbt;
+  cmGeneratorExpression ge(lfbt);
+
+  cmGeneratorExpressionDAGChecker dagChecker(lfbt,
+                                             this->GetName(),
+                                             defPropName, 0, 0);
+  return ge.Parse(prop)->Evaluate(this->Makefile,
+                                 config,
+                                 false,
+                                 this,
+                                 &dagChecker);
+}
+
 //----------------------------------------------------------------------------
 void cmTarget::MaybeInvalidatePropertyCache(const char* prop)
 {
@@ -4482,22 +4559,69 @@ void cmTarget::AddLinkDependentTargetsForProperties(
 }
 
 //----------------------------------------------------------------------------
-bool cmTarget::GetLinkInterfaceDependentBoolProperty(const std::string &p,
-                                                     const char *config)
+template<typename PropertyType>
+PropertyType getTypedProperty(cmTarget *tgt, const char *prop,
+                              PropertyType *);
+
+//----------------------------------------------------------------------------
+template<>
+bool getTypedProperty<bool>(cmTarget *tgt, const char *prop, bool *)
+{
+  return tgt->GetPropertyAsBool(prop);
+}
+
+//----------------------------------------------------------------------------
+template<>
+const char *getTypedProperty<const char *>(cmTarget *tgt, const char *prop,
+                                          const char **)
 {
-  bool propContent = this->GetPropertyAsBool(p.c_str());
-  const bool explicitlySet = this->GetProperties()
+  return tgt->GetProperty(prop);
+}
+
+//----------------------------------------------------------------------------
+template<typename PropertyType>
+bool consistentProperty(PropertyType lhs, PropertyType rhs);
+
+//----------------------------------------------------------------------------
+template<>
+bool consistentProperty(bool lhs, bool rhs)
+{
+  return lhs == rhs;
+}
+
+//----------------------------------------------------------------------------
+template<>
+bool consistentProperty(const char *lhs, const char *rhs)
+{
+  if (!lhs && !rhs)
+    return true;
+  if (!lhs || !rhs)
+    return false;
+  return strcmp(lhs, rhs) == 0;
+}
+
+//----------------------------------------------------------------------------
+template<typename PropertyType>
+PropertyType checkInterfacePropertyCompatibility(cmTarget *tgt,
+                                          const std::string &p,
+                                          const char *config,
+                                          const char *defaultValue,
+                                          PropertyType *)
+{
+  PropertyType propContent = getTypedProperty<PropertyType>(tgt, p.c_str(),
+                                                            0);
+  const bool explicitlySet = tgt->GetProperties()
                                   .find(p.c_str())
-                                  != this->GetProperties().end();
+                                  != tgt->GetProperties().end();
   std::set<std::string> dependentTargets;
-  this->GetLinkDependentTargetsForProperty(p,
+  tgt->GetLinkDependentTargetsForProperty(p,
                                           dependentTargets);
   const bool impliedByUse =
-          this->IsNullImpliedByLinkLibraries(p);
+          tgt->IsNullImpliedByLinkLibraries(p);
   assert((impliedByUse ^ explicitlySet)
       || (!impliedByUse && !explicitlySet));
 
-  cmComputeLinkInformation *info = this->GetLinkInformation(config);
+  cmComputeLinkInformation *info = tgt->GetLinkInformation(config);
   const cmComputeLinkInformation::ItemVector &deps = info->GetItems();
   bool propInitialized = explicitlySet;
 
@@ -4519,20 +4643,22 @@ bool cmTarget::GetLinkInterfaceDependentBoolProperty(const std::string &p,
     const bool ifaceIsSet = li->Target->GetProperties()
                             .find("INTERFACE_" + p)
                             != li->Target->GetProperties().end();
-    const bool ifacePropContent = li->Target->GetPropertyAsBool(
-                              ("INTERFACE_" + p).c_str());
+    PropertyType ifacePropContent =
+                    getTypedProperty<PropertyType>(li->Target,
+                              ("INTERFACE_" + p).c_str(), 0);
     if (explicitlySet)
       {
       if (ifaceIsSet)
         {
-        if (propContent != ifacePropContent)
+        if (!consistentProperty(propContent, ifacePropContent))
           {
           cmOStringStream e;
           e << "Property " << p << " on target \""
-            << this->GetName() << "\" does\nnot match the "
+            << tgt->GetName() << "\" does\nnot match the "
             "INTERFACE_" << p << " property requirement\nof "
             "dependency \"" << li->Target->GetName() << "\".\n";
           cmSystemTools::Error(e.str().c_str());
+          break;
           }
         else
           {
@@ -4550,15 +4676,16 @@ bool cmTarget::GetLinkInterfaceDependentBoolProperty(const std::string &p,
       {
       if (ifaceIsSet)
         {
-        if (propContent != ifacePropContent)
+        if (!consistentProperty(propContent, ifacePropContent))
           {
           cmOStringStream e;
           e << "Property " << p << " on target \""
-            << this->GetName() << "\" is\nimplied to be FALSE because it "
-            "was used to determine the link libraries\nalready. The "
-            "INTERFACE_" << p << " property on\ndependency \""
+            << tgt->GetName() << "\" is\nimplied to be " << defaultValue
+            << " because it was used to determine the link libraries\n"
+               "already. The INTERFACE_" << p << " property on\ndependency \""
             << li->Target->GetName() << "\" is in conflict.\n";
           cmSystemTools::Error(e.str().c_str());
+          break;
           }
         else
           {
@@ -4578,14 +4705,15 @@ bool cmTarget::GetLinkInterfaceDependentBoolProperty(const std::string &p,
         {
         if (propInitialized)
           {
-          if (propContent != ifacePropContent)
+          if (!consistentProperty(propContent, ifacePropContent))
             {
             cmOStringStream e;
             e << "The INTERFACE_" << p << " property of \""
               << li->Target->GetName() << "\" does\nnot agree with the value "
                 "of " << p << " already determined\nfor \""
-              << this->GetName() << "\".\n";
+              << tgt->GetName() << "\".\n";
             cmSystemTools::Error(e.str().c_str());
+            break;
             }
           else
             {
@@ -4609,6 +4737,80 @@ bool cmTarget::GetLinkInterfaceDependentBoolProperty(const std::string &p,
   return propContent;
 }
 
+//----------------------------------------------------------------------------
+bool cmTarget::GetLinkInterfaceDependentBoolProperty(const std::string &p,
+                                                     const char *config)
+{
+  return checkInterfacePropertyCompatibility<bool>(this, p, config, "FALSE",
+                                                   0);
+}
+
+//----------------------------------------------------------------------------
+const char * cmTarget::GetLinkInterfaceDependentStringProperty(
+                                                      const std::string &p,
+                                                      const char *config)
+{
+  return checkInterfacePropertyCompatibility<const char *>(this,
+                                                           p,
+                                                           config,
+                                                           "empty", 0);
+}
+
+//----------------------------------------------------------------------------
+bool isLinkDependentProperty(cmTarget *tgt, const std::string &p,
+                             const char *interfaceProperty,
+                             const char *config)
+{
+  cmComputeLinkInformation *info = tgt->GetLinkInformation(config);
+
+  const cmComputeLinkInformation::ItemVector &deps = info->GetItems();
+
+  for(cmComputeLinkInformation::ItemVector::const_iterator li =
+      deps.begin();
+      li != deps.end(); ++li)
+    {
+    if (!li->Target)
+      {
+      continue;
+      }
+    const char *prop = li->Target->GetProperty(interfaceProperty);
+    if (!prop)
+      {
+      continue;
+      }
+
+    std::vector<std::string> props;
+    cmSystemTools::ExpandListArgument(prop, props);
+
+    for(std::vector<std::string>::iterator pi = props.begin();
+        pi != props.end(); ++pi)
+      {
+      if (*pi == p)
+        {
+        return true;
+        }
+      }
+    }
+
+  return false;
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::IsLinkInterfaceDependentBoolProperty(const std::string &p,
+                                           const char *config)
+{
+  return isLinkDependentProperty(this, p, "COMPATIBLE_INTERFACE_BOOL",
+                                 config);
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::IsLinkInterfaceDependentStringProperty(const std::string &p,
+                                    const char *config)
+{
+  return isLinkDependentProperty(this, p, "COMPATIBLE_INTERFACE_STRING",
+                                 config);
+}
+
 //----------------------------------------------------------------------------
 void cmTarget::GetLanguages(std::set<cmStdString>& languages) const
 {
@@ -5349,6 +5551,73 @@ std::string cmTarget::CheckCMP0004(std::string const& item)
   return lib;
 }
 
+template<typename PropertyType>
+PropertyType getLinkInterfaceDependentProperty(cmTarget *tgt,
+                                               const std::string prop,
+                                               const char *config,
+                                               PropertyType *);
+
+template<>
+bool getLinkInterfaceDependentProperty(cmTarget *tgt,
+                                         const std::string prop,
+                                         const char *config, bool *)
+{
+  return tgt->GetLinkInterfaceDependentBoolProperty(prop, config);
+}
+
+template<>
+const char * getLinkInterfaceDependentProperty(cmTarget *tgt,
+                                                 const std::string prop,
+                                                 const char *config,
+                                                 const char **)
+{
+  return tgt->GetLinkInterfaceDependentStringProperty(prop, config);
+}
+
+//----------------------------------------------------------------------------
+template<typename PropertyType>
+void checkPropertyConsistency(cmTarget *depender, cmTarget *dependee,
+                              const char *propName,
+                              std::set<cmStdString> &emitted,
+                              const char *config,
+                              PropertyType *)
+{
+  const char *prop = dependee->GetProperty(propName);
+  if (!prop)
+    {
+    return;
+    }
+
+  std::vector<std::string> props;
+  cmSystemTools::ExpandListArgument(prop, props);
+
+  for(std::vector<std::string>::iterator pi = props.begin();
+      pi != props.end(); ++pi)
+    {
+    if (depender->GetMakefile()->GetCMakeInstance()
+                      ->GetIsPropertyDefined(pi->c_str(),
+                                              cmProperty::TARGET))
+      {
+      cmOStringStream e;
+      e << "Target \"" << dependee->GetName() << "\" has property \""
+        << *pi << "\" listed in its " << propName << " property.  "
+          "This is not allowed.  Only user-defined properties may appear "
+          "listed in the " << propName << " property.";
+      depender->GetMakefile()->IssueMessage(cmake::FATAL_ERROR, e.str());
+      return;
+      }
+    if(emitted.insert(*pi).second)
+      {
+      getLinkInterfaceDependentProperty<PropertyType>(depender, *pi, config,
+                                                      0);
+      if (cmSystemTools::GetErrorOccuredFlag())
+        {
+        return;
+        }
+      }
+    }
+}
+
 //----------------------------------------------------------------------------
 void cmTarget::CheckPropertyCompatibility(cmComputeLinkInformation *info,
                                           const char* config)
@@ -5365,38 +5634,20 @@ void cmTarget::CheckPropertyCompatibility(cmComputeLinkInformation *info,
       {
       continue;
       }
-    const char *prop = li->Target->GetProperty("COMPATIBLE_INTERFACE_BOOL");
-    if (!prop)
+
+    checkPropertyConsistency<bool>(this, li->Target,
+                                   "COMPATIBLE_INTERFACE_BOOL",
+                                   emitted, config, 0);
+    if (cmSystemTools::GetErrorOccuredFlag())
       {
-      continue;
+      return;
       }
-
-    std::vector<std::string> props;
-    cmSystemTools::ExpandListArgument(prop, props);
-
-    for(std::vector<std::string>::iterator pi = props.begin();
-        pi != props.end(); ++pi)
+    checkPropertyConsistency<const char *>(this, li->Target,
+                                           "COMPATIBLE_INTERFACE_STRING",
+                                           emitted, config, 0);
+    if (cmSystemTools::GetErrorOccuredFlag())
       {
-      if (this->Makefile->GetCMakeInstance()
-                        ->GetIsPropertyDefined(pi->c_str(),
-                                                cmProperty::TARGET))
-        {
-        cmOStringStream e;
-        e << "Target \"" << li->Target->GetName() << "\" has property \""
-          << *pi << "\" listed in its COMPATIBLE_INTERFACE_BOOL property.  "
-            "This is not allowed.  Only user-defined properties may appear "
-            "listed in the COMPATIBLE_INTERFACE_BOOL property.";
-        this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
-        return;
-        }
-      if(emitted.insert(*pi).second)
-        {
-        this->GetLinkInterfaceDependentBoolProperty(*pi, config);
-        if (cmSystemTools::GetErrorOccuredFlag())
-          {
-          return;
-          }
-        }
+      return;
       }
     }
 }
@@ -5422,14 +5673,14 @@ cmTarget::GetLinkInformation(const char* config, cmTarget *head)
       info = 0;
       }
 
+    // Store the information for this configuration.
+    cmTargetLinkInformationMap::value_type entry(key, info);
+    i = this->LinkInformation.insert(entry).first;
+
     if (info)
       {
       this->CheckPropertyCompatibility(info, config);
       }
-
-    // Store the information for this configuration.
-    cmTargetLinkInformationMap::value_type entry(key, info);
-    i = this->LinkInformation.insert(entry).first;
     }
   return i->second;
 }

+ 18 - 3
Source/cmTarget.h

@@ -102,6 +102,10 @@ public:
   cmPolicies::PolicyStatus GetPolicyStatusCMP0008() const
     { return this->PolicyStatusCMP0008; }
 
+  /** Get the status of policy CMP0020 when the target was created.  */
+  cmPolicies::PolicyStatus GetPolicyStatusCMP0020() const
+    { return this->PolicyStatusCMP0020; }
+
   /**
    * Get the list of the custom commands for this target
    */
@@ -426,6 +430,8 @@ public:
       If no macro should be defined null is returned.  */
   const char* GetExportMacro();
 
+  std::string GetCompileDefinitions(const char *config = 0);
+
   // Compute the set of languages compiled by the target.  This is
   // computed every time it is called because the languages can change
   // when source file properties are changed and we do not have enough
@@ -495,12 +501,22 @@ public:
   void GetLinkDependentTargetsForProperty(const std::string &p,
                                        std::set<std::string> &targets);
   bool IsNullImpliedByLinkLibraries(const std::string &p);
+  bool IsLinkInterfaceDependentBoolProperty(const std::string &p,
+                                            const char *config);
+  bool IsLinkInterfaceDependentStringProperty(const std::string &p,
+                                              const char *config);
 
   void AddLinkDependentTargetsForProperties(
           const std::map<cmStdString, cmStdString> &map);
 
   bool GetLinkInterfaceDependentBoolProperty(const std::string &p,
                                              const char *config);
+
+  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.
@@ -610,6 +626,7 @@ private:
   bool DLLPlatform;
   bool IsApple;
   bool IsImportedTarget;
+  bool DebugIncludesDone;
   mutable std::map<cmStdString, std::set<std::string> >
                                                       LinkDependentProperties;
   mutable std::set<std::string> LinkImplicitNullProperties;
@@ -645,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;
@@ -656,6 +670,7 @@ private:
   cmPolicies::PolicyStatus PolicyStatusCMP0003;
   cmPolicies::PolicyStatus PolicyStatusCMP0004;
   cmPolicies::PolicyStatus PolicyStatusCMP0008;
+  cmPolicies::PolicyStatus PolicyStatusCMP0020;
 
   // Internal representation details.
   friend class cmTargetInternals;

+ 25 - 14
Source/cmTargetCompileDefinitionsCommand.cxx

@@ -20,13 +20,11 @@ bool cmTargetCompileDefinitionsCommand
 }
 
 void cmTargetCompileDefinitionsCommand
-::HandleImportedTargetInvalidScope(const std::string &scope,
-                                   const std::string &tgt)
+::HandleImportedTarget(const std::string &tgt)
 {
   cmOStringStream e;
-  e << "Cannot specify " << scope << " compile definitions for imported "
-       "target \"" << tgt << "\".  Compile definitions can only be "
-       "specified for an imported target in the INTERFACE mode.";
+  e << "Cannot specify compile definitions for imported target \""
+    << tgt << "\".";
   this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
 }
 
@@ -39,19 +37,32 @@ void cmTargetCompileDefinitionsCommand
   this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
 }
 
-bool cmTargetCompileDefinitionsCommand
-::HandleNonTargetArg(std::string &content,
-                   const std::string &sep,
-                   const std::string &entry,
-                   const std::string &)
+//----------------------------------------------------------------------------
+std::string cmTargetCompileDefinitionsCommand
+::Join(const std::vector<std::string> &content)
 {
-  content += sep + entry;
-  return true;
+  std::string defs;
+  std::string sep;
+  for(std::vector<std::string>::const_iterator it = content.begin();
+    it != content.end(); ++it)
+    {
+    if (strncmp(it->c_str(), "-D", 2) == 0)
+      {
+      defs += sep + it->substr(2);
+      }
+    else
+      {
+      defs += sep + *it;
+      }
+    sep = ";";
+    }
+  return defs;
 }
 
+//----------------------------------------------------------------------------
 void cmTargetCompileDefinitionsCommand
-::HandleDirectContent(cmTarget *tgt, const std::string &content,
+::HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content,
                                    bool)
 {
-  tgt->AppendProperty("COMPILE_DEFINITIONS", content.c_str());
+  tgt->AppendProperty("COMPILE_DEFINITIONS", this->Join(content).c_str());
 }

+ 6 - 10
Source/cmTargetCompileDefinitionsCommand.h

@@ -59,7 +59,7 @@ public:
       "Specify compile definitions or targets to use when compiling a given "
       "target.  "
       "The named <target> must have been created by a command such as "
-      "add_executable or add_library.  "
+      "add_executable or add_library and must not be an IMPORTED target.  "
       "The INTERFACE, PUBLIC and PRIVATE keywords are required to specify "
       "the scope of the following arguments.  PRIVATE and PUBLIC items will "
       "populate the COMPILE_DEFINITIONS property of <target>.  PUBLIC and "
@@ -75,20 +75,16 @@ public:
       ;
     }
 
-  cmTypeMacro(cmTargetCompileDefinitionsCommand, cmCommand);
+  cmTypeMacro(cmTargetCompileDefinitionsCommand, cmTargetPropCommandBase);
 
 private:
-  virtual void HandleImportedTargetInvalidScope(const std::string &scope,
-                                   const std::string &tgt);
+  virtual void HandleImportedTarget(const std::string &tgt);
   virtual void HandleMissingTarget(const std::string &name);
 
-  virtual bool HandleNonTargetArg(std::string &content,
-                          const std::string &sep,
-                          const std::string &entry,
-                          const std::string &tgt);
-
-  virtual void HandleDirectContent(cmTarget *tgt, const std::string &content,
+  virtual void HandleDirectContent(cmTarget *tgt,
+                                   const std::vector<std::string> &content,
                                    bool prepend);
+  virtual std::string Join(const std::vector<std::string> &content);
 };
 
 #endif

+ 31 - 21
Source/cmTargetIncludeDirectoriesCommand.cxx

@@ -22,13 +22,11 @@ bool cmTargetIncludeDirectoriesCommand
 
 //----------------------------------------------------------------------------
 void cmTargetIncludeDirectoriesCommand
-::HandleImportedTargetInvalidScope(const std::string &tgt,
-                                   const std::string &scope)
+::HandleImportedTarget(const std::string &tgt)
 {
   cmOStringStream e;
-  e << "Cannot specify " << scope << " include directories for imported "
-       "target \"" << tgt << "\".  Include directories can only be "
-       "specified for an imported target in the INTERFACE mode.";
+  e << "Cannot specify include directories for imported target \""
+    << tgt << "\".";
   this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
 }
 
@@ -43,32 +41,44 @@ void cmTargetIncludeDirectoriesCommand
 }
 
 //----------------------------------------------------------------------------
-bool cmTargetIncludeDirectoriesCommand
-::HandleNonTargetArg(std::string &content,
-                   const std::string &sep,
-                   const std::string &entry,
-                   const std::string &tgt)
+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);
+}
+
+//----------------------------------------------------------------------------
+std::string cmTargetIncludeDirectoriesCommand
+::Join(const std::vector<std::string> &content)
 {
-  if (!cmSystemTools::FileIsFullPath(entry.c_str()))
+  std::string dirs;
+  std::string sep;
+  std::string prefix = this->Makefile->GetStartDirectory() + std::string("/");
+  for(std::vector<std::string>::const_iterator it = content.begin();
+    it != content.end(); ++it)
     {
-    cmOStringStream e;
-    e << "Cannot specify relative include directory \"" << entry << "\" for "
-         "target \"" << tgt << "\". Only absolute paths are permitted";
-    this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
-    return false;
+    if (cmSystemTools::FileIsFullPath(it->c_str())
+        || isGeneratorExpression(*it))
+      {
+      dirs += sep + *it;
+      }
+    else
+      {
+      dirs += sep + prefix + *it;
+      }
+    sep = ";";
     }
-
-  content += sep + entry;
-  return true;
+  return dirs;
 }
 
 //----------------------------------------------------------------------------
 void cmTargetIncludeDirectoriesCommand
-::HandleDirectContent(cmTarget *tgt, const std::string &content,
+::HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content,
                       bool prepend)
 {
   cmListFileBacktrace lfbt;
   this->Makefile->GetBacktrace(lfbt);
-  cmMakefileIncludeDirectoriesEntry entry(content, lfbt);
+  cmMakefileIncludeDirectoriesEntry entry(this->Join(content), lfbt);
   tgt->InsertInclude(entry, prepend);
 }

+ 6 - 10
Source/cmTargetIncludeDirectoriesCommand.h

@@ -60,7 +60,7 @@ public:
       "Specify include directories or targets to use when compiling a given "
       "target.  "
       "The named <target> must have been created by a command such as "
-      "add_executable or add_library.\n"
+      "add_executable or add_library and must not be an IMPORTED target.\n"
       "If BEFORE is specified, the content will be prepended to the property "
       "instead of being appended.\n"
       "The INTERFACE, PUBLIC and PRIVATE keywords are required to specify "
@@ -79,20 +79,16 @@ public:
       ;
     }
 
-  cmTypeMacro(cmTargetIncludeDirectoriesCommand, cmCommand);
+  cmTypeMacro(cmTargetIncludeDirectoriesCommand, cmTargetPropCommandBase);
 
 private:
-  virtual void HandleImportedTargetInvalidScope(const std::string &tgt,
-                                   const std::string &scope);
+  virtual void HandleImportedTarget(const std::string &tgt);
   virtual void HandleMissingTarget(const std::string &name);
 
-  virtual bool HandleNonTargetArg(std::string &content,
-                          const std::string &sep,
-                          const std::string &entry,
-                          const std::string &tgt);
-
-  virtual void HandleDirectContent(cmTarget *tgt, const std::string &content,
+  virtual void HandleDirectContent(cmTarget *tgt,
+                                   const std::vector<std::string> &content,
                                    bool prepend);
+  virtual std::string Join(const std::vector<std::string> &content);
 };
 
 #endif

+ 53 - 14
Source/cmTargetLinkLibrariesCommand.cxx

@@ -33,10 +33,6 @@ bool cmTargetLinkLibrariesCommand
   this->Target =
     this->Makefile->GetCMakeInstance()
     ->GetGlobalGenerator()->FindTarget(0, args[0].c_str());
-  if(!this->Target)
-    {
-    this->Target = this->Makefile->FindTargetToUse(args[0].c_str());
-    }
   if(!this->Target)
     {
     cmake::MessageType t = cmake::FATAL_ERROR;  // fail by default
@@ -253,24 +249,55 @@ cmTargetLinkLibrariesCommand
   this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
 }
 
+//----------------------------------------------------------------------------
+static std::string compileProperty(cmTarget *tgt, const std::string &lib,
+                                   bool isGenex,
+                                   const std::string &property,
+                                   cmTarget::LinkLibraryType llt)
+{
+  std::string value = !isGenex ? "$<LINKED:" + lib + ">"
+                               : "$<$<TARGET_DEFINED:" + lib + ">:" +
+                                   "$<TARGET_PROPERTY:" + lib +
+                                   ",INTERFACE_" + property + ">"
+                                 ">";
+
+  return tgt->GetDebugGeneratorExpressions(value, llt);
+}
+
+//----------------------------------------------------------------------------
+static bool isGeneratorExpression(const std::string &lib)
+{
+  const std::string::size_type openpos = lib.find("$<");
+  return (openpos != std::string::npos)
+      && (lib.find(">", openpos) != std::string::npos);
+}
+
 //----------------------------------------------------------------------------
 void
 cmTargetLinkLibrariesCommand::HandleLibrary(const char* lib,
                                             cmTarget::LinkLibraryType llt)
 {
+  const bool isGenex = isGeneratorExpression(lib);
+
+  cmsys::RegularExpression targetNameValidator;
+  targetNameValidator.compile("^[A-Za-z0-9_.:-]+$");
+  const bool potentialTargetName = targetNameValidator.find(lib);
+
+  if (potentialTargetName || isGenex)
+    {
+    this->Target->AppendProperty("INCLUDE_DIRECTORIES",
+                                 compileProperty(this->Target, lib,
+                                                 isGenex,
+                                      "INCLUDE_DIRECTORIES", llt).c_str());
+    this->Target->AppendProperty("COMPILE_DEFINITIONS",
+                                 compileProperty(this->Target, lib,
+                                                 isGenex,
+                                      "COMPILE_DEFINITIONS", llt).c_str());
+    }
+
   // Handle normal case first.
   if(this->CurrentProcessingState != ProcessingLinkInterface)
     {
-    if (this->Target->IsImported())
-      {
-      cmOStringStream e;
-      e << "Imported targets may only be used with the "
-          "LINK_INTERFACE_LIBRARIES specifier to target_link_libraries.";
-      this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
-      return;
-      }
-
-
     this->Makefile
       ->AddLinkLibraryForTarget(this->Target->GetName(), lib, llt);
     if (this->CurrentProcessingState != ProcessingPublicInterface)
@@ -280,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();

+ 12 - 1
Source/cmTargetLinkLibrariesCommand.h

@@ -93,7 +93,18 @@ public:
       "linked to this target will appear on the link line for the other "
       "target too.  "
       "See the LINK_INTERFACE_LIBRARIES target property to override the "
-      "set of transitive link dependencies for a target."
+      "set of transitive link dependencies for a target.  "
+      "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"

+ 8 - 17
Source/cmTargetPropCommandBase.cxx

@@ -80,17 +80,16 @@ bool cmTargetPropCommandBase
     return false;
     }
 
-  if(this->Target->IsImported() && scope != "INTERFACE")
+  if(this->Target->IsImported())
     {
-    this->HandleImportedTargetInvalidScope(args[0], scope);
+    this->HandleImportedTarget(args[0]);
     return false;
     }
 
   ++argIndex;
 
-  std::string content;
+  std::vector<std::string> content;
 
-  std::string sep;
   for(unsigned int i=argIndex; i < args.size(); ++i, ++argIndex)
     {
     if(args[i] == "PUBLIC"
@@ -100,16 +99,7 @@ bool cmTargetPropCommandBase
       this->PopulateTargetProperies(scope, content, prepend);
       return true;
       }
-    if (this->Makefile->FindTargetToUse(args[i].c_str()))
-      {
-      content += sep + "$<TARGET_PROPERTY:" + args[i]
-                      + ",INTERFACE_" + this->Property + ">";
-      }
-    else if (!this->HandleNonTargetArg(content, sep, args[i], args[0]))
-      {
-      return false;
-      }
-    sep = ";";
+    content.push_back(args[i]);
     }
   this->PopulateTargetProperies(scope, content, prepend);
   return true;
@@ -118,7 +108,8 @@ bool cmTargetPropCommandBase
 //----------------------------------------------------------------------------
 void cmTargetPropCommandBase
 ::PopulateTargetProperies(const std::string &scope,
-                          const std::string &content, bool prepend)
+                          const std::vector<std::string> &content,
+                          bool prepend)
 {
   if (scope == "PRIVATE" || scope == "PUBLIC")
     {
@@ -130,7 +121,7 @@ void cmTargetPropCommandBase
       {
       const std::string propName = std::string("INTERFACE_") + this->Property;
       const char *propValue = this->Target->GetProperty(propName.c_str());
-      const std::string totalContent = content + (propValue
+      const std::string totalContent = this->Join(content) + (propValue
                                                 ? std::string(";") + propValue
                                                 : std::string());
       this->Target->SetProperty(propName.c_str(), totalContent.c_str());
@@ -138,7 +129,7 @@ void cmTargetPropCommandBase
     else
       {
       this->Target->AppendProperty(("INTERFACE_" + this->Property).c_str(),
-                            content.c_str());
+                                   this->Join(content).c_str());
       }
     }
 }

+ 10 - 13
Source/cmTargetPropCommandBase.h

@@ -31,28 +31,25 @@ public:
   bool HandleArguments(std::vector<std::string> const& args,
                            const char *prop, ArgumentFlags flags = NO_FLAGS);
 
+  cmTypeMacro(cmTargetPropCommandBase, cmCommand);
+protected:
+  std::string Property;
+  cmTarget *Target;
+
 private:
-  virtual void HandleImportedTargetInvalidScope(const std::string &tgt,
-                                   const std::string &scope) = 0;
+  virtual void HandleImportedTarget(const std::string &tgt) = 0;
   virtual void HandleMissingTarget(const std::string &name) = 0;
 
-  virtual bool HandleNonTargetArg(std::string &content,
-                          const std::string &sep,
-                          const std::string &entry,
-                          const std::string &tgt) = 0;
-
   virtual void HandleDirectContent(cmTarget *tgt,
-                                   const std::string &content,
+                                   const std::vector<std::string> &content,
                                    bool prepend) = 0;
+  virtual std::string Join(const std::vector<std::string> &content) = 0;
 
   bool ProcessContentArgs(std::vector<std::string> const& args,
                           unsigned int &argIndex, bool prepend);
   void PopulateTargetProperies(const std::string &scope,
-                               const std::string &content, bool prepend);
-
-private:
-  cmTarget *Target;
-  std::string Property;
+                               const std::vector<std::string> &content,
+                               bool prepend);
 };
 
 #endif

+ 2 - 2
Source/cmVisualStudio10TargetGenerator.cxx

@@ -1221,8 +1221,8 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
   clOptions.Parse(flags.c_str());
   clOptions.Parse(defineFlags.c_str());
   clOptions.AddDefines(
-                     this->GeneratorTarget->GetCompileDefinitions().c_str());
-  clOptions.AddDefines(this->GeneratorTarget->GetCompileDefinitions(
+                     this->Target->GetCompileDefinitions().c_str());
+  clOptions.AddDefines(this->Target->GetCompileDefinitions(
                                                 configName.c_str()).c_str());
   clOptions.SetVerboseMakefile(
     this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE"));

+ 4 - 0
Source/cmake.cxx

@@ -4449,6 +4449,10 @@ void cmake::IssueMessage(cmake::MessageType t, std::string const& text,
     isError = true;
     msg << "CMake Internal Error (please report a bug)";
     }
+  else if(t == cmake::LOG)
+    {
+    msg << "CMake Debug Log";
+    }
   else
     {
     msg << "CMake Warning";

+ 52 - 0
Source/kwsys/DynamicLoader.cxx

@@ -428,6 +428,58 @@ const char* DynamicLoader::LastError()
 } // namespace KWSYS_NAMESPACE
 #endif
 
+#ifdef __MINT__
+#define DYNAMICLOADER_DEFINED 1
+#define _GNU_SOURCE /* for program_invocation_name */
+#include <string.h>
+#include <malloc.h>
+#include <errno.h>
+#include <dld.h>
+
+namespace KWSYS_NAMESPACE
+{
+
+//----------------------------------------------------------------------------
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(const char* libname )
+{
+  char *name = (char *)calloc(1, strlen(libname) + 1);
+  dld_init(program_invocation_name);
+  strncpy(name, libname, strlen(libname));
+  dld_link(libname);
+  return (void *)name;
+}
+
+//----------------------------------------------------------------------------
+int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
+{
+  dld_unlink_by_file((char *)lib, 0);
+  free(lib);
+  return 0;
+}
+
+//----------------------------------------------------------------------------
+DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
+  DynamicLoader::LibraryHandle lib, const char* sym)
+{
+  // Hack to cast pointer-to-data to pointer-to-function.
+  union
+  {
+    void* pvoid;
+    DynamicLoader::SymbolPointer psym;
+  } result;
+  result.pvoid = dld_get_symbol(sym);
+  return result.psym;
+}
+
+//----------------------------------------------------------------------------
+const char* DynamicLoader::LastError()
+{
+  return dld_strerror(dld_errno);
+}
+
+} // namespace KWSYS_NAMESPACE
+#endif
+
 // ---------------------------------------------------------------
 // 6. Implementation for default UNIX machines.
 // if nothing has been defined then use this

+ 1 - 1
Source/kwsys/Glob.cxx

@@ -399,7 +399,7 @@ bool Glob::FindFiles(const kwsys_stl::string& inexpr)
   if ( last_slash > 0 )
     {
     //kwsys_ios::cout << "I can skip: " << fexpr.substr(0, last_slash)
-    //<< kwsys_ios::endl;
+    // << kwsys_ios::endl;
     skip = last_slash;
     }
   if ( skip == 0 )

+ 1 - 0
Source/kwsys/IOStream.cxx

@@ -272,6 +272,7 @@ namespace KWSYS_NAMESPACE
 
 // Create one public symbol in this object file to avoid warnings from
 // archivers.
+void IOStreamSymbolToAvoidWarning();
 void IOStreamSymbolToAvoidWarning()
 {
 }

+ 1 - 1
Source/kwsys/ProcessUNIX.c

@@ -102,7 +102,7 @@ static inline void kwsysProcess_usleep(unsigned int msec)
  * pipes' file handles to be non-blocking and just poll them directly
  * without select().
  */
-#if !defined(__BEOS__) && !defined(__VMS)
+#if !defined(__BEOS__) && !defined(__VMS) && !defined(__MINT__)
 # define KWSYSPE_USE_SELECT 1
 #endif
 

+ 4 - 1
Source/kwsys/SystemInformation.cxx

@@ -2466,7 +2466,9 @@ bool SystemInformationImplementation::RetrieveCPUPowerManagement()
 #endif
 }
 
-void SystemInformationStripLeadingSpace(kwsys_stl::string& str)
+#if USE_CPUID
+// Used only in USE_CPUID implementation below.
+static void SystemInformationStripLeadingSpace(kwsys_stl::string& str)
 {
   // Because some manufacturers have leading white space - we have to post-process the name.
   kwsys_stl::string::size_type pos = str.find_first_not_of(" ");
@@ -2475,6 +2477,7 @@ void SystemInformationStripLeadingSpace(kwsys_stl::string& str)
     str = str.substr(pos);
     }
 }
+#endif
 
 /** */
 bool SystemInformationImplementation::RetrieveExtendedCPUIdentity()

+ 2 - 2
Source/kwsys/SystemTools.cxx

@@ -3037,7 +3037,7 @@ void SystemTools::CheckTranslationPath(kwsys_stl::string & path)
   path.erase(path.end()-1, path.end());
 }
 
-void
+static void
 SystemToolsAppendComponents(
   kwsys_stl::vector<kwsys_stl::string>& out_components,
   kwsys_stl::vector<kwsys_stl::string>::const_iterator first,
@@ -4704,7 +4704,7 @@ bool SystemTools::ParseURL( const kwsys_stl::string& URL,
 // ----------------------------------------------------------------------
 // These must NOT be initialized.  Default initialization to zero is
 // necessary.
-unsigned int SystemToolsManagerCount;
+static unsigned int SystemToolsManagerCount;
 SystemToolsTranslationMap *SystemTools::TranslationMap;
 SystemToolsTranslationMap *SystemTools::LongPathMap;
 #ifdef __CYGWIN__

+ 8 - 8
Source/kwsys/testCommandLineArguments.cxx

@@ -24,9 +24,9 @@
 #include <stddef.h> /* size_t */
 #include <string.h> /* strcmp */
 
-void* random_ptr = reinterpret_cast<void*>(0x123);
+static void* random_ptr = reinterpret_cast<void*>(0x123);
 
-int argument(const char* arg, const char* value, void* call_data)
+static int argument(const char* arg, const char* value, void* call_data)
 {
   kwsys_ios::cout << "Got argument: \"" << arg << "\" value: \"" << (value?value:"(null)") << "\"" << kwsys_ios::endl;
   if ( call_data != random_ptr )
@@ -37,7 +37,7 @@ int argument(const char* arg, const char* value, void* call_data)
   return 1;
 }
 
-int unknown_argument(const char* argument, void* call_data)
+static int unknown_argument(const char* argument, void* call_data)
 {
   kwsys_ios::cout << "Got unknown argument: \"" << argument << "\"" << kwsys_ios::endl;
   if ( call_data != random_ptr )
@@ -48,12 +48,12 @@ int unknown_argument(const char* argument, void* call_data)
   return 1;
 }
 
-bool CompareTwoItemsOnList(bool i1, bool i2) { return i1 == i2; }
-bool CompareTwoItemsOnList(int i1, int i2) { return i1 == i2; }
-bool CompareTwoItemsOnList(double i1, double i2) { return i1 == i2; }
-bool CompareTwoItemsOnList(const char* i1,
+static bool CompareTwoItemsOnList(bool i1, bool i2) { return i1 == i2; }
+static bool CompareTwoItemsOnList(int i1, int i2) { return i1 == i2; }
+static bool CompareTwoItemsOnList(double i1, double i2) { return i1 == i2; }
+static bool CompareTwoItemsOnList(const char* i1,
   const char* i2) { return strcmp(i1, i2) == 0; }
-bool CompareTwoItemsOnList(const kwsys_stl::string& i1,
+static bool CompareTwoItemsOnList(const kwsys_stl::string& i1,
   const kwsys_stl::string& i2) { return i1 == i2; }
 
 int testCommandLineArguments(int argc, char* argv[])

+ 1 - 1
Source/kwsys/testDynamicLoader.cxx

@@ -35,7 +35,7 @@
 // left on disk.
 #include <testSystemTools.h>
 
-kwsys_stl::string GetLibName(const char* lname)
+static kwsys_stl::string GetLibName(const char* lname)
 {
   // Construct proper name of lib
   kwsys_stl::string slname;

+ 11 - 11
Source/kwsys/testProcess.c

@@ -47,7 +47,7 @@ int runChild(const char* cmd[], int state, int exception, int value,
              int share, int output, int delay, double timeout, int poll,
              int repeat, int disown);
 
-int test1(int argc, const char* argv[])
+static int test1(int argc, const char* argv[])
 {
   (void)argc; (void)argv;
   fprintf(stdout, "Output on stdout from test returning 0.\n");
@@ -55,7 +55,7 @@ int test1(int argc, const char* argv[])
   return 0;
 }
 
-int test2(int argc, const char* argv[])
+static int test2(int argc, const char* argv[])
 {
   (void)argc; (void)argv;
   fprintf(stdout, "Output on stdout from test returning 123.\n");
@@ -63,7 +63,7 @@ int test2(int argc, const char* argv[])
   return 123;
 }
 
-int test3(int argc, const char* argv[])
+static int test3(int argc, const char* argv[])
 {
   (void)argc; (void)argv;
   fprintf(stdout, "Output before sleep on stdout from timeout test.\n");
@@ -80,7 +80,7 @@ int test3(int argc, const char* argv[])
   return 0;
 }
 
-int test4(int argc, const char* argv[])
+static int test4(int argc, const char* argv[])
 {
   /* Prepare a pointer to an invalid address.  Don't use null, because
   dereferencing null is undefined behaviour and compilers are free to
@@ -109,7 +109,7 @@ int test4(int argc, const char* argv[])
   return 0;
 }
 
-int test5(int argc, const char* argv[])
+static int test5(int argc, const char* argv[])
 {
   int r;
   const char* cmd[4];
@@ -132,7 +132,7 @@ int test5(int argc, const char* argv[])
 }
 
 #define TEST6_SIZE (4096*2)
-void test6(int argc, const char* argv[])
+static void test6(int argc, const char* argv[])
 {
   int i;
   char runaway[TEST6_SIZE+1];
@@ -156,7 +156,7 @@ void test6(int argc, const char* argv[])
    delaying 1/10th of a second should ever have to poll.  */
 #define MINPOLL 5
 #define MAXPOLL 20
-int test7(int argc, const char* argv[])
+static int test7(int argc, const char* argv[])
 {
   (void)argc; (void)argv;
   fprintf(stdout, "Output on stdout before sleep.\n");
@@ -176,7 +176,7 @@ int test7(int argc, const char* argv[])
   return 0;
 }
 
-int test8(int argc, const char* argv[])
+static int test8(int argc, const char* argv[])
 {
   /* Create a disowned grandchild to test handling of processes
      that exit before their children.  */
@@ -200,7 +200,7 @@ int test8(int argc, const char* argv[])
   return r;
 }
 
-int test8_grandchild(int argc, const char* argv[])
+static int test8_grandchild(int argc, const char* argv[])
 {
   (void)argc; (void)argv;
   fprintf(stdout, "Output on stdout from grandchild before sleep.\n");
@@ -221,7 +221,7 @@ int test8_grandchild(int argc, const char* argv[])
   return 0;
 }
 
-int runChild2(kwsysProcess* kp,
+static int runChild2(kwsysProcess* kp,
               const char* cmd[], int state, int exception, int value,
               int share, int output, int delay, double timeout,
               int poll, int disown)
@@ -505,7 +505,7 @@ int main(int argc, const char* argv[])
     fprintf(stderr, "Output on stderr after test %d.\n", n);
     fflush(stdout);
     fflush(stderr);
-#if _WIN32
+#if defined(_WIN32)
     if(argv0) { free(argv0); }
 #endif
     return r;

+ 13 - 13
Source/kwsys/testSystemTools.cxx

@@ -32,7 +32,7 @@
 #include <string.h> /* strcmp */
 
 //----------------------------------------------------------------------------
-const char* toUnixPaths[][2] =
+static const char* toUnixPaths[][2] =
 {
     { "/usr/local/bin/passwd", "/usr/local/bin/passwd" },
     { "/usr/lo cal/bin/pa sswd", "/usr/lo cal/bin/pa sswd" },
@@ -52,8 +52,8 @@ const char* toUnixPaths[][2] =
     {0, 0}
 };
 
-bool CheckConvertToUnixSlashes(kwsys_stl::string input,
-                               kwsys_stl::string output)
+static bool CheckConvertToUnixSlashes(kwsys_stl::string input,
+                                      kwsys_stl::string output)
 {
   kwsys_stl::string result = input;
   kwsys::SystemTools::ConvertToUnixSlashes(result);
@@ -69,17 +69,17 @@ bool CheckConvertToUnixSlashes(kwsys_stl::string input,
 }
 
 //----------------------------------------------------------------------------
-const char* checkEscapeChars[][4] =
+static const char* checkEscapeChars[][4] =
 {
   { "1 foo 2 bar 2", "12", "\\", "\\1 foo \\2 bar \\2"},
   { " {} ", "{}", "#", " #{#} "},
   {0, 0, 0, 0}
 };
 
-bool CheckEscapeChars(kwsys_stl::string input,
-                      const char *chars_to_escape,
-                      char escape_char,
-                      kwsys_stl::string output)
+static bool CheckEscapeChars(kwsys_stl::string input,
+                             const char *chars_to_escape,
+                             char escape_char,
+                             kwsys_stl::string output)
 {
   kwsys_stl::string result = kwsys::SystemTools::EscapeChars(
     input.c_str(), chars_to_escape, escape_char);
@@ -95,7 +95,7 @@ bool CheckEscapeChars(kwsys_stl::string input,
 }
 
 //----------------------------------------------------------------------------
-bool CheckFileOperations()
+static bool CheckFileOperations()
 {
   bool res = true;
 
@@ -129,7 +129,7 @@ bool CheckFileOperations()
 }
 
 //----------------------------------------------------------------------------
-bool CheckStringOperations()
+static bool CheckStringOperations()
 {
   bool res = true;
 
@@ -329,7 +329,7 @@ bool CheckStringOperations()
 
 //----------------------------------------------------------------------------
 
-bool CheckPutEnv(const char* env, const char* name, const char* value)
+static bool CheckPutEnv(const char* env, const char* name, const char* value)
 {
   if(!kwsys::SystemTools::PutEnv(env))
     {
@@ -348,7 +348,7 @@ bool CheckPutEnv(const char* env, const char* name, const char* value)
   return true;
 }
 
-bool CheckUnPutEnv(const char* env, const char* name)
+static bool CheckUnPutEnv(const char* env, const char* name)
 {
   if(!kwsys::SystemTools::UnPutEnv(env))
     {
@@ -365,7 +365,7 @@ bool CheckUnPutEnv(const char* env, const char* name)
   return true;
 }
 
-bool CheckEnvironmentOperations()
+static bool CheckEnvironmentOperations()
 {
   bool res = true;
   res &= CheckPutEnv("A=B", "A", "B");

+ 9 - 7
Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt

@@ -12,17 +12,19 @@ target_compile_definitions(target_compile_definitions
   INTERFACE MY_INTERFACE_DEFINE
 )
 
-add_library(importedlib UNKNOWN IMPORTED)
-target_compile_definitions(importedlib
-  INTERFACE MY_IMPORTEDINTERFACE_DEFINE
-)
-
 add_executable(consumer
   "${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp"
 )
 
+add_library(linked UNKNOWN IMPORTED)
+set_property(TARGET linked PROPERTY
+  INTERFACE_COMPILE_DEFINITIONS "MY_LINKED_DEFINE")
+
+
 target_compile_definitions(consumer
-  PRIVATE target_compile_definitions importedlib
+  PRIVATE $<TARGET_PROPERTY:target_compile_definitions,INTERFACE_COMPILE_DEFINITIONS>
   $<$<TARGET_DEFINED:notdefined>:SHOULD_NOT_BE_DEFINED>
-  $<$<TARGET_DEFINED:importedlib>:SHOULD_BE_DEFINED>
+  $<$<TARGET_DEFINED:target_compile_definitions>:SHOULD_BE_DEFINED>
+  $<LINKED:linked>
+  -DDASH_D_DEFINE
 )

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

@@ -11,10 +11,6 @@
 #error Expected MY_INTERFACE_DEFINE
 #endif
 
-#ifndef MY_IMPORTEDINTERFACE_DEFINE
-#error Expected MY_IMPORTEDINTERFACE_DEFINE
-#endif
-
 #ifdef SHOULD_NOT_BE_DEFINED
 #error Unexpected SHOULD_NOT_BE_DEFINED
 #endif
@@ -23,4 +19,12 @@
 #error Expected SHOULD_BE_DEFINED
 #endif
 
+#ifndef DASH_D_DEFINE
+#error Expected DASH_D_DEFINE
+#endif
+
+#ifndef MY_LINKED_DEFINE
+#error Expected MY_LINKED_DEFINE
+#endif
+
 int main() { return 0; }

+ 15 - 8
Tests/CMakeCommands/target_include_directories/CMakeLists.txt

@@ -11,15 +11,15 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/publicinclude/publicinclude.h" "#define
 file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/interfaceinclude")
 file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/interfaceinclude/interfaceinclude.h" "#define INTERFACEINCLUDE_DEFINE\n")
 
-file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/importedinterfaceinclude")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/importedinterfaceinclude/importedinterfaceinclude.h" "#define IMPORTEDINTERFACEINCLUDE_DEFINE\n")
-
 file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/poison")
 file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/poison/common.h" "#error Should not be included\n")
 
 file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/cure")
 file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cure/common.h" "#define CURE_DEFINE\n")
 
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/linkedinclude")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/linkedinclude/linkedinclude.h" "#define LINKEDINCLUDE_DEFINE\n")
+
 add_executable(target_include_directories
   "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
 )
@@ -33,18 +33,25 @@ target_include_directories(target_include_directories
   PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/poison"
 )
 target_include_directories(target_include_directories
-  BEFORE PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/cure"
+  BEFORE PUBLIC "$<$<TARGET_DEFINED:target_include_directories>:${CMAKE_CURRENT_BINARY_DIR}/cure>"
 )
 
-add_library(importedlib UNKNOWN IMPORTED)
-target_include_directories(importedlib
-  INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/importedinterfaceinclude"
+# Has no effect because the target is not defined:
+target_include_directories(target_include_directories
+  BEFORE PUBLIC "$<$<TARGET_DEFINED:notdefined>:${CMAKE_CURRENT_BINARY_DIR}/poison>"
 )
 
 add_executable(consumer
   "${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp"
 )
 
+add_library(linked UNKNOWN IMPORTED)
+set_property(TARGET linked PROPERTY
+  INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/linkedinclude")
+
 target_include_directories(consumer
-  PRIVATE target_include_directories importedlib
+  PRIVATE
+    $<TARGET_PROPERTY:target_include_directories,INTERFACE_INCLUDE_DIRECTORIES>
+    $<LINKED:linked>
+  relative_dir
 )

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

@@ -2,7 +2,8 @@
 #include "common.h"
 #include "publicinclude.h"
 #include "interfaceinclude.h"
-#include "importedinterfaceinclude.h"
+#include "relative_dir.h"
+#include "linkedinclude.h"
 
 #ifdef PRIVATEINCLUDE_DEFINE
 #error Unexpected PRIVATEINCLUDE_DEFINE
@@ -16,12 +17,16 @@
 #error Expected INTERFACEINCLUDE_DEFINE
 #endif
 
-#ifndef IMPORTEDINTERFACEINCLUDE_DEFINE
-#error Expected IMPORTEDINTERFACEINCLUDE_DEFINE
-#endif
-
 #ifndef CURE_DEFINE
 #error Expected CURE_DEFINE
 #endif
 
+#ifndef RELATIVE_DIR_DEFINE
+#error Expected RELATIVE_DIR_DEFINE
+#endif
+
+#ifndef LINKEDINCLUDE_DEFINE
+#error Expected LINKEDINCLUDE_DEFINE
+#endif
+
 int main() { return 0; }

+ 2 - 0
Tests/CMakeCommands/target_include_directories/relative_dir/relative_dir.h

@@ -0,0 +1,2 @@
+
+#define RELATIVE_DIR_DEFINE

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

@@ -29,9 +29,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
 add_library(depA SHARED depA.cpp)
 generate_export_header(depA)
 
-add_library(importedlib UNKNOWN IMPORTED)
-target_link_libraries(importedlib LINK_INTERFACE_LIBRARIES depA)
-
 add_library(depB SHARED depB.cpp)
 generate_export_header(depB)
 
@@ -65,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)
 
@@ -90,3 +83,24 @@ set_property(TARGET depD APPEND PROPERTY
 
 add_executable(targetB targetB.cpp)
 target_link_libraries(targetB depD)
+
+macro(create_header _name)
+  file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${_name}")
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_name}/${_name}.h" "//${_name}.h\n")
+endmacro()
+
+create_header(foo)
+create_header(bar)
+
+add_library(depG SHARED depG.cpp)
+generate_export_header(depG)
+target_include_directories(depG INTERFACE
+    "${CMAKE_CURRENT_BINARY_DIR}/foo"
+    "${CMAKE_CURRENT_BINARY_DIR}/bar"
+)
+target_compile_definitions(depG INTERFACE
+    TEST_DEF
+)
+
+add_executable(targetC targetC.cpp)
+target_link_libraries(targetC depG)

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

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

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

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

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

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

+ 15 - 0
Tests/CMakeLists.txt

@@ -216,6 +216,7 @@ if(BUILD_TESTING)
   ADD_TEST_MACRO(PolicyScope PolicyScope)
   ADD_TEST_MACRO(EmptyLibrary EmptyLibrary)
   ADD_TEST_MACRO(CompileDefinitions CompileDefinitions)
+  ADD_TEST_MACRO(CompatibleInterface CompatibleInterface)
   set_tests_properties(EmptyLibrary PROPERTIES
     PASS_REGULAR_EXPRESSION "CMake Error: CMake can not determine linker language for target:test")
   ADD_TEST_MACRO(CrossCompile CrossCompile)
@@ -311,6 +312,19 @@ if(BUILD_TESTING)
 
   ADD_TEST_MACRO(Module.CheckTypeSize CheckTypeSize)
 
+  add_test(Module.ExternalData ${CMAKE_CTEST_COMMAND}
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/Module/ExternalData"
+    "${CMake_BINARY_DIR}/Tests/Module/ExternalData"
+    --build-generator ${CMAKE_TEST_GENERATOR}
+    --build-project ExternalDataTest
+    --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
+    --build-noclean
+    --force-new-ctest-process
+    --test-command ${CMAKE_CTEST_COMMAND} -C \${CTEST_CONFIGURATION_TYPE} -V
+    )
+  list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Module/ExternalData")
+
   ADD_TEST_MACRO(Module.GenerateExportHeader GenerateExportHeader)
 
   if (APPLE OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
@@ -1976,6 +1990,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
     --output-log "${CMake_BINARY_DIR}/Tests/CTestTestParallel/testOutput.log"
     )
 
+  set(CTestLimitDashJ_EXTRA_OPTIONS --force-new-ctest-process)
   add_test_macro(CTestLimitDashJ ${CMAKE_CTEST_COMMAND} -j 4
     --output-on-failure -C "\${CTestTest_CONFIG}")
 

+ 3 - 2
Tests/CMakeTests/CMakeLists.txt

@@ -4,7 +4,8 @@ set(CMAKE_EXECUTABLE "${CMake_BIN_DIR}/cmake")
 macro(AddCMakeTest TestName PreArgs)
   configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${TestName}Test.cmake.in"
     "${CMAKE_CURRENT_BINARY_DIR}/${TestName}Test.cmake" @ONLY IMMEDIATE)
-  add_test(CMake.${TestName} ${CMAKE_EXECUTABLE} ${PreArgs}
+  add_test(NAME CMake.${TestName}
+    COMMAND ${CMAKE_EXECUTABLE} ${PreArgs}
     -P "${CMAKE_CURRENT_BINARY_DIR}/${TestName}Test.cmake" ${ARGN})
 endmacro()
 
@@ -28,7 +29,7 @@ AddCMakeTest(String "")
 AddCMakeTest(Math "")
 AddCMakeTest(CMakeMinimumRequired "")
 AddCMakeTest(CompilerIdVendor "")
-AddCMakeTest(ProcessorCount "")
+AddCMakeTest(ProcessorCount "-DKWSYS_TEST_EXE=$<TARGET_FILE:cmsysTestsCxx>")
 AddCMakeTest(PushCheckState "")
 AddCMakeTest(While "")
 

+ 9 - 2
Tests/CMakeTests/ProcessorCountTest.cmake.in

@@ -9,10 +9,17 @@ message("### 3. ProcessorCount(...) function call is emitting output that it sho
 message("processor_count='${processor_count}'")
 
 execute_process(
-  COMMAND "@CMAKE_BINARY_DIR@/Source/kwsys/$ENV{CMAKE_CONFIG_TYPE}/cmsysTestsCxx"
+  COMMAND "${KWSYS_TEST_EXE}"
   testSystemInformation
   OUTPUT_VARIABLE tsi_out
-  ERROR_VARIABLE tsi_err)
+  ERROR_VARIABLE tsi_err
+  RESULT_VARIABLE tsi_res
+)
+if (tsi_res)
+  message("executing \"${KWSYS_TEST_EXE}\" failed")
+  message(FATAL_ERROR "output: ${tsi_res}")
+endif ()
+
 string(REGEX REPLACE "(.*)GetNumberOfPhysicalCPU:.([0-9]*)(.*)" "\\2"
   system_info_processor_count "${tsi_out}")
 

+ 69 - 0
Tests/CompatibleInterface/CMakeLists.txt

@@ -0,0 +1,69 @@
+
+cmake_minimum_required(VERSION 2.8)
+
+project(CompatibleInterface)
+
+include(GenerateExportHeader)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+add_library(iface1 empty.cpp)
+set_property(TARGET iface1 APPEND PROPERTY
+  COMPATIBLE_INTERFACE_BOOL
+    BOOL_PROP1
+    BOOL_PROP2
+    BOOL_PROP3
+    BOOL_PROP4
+)
+set_property(TARGET iface1 APPEND PROPERTY
+  COMPATIBLE_INTERFACE_STRING
+    STRING_PROP1
+    STRING_PROP2
+    STRING_PROP3
+)
+
+set_property(TARGET iface1 PROPERTY INTERFACE_BOOL_PROP1 ON)
+set_property(TARGET iface1 PROPERTY INTERFACE_BOOL_PROP2 ON)
+set_property(TARGET iface1 PROPERTY INTERFACE_STRING_PROP1 prop1)
+set_property(TARGET iface1 PROPERTY INTERFACE_STRING_PROP2 prop2)
+
+add_executable(CompatibleInterface main.cpp)
+target_link_libraries(CompatibleInterface iface1)
+
+set_property(TARGET CompatibleInterface PROPERTY BOOL_PROP2 ON)
+set_property(TARGET CompatibleInterface PROPERTY BOOL_PROP3 ON)
+set_property(TARGET CompatibleInterface PROPERTY STRING_PROP2 prop2)
+set_property(TARGET CompatibleInterface PROPERTY STRING_PROP3 prop3)
+
+target_compile_definitions(CompatibleInterface
+  PRIVATE
+    $<$<BOOL:$<TARGET_PROPERTY:BOOL_PROP1>>:BOOL_PROP1>
+    $<$<BOOL:$<TARGET_PROPERTY:BOOL_PROP2>>:BOOL_PROP2>
+    $<$<BOOL:$<TARGET_PROPERTY:BOOL_PROP3>>:BOOL_PROP3>
+    $<$<STREQUAL:$<TARGET_PROPERTY:STRING_PROP1>,prop1>:STRING_PROP1>
+    $<$<STREQUAL:$<TARGET_PROPERTY:STRING_PROP2>,prop2>:STRING_PROP2>
+    $<$<STREQUAL:$<TARGET_PROPERTY:STRING_PROP3>,prop3>:STRING_PROP3>
+)
+
+
+add_library(iface2 SHARED iface2.cpp)
+generate_export_header(iface2)
+
+set_property(TARGET iface2 APPEND PROPERTY
+  COMPATIBLE_INTERFACE_STRING
+    Iface2_PROP
+)
+
+# For the LINK_LIBRARIES and related properties, we should not evaluate
+# properties defined only in the interface - they should be implicitly zero
+set_property(TARGET iface2
+  APPEND PROPERTY
+    LINK_INTERFACE_LIBRARIES $<$<BOOL:$<TARGET_PROPERTY:BOOL_PROP4>>:nonexistant>
+)
+target_link_libraries(CompatibleInterface iface2
+      $<$<BOOL:$<TARGET_PROPERTY:Iface2_PROP>>:nonexistant>
+)
+# Test that this does not segfault:
+target_compile_definitions(CompatibleInterface
+  PRIVATE
+    $<$<BOOL:$<TARGET_PROPERTY:Iface2_PROP>>:SOME_DEFINE>
+)

+ 1 - 0
Tests/CompatibleInterface/empty.cpp

@@ -0,0 +1 @@
+// no content

+ 7 - 0
Tests/CompatibleInterface/iface2.cpp

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

+ 13 - 0
Tests/CompatibleInterface/iface2.h

@@ -0,0 +1,13 @@
+
+#ifndef IFACE2_H
+#define IFACE2_H
+
+#include "iface2_export.h"
+
+class IFACE2_EXPORT Iface2
+{
+public:
+  int foo();
+};
+
+#endif

+ 32 - 0
Tests/CompatibleInterface/main.cpp

@@ -0,0 +1,32 @@
+
+#ifndef BOOL_PROP1
+#error Expected BOOL_PROP1
+#endif
+
+#ifndef BOOL_PROP2
+#error Expected BOOL_PROP2
+#endif
+
+#ifndef BOOL_PROP3
+#error Expected BOOL_PROP3
+#endif
+
+#ifndef STRING_PROP1
+#error Expected STRING_PROP1
+#endif
+
+#ifndef STRING_PROP2
+#error Expected STRING_PROP2
+#endif
+
+#ifndef STRING_PROP3
+#error Expected STRING_PROP3
+#endif
+
+#include "iface2.h"
+
+int main(int argc, char **argv)
+{
+  Iface2 if2;
+  return if2.foo();
+}

+ 56 - 20
Tests/ExportImport/Export/CMakeLists.txt

@@ -90,32 +90,23 @@ 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")
   add_library(${_libName} "${CMAKE_CURRENT_BINARY_DIR}/${_libName}.c")
   file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${_libName}")
   set_property(TARGET ${_libName} APPEND PROPERTY
-      INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/${_libName}")
+      INTERFACE_INCLUDE_DIRECTORIES
+        "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/${_libName}>"
+        "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include/${_libName}>"
+      )
   if (NOT "${ARGV1}" STREQUAL "NO_HEADER")
       file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_libName}/${_libName}.h" "// no content\n")
+      install(FILES
+        "${CMAKE_CURRENT_BINARY_DIR}/${_libName}/${_libName}.h"
+          DESTINATION include/${_libName}
+      )
   endif()
 endmacro()
 
@@ -129,6 +120,10 @@ add_include_lib(testLibIncludeRequired3 NO_HEADER)
 # but we are testing that the INSTALL_INTERFACE causes it not to be used
 # at build time.
 file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/testLibIncludeRequired3/testLibIncludeRequired4.h" "#error Should not be included\n")
+install(FILES
+  "${CMAKE_CURRENT_BINARY_DIR}/testLibIncludeRequired3/testLibIncludeRequired4.h"
+    DESTINATION include/testLibIncludeRequired3
+)
 add_include_lib(testLibIncludeRequired4)
 add_include_lib(testLibIncludeRequired5 NO_HEADER)
 # Generate testLibIncludeRequired6 in the testLibIncludeRequired5 directory
@@ -139,6 +134,10 @@ add_include_lib(testLibIncludeRequired5 NO_HEADER)
 # the Import side of this unit test, the '6' include from the '5' directory
 # will not be used because it is in the BUILD_INTERFACE only.
 file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/testLibIncludeRequired5/testLibIncludeRequired6.h" "#error Should not be included\n")
+install(FILES
+  "${CMAKE_CURRENT_BINARY_DIR}/testLibIncludeRequired5/testLibIncludeRequired6.h"
+    DESTINATION include/testLibIncludeRequired5
+)
 add_include_lib(testLibIncludeRequired6)
 
 set_property(TARGET testLibRequired APPEND PROPERTY
@@ -149,6 +148,8 @@ set_property(TARGET testLibRequired APPEND PROPERTY
     $<BUILD_INTERFACE:$<TARGET_PROPERTY:testLibIncludeRequired4,INTERFACE_INCLUDE_DIRECTORIES>>
     $<BUILD_INTERFACE:$<TARGET_PROPERTY:testLibIncludeRequired5,INTERFACE_INCLUDE_DIRECTORIES>>
     $<INSTALL_INTERFACE:$<TARGET_PROPERTY:testLibIncludeRequired6,INTERFACE_INCLUDE_DIRECTORIES>>
+    # Test that the below is non-fatal
+    $<$<TARGET_DEFINED:not_a_target>:$<TARGET_PROPERTY:not_a_target,INTERFACE_INCLUDE_DIRECTORIES>>
 )
 
 set_property(TARGET testLibRequired APPEND PROPERTY
@@ -173,6 +174,22 @@ set_property(TARGET testSharedLibRequired APPEND PROPERTY
   INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}"
                                 "${CMAKE_CURRENT_SOURCE_DIR}"
 )
+set_property(TARGET testSharedLibRequired
+  APPEND PROPERTY
+    COMPATIBLE_INTERFACE_BOOL CUSTOM_PROP
+)
+set_property(TARGET testSharedLibRequired
+  PROPERTY
+    INTERFACE_CUSTOM_PROP ON
+)
+set_property(TARGET testSharedLibRequired
+  APPEND PROPERTY
+    COMPATIBLE_INTERFACE_STRING CUSTOM_STRING
+)
+set_property(TARGET testSharedLibRequired
+  PROPERTY
+    INTERFACE_CUSTOM_STRING testcontent
+)
 
 add_library(testSharedLibDepends SHARED testSharedLibDepends.cpp)
 set_property(TARGET testSharedLibDepends APPEND PROPERTY
@@ -201,11 +218,30 @@ install(TARGETS testLibRequired
                 testLibIncludeRequired6
                 testSharedLibRequired
         EXPORT RequiredExp DESTINATION lib )
-install(EXPORT RequiredExp NAMESPACE Req:: FILE testLibRequiredConfig.cmake DESTINATION lib/cmake/testLibRequired)
+install(EXPORT RequiredExp NAMESPACE Req:: FILE testLibRequiredTargets.cmake DESTINATION lib/cmake/testLibRequired)
 
 install(TARGETS testLibDepends testSharedLibDepends EXPORT DependsExp DESTINATION lib )
-install(EXPORT DependsExp FILE testLibDependsConfig.cmake DESTINATION lib/cmake/testLibDepends)
+install(EXPORT DependsExp FILE testLibDependsTargets.cmake DESTINATION lib/cmake/testLibDepends)
 
+file(WRITE
+  "${CMAKE_CURRENT_BINARY_DIR}/testLibRequiredConfig.cmake"
+  "
+if(\${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION VERSION_LESS 2.3 AND NOT \${CMAKE_FIND_PACKAGE_NAME}_INTERFACES)
+  set(\${CMAKE_FIND_PACKAGE_NAME}_NO_INTERFACES 1)
+endif()
+include(\"\${CMAKE_CURRENT_LIST_DIR}/testLibRequiredTargets.cmake\")
+set(\${CMAKE_FIND_PACKAGE_NAME}_INCLUDE_DIRS \"${CMAKE_CURRENT_BINARY_DIR}\" \"${CMAKE_CURRENT_SOURCE_DIR}\" )
+"
+)
+
+include(CMakePackageConfigHelpers)
+write_basic_package_version_file( testLibRequiredConfigVersion.cmake VERSION 2.5 COMPATIBILITY AnyNewerVersion)
+
+install(FILES
+  "${CMAKE_CURRENT_BINARY_DIR}/testLibRequiredConfig.cmake"
+  "${CMAKE_CURRENT_BINARY_DIR}/testLibRequiredConfigVersion.cmake"
+  DESTINATION lib/cmake/testLibRequired
+)
 
 # Install and export from install tree.
 install(

+ 12 - 8
Tests/ExportImport/Import/A/CMakeLists.txt

@@ -5,8 +5,8 @@ include(${Import_BINARY_DIR}/../Export/ExportBuildTree.cmake)
 include(${CMAKE_INSTALL_PREFIX}/lib/exp/exp.cmake)
 
 # Import two exports, where the Depends one depends on an exported target from the Required one:
-include(${CMAKE_INSTALL_PREFIX}/lib/cmake/testLibRequired/testLibRequiredConfig.cmake)
-include(${CMAKE_INSTALL_PREFIX}/lib/cmake/testLibDepends/testLibDependsConfig.cmake)
+include(${CMAKE_INSTALL_PREFIX}/lib/cmake/testLibRequired/testLibRequiredTargets.cmake)
+include(${CMAKE_INSTALL_PREFIX}/lib/cmake/testLibDepends/testLibDependsTargets.cmake)
 
 # Try referencing an executable imported from the install tree.
 add_custom_command(
@@ -159,13 +159,15 @@ endif()
 
 add_executable(deps_iface deps_iface.c)
 target_link_libraries(deps_iface testLibDepends)
-target_include_directories(deps_iface PRIVATE testLibDepends)
-target_compile_definitions(deps_iface PRIVATE testLibDepends)
 
 add_executable(deps_shared_iface deps_shared_iface.cpp)
 target_link_libraries(deps_shared_iface testSharedLibDepends)
-target_include_directories(deps_shared_iface PRIVATE testSharedLibDepends)
-target_compile_definitions(deps_shared_iface PRIVATE testSharedLibDepends)
+target_compile_definitions(deps_shared_iface
+  PRIVATE
+    $<$<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>
+)
 
 if (APPLE OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
   include(CheckCXXCompilerFlag)
@@ -191,7 +193,9 @@ 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 bld_testSharedLibDepends bld_subdirlib)
 target_compile_definitions(deps_shared_iface2
-  PRIVATE bld_testSharedLibDepends 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>
 )

+ 12 - 0
Tests/ExportImport/Import/A/deps_shared_iface.cpp

@@ -8,6 +8,18 @@
 #endif
 #endif
 
+#ifndef PIC_PROPERTY_IS_ON
+#error Expected PIC_PROPERTY_IS_ON
+#endif
+
+#ifndef CUSTOM_PROPERTY_IS_ON
+#error Expected CUSTOM_PROPERTY_IS_ON
+#endif
+
+#ifndef CUSTOM_STRING_IS_MATCH
+#error Expected CUSTOM_STRING_IS_MATCH
+#endif
+
 #ifdef TEST_SUBDIR_LIB
 #include "subdir.h"
 #endif

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

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

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

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

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

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

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

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

+ 3 - 1
Tests/ExternalProject/CMakeLists.txt

@@ -50,6 +50,8 @@ if(NOT DEFINED can_build_tutorial_step5)
   endif()
 endif()
 
+add_custom_target(NonExternalProjectTarget
+  COMMAND ${CMAKE_COMMAND} -E echo NonExternalProjectTarget)
 
 # Empty projects that test all the known ExternalProject_Add argument key words:
 #
@@ -94,7 +96,7 @@ ExternalProject_Add(${proj}
   CVS_REPOSITORY ""
   CVS_MODULE ""
   CVS_TAG ""
-  DEPENDS "MinimalNoOpProject"
+  DEPENDS "MinimalNoOpProject" NonExternalProjectTarget
   DOWNLOAD_COMMAND ""
   INSTALL_COMMAND ""
   PATCH_COMMAND ""

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

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

+ 38 - 0
Tests/Module/ExternalData/CMakeLists.txt

@@ -0,0 +1,38 @@
+cmake_minimum_required(VERSION 2.8.10.20130115)
+project(ExternalDataTest NONE)
+
+include(CTest)
+
+include(ExternalData)
+
+if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" MATCHES "^/")
+  set(slash /)
+endif()
+set(ExternalData_URL_TEMPLATES
+  "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/%(algo)/%(hash)"
+  )
+set(ExternalData_BINARY_ROOT "${CMAKE_CURRENT_BINARY_DIR}/ExternalData")
+file(REMOVE_RECURSE ${ExternalData_BINARY_ROOT}) # clean test
+
+ExternalData_Add_Test(Data1
+  NAME Data1Check
+  COMMAND ${CMAKE_COMMAND}
+    -D Data=DATA{Data.dat}
+    -D SeriesA=DATA{SeriesA.dat,:}
+    -D SeriesB=DATA{SeriesB.dat,:}
+    -D SeriesC=DATA{SeriesC.dat,:}
+    -D SeriesD=DATA{SeriesD.dat,:}
+    -D SeriesAn=DATA{SeriesAn1.dat,:}
+    -D SeriesBn=DATA{SeriesBn_1.dat,:}
+    -D SeriesCn=DATA{SeriesCn.1.dat,:}
+    -D SeriesDn=DATA{SeriesDn-1.dat,:}
+    -D SeriesMixed=DATA{SeriesMixed.1.dat,:}
+    -D Paired=DATA{PairedA.dat,PairedB.dat}
+    -D Meta=DATA{MetaTop.dat,REGEX:Meta[ABC].dat}
+    -D Directory=DATA{Directory/,A.dat,REGEX:[BC].dat}
+    -P ${CMAKE_CURRENT_SOURCE_DIR}/Data1Check.cmake
+  )
+ExternalData_Add_Target(Data1)
+
+add_subdirectory(Data2)
+add_subdirectory(Data3)

+ 1 - 0
Tests/Module/ExternalData/Data.dat.md5

@@ -0,0 +1 @@
+8c018830e3efa5caf3c7415028335a57

+ 52 - 0
Tests/Module/ExternalData/Data1Check.cmake

@@ -0,0 +1,52 @@
+file(STRINGS "${Data}" lines LIMIT_INPUT 1024)
+if(NOT "x${lines}" STREQUAL "xInput file already transformed.")
+  message(SEND_ERROR "Input file:\n  ${Data}\ndoes not have expected content, but [[${lines}]]")
+endif()
+set(SeriesAn1 "1\\.dat")
+set(SeriesBn1 "_1\\.dat")
+set(SeriesCn1 "\\.1\\.dat")
+set(SeriesDn1 "-1\\.dat")
+set(SeriesAl 1 2 3)
+set(SeriesBl _1 _2 _3)
+set(SeriesCl .1 .2 .3)
+set(SeriesDl -1 -2 -3)
+foreach(s A B C D)
+  foreach(n "" ${Series${s}l})
+    string(REGEX REPLACE "\\.dat$" "${n}.dat" file "${Series${s}}")
+    if(NOT EXISTS "${file}")
+      message(SEND_ERROR "Input file:\n  ${file}\ndoes not exist!")
+    endif()
+  endforeach()
+endforeach()
+foreach(s A B C D)
+  foreach(n ${Series${s}l})
+    string(REGEX REPLACE "${Series${s}n1}$" "${n}.dat" file "${Series${s}n}")
+    if(NOT EXISTS "${file}")
+      message(SEND_ERROR "Input file:\n  ${file}\ndoes not exist!")
+    endif()
+  endforeach()
+endforeach()
+foreach(n .1 .2 .3 .4)
+  string(REGEX REPLACE "\\.1\\.dat$" "${n}.dat" file "${SeriesMixed}")
+  if(NOT EXISTS "${file}")
+    message(SEND_ERROR "Input file:\n  ${file}\ndoes not exist!")
+  endif()
+endforeach()
+foreach(n A B)
+  string(REGEX REPLACE "A\\.dat$" "${n}.dat" file "${Paired}")
+  if(NOT EXISTS "${file}")
+    message(SEND_ERROR "Input file:\n  ${file}\ndoes not exist!")
+  endif()
+endforeach()
+foreach(n Top A B C)
+  string(REGEX REPLACE "Top\\.dat$" "${n}.dat" file "${Meta}")
+  if(NOT EXISTS "${file}")
+    message(SEND_ERROR "Input file:\n  ${file}\ndoes not exist!")
+  endif()
+endforeach()
+foreach(n A B C)
+  set(file "${Directory}/${n}.dat")
+  if(NOT EXISTS "${file}")
+    message(SEND_ERROR "Input file:\n  ${file}\ndoes not exist!")
+  endif()
+endforeach()

+ 1 - 0
Tests/Module/ExternalData/Data2.dat.md5

@@ -0,0 +1 @@
+8c018830e3efa5caf3c7415028335a57

+ 11 - 0
Tests/Module/ExternalData/Data2/CMakeLists.txt

@@ -0,0 +1,11 @@
+set(ExternalData_SERIES_PARSE "([0-9]+)(_\\.my\\.dat)$")
+set(ExternalData_SERIES_MATCH "([0-9]+)")
+ExternalData_Add_Test(Data2
+  NAME Data2Check
+  COMMAND ${CMAKE_COMMAND}
+    -D Data2=DATA{../Data2.dat}
+    -D Data2b=DATA{${CMAKE_CURRENT_SOURCE_DIR}/../Data2b.dat}
+    -D SeriesC=DATA{SeriesC_1_.my.dat,:}
+    -P ${CMAKE_CURRENT_SOURCE_DIR}/Data2Check.cmake
+  )
+ExternalData_Add_Target(Data2)

+ 12 - 0
Tests/Module/ExternalData/Data2/Data2Check.cmake

@@ -0,0 +1,12 @@
+foreach(d "${Data2}" "${Data2b}")
+  file(STRINGS "${d}" lines LIMIT_INPUT 1024)
+  if(NOT "x${lines}" STREQUAL "xInput file already transformed.")
+    message(SEND_ERROR "Input file:\n  ${d}\ndoes not have expected content, but [[${lines}]]")
+  endif()
+endforeach()
+foreach(n 1 2 3)
+  string(REGEX REPLACE "_1_\\.my\\.dat$" "_${n}_.my.dat" SeriesCFile "${SeriesC}")
+  if(NOT EXISTS "${SeriesCFile}")
+    message(SEND_ERROR "Input file:\n  ${SeriesCFile}\ndoes not exist!")
+  endif()
+endforeach()

+ 1 - 0
Tests/Module/ExternalData/Data2/SeriesC_1_.my.dat.md5

@@ -0,0 +1 @@
+31eff09e84fca01415f8cd9d82ec432b

+ 1 - 0
Tests/Module/ExternalData/Data2/SeriesC_2_.my.dat.md5

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

+ 1 - 0
Tests/Module/ExternalData/Data2/SeriesC_3_.my.dat.md5

@@ -0,0 +1 @@
+30ba0acdee9096b3b9fc6c69362c6b42

+ 1 - 0
Tests/Module/ExternalData/Data2b.dat.md5

@@ -0,0 +1 @@
+8c018830e3efa5caf3c7415028335a57

+ 14 - 0
Tests/Module/ExternalData/Data3/CMakeLists.txt

@@ -0,0 +1,14 @@
+set(Store0 ${CMAKE_BINARY_DIR}/ExternalData/Other)
+set(Store1 ${CMAKE_BINARY_DIR}/ExternalData/Objects)
+set(ExternalData_OBJECT_STORES ${Store0} ${Store1})
+ExternalData_Add_Test(Data3
+  NAME Data3Check
+  COMMAND ${CMAKE_COMMAND}
+    -D Data=DATA{Data.dat}
+    -D Other=DATA{Other.dat}
+    -D Store0=${Store0}
+    -D Store1=${Store1}
+    -P ${CMAKE_CURRENT_SOURCE_DIR}/Data3Check.cmake
+  )
+ExternalData_Add_Target(Data3)
+add_dependencies(Data3 Data1 Data2)

Някои файлове не бяха показани, защото твърде много файлове са промени