Browse Source

Merge topic 'device-link'

4248bb452a CUDA: Device linking use now link options
ec48e023f6 CUDA: Add information for LINKER: pattern translation
3fdae5acaa Genex: Add generator expressions $<DEVICE_LINK> and $<HOST_LINK>
38332fc4fa cmGeneratorExpressionDAGChecker: introduce method Top()

Acked-by: Kitware Robot <[email protected]>
Acked-by: Robert Maynard <[email protected]>
Merge-request: !4577
Brad King 5 years ago
parent
commit
5d32699975
100 changed files with 788 additions and 208 deletions
  1. 10 0
      Help/command/DEVICE_LINK_OPTIONS.txt
  2. 2 0
      Help/command/add_link_options.rst
  3. 2 0
      Help/command/target_link_options.rst
  4. 12 0
      Help/manual/cmake-generator-expressions.7.rst
  5. 1 0
      Help/manual/cmake-policies.7.rst
  6. 19 0
      Help/policy/CMP0105.rst
  7. 1 1
      Help/prop_dir/LINK_OPTIONS.rst
  8. 8 4
      Help/prop_tgt/LINK_OPTIONS.rst
  9. 5 0
      Help/release/dev/device-link-options.rst
  10. 6 0
      Help/release/dev/genex-DEVICE_LINK-HOST_LINK.rst
  11. 2 3
      Modules/CMakeCUDAInformation.cmake
  12. 13 0
      Modules/Compiler/NVIDIA-CUDA.cmake
  13. 10 0
      Modules/Compiler/NVIDIA-DetermineCompiler.cmake
  14. 2 2
      Modules/Platform/Windows-NVIDIA-CUDA.cmake
  15. 25 43
      Source/cmGeneratorExpressionDAGChecker.cxx
  16. 8 5
      Source/cmGeneratorExpressionDAGChecker.h
  17. 68 0
      Source/cmGeneratorExpressionNode.cxx
  18. 166 72
      Source/cmGeneratorTarget.cxx
  19. 19 0
      Source/cmGeneratorTarget.h
  20. 28 12
      Source/cmLocalGenerator.cxx
  21. 5 0
      Source/cmLocalGenerator.h
  22. 5 21
      Source/cmMakefileExecutableTargetGenerator.cxx
  23. 7 8
      Source/cmMakefileLibraryTargetGenerator.cxx
  24. 12 0
      Source/cmMakefileTargetGenerator.cxx
  25. 2 0
      Source/cmMakefileTargetGenerator.h
  26. 10 26
      Source/cmNinjaNormalTargetGenerator.cxx
  27. 6 3
      Source/cmPolicies.h
  28. 1 1
      Source/cmStringAlgorithms.h
  29. 16 6
      Source/cmVisualStudio10TargetGenerator.cxx
  30. 2 1
      Tests/RunCMake/CMakeLists.txt
  31. 1 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_custom_command-result.txt
  32. 9 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_custom_command-stderr.txt
  33. 4 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_custom_command.cmake
  34. 1 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_custom_target-result.txt
  35. 9 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_custom_target-stderr.txt
  36. 3 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_custom_target.cmake
  37. 1 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_executable-result.txt
  38. 9 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_executable-stderr.txt
  39. 1 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_executable.cmake
  40. 1 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_library-result.txt
  41. 9 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_library-stderr.txt
  42. 1 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_library.cmake
  43. 1 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_test-result.txt
  44. 9 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_test-stderr.txt
  45. 5 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_test.cmake
  46. 1 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-install-result.txt
  47. 7 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-install-stderr.txt
  48. 5 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-install.cmake
  49. 1 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-link_depends-result.txt
  50. 7 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-link_depends-stderr.txt
  51. 7 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-link_depends.cmake
  52. 1 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_compile_definitions-result.txt
  53. 9 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_compile_definitions-stderr.txt
  54. 4 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_compile_definitions.cmake
  55. 1 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_compile_options-result.txt
  56. 9 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_compile_options-stderr.txt
  57. 4 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_compile_options.cmake
  58. 1 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_include_directories-result.txt
  59. 9 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_include_directories-stderr.txt
  60. 4 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_include_directories.cmake
  61. 1 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_link_directories-result.txt
  62. 9 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_link_directories-stderr.txt
  63. 7 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_link_directories.cmake
  64. 1 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_link_libraries-result.txt
  65. 9 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_link_libraries-stderr.txt
  66. 7 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_link_libraries.cmake
  67. 1 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_sources-result.txt
  68. 9 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_sources-stderr.txt
  69. 2 0
      Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_sources.cmake
  70. 1 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-add_custom_command-result.txt
  71. 9 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-add_custom_command-stderr.txt
  72. 4 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-add_custom_command.cmake
  73. 1 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-add_custom_target-result.txt
  74. 9 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-add_custom_target-stderr.txt
  75. 3 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-add_custom_target.cmake
  76. 1 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-add_executable-result.txt
  77. 9 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-add_executable-stderr.txt
  78. 1 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-add_executable.cmake
  79. 1 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-add_library-result.txt
  80. 9 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-add_library-stderr.txt
  81. 1 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-add_library.cmake
  82. 1 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-add_test-result.txt
  83. 9 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-add_test-stderr.txt
  84. 5 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-add_test.cmake
  85. 1 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-install-result.txt
  86. 7 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-install-stderr.txt
  87. 5 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-install.cmake
  88. 1 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-link_depends-result.txt
  89. 7 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-link_depends-stderr.txt
  90. 7 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-link_depends.cmake
  91. 1 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-target_compile_definitions-result.txt
  92. 9 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-target_compile_definitions-stderr.txt
  93. 4 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-target_compile_definitions.cmake
  94. 1 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-target_compile_options-result.txt
  95. 9 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-target_compile_options-stderr.txt
  96. 4 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-target_compile_options.cmake
  97. 1 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-target_include_directories-result.txt
  98. 9 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-target_include_directories-stderr.txt
  99. 4 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-target_include_directories.cmake
  100. 1 0
      Tests/RunCMake/GeneratorExpression/HOST_LINK-target_link_directories-result.txt

+ 10 - 0
Help/command/DEVICE_LINK_OPTIONS.txt

@@ -0,0 +1,10 @@
+
+When a device link step is involved, which is controlled by
+:prop_tgt:`CUDA_SEPARABLE_COMPILATION` and
+:prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` properties, the raw options will be
+delivered to the host and device link steps (wrapped in ``-Xcompiler`` or
+equivalent for device link). Options wrapped with ``$<DEVICE_LINK:...>``
+:manual:`generator expression <cmake-generator-expressions(7)>` will be used
+only for the device link step. Options wrapped with ``$<HOST_LINK:...>``
+:manual:`generator expression <cmake-generator-expressions(7)>` will be used
+only for the host link step.

+ 2 - 0
Help/command/add_link_options.rst

@@ -26,6 +26,8 @@ the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
 manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
 manual for more on defining buildsystem properties.
 
+.. include:: DEVICE_LINK_OPTIONS.txt
+
 .. include:: OPTIONS_SHELL.txt
 
 .. include:: LINK_OPTIONS_LINKER.txt

+ 2 - 0
Help/command/target_link_options.rst

@@ -43,6 +43,8 @@ with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
 manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
 manual for more on defining buildsystem properties.
 
+.. include:: DEVICE_LINK_OPTIONS.txt
+
 .. include:: OPTIONS_SHELL.txt
 
 .. include:: LINK_OPTIONS_LINKER.txt

+ 12 - 0
Help/manual/cmake-generator-expressions.7.rst

@@ -362,6 +362,18 @@ Variable Queries
     evaluation will give ``C`` as link language, so the second pass will
     correctly add target ``libother`` as link dependency.
 
+``$<DEVICE_LINK:list>``
+  Returns the list if it is the device link step, an empty list otherwise.
+  The device link step is controlled by :prop_tgt:`CUDA_SEPARABLE_COMPILATION`
+  and :prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` properties. This expression can
+  only be used to specify link options.
+
+``$<HOST_LINK:list>``
+  Returns the list if it is the normal link step, an empty list otherwise.
+  This expression is mainly useful when a device link step is also involved
+  (see ``$<DEVICE_LINK:list>`` generator expression). This expression can only
+  be used to specify link options.
+
 String-Valued Generator Expressions
 ===================================
 

+ 1 - 0
Help/manual/cmake-policies.7.rst

@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.18
 .. toctree::
    :maxdepth: 1
 
+   CMP0105: Device link step uses the link options. </policy/CMP0105>
    CMP0104: CMAKE_CUDA_ARCHITECTURES now detected for NVCC, empty CUDA_ARCHITECTURES not allowed. </policy/CMP0104>
    CMP0103: Multiple export() with same FILE without APPEND is not allowed. </policy/CMP0103>
 

+ 19 - 0
Help/policy/CMP0105.rst

@@ -0,0 +1,19 @@
+CMP0105
+-------
+
+:prop_tgt:`LINK_OPTIONS` and :prop_tgt:`INTERFACE_LINK_OPTIONS` target
+properties are now used for the device link step.
+
+In CMake 3.17 and below, link options are not used by the device link step.
+
+The ``OLD`` behavior for this policy is to ignore the link options.
+
+The ``NEW`` behavior of this policy is to use the link options during the
+device link step.
+
+This policy was introduced in CMake version 3.17.  Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt

+ 1 - 1
Help/prop_dir/LINK_OPTIONS.rst

@@ -2,7 +2,7 @@ LINK_OPTIONS
 ------------
 
 List of options to use for the link step of shared library, module
-and executable targets.
+and executable targets as well as the device link step.
 
 This property holds a :ref:`semicolon-separated list <CMake Language Lists>` of options
 given so far to the :command:`add_link_options` command.

+ 8 - 4
Help/prop_tgt/LINK_OPTIONS.rst

@@ -2,12 +2,16 @@ LINK_OPTIONS
 ------------
 
 List of options to use for the link step of shared library, module
-and executable targets. Targets that are static libraries need to use
-the :prop_tgt:`STATIC_LIBRARY_OPTIONS` target property.
+and executable targets as well as the device link step. Targets that are static
+libraries need to use the :prop_tgt:`STATIC_LIBRARY_OPTIONS` target property.
 
+These options are used for both normal linking and device linking
+(see policy :policy:`CMP0105`). To control link options for normal and device
+link steps, ``$<HOST_LINK>`` and ``$<DEVICE_LINK>``
+:manual:`generator expressions <cmake-generator-expressions(7)>` can be used.
 
-This property holds a :ref:`semicolon-separated list <CMake Language Lists>` of options
-specified so far for its target.  Use the :command:`target_link_options`
+This property holds a :ref:`semicolon-separated list <CMake Language Lists>` of
+options specified so far for its target.  Use the :command:`target_link_options`
 command to append more options.
 
 This property is initialized by the :prop_dir:`LINK_OPTIONS` directory

+ 5 - 0
Help/release/dev/device-link-options.rst

@@ -0,0 +1,5 @@
+device-link-options
+-------------------
+
+* the :prop_tgt:`LINK_OPTIONS` and :prop_tgt:`INTERFACE_LINK_OPTIONS` target
+  properties are now used for the device link step. See policy :policy:`CMP0105`.

+ 6 - 0
Help/release/dev/genex-DEVICE_LINK-HOST_LINK.rst

@@ -0,0 +1,6 @@
+genex-DEVICE_LINK-HOST_LINK
+---------------------------
+
+* To manage device and host link steps, the ``$<DEVICE_LINK:...>`` and
+  ``$<HOST_LINK:...>``
+  :manual:`generator expressions <cmake-generator-expressions(7)>` were added.

+ 2 - 3
Modules/CMakeCUDAInformation.cmake

@@ -192,14 +192,13 @@ unset(__IMPLICT_DLINK_DIRS)
 #These are used when linking relocatable (dc) cuda code
 if(NOT CMAKE_CUDA_DEVICE_LINK_LIBRARY)
   set(CMAKE_CUDA_DEVICE_LINK_LIBRARY
-    "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_DLINK_FLAGS}")
+    "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_DLINK_FLAGS}")
 endif()
 if(NOT CMAKE_CUDA_DEVICE_LINK_EXECUTABLE)
   set(CMAKE_CUDA_DEVICE_LINK_EXECUTABLE
-    "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_DLINK_FLAGS}")
+    "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_DLINK_FLAGS}")
 endif()
 
-unset(_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS)
 unset(__IMPLICT_DLINK_FLAGS)
 
 set(CMAKE_CUDA_INFORMATION_LOADED 1)

+ 13 - 0
Modules/Compiler/NVIDIA-CUDA.cmake

@@ -46,6 +46,19 @@ endif()
 set(CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS -shared)
 set(CMAKE_INCLUDE_SYSTEM_FLAG_CUDA -isystem=)
 
+if (CMAKE_CUDA_SIMULATE_ID STREQUAL "GNU")
+  set(CMAKE_CUDA_LINKER_WRAPPER_FLAG "-Wl,")
+  set(CMAKE_CUDA_LINKER_WRAPPER_FLAG_SEP ",")
+elseif(CMAKE_CUDA_SIMULATE_ID STREQUAL "Clang")
+  set(CMAKE_CUDA_LINKER_WRAPPER_FLAG "-Xlinker" " ")
+  set(CMAKE_CUDA_LINKER_WRAPPER_FLAG_SEP)
+endif()
+
+set(CMAKE_CUDA_DEVICE_COMPILER_WRAPPER_FLAG "-Xcompiler=")
+set(CMAKE_CUDA_DEVICE_COMPILER_WRAPPER_FLAG_SEP ",")
+set(CMAKE_CUDA_DEVICE_LINKER_WRAPPER_FLAG "-Xlinker=")
+set(CMAKE_CUDA_DEVICE_LINKER_WRAPPER_FLAG_SEP ",")
+
 set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "STATIC")
 set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_STATIC  "cudadevrt;cudart_static")
 set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_SHARED  "cudadevrt;cudart")

+ 10 - 0
Modules/Compiler/NVIDIA-DetermineCompiler.cmake

@@ -11,9 +11,19 @@ set(_compiler_id_version_compute "
    /* _MSC_VER = VVRR */
 #  define @PREFIX@SIMULATE_VERSION_MAJOR @MACRO_DEC@(_MSC_VER / 100)
 #  define @PREFIX@SIMULATE_VERSION_MINOR @MACRO_DEC@(_MSC_VER % 100)
+# elif defined(__clang__)
+#  define @PREFIX@SIMULATE_VERSION_MAJOR @MACRO_DEC@(__clang_major__)
+#  define @PREFIX@SIMULATE_VERSION_MINOR @MACRO_DEC@(__clang_minor__)
+# elif defined(__GNUC__)
+#  define @PREFIX@SIMULATE_VERSION_MAJOR @MACRO_DEC@(__GNUC__)
+#  define @PREFIX@SIMULATE_VERSION_MINOR @MACRO_DEC@(__GNUC_MINOR__)
 # endif")
 
 set(_compiler_id_simulate "
 # if defined(_MSC_VER)
 #  define @PREFIX@SIMULATE_ID \"MSVC\"
+# elif defined(__clang__)
+#  define @PREFIX@SIMULATE_ID \"Clang\"
+# elif defined(__GNUC__)
+#  define @PREFIX@SIMULATE_ID \"GNU\"
 # endif")

+ 2 - 2
Modules/Platform/Windows-NVIDIA-CUDA.cmake

@@ -46,9 +46,9 @@ endforeach()
 unset(__IMPLICT_DLINK_DIRS)
 
 set(CMAKE_CUDA_DEVICE_LINK_LIBRARY
-  "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICT_DLINK_FLAGS}")
+  "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICT_DLINK_FLAGS}")
 set(CMAKE_CUDA_DEVICE_LINK_EXECUTABLE
-  "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICT_DLINK_FLAGS}")
+  "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICT_DLINK_FLAGS}")
 unset(__IMPLICT_DLINK_FLAGS)
 
 string(REPLACE "/D" "-D" _PLATFORM_DEFINES_CUDA "${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_CXX}")

+ 25 - 43
Source/cmGeneratorExpressionDAGChecker.cxx

@@ -48,12 +48,7 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
 
 void cmGeneratorExpressionDAGChecker::Initialize()
 {
-  const cmGeneratorExpressionDAGChecker* top = this;
-  const cmGeneratorExpressionDAGChecker* p = this->Parent;
-  while (p) {
-    top = p;
-    p = p->Parent;
-  }
+  const auto* top = this->Top();
   this->CheckResult = this->CheckGraph();
 
 #define TEST_TRANSITIVE_PROPERTY_METHOD(METHOD) top->METHOD() ||
@@ -144,60 +139,41 @@ cmGeneratorExpressionDAGChecker::CheckGraph() const
   return DAG;
 }
 
-bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnly()
+bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnly() const
 {
-  const cmGeneratorExpressionDAGChecker* top = this;
-  const cmGeneratorExpressionDAGChecker* parent = this->Parent;
-  while (parent) {
-    top = parent;
-    parent = parent->Parent;
-  }
-
-  return top->TransitivePropertiesOnly;
+  return this->Top()->TransitivePropertiesOnly;
 }
 
-bool cmGeneratorExpressionDAGChecker::EvaluatingGenexExpression()
+bool cmGeneratorExpressionDAGChecker::EvaluatingGenexExpression() const
 {
   return cmHasLiteralPrefix(this->Property, "TARGET_GENEX_EVAL:") ||
     cmHasLiteralPrefix(this->Property, "GENEX_EVAL:");
 }
 
-bool cmGeneratorExpressionDAGChecker::EvaluatingPICExpression()
+bool cmGeneratorExpressionDAGChecker::EvaluatingPICExpression() const
 {
-  const cmGeneratorExpressionDAGChecker* top = this;
-  const cmGeneratorExpressionDAGChecker* parent = this->Parent;
-  while (parent) {
-    top = parent;
-    parent = parent->Parent;
-  }
-
-  return top->Property == "INTERFACE_POSITION_INDEPENDENT_CODE";
+  return this->Top()->Property == "INTERFACE_POSITION_INDEPENDENT_CODE";
 }
 
-bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression()
+bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const
 {
-  const cmGeneratorExpressionDAGChecker* top = this;
-  const cmGeneratorExpressionDAGChecker* parent = this->Parent;
-  while (parent) {
-    top = parent;
-    parent = parent->Parent;
-  }
-
-  cm::string_view property(top->Property);
+  cm::string_view property(this->Top()->Property);
 
   return property == "LINK_DIRECTORIES"_s || property == "LINK_OPTIONS"_s ||
     property == "LINK_DEPENDS"_s;
 }
 
+bool cmGeneratorExpressionDAGChecker::EvaluatingLinkOptionsExpression() const
+{
+  cm::string_view property(this->Top()->Property);
+
+  return property == "LINK_OPTIONS"_s;
+}
+
 bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(
-  cmGeneratorTarget const* tgt)
+  cmGeneratorTarget const* tgt) const
 {
-  const cmGeneratorExpressionDAGChecker* top = this;
-  const cmGeneratorExpressionDAGChecker* parent = this->Parent;
-  while (parent) {
-    top = parent;
-    parent = parent->Parent;
-  }
+  const auto* top = this->Top();
 
   cm::string_view prop(top->Property);
 
@@ -212,7 +188,8 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(
     prop == "INTERFACE_LINK_LIBRARIES"_s;
 }
 
-cmGeneratorTarget const* cmGeneratorExpressionDAGChecker::TopTarget() const
+cmGeneratorExpressionDAGChecker const* cmGeneratorExpressionDAGChecker::Top()
+  const
 {
   const cmGeneratorExpressionDAGChecker* top = this;
   const cmGeneratorExpressionDAGChecker* parent = this->Parent;
@@ -220,7 +197,12 @@ cmGeneratorTarget const* cmGeneratorExpressionDAGChecker::TopTarget() const
     top = parent;
     parent = parent->Parent;
   }
-  return top->Target;
+  return top;
+}
+
+cmGeneratorTarget const* cmGeneratorExpressionDAGChecker::TopTarget() const
+{
+  return this->Top()->Target;
 }
 
 enum TransitiveProperty

+ 8 - 5
Source/cmGeneratorExpressionDAGChecker.h

@@ -66,10 +66,12 @@ struct cmGeneratorExpressionDAGChecker
   void ReportError(cmGeneratorExpressionContext* context,
                    const std::string& expr);
 
-  bool EvaluatingGenexExpression();
-  bool EvaluatingPICExpression();
-  bool EvaluatingLinkExpression();
-  bool EvaluatingLinkLibraries(cmGeneratorTarget const* tgt = nullptr);
+  bool EvaluatingGenexExpression() const;
+  bool EvaluatingPICExpression() const;
+  bool EvaluatingLinkExpression() const;
+  bool EvaluatingLinkOptionsExpression() const;
+
+  bool EvaluatingLinkLibraries(cmGeneratorTarget const* tgt = nullptr) const;
 
 #define DECLARE_TRANSITIVE_PROPERTY_METHOD(METHOD) bool METHOD() const;
 
@@ -77,9 +79,10 @@ struct cmGeneratorExpressionDAGChecker
 
 #undef DECLARE_TRANSITIVE_PROPERTY_METHOD
 
-  bool GetTransitivePropertiesOnly();
+  bool GetTransitivePropertiesOnly() const;
   void SetTransitivePropertiesOnly() { this->TransitivePropertiesOnly = true; }
 
+  cmGeneratorExpressionDAGChecker const* Top() const;
   cmGeneratorTarget const* TopTarget() const;
 
 private:

+ 68 - 0
Source/cmGeneratorExpressionNode.cxx

@@ -15,6 +15,7 @@
 
 #include <cm/iterator>
 #include <cm/string_view>
+#include <cm/vector>
 #include <cmext/algorithm>
 
 #include "cmsys/RegularExpression.hxx"
@@ -1187,6 +1188,70 @@ static const struct LinkLanguageAndIdNode : public cmGeneratorExpressionNode
   }
 } linkLanguageAndIdNode;
 
+static const struct HostLinkNode : public cmGeneratorExpressionNode
+{
+  HostLinkNode() {} // NOLINT(modernize-use-equals-default)
+
+  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
+
+  std::string Evaluate(
+    const std::vector<std::string>& parameters,
+    cmGeneratorExpressionContext* context,
+    const GeneratorExpressionContent* content,
+    cmGeneratorExpressionDAGChecker* dagChecker) const override
+  {
+    if (!context->HeadTarget || !dagChecker ||
+        !dagChecker->EvaluatingLinkOptionsExpression()) {
+      reportError(context, content->GetOriginalExpression(),
+                  "$<HOST_LINK:...> may only be used with binary targets "
+                  "to specify link options.");
+      return std::string();
+    }
+
+    return context->HeadTarget->IsDeviceLink() ? std::string()
+                                               : cmJoin(parameters, ";");
+  }
+} hostLinkNode;
+
+static const struct DeviceLinkNode : public cmGeneratorExpressionNode
+{
+  DeviceLinkNode() {} // NOLINT(modernize-use-equals-default)
+
+  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
+
+  std::string Evaluate(
+    const std::vector<std::string>& parameters,
+    cmGeneratorExpressionContext* context,
+    const GeneratorExpressionContent* content,
+    cmGeneratorExpressionDAGChecker* dagChecker) const override
+  {
+    if (!context->HeadTarget || !dagChecker ||
+        !dagChecker->EvaluatingLinkOptionsExpression()) {
+      reportError(context, content->GetOriginalExpression(),
+                  "$<DEVICE_LINK:...> may only be used with binary targets "
+                  "to specify link options.");
+      return std::string();
+    }
+
+    if (context->HeadTarget->IsDeviceLink()) {
+      std::vector<std::string> list;
+      cmExpandLists(parameters.begin(), parameters.end(), list);
+      const auto DL_BEGIN = "<DEVICE_LINK>"_s;
+      const auto DL_END = "</DEVICE_LINK>"_s;
+      cm::erase_if(list, [&](const std::string& item) {
+        return item == DL_BEGIN || item == DL_END;
+      });
+
+      list.insert(list.begin(), static_cast<std::string>(DL_BEGIN));
+      list.push_back(static_cast<std::string>(DL_END));
+
+      return cmJoin(list, ";");
+    }
+
+    return std::string();
+  }
+} deviceLinkNode;
+
 std::string getLinkedTargetsContent(
   cmGeneratorTarget const* target, std::string const& prop,
   cmGeneratorExpressionContext* context,
@@ -1304,6 +1369,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
           context, content->GetOriginalExpression(),
           "$<TARGET_PROPERTY:prop>  may only be used with binary targets.  "
           "It may not be used with add_custom_command or add_custom_target.  "
+          " "
           "Specify the target to read a property from using the "
           "$<TARGET_PROPERTY:tgt,prop> signature instead.");
         return std::string();
@@ -2464,6 +2530,8 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode(
     { "COMPILE_LANGUAGE", &languageNode },
     { "LINK_LANG_AND_ID", &linkLanguageAndIdNode },
     { "LINK_LANGUAGE", &linkLanguageNode },
+    { "HOST_LINK", &hostLinkNode },
+    { "DEVICE_LINK", &deviceLinkNode },
     { "SHELL_PATH", &shellPathNode }
   };
 

+ 166 - 72
Source/cmGeneratorTarget.cxx

@@ -21,6 +21,8 @@
 
 #include "cmsys/RegularExpression.hxx"
 
+#include "cm_static_string_view.hxx"
+
 #include "cmAlgorithms.h"
 #include "cmComputeLinkInformation.h"
 #include "cmCustomCommand.h"
@@ -3392,22 +3394,38 @@ enum class OptionsParse
 };
 
 namespace {
+const auto DL_BEGIN = "<DEVICE_LINK>"_s;
+const auto DL_END = "</DEVICE_LINK>"_s;
+
 void processOptions(cmGeneratorTarget const* tgt,
                     std::vector<EvaluatedTargetPropertyEntry> const& entries,
                     std::vector<BT<std::string>>& options,
                     std::unordered_set<std::string>& uniqueOptions,
-                    bool debugOptions, const char* logName, OptionsParse parse)
+                    bool debugOptions, const char* logName, OptionsParse parse,
+                    bool processDeviceOptions = false)
 {
+  bool splitOption = !processDeviceOptions;
   for (EvaluatedTargetPropertyEntry const& entry : entries) {
     std::string usedOptions;
     for (std::string const& opt : entry.Values) {
+      if (processDeviceOptions && (opt == DL_BEGIN || opt == DL_END)) {
+        options.emplace_back(opt, entry.Backtrace);
+        splitOption = opt == DL_BEGIN;
+        continue;
+      }
+
       if (uniqueOptions.insert(opt).second) {
         if (parse == OptionsParse::Shell &&
             cmHasLiteralPrefix(opt, "SHELL:")) {
-          std::vector<std::string> tmp;
-          cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp);
-          for (std::string& o : tmp) {
-            options.emplace_back(std::move(o), entry.Backtrace);
+          if (splitOption) {
+            std::vector<std::string> tmp;
+            cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp);
+            for (std::string& o : tmp) {
+              options.emplace_back(std::move(o), entry.Backtrace);
+            }
+          } else {
+            options.emplace_back(std::string(opt.c_str() + 6),
+                                 entry.Backtrace);
           }
         } else {
           options.emplace_back(opt, entry.Backtrace);
@@ -3426,6 +3444,63 @@ void processOptions(cmGeneratorTarget const* tgt,
     }
   }
 }
+
+std::vector<BT<std::string>> wrapOptions(
+  std::vector<std::string>& options, const cmListFileBacktrace& bt,
+  const std::vector<std::string>& wrapperFlag, const std::string& wrapperSep,
+  bool concatFlagAndArgs)
+{
+  std::vector<BT<std::string>> result;
+
+  if (options.empty()) {
+    return result;
+  }
+
+  if (wrapperFlag.empty() || cmHasLiteralPrefix(options.front(), "LINKER:")) {
+    // nothing specified or LINKER wrapper, insert elements as is
+    result.reserve(options.size());
+    for (std::string& o : options) {
+      result.emplace_back(std::move(o), bt);
+    }
+  } else {
+    if (!wrapperSep.empty()) {
+      if (concatFlagAndArgs) {
+        // insert flag elements except last one
+        for (auto i = wrapperFlag.begin(); i != wrapperFlag.end() - 1; ++i) {
+          result.emplace_back(*i, bt);
+        }
+        // concatenate last flag element and all list values
+        // in one option
+        result.emplace_back(wrapperFlag.back() + cmJoin(options, wrapperSep),
+                            bt);
+      } else {
+        for (std::string const& i : wrapperFlag) {
+          result.emplace_back(i, bt);
+        }
+        // concatenate all list values in one option
+        result.emplace_back(cmJoin(options, wrapperSep), bt);
+      }
+    } else {
+      // prefix each element of list with wrapper
+      if (concatFlagAndArgs) {
+        std::transform(options.begin(), options.end(), options.begin(),
+                       [&wrapperFlag](std::string const& o) -> std::string {
+                         return wrapperFlag.back() + o;
+                       });
+      }
+      for (std::string& o : options) {
+        for (auto i = wrapperFlag.begin(),
+                  e = concatFlagAndArgs ? wrapperFlag.end() - 1
+                                        : wrapperFlag.end();
+             i != e; ++i) {
+          result.emplace_back(*i, bt);
+        }
+        result.emplace_back(std::move(o), bt);
+      }
+    }
+  }
+  return result;
+}
 }
 
 void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result,
@@ -3958,6 +4033,12 @@ void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result,
                                        const std::string& config,
                                        const std::string& language) const
 {
+  if (this->IsDeviceLink() &&
+      this->GetPolicyStatusCMP0105() != cmPolicies::NEW) {
+    // link options are not propagated to the device link step
+    return;
+  }
+
   std::vector<BT<std::string>> tmp = this->GetLinkOptions(config, language);
   result.reserve(tmp.size());
   for (BT<std::string>& v : tmp) {
@@ -3997,15 +4078,65 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions(
                       this->GetPolicyStatusCMP0099() != cmPolicies::NEW);
 
   processOptions(this, entries, result, uniqueOptions, debugOptions,
-                 "link options", OptionsParse::Shell);
+                 "link options", OptionsParse::Shell, this->IsDeviceLink());
+
+  if (this->IsDeviceLink()) {
+    // wrap host link options
+    const std::string wrapper(this->Makefile->GetSafeDefinition(
+      "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG"));
+    std::vector<std::string> wrapperFlag = cmExpandedList(wrapper);
+    const std::string wrapperSep(this->Makefile->GetSafeDefinition(
+      "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG_SEP"));
+    bool concatFlagAndArgs = true;
+    if (!wrapperFlag.empty() && wrapperFlag.back() == " ") {
+      concatFlagAndArgs = false;
+      wrapperFlag.pop_back();
+    }
+
+    auto it = result.begin();
+    while (it != result.end()) {
+      if (it->Value == DL_BEGIN) {
+        // device link options, no treatment
+        it = result.erase(it);
+        it = std::find_if(it, result.end(), [](const BT<std::string>& item) {
+          return item.Value == DL_END;
+        });
+        if (it != result.end()) {
+          it = result.erase(it);
+        }
+      } else {
+        // host link options must be wrapped
+        std::vector<std::string> options;
+        cmSystemTools::ParseUnixCommandLine(it->Value.c_str(), options);
+        auto hostOptions = wrapOptions(options, it->Backtrace, wrapperFlag,
+                                       wrapperSep, concatFlagAndArgs);
+        it = result.erase(it);
+        // some compilers (like gcc 4.8 or Intel 19.0 or XLC 16) do not respect
+        // C++11 standard: 'std::vector::insert()' do not returns an iterator,
+        // so need to recompute the iterator after insertion.
+        if (it == result.end()) {
+          cm::append(result, hostOptions);
+          it = result.end();
+        } else {
+          auto index = it - result.begin();
+          result.insert(it, hostOptions.begin(), hostOptions.end());
+          it = result.begin() + index + hostOptions.size();
+        }
+      }
+    }
+  }
 
   // Last step: replace "LINKER:" prefixed elements by
   // actual linker wrapper
   const std::string wrapper(this->Makefile->GetSafeDefinition(
-    "CMAKE_" + language + "_LINKER_WRAPPER_FLAG"));
+    "CMAKE_" + language +
+    (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG"
+                          : "_LINKER_WRAPPER_FLAG")));
   std::vector<std::string> wrapperFlag = cmExpandedList(wrapper);
   const std::string wrapperSep(this->Makefile->GetSafeDefinition(
-    "CMAKE_" + language + "_LINKER_WRAPPER_FLAG_SEP"));
+    "CMAKE_" + language +
+    (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG_SEP"
+                          : "_LINKER_WRAPPER_FLAG_SEP")));
   bool concatFlagAndArgs = true;
   if (!wrapperFlag.empty() && wrapperFlag.back() == " ") {
     concatFlagAndArgs = false;
@@ -4051,51 +4182,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions(
       return result;
     }
 
-    std::vector<BT<std::string>> options;
-    if (wrapperFlag.empty()) {
-      // nothing specified, insert elements as is
-      options.reserve(linkerOptions.size());
-      for (std::string& o : linkerOptions) {
-        options.emplace_back(std::move(o), bt);
-      }
-    } else {
-      if (!wrapperSep.empty()) {
-        if (concatFlagAndArgs) {
-          // insert flag elements except last one
-          for (auto i = wrapperFlag.begin(); i != wrapperFlag.end() - 1; ++i) {
-            options.emplace_back(*i, bt);
-          }
-          // concatenate last flag element and all LINKER list values
-          // in one option
-          options.emplace_back(
-            wrapperFlag.back() + cmJoin(linkerOptions, wrapperSep), bt);
-        } else {
-          for (std::string const& i : wrapperFlag) {
-            options.emplace_back(i, bt);
-          }
-          // concatenate all LINKER list values in one option
-          options.emplace_back(cmJoin(linkerOptions, wrapperSep), bt);
-        }
-      } else {
-        // prefix each element of LINKER list with wrapper
-        if (concatFlagAndArgs) {
-          std::transform(linkerOptions.begin(), linkerOptions.end(),
-                         linkerOptions.begin(),
-                         [&wrapperFlag](std::string const& o) -> std::string {
-                           return wrapperFlag.back() + o;
-                         });
-        }
-        for (std::string& o : linkerOptions) {
-          for (auto i = wrapperFlag.begin(),
-                    e = concatFlagAndArgs ? wrapperFlag.end() - 1
-                                          : wrapperFlag.end();
-               i != e; ++i) {
-            options.emplace_back(*i, bt);
-          }
-          options.emplace_back(std::move(o), bt);
-        }
-      }
-    }
+    std::vector<BT<std::string>> options = wrapOptions(
+      linkerOptions, bt, wrapperFlag, wrapperSep, concatFlagAndArgs);
     result.insert(entry, options.begin(), options.end());
   }
   return result;
@@ -4651,9 +4739,9 @@ void cmGeneratorTarget::GetFullNameInternal(
   outBase += this->GetOutputName(config, artifact);
 
   // Append the per-configuration postfix.
-  // When using Xcode, the postfix should be part of the suffix rather than the
-  // base, because the suffix ends up being used in Xcode's EXECUTABLE_SUFFIX
-  // attribute.
+  // When using Xcode, the postfix should be part of the suffix rather than
+  // the base, because the suffix ends up being used in Xcode's
+  // EXECUTABLE_SUFFIX attribute.
   if (this->IsFrameworkOnApple() &&
       GetGlobalGenerator()->GetName() == "Xcode") {
     targetSuffix = configPostfix.c_str();
@@ -5150,7 +5238,8 @@ void cmGeneratorTarget::CheckPropertyCompatibility(
     std::ostringstream e;
     e << "Property \"" << prop << "\" appears in both the " << propsString
       << " property in the dependencies of target \"" << this->GetName()
-      << "\".  This is not allowed. A property may only require compatibility "
+      << "\".  This is not allowed. A property may only require "
+         "compatibility "
          "in a boolean interpretation, a numeric minimum, a numeric maximum "
          "or a "
          "string interpretation, but not a mixture.";
@@ -5532,6 +5621,13 @@ PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt,
   return propContent;
 }
 
+bool cmGeneratorTarget::SetDeviceLink(bool deviceLink)
+{
+  bool previous = this->DeviceLink;
+  this->DeviceLink = deviceLink;
+  return previous;
+}
+
 bool cmGeneratorTarget::GetLinkInterfaceDependentBoolProperty(
   const std::string& p, const std::string& config) const
 {
@@ -5793,8 +5889,9 @@ void cmGeneratorTarget::ExpandLinkItems(
   // Keep this logic in sync with ComputeLinkImplementationLibraries.
   cmGeneratorExpression ge;
   cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr);
-  // The $<LINK_ONLY> expression may be in a link interface to specify private
-  // link dependencies that are otherwise excluded from usage requirements.
+  // The $<LINK_ONLY> expression may be in a link interface to specify
+  // private link dependencies that are otherwise excluded from usage
+  // requirements.
   if (usage_requirements_only) {
     dagChecker.SetTransitivePropertiesOnly();
   }
@@ -5892,9 +5989,9 @@ void cmGeneratorTarget::ComputeLinkInterface(
               }
             } else {
               // TODO: Recognize shared library file names.  Perhaps this
-              // should be moved to cmComputeLinkInformation, but that creates
-              // a chicken-and-egg problem since this list is needed for its
-              // construction.
+              // should be moved to cmComputeLinkInformation, but that
+              // creates a chicken-and-egg problem since this list is needed
+              // for its construction.
             }
           }
         }
@@ -5955,7 +6052,6 @@ const cmLinkInterfaceLibraries* cmGeneratorTarget::GetLinkInterfaceLibraries(
   }
 
   // Lookup any existing link interface for this configuration.
-  std::string CONFIG = cmSystemTools::UpperCase(config);
   cmHeadToLinkInterfaceMap& hm =
     (usage_requirements_only
        ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config)
@@ -6377,7 +6473,6 @@ const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface(
     return nullptr;
   }
 
-  std::string CONFIG = cmSystemTools::UpperCase(config);
   cmHeadToLinkInterfaceMap& hm =
     (usage_requirements_only
        ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config)
@@ -6591,16 +6686,15 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
 cmHeadToLinkInterfaceMap& cmGeneratorTarget::GetHeadToLinkInterfaceMap(
   const std::string& config) const
 {
-  std::string CONFIG = cmSystemTools::UpperCase(config);
-  return this->LinkInterfaceMap[CONFIG];
+  return this->LinkInterfaceMap[cmSystemTools::UpperCase(config)];
 }
 
 cmHeadToLinkInterfaceMap&
 cmGeneratorTarget::GetHeadToLinkInterfaceUsageRequirementsMap(
   const std::string& config) const
 {
-  std::string CONFIG = cmSystemTools::UpperCase(config);
-  return this->LinkInterfaceUsageRequirementsOnlyMap[CONFIG];
+  return this
+    ->LinkInterfaceUsageRequirementsOnlyMap[cmSystemTools::UpperCase(config)];
 }
 
 const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation(
@@ -6617,8 +6711,8 @@ const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation(
     return nullptr;
   }
 
-  std::string CONFIG = cmSystemTools::UpperCase(config);
-  cmOptionalLinkImplementation& impl = this->LinkImplMap[CONFIG][this];
+  cmOptionalLinkImplementation& impl =
+    this->LinkImplMap[cmSystemTools::UpperCase(config)][this];
   if (secondPass) {
     impl = cmOptionalLinkImplementation();
   }
@@ -6877,8 +6971,8 @@ cmGeneratorTarget::GetLinkImplementationLibrariesInternal(
   }
 
   // Populate the link implementation libraries for this configuration.
-  std::string CONFIG = cmSystemTools::UpperCase(config);
-  HeadToLinkImplementationMap& hm = this->LinkImplMap[CONFIG];
+  HeadToLinkImplementationMap& hm =
+    this->LinkImplMap[cmSystemTools::UpperCase(config)];
 
   // If the link implementation does not depend on the head target
   // then return the one we computed first.

+ 19 - 0
Source/cmGeneratorTarget.h

@@ -204,6 +204,24 @@ public:
   const char* GetLinkInterfaceDependentNumberMaxProperty(
     const std::string& p, const std::string& config) const;
 
+  class DeviceLinkSetter
+  {
+  public:
+    DeviceLinkSetter(cmGeneratorTarget& target)
+      : Target(target)
+    {
+      this->PreviousState = target.SetDeviceLink(true);
+    }
+    ~DeviceLinkSetter() { this->Target.SetDeviceLink(this->PreviousState); };
+
+  private:
+    cmGeneratorTarget& Target;
+    bool PreviousState;
+  };
+
+  bool SetDeviceLink(bool deviceLink);
+  bool IsDeviceLink() const { return this->DeviceLink; }
+
   cmLinkInterface const* GetLinkInterface(
     const std::string& config, const cmGeneratorTarget* headTarget) const;
   void ComputeLinkInterface(const std::string& config,
@@ -829,6 +847,7 @@ private:
   mutable std::string LinkerLanguage;
   using LinkClosureMapType = std::map<std::string, LinkClosure>;
   mutable LinkClosureMapType LinkClosureMap;
+  bool DeviceLink = false;
 
   // Returns ARCHIVE, LIBRARY, or RUNTIME based on platform and type.
   const char* GetOutputTargetType(cmStateEnums::ArtifactType artifact) const;

+ 28 - 12
Source/cmLocalGenerator.cxx

@@ -34,7 +34,6 @@
 #include "cmInstallScriptGenerator.h"
 #include "cmInstallTargetGenerator.h"
 #include "cmLinkLineComputer.h"
-#include "cmLinkLineDeviceComputer.h"
 #include "cmMakefile.h"
 #include "cmRulePlaceholderExpander.h"
 #include "cmSourceFile.h"
@@ -1423,6 +1422,30 @@ std::vector<BT<std::string>> cmLocalGenerator::GetStaticLibraryFlags(
   return flags;
 }
 
+void cmLocalGenerator::GetDeviceLinkFlags(
+  cmLinkLineComputer* linkLineComputer, const std::string& config,
+  std::string& linkLibs, std::string& linkFlags, std::string& frameworkPath,
+  std::string& linkPath, cmGeneratorTarget* target)
+{
+  cmGeneratorTarget::DeviceLinkSetter setter(*target);
+
+  cmComputeLinkInformation* pcli = target->GetLinkInformation(config);
+  const std::string linkLanguage =
+    linkLineComputer->GetLinkerLanguage(target, config);
+
+  if (pcli) {
+    // Compute the required cuda device link libraries when
+    // resolving cuda device symbols
+    this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, frameworkPath,
+                              linkPath);
+  }
+
+  std::vector<std::string> linkOpts;
+  target->GetLinkOptions(linkOpts, config, linkLanguage);
+  // LINK_OPTIONS are escaped.
+  this->AppendCompileOptions(linkFlags, linkOpts);
+}
+
 void cmLocalGenerator::GetTargetFlags(
   cmLinkLineComputer* linkLineComputer, const std::string& config,
   std::string& linkLibs, std::string& flags, std::string& linkFlags,
@@ -1455,12 +1478,6 @@ void cmLocalGenerator::GetTargetFlags(
   switch (target->GetType()) {
     case cmStateEnums::STATIC_LIBRARY:
       linkFlags = this->GetStaticLibraryFlags(config, linkLanguage, target);
-      if (pcli && dynamic_cast<cmLinkLineDeviceComputer*>(linkLineComputer)) {
-        // Compute the required cuda device link libraries when
-        // resolving cuda device symbols
-        this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
-                                  frameworkPath, linkPath);
-      }
       break;
     case cmStateEnums::MODULE_LIBRARY:
       libraryLinkVariable = "CMAKE_MODULE_LINKER_FLAGS";
@@ -1827,10 +1844,10 @@ std::string cmLocalGenerator::GetLinkLibsCMP0065(
               "CMAKE_POLICY_WARNING_CMP0065")) {
           std::ostringstream w;
           /* clang-format off */
-          w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0065) << "\n"
-            "For compatibility with older versions of CMake, "
-            "additional flags may be added to export symbols on all "
-            "executables regardless of their ENABLE_EXPORTS property.";
+            w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0065) << "\n"
+              "For compatibility with older versions of CMake, "
+              "additional flags may be added to export symbols on all "
+              "executables regardless of their ENABLE_EXPORTS property.";
           /* clang-format on */
           this->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
         }
@@ -2033,7 +2050,6 @@ bool cmLocalGenerator::GetRealDependency(const std::string& inName,
   if (name.empty()) {
     return false;
   }
-
   if (cmSystemTools::GetFilenameLastExtension(name) == ".exe") {
     name = cmSystemTools::GetFilenameWithoutLastExtension(name);
   }

+ 5 - 0
Source/cmLocalGenerator.h

@@ -421,6 +421,11 @@ public:
 
   /** Fill out these strings for the given target.  Libraries to link,
    *  flags, and linkflags. */
+  void GetDeviceLinkFlags(cmLinkLineComputer* linkLineComputer,
+                          const std::string& config, std::string& linkLibs,
+                          std::string& linkFlags, std::string& frameworkPath,
+                          std::string& linkPath, cmGeneratorTarget* target);
+
   void GetTargetFlags(cmLinkLineComputer* linkLineComputer,
                       const std::string& config, std::string& linkLibs,
                       std::string& flags, std::string& linkFlags,

+ 5 - 21
Source/cmMakefileExecutableTargetGenerator.cxx

@@ -122,31 +122,15 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
   }
 
   // Build a list of compiler flags and linker flags.
-  std::string flags;
+  std::string langFlags;
   std::string linkFlags;
 
-  // Add flags to create an executable.
-  // Add symbol export flags if necessary.
-  if (this->GeneratorTarget->IsExecutableWithExports()) {
-    std::string export_flag_var =
-      cmStrCat("CMAKE_EXE_EXPORTS_", linkLanguage, "_FLAG");
-    this->LocalGenerator->AppendFlags(
-      linkFlags, this->Makefile->GetSafeDefinition(export_flag_var));
-  }
-
-  this->LocalGenerator->AppendFlags(linkFlags,
-                                    this->LocalGenerator->GetLinkLibsCMP0065(
-                                      linkLanguage, *this->GeneratorTarget));
-
   // Add language feature flags.
   this->LocalGenerator->AddLanguageFlagsForLinking(
-    flags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
-
-  this->LocalGenerator->AddArchitectureFlags(
-    flags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
+    langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
 
-  // Add target-specific linker flags.
-  this->GetTargetLinkFlags(linkFlags, linkLanguage);
+  // Add device-specific linker flags.
+  this->GetDeviceLinkFlags(linkFlags, linkLanguage);
 
   // Construct a list of files associated with this executable that
   // may need to be cleaned.
@@ -226,7 +210,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
     vars.ObjectDir = objectDir.c_str();
     vars.Target = target.c_str();
     vars.LinkLibraries = linkLibs.c_str();
-    vars.Flags = flags.c_str();
+    vars.LanguageCompileFlags = langFlags.c_str();
     vars.LinkFlags = linkFlags.c_str();
     vars.TargetCompilePDB = targetOutPathCompilePDB.c_str();
 

+ 7 - 8
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -249,9 +249,14 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules(
   std::vector<std::string> depends;
   this->AppendLinkDepends(depends, linkLanguage);
 
+  // Add language-specific flags.
+  std::string langFlags;
+  this->LocalGenerator->AddLanguageFlagsForLinking(
+    langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
+
   // Create set of linking flags.
   std::string linkFlags;
-  this->GetTargetLinkFlags(linkFlags, linkLanguage);
+  this->GetDeviceLinkFlags(linkFlags, linkLanguage);
 
   // Get the name of the device object to generate.
   std::string const targetOutputReal =
@@ -344,16 +349,10 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules(
     vars.Target = target.c_str();
     vars.LinkLibraries = linkLibs.c_str();
     vars.ObjectsQuoted = buildObjs.c_str();
+    vars.LanguageCompileFlags = langFlags.c_str();
     vars.LinkFlags = linkFlags.c_str();
     vars.TargetCompilePDB = targetOutPathCompilePDB.c_str();
 
-    // Add language-specific flags.
-    std::string langFlags;
-    this->LocalGenerator->AddLanguageFlagsForLinking(
-      langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
-
-    vars.LanguageCompileFlags = langFlags.c_str();
-
     std::string launcher;
     const char* val = this->LocalGenerator->GetRuleLauncher(
       this->GeneratorTarget, "RULE_LAUNCH_LINK");

+ 12 - 0
Source/cmMakefileTargetGenerator.cxx

@@ -87,6 +87,18 @@ std::string cmMakefileTargetGenerator::GetConfigName()
   return configNames.front();
 }
 
+void cmMakefileTargetGenerator::GetDeviceLinkFlags(
+  std::string& linkFlags, const std::string& linkLanguage)
+{
+  cmGeneratorTarget::DeviceLinkSetter setter(*this->GetGeneratorTarget());
+
+  std::vector<std::string> linkOpts;
+  this->GeneratorTarget->GetLinkOptions(linkOpts, this->GetConfigName(),
+                                        linkLanguage);
+  // LINK_OPTIONS are escaped.
+  this->LocalGenerator->AppendCompileOptions(linkFlags, linkOpts);
+}
+
 void cmMakefileTargetGenerator::GetTargetLinkFlags(
   std::string& flags, const std::string& linkLanguage)
 {

+ 2 - 0
Source/cmMakefileTargetGenerator.h

@@ -60,6 +60,8 @@ public:
   std::string GetConfigName();
 
 protected:
+  void GetDeviceLinkFlags(std::string& linkFlags,
+                          const std::string& linkLanguage);
   void GetTargetLinkFlags(std::string& flags, const std::string& linkLanguage);
 
   // create the file and directory etc

+ 10 - 26
Source/cmNinjaNormalTargetGenerator.cxx

@@ -233,11 +233,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(
     vars.LinkFlags = "$LINK_FLAGS";
     vars.Manifests = "$MANIFESTS";
 
-    std::string langFlags;
-    if (this->GetGeneratorTarget()->GetType() != cmStateEnums::EXECUTABLE) {
-      langFlags += "$LANGUAGE_COMPILE_FLAGS $ARCH_FLAGS";
-      vars.LanguageCompileFlags = langFlags.c_str();
-    }
+    vars.LanguageCompileFlags = "$LANGUAGE_COMPILE_FLAGS";
 
     std::string launcher;
     const char* val = this->GetLocalGenerator()->GetRuleLauncher(
@@ -590,8 +586,6 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement(
     return;
   }
 
-  // Now we can do device linking
-
   // First and very important step is to make sure while inside this
   // step our link language is set to CUDA
   std::string cudaLinkLanguage = "CUDA";
@@ -677,9 +671,9 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement(
   linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
   linkLineComputer->SetUseNinjaMulti(globalGen->IsMultiConfig());
 
-  localGen.GetTargetFlags(
-    linkLineComputer.get(), config, vars["LINK_LIBRARIES"], vars["FLAGS"],
-    vars["LINK_FLAGS"], frameworkPath, linkPath, genTarget);
+  localGen.GetDeviceLinkFlags(linkLineComputer.get(), config,
+                              vars["LINK_LIBRARIES"], vars["LINK_FLAGS"],
+                              frameworkPath, linkPath, genTarget);
 
   this->addPoolNinjaVariable("JOB_POOL_LINK", genTarget, vars);
 
@@ -689,22 +683,12 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement(
 
   vars["LINK_PATH"] = frameworkPath + linkPath;
 
-  // Compute architecture specific link flags.  Yes, these go into a different
-  // variable for executables, probably due to a mistake made when duplicating
-  // code between the Makefile executable and library generators.
-  if (targetType == cmStateEnums::EXECUTABLE) {
-    std::string t = vars["FLAGS"];
-    localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, config);
-    vars["FLAGS"] = t;
-  } else {
-    std::string t = vars["ARCH_FLAGS"];
-    localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, config);
-    vars["ARCH_FLAGS"] = t;
-    t.clear();
-    localGen.AddLanguageFlagsForLinking(t, genTarget, cudaLinkLanguage,
-                                        config);
-    vars["LANGUAGE_COMPILE_FLAGS"] = t;
-  }
+  // Compute language specific link flags.
+  std::string langFlags;
+  localGen.AddLanguageFlagsForLinking(langFlags, genTarget, cudaLinkLanguage,
+                                      config);
+  vars["LANGUAGE_COMPILE_FLAGS"] = langFlags;
+
   auto const tgtNames = this->TargetNames(config);
   if (genTarget->HasSOName(config)) {
     vars["SONAME_FLAG"] =

+ 6 - 3
Source/cmPolicies.h

@@ -307,12 +307,14 @@ class cmMakefile;
          "mark_as_advanced() does nothing if a cache entry does not exist.",  \
          3, 17, 0, cmPolicies::WARN)                                          \
   SELECT(POLICY, CMP0103,                                                     \
-         "multiple export() with same FILE without APPEND is not allowed.",   \
+         "Multiple export() with same FILE without APPEND is not allowed.",   \
          3, 18, 0, cmPolicies::WARN)                                          \
   SELECT(POLICY, CMP0104,                                                     \
          "CMAKE_CUDA_ARCHITECTURES now detected for NVCC, empty "             \
          "CUDA_ARCHITECTURES not allowed.",                                   \
-         3, 18, 0, cmPolicies::WARN)
+         3, 18, 0, cmPolicies::WARN)                                          \
+  SELECT(POLICY, CMP0105, "Device link step uses the link options.", 3, 18,   \
+         0, cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \
@@ -343,7 +345,8 @@ class cmMakefile;
   F(CMP0083)                                                                  \
   F(CMP0095)                                                                  \
   F(CMP0099)                                                                  \
-  F(CMP0104)
+  F(CMP0104)                                                                  \
+  F(CMP0105)
 
 /** \class cmPolicies
  * \brief Handles changes in CMake behavior and policies

+ 1 - 1
Source/cmStringAlgorithms.h

@@ -87,7 +87,7 @@ void cmExpandLists(InputIt first, InputIt last,
                    std::vector<std::string>& argsOut)
 {
   for (; first != last; ++first) {
-    ExpandList(*first, argsOut);
+    cmExpandList(*first, argsOut);
   }
 }
 

+ 16 - 6
Source/cmVisualStudio10TargetGenerator.cxx

@@ -3184,6 +3184,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions(
     this->LocalGenerator, Options::CudaCompiler, gg->GetCudaFlagTable());
   Options& cudaLinkOptions = *pOptions;
 
+  cmGeneratorTarget::DeviceLinkSetter setter(*this->GeneratorTarget);
+
   // Determine if we need to do a device link
   const bool doDeviceLinking = requireDeviceLinking(
     *this->GeneratorTarget, *this->LocalGenerator, configName);
@@ -3191,12 +3193,20 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions(
   cudaLinkOptions.AddFlag("PerformDeviceLink",
                           doDeviceLinking ? "true" : "false");
 
-  // Suppress deprecation warnings for default GPU targets during device link.
-  if (cmSystemTools::VersionCompareGreaterEq(
-        this->GlobalGenerator->GetPlatformToolsetCudaString(), "8.0")) {
-    cudaLinkOptions.AppendFlagString("AdditionalOptions",
-                                     "-Wno-deprecated-gpu-targets");
-  }
+  // Add extra flags for device linking
+  cudaLinkOptions.AppendFlagString(
+    "AdditionalOptions",
+    this->Makefile->GetSafeDefinition("_CMAKE_CUDA_EXTRA_FLAGS"));
+  cudaLinkOptions.AppendFlagString(
+    "AdditionalOptions",
+    this->Makefile->GetSafeDefinition("_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS"));
+
+  std::vector<std::string> linkOpts;
+  std::string linkFlags;
+  this->GeneratorTarget->GetLinkOptions(linkOpts, configName, "CUDA");
+  // LINK_OPTIONS are escaped.
+  this->LocalGenerator->AppendCompileOptions(linkFlags, linkOpts);
+  cudaLinkOptions.AppendFlagString("AdditionalOptions", linkFlags);
 
   // For static libraries that have device linking enabled compute
   // the  libraries

+ 2 - 1
Tests/RunCMake/CMakeLists.txt

@@ -471,7 +471,8 @@ add_RunCMake_test(ExportWithoutLanguage)
 add_RunCMake_test(target_link_directories)
 add_RunCMake_test(target_link_libraries)
 add_RunCMake_test(add_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
-add_RunCMake_test(target_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
+add_RunCMake_test(target_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
+                                      -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
 
 add_RunCMake_test(target_compile_definitions)
 add_RunCMake_test(target_compile_features)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_custom_command-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_custom_command-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at DEVICE_LINK-add_custom_command.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<DEVICE_LINK>
+
+  \$<DEVICE_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 4 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_custom_command.cmake

@@ -0,0 +1,4 @@
+add_custom_target(drive)
+add_custom_command(TARGET drive PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E echo $<DEVICE_LINK>
+)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_custom_target-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_custom_target-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at DEVICE_LINK-add_custom_target.cmake:[0-9]+ \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<DEVICE_LINK>
+
+  \$<DEVICE_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 3 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_custom_target.cmake

@@ -0,0 +1,3 @@
+add_custom_target(drive
+  COMMAND ${CMAKE_COMMAND} -E echo $<DEVICE_LINK>
+)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_executable-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_executable-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at DEVICE_LINK-add_executable.cmake:[0-9]+ \(add_executable\):
+  Error evaluating generator expression:
+
+    \$<DEVICE_LINK:empty.c>
+
+  \$<DEVICE_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_executable.cmake

@@ -0,0 +1 @@
+add_executable(empty $<DEVICE_LINK:empty.c>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_library-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_library-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at DEVICE_LINK-add_library.cmake:[0-9]+ \(add_library\):
+  Error evaluating generator expression:
+
+    \$<DEVICE_LINK:empty.c>
+
+  \$<DEVICE_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_library.cmake

@@ -0,0 +1 @@
+add_library(empty $<DEVICE_LINK:empty.c>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_test-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_test-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at DEVICE_LINK-add_test.cmake:[0-9]+ \(add_test\):
+  Error evaluating generator expression:
+
+    \$<DEVICE_LINK>
+
+  \$<DEVICE_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 5 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-add_test.cmake

@@ -0,0 +1,5 @@
+
+include(CTest)
+enable_testing()
+
+add_test(NAME dummy COMMAND ${CMAKE_COMMAND} -E echo $<DEVICE_LINK>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-install-result.txt

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

+ 7 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-install-stderr.txt

@@ -0,0 +1,7 @@
+CMake Error:
+  Error evaluating generator expression:
+
+    \$<DEVICE_LINK:empty>
+
+  \$<DEVICE_LINK:...> may only be used with binary targets to specify link
+  options.

+ 5 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-install.cmake

@@ -0,0 +1,5 @@
+
+install(FILES
+  $<DEVICE_LINK:empty>
+  DESTINATION src
+)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-link_depends-result.txt

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

+ 7 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-link_depends-stderr.txt

@@ -0,0 +1,7 @@
+CMake Error:
+  Error evaluating generator expression:
+
+    \$<DEVICE_LINK:lib>
+
+  \$<DEVICE_LINK:...> may only be used with binary targets to specify link
+  options.

+ 7 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-link_depends.cmake

@@ -0,0 +1,7 @@
+
+enable_language(C)
+
+add_library(lib empty.c)
+
+add_executable(empty empty.c)
+set_property(TARGET empty PROPERTY LINK_DEPENDS $<DEVICE_LINK:lib>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_compile_definitions-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_compile_definitions-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at DEVICE_LINK-target_compile_definitions.cmake:[0-9]+ \(target_compile_definitions\):
+  Error evaluating generator expression:
+
+    \$<DEVICE_LINK:DEF>
+
+  \$<DEVICE_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 4 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_compile_definitions.cmake

@@ -0,0 +1,4 @@
+
+enable_language(C)
+add_executable(empty empty.c)
+target_compile_definitions(empty PRIVATE $<DEVICE_LINK:DEF>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_compile_options-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_compile_options-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at DEVICE_LINK-target_compile_options.cmake:[0-9]+ \(target_compile_options\):
+  Error evaluating generator expression:
+
+    \$<DEVICE_LINK:-OPT>
+
+  \$<DEVICE_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 4 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_compile_options.cmake

@@ -0,0 +1,4 @@
+
+enable_language(C)
+add_executable(empty empty.c)
+target_compile_options(empty PRIVATE $<DEVICE_LINK:-OPT>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_include_directories-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_include_directories-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at DEVICE_LINK-target_include_directories.cmake:[0-9]+ \(target_include_directories\):
+  Error evaluating generator expression:
+
+    \$<DEVICE_LINK:/DIR>
+
+  \$<DEVICE_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 4 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_include_directories.cmake

@@ -0,0 +1,4 @@
+
+enable_language(C)
+add_executable(empty empty.c)
+target_include_directories(empty PRIVATE $<DEVICE_LINK:/DIR>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_link_directories-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_link_directories-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at DEVICE_LINK-target_link_directories.cmake:[0-9]+ \(target_link_directories\):
+  Error evaluating generator expression:
+
+    \$<DEVICE_LINK:/DIR>
+
+  \$<DEVICE_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 7 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_link_directories.cmake

@@ -0,0 +1,7 @@
+
+enable_language(C)
+
+add_library(lib empty.c)
+
+add_executable(empty empty.c)
+target_link_directories(empty PRIVATE $<DEVICE_LINK:/DIR>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_link_libraries-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_link_libraries-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at DEVICE_LINK-target_link_libraries.cmake:[0-9]+ \(target_link_libraries\):
+  Error evaluating generator expression:
+
+    \$<DEVICE_LINK:lib>
+
+  \$<DEVICE_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 7 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_link_libraries.cmake

@@ -0,0 +1,7 @@
+
+enable_language(C)
+
+add_library(lib empty.c)
+
+add_executable(empty empty.c)
+target_link_libraries(empty PRIVATE $<DEVICE_LINK:lib>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_sources-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_sources-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at DEVICE_LINK-target_sources.cmake:[0-9]+ \(target_sources\):
+  Error evaluating generator expression:
+
+    \$<DEVICE_LINK:empty.c>
+
+  \$<DEVICE_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 2 - 0
Tests/RunCMake/GeneratorExpression/DEVICE_LINK-target_sources.cmake

@@ -0,0 +1,2 @@
+add_library(empty)
+target_sources(empty PRIVATE $<DEVICE_LINK:empty.c>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-add_custom_command-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-add_custom_command-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at HOST_LINK-add_custom_command.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<HOST_LINK>
+
+  \$<HOST_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 4 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-add_custom_command.cmake

@@ -0,0 +1,4 @@
+add_custom_target(drive)
+add_custom_command(TARGET drive PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E echo $<HOST_LINK>
+)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-add_custom_target-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-add_custom_target-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at HOST_LINK-add_custom_target.cmake:[0-9]+ \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<HOST_LINK>
+
+  \$<HOST_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 3 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-add_custom_target.cmake

@@ -0,0 +1,3 @@
+add_custom_target(drive
+  COMMAND ${CMAKE_COMMAND} -E echo $<HOST_LINK>
+)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-add_executable-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-add_executable-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at HOST_LINK-add_executable.cmake:[0-9]+ \(add_executable\):
+  Error evaluating generator expression:
+
+    \$<HOST_LINK:empty.c>
+
+  \$<HOST_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-add_executable.cmake

@@ -0,0 +1 @@
+add_executable(empty $<HOST_LINK:empty.c>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-add_library-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-add_library-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at HOST_LINK-add_library.cmake:[0-9]+ \(add_library\):
+  Error evaluating generator expression:
+
+    \$<HOST_LINK:empty.c>
+
+  \$<HOST_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-add_library.cmake

@@ -0,0 +1 @@
+add_library(empty $<HOST_LINK:empty.c>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-add_test-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-add_test-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at HOST_LINK-add_test.cmake:[0-9]+ \(add_test\):
+  Error evaluating generator expression:
+
+    \$<HOST_LINK>
+
+  \$<HOST_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 5 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-add_test.cmake

@@ -0,0 +1,5 @@
+
+include(CTest)
+enable_testing()
+
+add_test(NAME dummy COMMAND ${CMAKE_COMMAND} -E echo $<HOST_LINK>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-install-result.txt

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

+ 7 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-install-stderr.txt

@@ -0,0 +1,7 @@
+CMake Error:
+  Error evaluating generator expression:
+
+    \$<HOST_LINK:empty>
+
+  \$<HOST_LINK:...> may only be used with binary targets to specify link
+  options.

+ 5 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-install.cmake

@@ -0,0 +1,5 @@
+
+install(FILES
+  $<HOST_LINK:empty>
+  DESTINATION src
+)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-link_depends-result.txt

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

+ 7 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-link_depends-stderr.txt

@@ -0,0 +1,7 @@
+CMake Error:
+  Error evaluating generator expression:
+
+    \$<HOST_LINK:lib>
+
+  \$<HOST_LINK:...> may only be used with binary targets to specify link
+  options.

+ 7 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-link_depends.cmake

@@ -0,0 +1,7 @@
+
+enable_language(C)
+
+add_library(lib empty.c)
+
+add_executable(empty empty.c)
+set_property(TARGET empty PROPERTY LINK_DEPENDS $<HOST_LINK:lib>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-target_compile_definitions-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-target_compile_definitions-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at HOST_LINK-target_compile_definitions.cmake:[0-9]+ \(target_compile_definitions\):
+  Error evaluating generator expression:
+
+    \$<HOST_LINK:DEF>
+
+  \$<HOST_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 4 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-target_compile_definitions.cmake

@@ -0,0 +1,4 @@
+
+enable_language(C)
+add_executable(empty empty.c)
+target_compile_definitions(empty PRIVATE $<HOST_LINK:DEF>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-target_compile_options-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-target_compile_options-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at HOST_LINK-target_compile_options.cmake:[0-9]+ \(target_compile_options\):
+  Error evaluating generator expression:
+
+    \$<HOST_LINK:-OPT>
+
+  \$<HOST_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 4 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-target_compile_options.cmake

@@ -0,0 +1,4 @@
+
+enable_language(C)
+add_executable(empty empty.c)
+target_compile_options(empty PRIVATE $<HOST_LINK:-OPT>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-target_include_directories-result.txt

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

+ 9 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-target_include_directories-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at HOST_LINK-target_include_directories.cmake:[0-9]+ \(target_include_directories\):
+  Error evaluating generator expression:
+
+    \$<HOST_LINK:/DIR>
+
+  \$<HOST_LINK:...> may only be used with binary targets to specify link
+  options.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 4 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-target_include_directories.cmake

@@ -0,0 +1,4 @@
+
+enable_language(C)
+add_executable(empty empty.c)
+target_include_directories(empty PRIVATE $<HOST_LINK:/DIR>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/HOST_LINK-target_link_directories-result.txt

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

Some files were not shown because too many files changed in this diff