Просмотр исходного кода

Merge topic 'LINK_OPTIONS'

66ea1a3795 LINK_OPTIONS: Add support of "LINKER:" prefix
c1f5a44b28 LINK_OPTIONS: Add new family of properties
8e28d2630a Makefile generator: link flags management refactoring

Acked-by: Kitware Robot <[email protected]>
Acked-by: Alex Turbov <[email protected]>
Merge-request: !2033
Brad King 7 лет назад
Родитель
Сommit
812eaa465c
100 измененных файлов с 1069 добавлено и 77 удалено
  1. 10 0
      Help/command/LINK_OPTIONS_LINKER.txt
  2. 1 1
      Help/command/OPTIONS_SHELL.txt
  3. 1 1
      Help/command/add_compile_options.rst
  4. 26 0
      Help/command/add_link_options.rst
  5. 1 1
      Help/command/target_compile_options.rst
  6. 2 1
      Help/command/target_link_libraries.rst
  7. 42 0
      Help/command/target_link_options.rst
  8. 2 0
      Help/manual/cmake-commands.7.rst
  9. 3 0
      Help/manual/cmake-properties.7.rst
  10. 2 0
      Help/manual/cmake-variables.7.rst
  11. 16 0
      Help/prop_dir/LINK_OPTIONS.rst
  12. 9 0
      Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst
  13. 6 2
      Help/prop_tgt/LINK_FLAGS.rst
  14. 4 0
      Help/prop_tgt/LINK_FLAGS_CONFIG.rst
  15. 21 0
      Help/prop_tgt/LINK_OPTIONS.rst
  16. 11 0
      Help/release/dev/LINK_OPTIONS.rst
  17. 39 0
      Help/variable/CMAKE_LANG_LINKER_WRAPPER_FLAG.rst
  18. 9 0
      Help/variable/CMAKE_LANG_LINKER_WRAPPER_FLAG_SEP.rst
  19. 2 0
      Modules/Compiler/ARMCC.cmake
  20. 1 0
      Modules/Compiler/Absoft-Fortran.cmake
  21. 2 0
      Modules/Compiler/Bruce-C.cmake
  22. 2 0
      Modules/Compiler/Clang.cmake
  23. 2 0
      Modules/Compiler/G95-Fortran.cmake
  24. 3 0
      Modules/Compiler/GNU.cmake
  25. 3 0
      Modules/Compiler/HP-C.cmake
  26. 3 0
      Modules/Compiler/HP-CXX.cmake
  27. 3 0
      Modules/Compiler/HP-Fortran.cmake
  28. 3 0
      Modules/Compiler/PGI.cmake
  29. 3 0
      Modules/Compiler/QCC.cmake
  30. 3 0
      Modules/Compiler/SCO.cmake
  31. 3 0
      Modules/Compiler/SunPro-C.cmake
  32. 3 0
      Modules/Compiler/SunPro-CXX.cmake
  33. 3 0
      Modules/Compiler/SunPro-Fortran.cmake
  34. 3 0
      Modules/Compiler/TinyCC-C.cmake
  35. 3 0
      Modules/Compiler/XL.cmake
  36. 3 0
      Modules/Platform/Apple-Intel.cmake
  37. 3 1
      Modules/Platform/Generic-ADSP-C.cmake
  38. 3 1
      Modules/Platform/Generic-ADSP-CXX.cmake
  39. 2 1
      Modules/Platform/Generic-SDCC-C.cmake
  40. 3 0
      Modules/Platform/Linux-Intel.cmake
  41. 2 0
      Modules/Platform/Windows-Embarcadero.cmake
  42. 4 0
      Source/CMakeLists.txt
  43. 20 0
      Source/cmAddLinkOptionsCommand.cxx
  44. 31 0
      Source/cmAddLinkOptionsCommand.h
  45. 5 0
      Source/cmCommands.cxx
  46. 6 0
      Source/cmExportBuildAndroidMKGenerator.cxx
  47. 3 0
      Source/cmExportBuildFileGenerator.cxx
  48. 3 0
      Source/cmExportInstallFileGenerator.cxx
  49. 2 1
      Source/cmGeneratorExpressionDAGChecker.h
  50. 164 11
      Source/cmGeneratorTarget.cxx
  51. 6 0
      Source/cmGeneratorTarget.h
  52. 4 0
      Source/cmGlobalXCodeGenerator.cxx
  53. 8 0
      Source/cmLocalGenerator.cxx
  54. 7 0
      Source/cmLocalVisualStudio7Generator.cxx
  55. 15 0
      Source/cmMakefile.cxx
  56. 3 0
      Source/cmMakefile.h
  57. 2 12
      Source/cmMakefileExecutableTargetGenerator.cxx
  58. 8 34
      Source/cmMakefileLibraryTargetGenerator.cxx
  59. 1 2
      Source/cmMakefileLibraryTargetGenerator.h
  60. 17 0
      Source/cmMakefileTargetGenerator.cxx
  61. 2 0
      Source/cmMakefileTargetGenerator.h
  62. 2 0
      Source/cmState.cxx
  63. 52 0
      Source/cmStateDirectory.cxx
  64. 7 0
      Source/cmStateDirectory.h
  65. 4 0
      Source/cmStatePrivate.h
  66. 7 0
      Source/cmStateSnapshot.cxx
  67. 71 6
      Source/cmTarget.cxx
  68. 6 0
      Source/cmTarget.h
  69. 41 0
      Source/cmTargetLinkOptionsCommand.cxx
  70. 41 0
      Source/cmTargetLinkOptionsCommand.h
  71. 5 0
      Source/cmVisualStudio10TargetGenerator.cxx
  72. 20 0
      Tests/CMakeCommands/add_link_options/CMakeLists.txt
  73. 4 0
      Tests/CMakeCommands/add_link_options/LinkOptionsExe.c
  74. 19 0
      Tests/CMakeCommands/target_link_options/CMakeLists.txt
  75. 7 0
      Tests/CMakeCommands/target_link_options/LinkOptionsLib.c
  76. 3 0
      Tests/CMakeLists.txt
  77. 10 0
      Tests/ExportImport/Export/CMakeLists.txt
  78. 5 0
      Tests/ExportImport/Import/A/CMakeLists.txt
  79. 8 0
      Tests/ExportImport/Import/A/imp_testLinkOptions.cpp
  80. 4 2
      Tests/RunCMake/AndroidMK/AndroidMK.cmake
  81. 8 0
      Tests/RunCMake/AndroidMK/expectedBuildAndroidMK.txt
  82. 8 0
      Tests/RunCMake/AndroidMK/expectedInstallAndroidMK.txt
  83. 2 0
      Tests/RunCMake/CMakeLists.txt
  84. 5 0
      Tests/RunCMake/add_link_options/CMakeLists.txt
  85. 2 0
      Tests/RunCMake/add_link_options/LINKER_SHELL_expansion-build-check.cmake
  86. 4 0
      Tests/RunCMake/add_link_options/LINKER_SHELL_expansion.cmake
  87. 2 0
      Tests/RunCMake/add_link_options/LINKER_expansion-build-check.cmake
  88. 36 0
      Tests/RunCMake/add_link_options/LINKER_expansion-list.cmake
  89. 15 0
      Tests/RunCMake/add_link_options/LINKER_expansion-validation.cmake
  90. 4 0
      Tests/RunCMake/add_link_options/LINKER_expansion.cmake
  91. 7 0
      Tests/RunCMake/add_link_options/LINK_OPTIONS-exe-check.cmake
  92. 1 0
      Tests/RunCMake/add_link_options/LINK_OPTIONS-exe-result.txt
  93. 7 0
      Tests/RunCMake/add_link_options/LINK_OPTIONS-mod-check.cmake
  94. 1 0
      Tests/RunCMake/add_link_options/LINK_OPTIONS-mod-result.txt
  95. 7 0
      Tests/RunCMake/add_link_options/LINK_OPTIONS-shared-check.cmake
  96. 1 0
      Tests/RunCMake/add_link_options/LINK_OPTIONS-shared-result.txt
  97. 17 0
      Tests/RunCMake/add_link_options/LINK_OPTIONS.cmake
  98. 4 0
      Tests/RunCMake/add_link_options/LinkOptionsExe.c
  99. 7 0
      Tests/RunCMake/add_link_options/LinkOptionsLib.c
  100. 38 0
      Tests/RunCMake/add_link_options/RunCMakeTest.cmake

+ 10 - 0
Help/command/LINK_OPTIONS_LINKER.txt

@@ -0,0 +1,10 @@
+To pass options to the linker tool, each compiler driver has is own syntax.
+The ``LINKER:`` prefix can be used to specify, in a portable way, options
+to pass to the linker tool. The ``LINKER:`` prefix is replaced by the required
+driver option and the rest of the option string defines linker arguments using
+``,`` as separator. These arguments will be formatted according to the
+:variable:`CMAKE_<LANG>_LINKER_WRAPPER_FLAG` and
+:variable:`CMAKE_<LANG>_LINKER_WRAPPER_FLAG_SEP` variables.
+
+For example, ``"LINKER:-z,defs"`` becomes ``-Xlinker -z -Xlinker defs`` for
+``Clang`` and ``-Wl,-z,defs`` for ``GNU GCC``.

+ 1 - 1
Help/command/COMPILE_OPTIONS_SHELL.txt → Help/command/OPTIONS_SHELL.txt

@@ -1,4 +1,4 @@
-The final set of compile options used for a target is constructed by
+The final set of compile or link options used for a target is constructed by
 accumulating options from the current target and the usage requirements of
 accumulating options from the current target and the usage requirements of
 it dependencies.  The set of options is de-duplicated to avoid repetition.
 it dependencies.  The set of options is de-duplicated to avoid repetition.
 While beneficial for individual options, the de-duplication step can break
 While beneficial for individual options, the de-duplication step can break

+ 1 - 1
Help/command/add_compile_options.rst

@@ -22,4 +22,4 @@ the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
 manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
 manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
 manual for more on defining buildsystem properties.
 manual for more on defining buildsystem properties.
 
 
-.. include:: COMPILE_OPTIONS_SHELL.txt
+.. include:: OPTIONS_SHELL.txt

+ 26 - 0
Help/command/add_link_options.rst

@@ -0,0 +1,26 @@
+add_link_options
+----------------
+
+Adds options to the link of targets.
+
+::
+
+  add_link_options(<option> ...)
+
+Adds options to the link step for targets in the current directory and below
+that are added after this command is invoked. See documentation of the
+:prop_dir:`directory <LINK_OPTIONS>` and
+:prop_tgt:`target <LINK_OPTIONS>` ``LINK_OPTIONS`` properties.
+
+This command can be used to add any options, but alternative commands
+exist to add libraries (:command:`target_link_libraries` or
+:command:`link_libraries`).
+
+Arguments to ``add_link_options`` may use "generator expressions" 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:: LINK_OPTIONS_LINKER.txt
+
+.. include:: OPTIONS_SHELL.txt

+ 1 - 1
Help/command/target_compile_options.rst

@@ -39,4 +39,4 @@ with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
 manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
 manual for available expressions.  See the :manual:`cmake-buildsystem(7)`
 manual for more on defining buildsystem properties.
 manual for more on defining buildsystem properties.
 
 
-.. include:: COMPILE_OPTIONS_SHELL.txt
+.. include:: OPTIONS_SHELL.txt

+ 2 - 1
Help/command/target_link_libraries.rst

@@ -70,7 +70,8 @@ Each ``<item>`` may be:
 
 
   Link flags specified here are inserted into the link command in the same
   Link flags specified here are inserted into the link command in the same
   place as the link libraries. This might not be correct, depending on
   place as the link libraries. This might not be correct, depending on
-  the linker. Use the :prop_tgt:`LINK_FLAGS` target property to add link
+  the linker. Use the :prop_tgt:`LINK_OPTIONS` target property or
+  :command:`target_link_options` command to add link
   flags explicitly. The flags will then be placed at the toolchain-defined
   flags explicitly. The flags will then be placed at the toolchain-defined
   flag position in the link command.
   flag position in the link command.
 
 

+ 42 - 0
Help/command/target_link_options.rst

@@ -0,0 +1,42 @@
+target_link_options
+-------------------
+
+Add link options to a target.
+
+::
+
+  target_link_options(<target> [BEFORE]
+    <INTERFACE|PUBLIC|PRIVATE> [items1...]
+    [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
+
+Specify link options to use when linking a given target.  The
+named ``<target>`` must have been created by a command such as
+:command:`add_executable` or :command:`add_library` and must not be an
+:ref:`ALIAS target <Alias Targets>`.
+
+If ``BEFORE`` is specified, the content will be prepended to the property
+instead of being appended.
+
+This command can be used to add any options, but
+alternative commands exist to add libraries
+(:command:`target_link_libraries` and :command:`link_libraries`).
+See documentation of the :prop_dir:`directory <LINK_OPTIONS>` and
+:prop_tgt:`target <LINK_OPTIONS>` ``LINK_OPTIONS`` properties.
+
+The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
+specify the scope of the following arguments.  ``PRIVATE`` and ``PUBLIC``
+items will populate the :prop_tgt:`LINK_OPTIONS` property of
+``<target>``.  ``PUBLIC`` and ``INTERFACE`` items will populate the
+:prop_tgt:`INTERFACE_LINK_OPTIONS` property of ``<target>``.
+(:ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items.)
+The following arguments specify link options.  Repeated calls for the same
+``<target>`` append items in the order called.
+
+Arguments to ``target_link_options`` may use "generator expressions"
+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:: LINK_OPTIONS_LINKER.txt
+
+.. include:: OPTIONS_SHELL.txt

+ 2 - 0
Help/manual/cmake-commands.7.rst

@@ -78,6 +78,7 @@ These commands are available only in CMake projects.
    /command/add_dependencies
    /command/add_dependencies
    /command/add_executable
    /command/add_executable
    /command/add_library
    /command/add_library
+   /command/add_link_options
    /command/add_subdirectory
    /command/add_subdirectory
    /command/add_test
    /command/add_test
    /command/aux_source_directory
    /command/aux_source_directory
@@ -111,6 +112,7 @@ These commands are available only in CMake projects.
    /command/target_compile_options
    /command/target_compile_options
    /command/target_include_directories
    /command/target_include_directories
    /command/target_link_libraries
    /command/target_link_libraries
+   /command/target_link_options
    /command/target_sources
    /command/target_sources
    /command/try_compile
    /command/try_compile
    /command/try_run
    /command/try_run

+ 3 - 0
Help/manual/cmake-properties.7.rst

@@ -77,6 +77,7 @@ Properties on Directories
    /prop_dir/INTERPROCEDURAL_OPTIMIZATION
    /prop_dir/INTERPROCEDURAL_OPTIMIZATION
    /prop_dir/LABELS
    /prop_dir/LABELS
    /prop_dir/LINK_DIRECTORIES
    /prop_dir/LINK_DIRECTORIES
+   /prop_dir/LINK_OPTIONS
    /prop_dir/LISTFILE_STACK
    /prop_dir/LISTFILE_STACK
    /prop_dir/MACROS
    /prop_dir/MACROS
    /prop_dir/PARENT_DIRECTORY
    /prop_dir/PARENT_DIRECTORY
@@ -225,6 +226,7 @@ Properties on Targets
    /prop_tgt/INTERFACE_COMPILE_OPTIONS
    /prop_tgt/INTERFACE_COMPILE_OPTIONS
    /prop_tgt/INTERFACE_INCLUDE_DIRECTORIES
    /prop_tgt/INTERFACE_INCLUDE_DIRECTORIES
    /prop_tgt/INTERFACE_LINK_LIBRARIES
    /prop_tgt/INTERFACE_LINK_LIBRARIES
+   /prop_tgt/INTERFACE_LINK_OPTIONS
    /prop_tgt/INTERFACE_POSITION_INDEPENDENT_CODE
    /prop_tgt/INTERFACE_POSITION_INDEPENDENT_CODE
    /prop_tgt/INTERFACE_SOURCES
    /prop_tgt/INTERFACE_SOURCES
    /prop_tgt/INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
    /prop_tgt/INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
@@ -254,6 +256,7 @@ Properties on Targets
    /prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG
    /prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG
    /prop_tgt/LINK_INTERFACE_MULTIPLICITY
    /prop_tgt/LINK_INTERFACE_MULTIPLICITY
    /prop_tgt/LINK_LIBRARIES
    /prop_tgt/LINK_LIBRARIES
+   /prop_tgt/LINK_OPTIONS
    /prop_tgt/LINK_SEARCH_END_STATIC
    /prop_tgt/LINK_SEARCH_END_STATIC
    /prop_tgt/LINK_SEARCH_START_STATIC
    /prop_tgt/LINK_SEARCH_START_STATIC
    /prop_tgt/LINK_WHAT_YOU_USE
    /prop_tgt/LINK_WHAT_YOU_USE

+ 2 - 0
Help/manual/cmake-variables.7.rst

@@ -460,6 +460,8 @@ Variables for Languages
    /variable/CMAKE_LANG_LIBRARY_ARCHITECTURE
    /variable/CMAKE_LANG_LIBRARY_ARCHITECTURE
    /variable/CMAKE_LANG_LINKER_PREFERENCE
    /variable/CMAKE_LANG_LINKER_PREFERENCE
    /variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES
    /variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES
+   /variable/CMAKE_LANG_LINKER_WRAPPER_FLAG
+   /variable/CMAKE_LANG_LINKER_WRAPPER_FLAG_SEP
    /variable/CMAKE_LANG_LINK_EXECUTABLE
    /variable/CMAKE_LANG_LINK_EXECUTABLE
    /variable/CMAKE_LANG_OUTPUT_EXTENSION
    /variable/CMAKE_LANG_OUTPUT_EXTENSION
    /variable/CMAKE_LANG_PLATFORM_ID
    /variable/CMAKE_LANG_PLATFORM_ID

+ 16 - 0
Help/prop_dir/LINK_OPTIONS.rst

@@ -0,0 +1,16 @@
+LINK_OPTIONS
+------------
+
+List of options to use for the link step.
+
+This property holds a :ref:`;-list <CMake Language Lists>` of options
+given so far to the :command:`add_link_options` command.
+
+This property is used to initialize the :prop_tgt:`LINK_OPTIONS` target
+property when a target is created, which is used by the generators to set
+the options for the compiler.
+
+Contents of ``LINK_OPTIONS`` may use "generator expressions" 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.

+ 9 - 0
Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst

@@ -0,0 +1,9 @@
+INTERFACE_LINK_OPTIONS
+----------------------
+
+.. |property_name| replace:: link options
+.. |command_name| replace:: :command:`target_link_options`
+.. |PROPERTY_INTERFACE_NAME| replace:: ``INTERFACE_LINK_OPTIONS``
+.. |PROPERTY_LINK| replace:: :prop_tgt:`LINK_OPTIONS`
+.. |PROPERTY_GENEX| replace:: ``$<TARGET_PROPERTY:foo,INTERFACE_LINK_OPTIONS>``
+.. include:: INTERFACE_BUILD_PROPERTY.txt

+ 6 - 2
Help/prop_tgt/LINK_FLAGS.rst

@@ -3,7 +3,11 @@ LINK_FLAGS
 
 
 Additional flags to use when linking this target.
 Additional flags to use when linking this target.
 
 
-The LINK_FLAGS property can be used to add extra flags to the link
-step of a target.  :prop_tgt:`LINK_FLAGS_<CONFIG>` will add to the
+The LINK_FLAGS property, managed as a string, can be used to add extra flags
+to the link step of a target.  :prop_tgt:`LINK_FLAGS_<CONFIG>` will add to the
 configuration ``<CONFIG>``, for example, ``DEBUG``, ``RELEASE``,
 configuration ``<CONFIG>``, for example, ``DEBUG``, ``RELEASE``,
 ``MINSIZEREL``, ``RELWITHDEBINFO``, ...
 ``MINSIZEREL``, ``RELWITHDEBINFO``, ...
+
+.. note::
+
+  This property has been superseded by :prop_tgt:`LINK_OPTIONS` property.

+ 4 - 0
Help/prop_tgt/LINK_FLAGS_CONFIG.rst

@@ -4,3 +4,7 @@ LINK_FLAGS_<CONFIG>
 Per-configuration linker flags for a target.
 Per-configuration linker flags for a target.
 
 
 This is the configuration-specific version of LINK_FLAGS.
 This is the configuration-specific version of LINK_FLAGS.
+
+.. note::
+
+  This property has been superseded by :prop_tgt:`LINK_OPTIONS` property.

+ 21 - 0
Help/prop_tgt/LINK_OPTIONS.rst

@@ -0,0 +1,21 @@
+LINK_OPTIONS
+------------
+
+List of options to use when linking this target.
+
+This property holds a :ref:`;-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
+property when a target is created, and is used by the generators to set
+the options for the compiler.
+
+Contents of ``LINK_OPTIONS`` may use "generator expressions" 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.
+
+.. note::
+
+  This property must be used in preference to :prop_tgt:`LINK_FLAGS` property.

+ 11 - 0
Help/release/dev/LINK_OPTIONS.rst

@@ -0,0 +1,11 @@
+LINK_OPTIONS
+------------
+
+* CMake gained new capabilities to manage link step:
+
+  * :prop_dir:`LINK_OPTIONS` directory property.
+  * :prop_tgt:`LINK_OPTIONS` and :prop_tgt:`INTERFACE_LINK_OPTIONS` target
+    properties.
+  * :command:`add_link_options` command to add link options in the current
+    directory.
+  * :command:`target_link_options` command to add link options to targets.

+ 39 - 0
Help/variable/CMAKE_LANG_LINKER_WRAPPER_FLAG.rst

@@ -0,0 +1,39 @@
+CMAKE_<LANG>_LINKER_WRAPPER_FLAG
+--------------------------------
+
+Defines the syntax of compiler driver option to pass options to the linker
+tool. It will be used to translate the ``LINKER:`` prefix in the link options
+(see :command:`add_link_options` and :command:`target_link_options`).
+
+This variable holds a :ref:`;-list <CMake Language Lists>` of tokens.
+If a space (i.e. " ") is specified as last token, flag and ``LINKER:``
+arguments will be specified as separate arguments to the compiler driver.
+The :variable:`CMAKE_<LANG>_LINKER_WRAPPER_FLAG_SEP` variable can be specified
+to manage concatenation of arguments.
+
+For example, for ``Clang`` we have:
+
+.. code-block:: cmake
+
+  set (CMAKE_C_LINKER_WRAPPER_FLAG "-Xlinker" " ")
+
+Specifying ``"LINKER:-z defs"`` will be transformed in
+``-Xlinker -z -Xlinker defs``.
+
+For ``GNU GCC``:
+
+.. code-block:: cmake
+
+  set (CMAKE_C_LINKER_WRAPPER_FLAG "-Wl,")
+  set (CMAKE_C_LINKER_WRAPPER_FLAG_SEP ",")
+
+Specifying ``"LINKER:-z defs"`` will be transformed in ``-Wl,-z,defs``.
+
+And for ``SunPro``:
+
+.. code-block:: cmake
+
+  set (CMAKE_C_LINKER_WRAPPER_FLAG "-Qoption" "ld" " ")
+  set (CMAKE_C_LINKER_WRAPPER_FLAG_SEP ",")
+
+Specifying ``"LINKER:-z defs"`` will be transformed in ``-Qoption ld -z,defs``.

+ 9 - 0
Help/variable/CMAKE_LANG_LINKER_WRAPPER_FLAG_SEP.rst

@@ -0,0 +1,9 @@
+CMAKE_<LANG>_LINKER_WRAPPER_FLAG_SEP
+------------------------------------
+
+This variable is used with :variable:`CMAKE_<LANG>_LINKER_WRAPPER_FLAG`
+variable to format ``LINKER:`` prefix in the link options
+(see :command:`add_link_options` and :command:`target_link_options`).
+
+When specified, arguments of the ``LINKER:`` prefix will be concatenated using
+this value as separator.

+ 2 - 0
Modules/Compiler/ARMCC.cmake

@@ -34,4 +34,6 @@ macro(__compiler_armcc lang)
   set(CMAKE_${lang}_CREATE_STATIC_LIBRARY  "<CMAKE_AR> --create -cr <TARGET> <LINK_FLAGS> <OBJECTS>")
   set(CMAKE_${lang}_CREATE_STATIC_LIBRARY  "<CMAKE_AR> --create -cr <TARGET> <LINK_FLAGS> <OBJECTS>")
 
 
   set(CMAKE_DEPFILE_FLAGS_${lang} "--depend=<DEPFILE> --depend_single_line --no_depend_system_headers")
   set(CMAKE_DEPFILE_FLAGS_${lang} "--depend=<DEPFILE> --depend_single_line --no_depend_system_headers")
+
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Xlinker" " ")
 endmacro()
 endmacro()

+ 1 - 0
Modules/Compiler/Absoft-Fortran.cmake

@@ -8,3 +8,4 @@ set(CMAKE_Fortran_MODPATH_FLAG "-p")
 set(CMAKE_Fortran_VERBOSE_FLAG "-v")
 set(CMAKE_Fortran_VERBOSE_FLAG "-v")
 set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed")
 set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed")
 set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree")
 set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree")
+set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-X")

+ 2 - 0
Modules/Compiler/Bruce-C.cmake

@@ -5,3 +5,5 @@ string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " -g")
 string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
 string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
 string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
 string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
 string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -g -DNDEBUG")
 string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -g -DNDEBUG")
+
+set(CMAKE_C_LINKER_WRAPPER_FLAG "-X")

+ 2 - 0
Modules/Compiler/Clang.cmake

@@ -30,6 +30,8 @@ else()
       set(CMAKE_${lang}_COMPILE_OPTIONS_TARGET "--target=")
       set(CMAKE_${lang}_COMPILE_OPTIONS_TARGET "--target=")
       set(CMAKE_${lang}_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN "--gcc-toolchain=")
       set(CMAKE_${lang}_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN "--gcc-toolchain=")
     endif()
     endif()
+    set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Xlinker" " ")
+    set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP)
 
 
     set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
     set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
     set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
     set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)

+ 2 - 0
Modules/Compiler/G95-Fortran.cmake

@@ -7,3 +7,5 @@ set(CMAKE_Fortran_MODDIR_FLAG "-fmod=")
 set(CMAKE_Fortran_VERBOSE_FLAG "-v")
 set(CMAKE_Fortran_VERBOSE_FLAG "-v")
 set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
 set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
 set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
 set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
+set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
+set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")

+ 3 - 0
Modules/Compiler/GNU.cmake

@@ -24,6 +24,9 @@ macro(__compiler_gnu lang)
   set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
   set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
   set(CMAKE_${lang}_COMPILE_OPTIONS_SYSROOT "--sysroot=")
   set(CMAKE_${lang}_COMPILE_OPTIONS_SYSROOT "--sysroot=")
 
 
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
   # Older versions of gcc (< 4.5) contain a bug causing them to report a missing
   # Older versions of gcc (< 4.5) contain a bug causing them to report a missing
   # header file as a warning if depfiles are enabled, causing check_header_file
   # header file as a warning if depfiles are enabled, causing check_header_file
   # tests to always succeed.  Work around this by disabling dependency tracking
   # tests to always succeed.  Work around this by disabling dependency tracking

+ 3 - 0
Modules/Compiler/HP-C.cmake

@@ -2,3 +2,6 @@ set(CMAKE_C_VERBOSE_FLAG "-v")
 
 
 set(CMAKE_C_CREATE_ASSEMBLY_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
 set(CMAKE_C_CREATE_ASSEMBLY_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
 set(CMAKE_C_CREATE_PREPROCESSED_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
 set(CMAKE_C_CREATE_PREPROCESSED_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+
+set(CMAKE_C_LINKER_WRAPPER_FLAG "-Wl,")
+set(CMAKE_C_LINKER_WRAPPER_FLAG_SEP ",")

+ 3 - 0
Modules/Compiler/HP-CXX.cmake

@@ -3,6 +3,9 @@ set(CMAKE_CXX_VERBOSE_FLAG "-v")
 set(CMAKE_CXX_CREATE_ASSEMBLY_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
 set(CMAKE_CXX_CREATE_ASSEMBLY_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
 set(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
 set(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
 
 
+set(CMAKE_CXX_LINKER_WRAPPER_FLAG "-Wl,")
+set(CMAKE_CXX_LINKER_WRAPPER_FLAG_SEP ",")
+
 # HP aCC since version 3.80 supports the flag +hpxstd98 to get ANSI C++98
 # HP aCC since version 3.80 supports the flag +hpxstd98 to get ANSI C++98
 # template support. It is known that version 6.25 doesn't need that flag.
 # template support. It is known that version 6.25 doesn't need that flag.
 # Current assumption: the flag is needed for every version from 3.80 to 4
 # Current assumption: the flag is needed for every version from 3.80 to 4

+ 3 - 0
Modules/Compiler/HP-Fortran.cmake

@@ -4,3 +4,6 @@ set(CMAKE_Fortran_FORMAT_FREE_FLAG "+source=free")
 
 
 set(CMAKE_Fortran_CREATE_ASSEMBLY_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
 set(CMAKE_Fortran_CREATE_ASSEMBLY_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
 set(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
 set(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+
+set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
+set(CMAKE_Fortran_LINKER_WRAPPER_FLAG ",")

+ 3 - 0
Modules/Compiler/PGI.cmake

@@ -25,6 +25,9 @@ macro(__compiler_pgi lang)
     string(APPEND CMAKE_${lang}_FLAGS_INIT " -Bdynamic")
     string(APPEND CMAKE_${lang}_FLAGS_INIT " -Bdynamic")
   endif()
   endif()
 
 
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG ",")
+
   set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
   set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
   if(NOT CMAKE_SYSTEM_PROCESSOR STREQUAL ppc64le AND (NOT CMAKE_HOST_WIN32 OR CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 16.3))
   if(NOT CMAKE_SYSTEM_PROCESSOR STREQUAL ppc64le AND (NOT CMAKE_HOST_WIN32 OR CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 16.3))
     set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
     set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)

+ 3 - 0
Modules/Compiler/QCC.cmake

@@ -13,6 +13,9 @@ macro(__compiler_qcc lang)
   set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-Wp,-isystem,")
   set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-Wp,-isystem,")
   set(CMAKE_DEPFILE_FLAGS_${lang} "-Wc,-MD,<DEPFILE>,-MT,<OBJECT>,-MF,<DEPFILE>")
   set(CMAKE_DEPFILE_FLAGS_${lang} "-Wc,-MD,<DEPFILE>,-MT,<OBJECT>,-MF,<DEPFILE>")
 
 
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
   set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE NO)
   set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE NO)
   set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER NO)
   set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER NO)
 
 

+ 3 - 0
Modules/Compiler/SCO.cmake

@@ -15,4 +15,7 @@ macro(__compiler_sco lang)
   set(CMAKE_${lang}_COMPILE_OPTIONS_DLL -belf)
   set(CMAKE_${lang}_COMPILE_OPTIONS_DLL -belf)
   set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-Kpic -belf")
   set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-Kpic -belf")
   set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-belf -Wl,-Bexport")
   set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-belf -Wl,-Bexport")
+
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
 endmacro()
 endmacro()

+ 3 - 0
Modules/Compiler/SunPro-C.cmake

@@ -29,6 +29,9 @@ foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
   set(CMAKE_${type}_LINK_DYNAMIC_C_FLAGS "-Bdynamic")
   set(CMAKE_${type}_LINK_DYNAMIC_C_FLAGS "-Bdynamic")
 endforeach()
 endforeach()
 
 
+set(CMAKE_C_LINKER_WRAPPER_FLAG "-Qoption" "ld" " ")
+set(CMAKE_C_LINKER_WRAPPER_FLAG_SEP ",")
+
 if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 5.13)
 if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 5.13)
   set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c89")
   set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c89")
   set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=c89")
   set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=c89")

+ 3 - 0
Modules/Compiler/SunPro-CXX.cmake

@@ -29,6 +29,9 @@ foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
   set(CMAKE_${type}_LINK_DYNAMIC_CXX_FLAGS "-Bdynamic")
   set(CMAKE_${type}_LINK_DYNAMIC_CXX_FLAGS "-Bdynamic")
 endforeach()
 endforeach()
 
 
+set(CMAKE_CXX_LINKER_WRAPPER_FLAG "-Qoption" "ld" " ")
+set(CMAKE_CXX_LINKER_WRAPPER_FLAG_SEP ",")
+
 set(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
 set(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
 set(CMAKE_CXX_CREATE_ASSEMBLY_SOURCE "<CMAKE_CXX_COMPILER> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
 set(CMAKE_CXX_CREATE_ASSEMBLY_SOURCE "<CMAKE_CXX_COMPILER> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
 
 

+ 3 - 0
Modules/Compiler/SunPro-Fortran.cmake

@@ -18,6 +18,9 @@ string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -g -xO2 -DNDEBUG")
 set(CMAKE_Fortran_MODDIR_FLAG "-moddir=")
 set(CMAKE_Fortran_MODDIR_FLAG "-moddir=")
 set(CMAKE_Fortran_MODPATH_FLAG "-M")
 set(CMAKE_Fortran_MODPATH_FLAG "-M")
 
 
+set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Qoption" "ld" " ")
+set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")
+
 set(CMAKE_Fortran_PREPROCESS_SOURCE
 set(CMAKE_Fortran_PREPROCESS_SOURCE
   "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -F -fpp <SOURCE> -o <PREPROCESSED_SOURCE>")
   "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -F -fpp <SOURCE> -o <PREPROCESSED_SOURCE>")
 
 

+ 3 - 0
Modules/Compiler/TinyCC-C.cmake

@@ -6,3 +6,6 @@ string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " -g")
 string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
 string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -DNDEBUG")
 string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
 string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -DNDEBUG")
 string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -g -DNDEBUG")
 string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -g -DNDEBUG")
+
+set(CMAKE_C_LINKER_WRAPPER_FLAG "-Wl,")
+set(CMAKE_C_LINKER_WRAPPER_FLAG_SEP ",")

+ 3 - 0
Modules/Compiler/XL.cmake

@@ -23,6 +23,9 @@ macro(__compiler_xl lang)
   set(CMAKE_${lang}_RESPONSE_FILE_FLAG "-qoptfile=")
   set(CMAKE_${lang}_RESPONSE_FILE_FLAG "-qoptfile=")
   set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "-qoptfile=")
   set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "-qoptfile=")
 
 
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
   string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g")
   string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g")
   string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O")
   string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O")
   string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -O")
   string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -O")

+ 3 - 0
Modules/Platform/Apple-Intel.cmake

@@ -10,6 +10,9 @@ macro(__apple_compiler_intel lang)
   set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names")
   set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names")
   set(CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS "-bundle -Wl,-headerpad_max_install_names")
   set(CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS "-bundle -Wl,-headerpad_max_install_names")
 
 
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
   if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 12.0)
   if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 12.0)
     set(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY "-fvisibility=")
     set(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY "-fvisibility=")
   endif()
   endif()

+ 3 - 1
Modules/Platform/Generic-ADSP-C.cmake

@@ -9,6 +9,9 @@ string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " ")
 string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " ")
 string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " ")
 string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " ")
 string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " ")
 
 
+set(CMAKE_C_LINKER_WRAPPER_FLAG "-flags-link" " ")
+set(CMAKE_C_LINKER_WRAPPER_FLAG_SEP ",")
+
 set(CMAKE_C_CREATE_STATIC_LIBRARY
 set(CMAKE_C_CREATE_STATIC_LIBRARY
     "<CMAKE_C_COMPILER> -build-lib -proc ${ADSP_PROCESSOR} -si-revision ${ADSP_PROCESSOR_SILICIUM_REVISION} -o <TARGET> <CMAKE_C_LINK_FLAGS> <OBJECTS>")
     "<CMAKE_C_COMPILER> -build-lib -proc ${ADSP_PROCESSOR} -si-revision ${ADSP_PROCESSOR_SILICIUM_REVISION} -o <TARGET> <CMAKE_C_LINK_FLAGS> <OBJECTS>")
 
 
@@ -17,4 +20,3 @@ set(CMAKE_C_LINK_EXECUTABLE
 
 
 set(CMAKE_C_CREATE_SHARED_LIBRARY)
 set(CMAKE_C_CREATE_SHARED_LIBRARY)
 set(CMAKE_C_CREATE_MODULE_LIBRARY)
 set(CMAKE_C_CREATE_MODULE_LIBRARY)
-

+ 3 - 1
Modules/Platform/Generic-ADSP-CXX.cmake

@@ -7,6 +7,9 @@ string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " ")
 string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " ")
 string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " ")
 string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " ")
 string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT " ")
 
 
+set(CMAKE_CXX_LINKER_WRAPPER_FLAG "-flags-link" " ")
+set(CMAKE_CXX_LINKER_WRAPPER_FLAG_SEP ",")
+
 set(CMAKE_CXX_CREATE_STATIC_LIBRARY
 set(CMAKE_CXX_CREATE_STATIC_LIBRARY
      "<CMAKE_CXX_COMPILER> -build-lib -proc ${ADSP_PROCESSOR} -si-revision ${ADSP_PROCESSOR_SILICIUM_REVISION} -o <TARGET> <CMAKE_CXX_LINK_FLAGS> <OBJECTS>")
      "<CMAKE_CXX_COMPILER> -build-lib -proc ${ADSP_PROCESSOR} -si-revision ${ADSP_PROCESSOR_SILICIUM_REVISION} -o <TARGET> <CMAKE_CXX_LINK_FLAGS> <OBJECTS>")
 
 
@@ -15,4 +18,3 @@ set(CMAKE_CXX_LINK_EXECUTABLE
 
 
 set(CMAKE_CXX_CREATE_SHARED_LIBRARY)
 set(CMAKE_CXX_CREATE_SHARED_LIBRARY)
 set(CMAKE_CXX_CREATE_MODULE_LIBRARY)
 set(CMAKE_CXX_CREATE_MODULE_LIBRARY)
-

+ 2 - 1
Modules/Platform/Generic-SDCC-C.cmake

@@ -37,6 +37,8 @@ if(NOT DEFINED CMAKE_EXE_LINKER_FLAGS_INIT)
   set (CMAKE_EXE_LINKER_FLAGS_INIT --model-small)
   set (CMAKE_EXE_LINKER_FLAGS_INIT --model-small)
 endif()
 endif()
 
 
+set(CMAKE_C_LINKER_WRAPPER_FLAG "-Wl" ",")
+
 # compile a C file into an object file
 # compile a C file into an object file
 set(CMAKE_C_COMPILE_OBJECT  "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
 set(CMAKE_C_COMPILE_OBJECT  "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
 
 
@@ -51,4 +53,3 @@ set(CMAKE_C_CREATE_STATIC_LIBRARY
 # not supported by sdcc
 # not supported by sdcc
 set(CMAKE_C_CREATE_SHARED_LIBRARY "")
 set(CMAKE_C_CREATE_SHARED_LIBRARY "")
 set(CMAKE_C_CREATE_MODULE_LIBRARY "")
 set(CMAKE_C_CREATE_MODULE_LIBRARY "")
-

+ 3 - 0
Modules/Platform/Linux-Intel.cmake

@@ -30,6 +30,9 @@ macro(__linux_compiler_intel lang)
   # executables that use dlopen but do not set ENABLE_EXPORTS.
   # executables that use dlopen but do not set ENABLE_EXPORTS.
   set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-rdynamic")
   set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-rdynamic")
 
 
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
   set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
   set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
 
 
   if(XIAR)
   if(XIAR)

+ 2 - 0
Modules/Platform/Windows-Embarcadero.cmake

@@ -76,6 +76,8 @@ macro(__embarcadero_language lang)
   set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "${_tD}") # ... while this is a space separated string.
   set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "${_tD}") # ... while this is a space separated string.
   set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_INCLUDES 1)
   set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_INCLUDES 1)
 
 
+  set (CMAKE_${lang}_LINKER_WRAPPER_FLAG "-l")
+
   # compile a source file into an object file
   # compile a source file into an object file
   # place <DEFINES> outside the response file because Borland refuses
   # place <DEFINES> outside the response file because Borland refuses
   # to parse quotes from the response file.
   # to parse quotes from the response file.

+ 4 - 0
Source/CMakeLists.txt

@@ -379,6 +379,8 @@ set(SRCS
   cmAddCompileDefinitionsCommand.h
   cmAddCompileDefinitionsCommand.h
   cmAddCompileOptionsCommand.cxx
   cmAddCompileOptionsCommand.cxx
   cmAddCompileOptionsCommand.h
   cmAddCompileOptionsCommand.h
+  cmAddLinkOptionsCommand.cxx
+  cmAddLinkOptionsCommand.h
   cmAddCustomCommandCommand.cxx
   cmAddCustomCommandCommand.cxx
   cmAddCustomCommandCommand.h
   cmAddCustomCommandCommand.h
   cmAddCustomTargetCommand.cxx
   cmAddCustomTargetCommand.cxx
@@ -574,6 +576,8 @@ set(SRCS
   cmTargetCompileOptionsCommand.h
   cmTargetCompileOptionsCommand.h
   cmTargetIncludeDirectoriesCommand.cxx
   cmTargetIncludeDirectoriesCommand.cxx
   cmTargetIncludeDirectoriesCommand.h
   cmTargetIncludeDirectoriesCommand.h
+  cmTargetLinkOptionsCommand.cxx
+  cmTargetLinkOptionsCommand.h
   cmTargetLinkLibrariesCommand.cxx
   cmTargetLinkLibrariesCommand.cxx
   cmTargetLinkLibrariesCommand.h
   cmTargetLinkLibrariesCommand.h
   cmTargetPropCommandBase.cxx
   cmTargetPropCommandBase.cxx

+ 20 - 0
Source/cmAddLinkOptionsCommand.cxx

@@ -0,0 +1,20 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmAddLinkOptionsCommand.h"
+
+#include "cmMakefile.h"
+
+class cmExecutionStatus;
+
+bool cmAddLinkOptionsCommand::InitialPass(std::vector<std::string> const& args,
+                                          cmExecutionStatus&)
+{
+  if (args.empty()) {
+    return true;
+  }
+
+  for (std::string const& i : args) {
+    this->Makefile->AddLinkOption(i);
+  }
+  return true;
+}

+ 31 - 0
Source/cmAddLinkOptionsCommand.h

@@ -0,0 +1,31 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmAddLinkOptionsCommand_h
+#define cmAddLinkOptionsCommand_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+#include "cmCommand.h"
+
+class cmExecutionStatus;
+
+class cmAddLinkOptionsCommand : public cmCommand
+{
+public:
+  /**
+   * This is a virtual constructor for the command.
+   */
+  cmCommand* Clone() override { return new cmAddLinkOptionsCommand; }
+
+  /**
+   * This is called when the command is first encountered in
+   * the CMakeLists.txt file.
+   */
+  bool InitialPass(std::vector<std::string> const& args,
+                   cmExecutionStatus& status) override;
+};
+
+#endif

+ 5 - 0
Source/cmCommands.cxx

@@ -82,6 +82,7 @@
 
 
 #if defined(CMAKE_BUILD_WITH_CMAKE)
 #if defined(CMAKE_BUILD_WITH_CMAKE)
 #  include "cmAddCompileOptionsCommand.h"
 #  include "cmAddCompileOptionsCommand.h"
+#  include "cmAddLinkOptionsCommand.h"
 #  include "cmAuxSourceDirectoryCommand.h"
 #  include "cmAuxSourceDirectoryCommand.h"
 #  include "cmBuildNameCommand.h"
 #  include "cmBuildNameCommand.h"
 #  include "cmCMakeHostSystemInformationCommand.h"
 #  include "cmCMakeHostSystemInformationCommand.h"
@@ -100,6 +101,7 @@
 #  include "cmRemoveDefinitionsCommand.h"
 #  include "cmRemoveDefinitionsCommand.h"
 #  include "cmSourceGroupCommand.h"
 #  include "cmSourceGroupCommand.h"
 #  include "cmSubdirDependsCommand.h"
 #  include "cmSubdirDependsCommand.h"
+#  include "cmTargetLinkOptionsCommand.h"
 #  include "cmUseMangledMesaCommand.h"
 #  include "cmUseMangledMesaCommand.h"
 #  include "cmUtilitySourceCommand.h"
 #  include "cmUtilitySourceCommand.h"
 #  include "cmVariableRequiresCommand.h"
 #  include "cmVariableRequiresCommand.h"
@@ -272,7 +274,10 @@ void GetProjectCommands(cmState* state)
   state->AddBuiltinCommand("include_external_msproject",
   state->AddBuiltinCommand("include_external_msproject",
                            new cmIncludeExternalMSProjectCommand);
                            new cmIncludeExternalMSProjectCommand);
   state->AddBuiltinCommand("install_programs", new cmInstallProgramsCommand);
   state->AddBuiltinCommand("install_programs", new cmInstallProgramsCommand);
+  state->AddBuiltinCommand("add_link_options", new cmAddLinkOptionsCommand);
   state->AddBuiltinCommand("link_libraries", new cmLinkLibrariesCommand);
   state->AddBuiltinCommand("link_libraries", new cmLinkLibrariesCommand);
+  state->AddBuiltinCommand("target_link_options",
+                           new cmTargetLinkOptionsCommand);
   state->AddBuiltinCommand("load_cache", new cmLoadCacheCommand);
   state->AddBuiltinCommand("load_cache", new cmLoadCacheCommand);
   state->AddBuiltinCommand("qt_wrap_cpp", new cmQTWrapCPPCommand);
   state->AddBuiltinCommand("qt_wrap_cpp", new cmQTWrapCPPCommand);
   state->AddBuiltinCommand("qt_wrap_ui", new cmQTWrapUICommand);
   state->AddBuiltinCommand("qt_wrap_ui", new cmQTWrapUICommand);

+ 6 - 0
Source/cmExportBuildAndroidMKGenerator.cxx

@@ -7,6 +7,7 @@
 #include <sstream>
 #include <sstream>
 #include <utility>
 #include <utility>
 
 
+#include "cmAlgorithms.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorExpressionDAGChecker.h"
 #include "cmGeneratorExpressionDAGChecker.h"
 #include "cmGeneratorTarget.h"
 #include "cmGeneratorTarget.h"
@@ -169,6 +170,11 @@ void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
           end = "\\\n";
           end = "\\\n";
         }
         }
         os << "\n";
         os << "\n";
+      } else if (property.first == "INTERFACE_LINK_OPTIONS") {
+        os << "LOCAL_EXPORT_LDFLAGS := ";
+        std::vector<std::string> linkFlagsList;
+        cmSystemTools::ExpandListArgument(property.second, linkFlagsList);
+        os << cmJoin(linkFlagsList, " ") << "\n";
       } else {
       } else {
         os << "# " << property.first << " " << (property.second) << "\n";
         os << "# " << property.first << " " << (property.second) << "\n";
       }
       }

+ 3 - 0
Source/cmExportBuildFileGenerator.cxx

@@ -95,6 +95,9 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
     this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gte,
     this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gte,
                                     cmGeneratorExpression::BuildInterface,
                                     cmGeneratorExpression::BuildInterface,
                                     properties, missingTargets);
                                     properties, missingTargets);
+    this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gte,
+                                    cmGeneratorExpression::BuildInterface,
+                                    properties, missingTargets);
     this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte,
     this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte,
                                     properties);
                                     properties);
 
 

+ 3 - 0
Source/cmExportInstallFileGenerator.cxx

@@ -103,6 +103,9 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
     this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gt,
     this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gt,
                                     cmGeneratorExpression::InstallInterface,
                                     cmGeneratorExpression::InstallInterface,
                                     properties, missingTargets);
                                     properties, missingTargets);
+    this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gt,
+                                    cmGeneratorExpression::InstallInterface,
+                                    properties, missingTargets);
 
 
     std::string errorMessage;
     std::string errorMessage;
     if (!this->PopulateExportProperties(gt, properties, errorMessage)) {
     if (!this->PopulateExportProperties(gt, properties, errorMessage)) {

+ 2 - 1
Source/cmGeneratorExpressionDAGChecker.h

@@ -25,7 +25,8 @@ struct cmGeneratorExpressionContext;
   SELECT(F, EvaluatingCompileOptions, COMPILE_OPTIONS)                        \
   SELECT(F, EvaluatingCompileOptions, COMPILE_OPTIONS)                        \
   SELECT(F, EvaluatingAutoUicOptions, AUTOUIC_OPTIONS)                        \
   SELECT(F, EvaluatingAutoUicOptions, AUTOUIC_OPTIONS)                        \
   SELECT(F, EvaluatingSources, SOURCES)                                       \
   SELECT(F, EvaluatingSources, SOURCES)                                       \
-  SELECT(F, EvaluatingCompileFeatures, COMPILE_FEATURES)
+  SELECT(F, EvaluatingCompileFeatures, COMPILE_FEATURES)                      \
+  SELECT(F, EvaluatingLinkOptions, LINK_OPTIONS)
 
 
 #define CM_FOR_EACH_TRANSITIVE_PROPERTY(F)                                    \
 #define CM_FOR_EACH_TRANSITIVE_PROPERTY(F)                                    \
   CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_BOTH)
   CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_BOTH)

+ 164 - 11
Source/cmGeneratorTarget.cxx

@@ -102,6 +102,7 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
   , DebugCompileOptionsDone(false)
   , DebugCompileOptionsDone(false)
   , DebugCompileFeaturesDone(false)
   , DebugCompileFeaturesDone(false)
   , DebugCompileDefinitionsDone(false)
   , DebugCompileDefinitionsDone(false)
+  , DebugLinkOptionsDone(false)
   , DebugSourcesDone(false)
   , DebugSourcesDone(false)
   , LinkImplementationLanguageIsContextDependent(true)
   , LinkImplementationLanguageIsContextDependent(true)
   , UtilityItemsDone(false)
   , UtilityItemsDone(false)
@@ -128,6 +129,10 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
                                      t->GetCompileDefinitionsBacktraces(),
                                      t->GetCompileDefinitionsBacktraces(),
                                      this->CompileDefinitionsEntries);
                                      this->CompileDefinitionsEntries);
 
 
+  CreatePropertyGeneratorExpressions(t->GetLinkOptionsEntries(),
+                                     t->GetLinkOptionsBacktraces(),
+                                     this->LinkOptionsEntries);
+
   CreatePropertyGeneratorExpressions(t->GetSourceEntries(),
   CreatePropertyGeneratorExpressions(t->GetSourceEntries(),
                                      t->GetSourceBacktraces(),
                                      t->GetSourceBacktraces(),
                                      this->SourceEntries, true);
                                      this->SourceEntries, true);
@@ -145,6 +150,7 @@ cmGeneratorTarget::~cmGeneratorTarget()
   cmDeleteAll(this->CompileOptionsEntries);
   cmDeleteAll(this->CompileOptionsEntries);
   cmDeleteAll(this->CompileFeaturesEntries);
   cmDeleteAll(this->CompileFeaturesEntries);
   cmDeleteAll(this->CompileDefinitionsEntries);
   cmDeleteAll(this->CompileDefinitionsEntries);
+  cmDeleteAll(this->LinkOptionsEntries);
   cmDeleteAll(this->SourceEntries);
   cmDeleteAll(this->SourceEntries);
   cmDeleteAll(this->LinkInformation);
   cmDeleteAll(this->LinkInformation);
 }
 }
@@ -2633,7 +2639,7 @@ enum class OptionsParse
   Shell
   Shell
 };
 };
 
 
-static void processCompileOptionsInternal(
+static void processOptionsInternal(
   cmGeneratorTarget const* tgt,
   cmGeneratorTarget const* tgt,
   const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
   const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
   std::vector<std::string>& options,
   std::vector<std::string>& options,
@@ -2665,7 +2671,7 @@ static void processCompileOptionsInternal(
     if (!usedOptions.empty()) {
     if (!usedOptions.empty()) {
       tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
       tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
         cmake::LOG,
         cmake::LOG,
-        std::string("Used compile ") + logName + std::string(" for target ") +
+        std::string("Used ") + logName + std::string(" for target ") +
           tgt->GetName() + ":\n" + usedOptions,
           tgt->GetName() + ":\n" + usedOptions,
         entry->ge->GetBacktrace());
         entry->ge->GetBacktrace());
     }
     }
@@ -2680,9 +2686,9 @@ static void processCompileOptions(
   cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
   cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
   bool debugOptions, std::string const& language)
   bool debugOptions, std::string const& language)
 {
 {
-  processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
-                                dagChecker, config, debugOptions, "options",
-                                language, OptionsParse::Shell);
+  processOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker,
+                         config, debugOptions, "compile options", language,
+                         OptionsParse::Shell);
 }
 }
 
 
 void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result,
 void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result,
@@ -2734,9 +2740,9 @@ static void processCompileFeatures(
   cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
   cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
   bool debugOptions)
   bool debugOptions)
 {
 {
-  processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
-                                dagChecker, config, debugOptions, "features",
-                                std::string(), OptionsParse::None);
+  processOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker,
+                         config, debugOptions, "compile features",
+                         std::string(), OptionsParse::None);
 }
 }
 
 
 void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result,
 void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result,
@@ -2784,9 +2790,9 @@ static void processCompileDefinitions(
   cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
   cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
   bool debugOptions, std::string const& language)
   bool debugOptions, std::string const& language)
 {
 {
-  processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
-                                dagChecker, config, debugOptions,
-                                "definitions", language, OptionsParse::None);
+  processOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker,
+                         config, debugOptions, "compile definitions", language,
+                         OptionsParse::None);
 }
 }
 
 
 void cmGeneratorTarget::GetCompileDefinitions(
 void cmGeneratorTarget::GetCompileDefinitions(
@@ -2855,6 +2861,153 @@ void cmGeneratorTarget::GetCompileDefinitions(
   cmDeleteAll(linkInterfaceCompileDefinitionsEntries);
   cmDeleteAll(linkInterfaceCompileDefinitionsEntries);
 }
 }
 
 
+namespace {
+void processLinkOptions(
+  cmGeneratorTarget const* tgt,
+  const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
+  std::vector<std::string>& options,
+  std::unordered_set<std::string>& uniqueOptions,
+  cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
+  bool debugOptions, std::string const& language)
+{
+  processOptionsInternal(tgt, entries, options, uniqueOptions, dagChecker,
+                         config, debugOptions, "link options", language,
+                         OptionsParse::Shell);
+}
+}
+
+void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result,
+                                       const std::string& config,
+                                       const std::string& language) const
+{
+  std::unordered_set<std::string> uniqueOptions;
+
+  cmGeneratorExpressionDAGChecker dagChecker(this->GetName(), "LINK_OPTIONS",
+                                             nullptr, nullptr);
+
+  std::vector<std::string> debugProperties;
+  const char* debugProp =
+    this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
+  if (debugProp) {
+    cmSystemTools::ExpandListArgument(debugProp, debugProperties);
+  }
+
+  bool debugOptions = !this->DebugLinkOptionsDone &&
+    std::find(debugProperties.begin(), debugProperties.end(),
+              "LINK_OPTIONS") != debugProperties.end();
+
+  if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+    this->DebugLinkOptionsDone = true;
+  }
+
+  processLinkOptions(this, this->LinkOptionsEntries, result, uniqueOptions,
+                     &dagChecker, config, debugOptions, language);
+
+  std::vector<cmGeneratorTarget::TargetPropertyEntry*>
+    linkInterfaceLinkOptionsEntries;
+
+  AddInterfaceEntries(this, config, "INTERFACE_LINK_OPTIONS",
+                      linkInterfaceLinkOptionsEntries);
+
+  processLinkOptions(this, linkInterfaceLinkOptionsEntries, result,
+                     uniqueOptions, &dagChecker, config, debugOptions,
+                     language);
+
+  cmDeleteAll(linkInterfaceLinkOptionsEntries);
+
+  // Last step: replace "LINKER:" prefixed elements by
+  // actual linker wrapper
+  const std::string wrapper(this->Makefile->GetSafeDefinition(
+    "CMAKE_" + language + "_LINKER_WRAPPER_FLAG"));
+  std::vector<std::string> wrapperFlag;
+  cmSystemTools::ExpandListArgument(wrapper, wrapperFlag);
+  const std::string wrapperSep(this->Makefile->GetSafeDefinition(
+    "CMAKE_" + language + "_LINKER_WRAPPER_FLAG_SEP"));
+  bool concatFlagAndArgs = true;
+  if (!wrapperFlag.empty() && wrapperFlag.back() == " ") {
+    concatFlagAndArgs = false;
+    wrapperFlag.pop_back();
+  }
+
+  const std::string LINKER{ "LINKER:" };
+  const std::string SHELL{ "SHELL:" };
+  const std::string LINKER_SHELL = LINKER + SHELL;
+
+  std::vector<std::string>::iterator entry;
+  while ((entry = std::find_if(result.begin(), result.end(),
+                               [&LINKER](const std::string& item) -> bool {
+                                 return item.compare(0, LINKER.length(),
+                                                     LINKER) == 0;
+                               })) != result.end()) {
+    std::vector<std::string> linkerOptions;
+    if (entry->compare(0, LINKER_SHELL.length(), LINKER_SHELL) == 0) {
+      cmSystemTools::ParseUnixCommandLine(
+        entry->c_str() + LINKER_SHELL.length(), linkerOptions);
+    } else {
+      linkerOptions =
+        cmSystemTools::tokenize(entry->substr(LINKER.length()), ",");
+    }
+    entry = result.erase(entry);
+
+    if (linkerOptions.empty() ||
+        (linkerOptions.size() == 1 && linkerOptions.front().empty())) {
+      continue;
+    }
+
+    // for now, raise an error if prefix SHELL: is part of arguments
+    if (std::find_if(linkerOptions.begin(), linkerOptions.end(),
+                     [&SHELL](const std::string& item) -> bool {
+                       return item.find(SHELL) != std::string::npos;
+                     }) != linkerOptions.end()) {
+      this->LocalGenerator->GetCMakeInstance()->IssueMessage(
+        cmake::FATAL_ERROR,
+        "'SHELL:' prefix is not supported as part of 'LINKER:' arguments.",
+        this->GetBacktrace());
+      return;
+    }
+
+    if (wrapperFlag.empty()) {
+      // nothing specified, insert elements as is
+      result.insert(entry, linkerOptions.begin(), linkerOptions.end());
+    } else {
+      std::vector<std::string> options;
+
+      if (!wrapperSep.empty()) {
+        if (concatFlagAndArgs) {
+          // insert flag elements except last one
+          options.insert(options.end(), wrapperFlag.begin(),
+                         wrapperFlag.end() - 1);
+          // concatenate last flag element and all LINKER list values
+          // in one option
+          options.push_back(wrapperFlag.back() +
+                            cmJoin(linkerOptions, wrapperSep));
+        } else {
+          options.insert(options.end(), wrapperFlag.begin(),
+                         wrapperFlag.end());
+          // concatenate all LINKER list values in one option
+          options.push_back(cmJoin(linkerOptions, wrapperSep));
+        }
+      } else {
+        // prefix each element of LINKER list with wrapper
+        if (concatFlagAndArgs) {
+          std::transform(
+            linkerOptions.begin(), linkerOptions.end(), linkerOptions.begin(),
+            [&wrapperFlag](const std::string& value) -> std::string {
+              return wrapperFlag.back() + value;
+            });
+        }
+        for (const auto& value : linkerOptions) {
+          options.insert(options.end(), wrapperFlag.begin(),
+                         concatFlagAndArgs ? wrapperFlag.end() - 1
+                                           : wrapperFlag.end());
+          options.push_back(value);
+        }
+      }
+      result.insert(entry, options.begin(), options.end());
+    }
+  }
+}
+
 void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const
 void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const
 {
 {
   if (this->IsImported()) {
   if (this->IsImported()) {

+ 6 - 0
Source/cmGeneratorTarget.h

@@ -418,6 +418,10 @@ public:
                              const std::string& config,
                              const std::string& config,
                              const std::string& language) const;
                              const std::string& language) const;
 
 
+  void GetLinkOptions(std::vector<std::string>& result,
+                      const std::string& config,
+                      const std::string& language) const;
+
   bool IsSystemIncludeDirectory(const std::string& dir,
   bool IsSystemIncludeDirectory(const std::string& dir,
                                 const std::string& config,
                                 const std::string& config,
                                 const std::string& language) const;
                                 const std::string& language) const;
@@ -803,6 +807,7 @@ private:
   std::vector<TargetPropertyEntry*> CompileOptionsEntries;
   std::vector<TargetPropertyEntry*> CompileOptionsEntries;
   std::vector<TargetPropertyEntry*> CompileFeaturesEntries;
   std::vector<TargetPropertyEntry*> CompileFeaturesEntries;
   std::vector<TargetPropertyEntry*> CompileDefinitionsEntries;
   std::vector<TargetPropertyEntry*> CompileDefinitionsEntries;
+  std::vector<TargetPropertyEntry*> LinkOptionsEntries;
   std::vector<TargetPropertyEntry*> SourceEntries;
   std::vector<TargetPropertyEntry*> SourceEntries;
   mutable std::set<std::string> LinkImplicitNullProperties;
   mutable std::set<std::string> LinkImplicitNullProperties;
 
 
@@ -851,6 +856,7 @@ private:
   mutable bool DebugCompileOptionsDone;
   mutable bool DebugCompileOptionsDone;
   mutable bool DebugCompileFeaturesDone;
   mutable bool DebugCompileFeaturesDone;
   mutable bool DebugCompileDefinitionsDone;
   mutable bool DebugCompileDefinitionsDone;
+  mutable bool DebugLinkOptionsDone;
   mutable bool DebugSourcesDone;
   mutable bool DebugSourcesDone;
   mutable bool LinkImplementationLanguageIsContextDependent;
   mutable bool LinkImplementationLanguageIsContextDependent;
   mutable bool UtilityItemsDone;
   mutable bool UtilityItemsDone;

+ 4 - 0
Source/cmGlobalXCodeGenerator.cxx

@@ -1817,6 +1817,10 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
         this->CurrentLocalGenerator->AppendFlags(extraLinkOptions, linkFlags);
         this->CurrentLocalGenerator->AppendFlags(extraLinkOptions, linkFlags);
       }
       }
     }
     }
+    std::vector<std::string> opts;
+    gtgt->GetLinkOptions(opts, configName, llang);
+    // LINK_OPTIONS are escaped.
+    this->CurrentLocalGenerator->AppendCompileOptions(extraLinkOptions, opts);
   }
   }
 
 
   // Set target-specific architectures.
   // Set target-specific architectures.

+ 8 - 0
Source/cmLocalGenerator.cxx

@@ -1042,6 +1042,10 @@ void cmLocalGenerator::GetTargetFlags(
           linkFlags += " ";
           linkFlags += " ";
         }
         }
       }
       }
+      std::vector<std::string> opts;
+      target->GetLinkOptions(opts, config, linkLanguage);
+      // LINK_OPTIONS are escaped.
+      this->AppendCompileOptions(linkFlags, opts);
       if (pcli) {
       if (pcli) {
         this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
         this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
                                   frameworkPath, linkPath);
                                   frameworkPath, linkPath);
@@ -1113,6 +1117,10 @@ void cmLocalGenerator::GetTargetFlags(
           linkFlags += " ";
           linkFlags += " ";
         }
         }
       }
       }
+      std::vector<std::string> opts;
+      target->GetLinkOptions(opts, config, linkLanguage);
+      // LINK_OPTIONS are escaped.
+      this->AppendCompileOptions(linkFlags, opts);
     } break;
     } break;
     default:
     default:
       break;
       break;

+ 7 - 0
Source/cmLocalVisualStudio7Generator.cxx

@@ -977,6 +977,13 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
     extraLinkOptions += " ";
     extraLinkOptions += " ";
     extraLinkOptions += targetLinkFlags;
     extraLinkOptions += targetLinkFlags;
   }
   }
+
+  std::vector<std::string> opts;
+  target->GetLinkOptions(opts, configName,
+                         target->GetLinkerLanguage(configName));
+  // LINK_OPTIONS are escaped.
+  this->AppendCompileOptions(extraLinkOptions, opts);
+
   Options linkOptions(this, Options::Linker);
   Options linkOptions(this, Options::Linker);
   if (this->FortranProject) {
   if (this->FortranProject) {
     linkOptions.AddTable(cmLocalVisualStudio7GeneratorFortranLinkFlagTable);
     linkOptions.AddTable(cmLocalVisualStudio7GeneratorFortranLinkFlagTable);

+ 15 - 0
Source/cmMakefile.cxx

@@ -216,6 +216,16 @@ cmBacktraceRange cmMakefile::GetCompileDefinitionsBacktraces() const
     .GetCompileDefinitionsEntryBacktraces();
     .GetCompileDefinitionsEntryBacktraces();
 }
 }
 
 
+cmStringRange cmMakefile::GetLinkOptionsEntries() const
+{
+  return this->StateSnapshot.GetDirectory().GetLinkOptionsEntries();
+}
+
+cmBacktraceRange cmMakefile::GetLinkOptionsBacktraces() const
+{
+  return this->StateSnapshot.GetDirectory().GetLinkOptionsEntryBacktraces();
+}
+
 cmListFileBacktrace cmMakefile::GetBacktrace() const
 cmListFileBacktrace cmMakefile::GetBacktrace() const
 {
 {
   return this->Backtrace;
   return this->Backtrace;
@@ -1205,6 +1215,11 @@ void cmMakefile::AddCompileOption(std::string const& option)
   this->AppendProperty("COMPILE_OPTIONS", option.c_str());
   this->AppendProperty("COMPILE_OPTIONS", option.c_str());
 }
 }
 
 
+void cmMakefile::AddLinkOption(std::string const& option)
+{
+  this->AppendProperty("LINK_OPTIONS", option.c_str());
+}
+
 bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove)
 bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove)
 {
 {
   // Create a regular expression to match valid definitions.
   // Create a regular expression to match valid definitions.

+ 3 - 0
Source/cmMakefile.h

@@ -171,6 +171,7 @@ public:
   void RemoveDefineFlag(std::string const& definition);
   void RemoveDefineFlag(std::string const& definition);
   void AddCompileDefinition(std::string const& definition);
   void AddCompileDefinition(std::string const& definition);
   void AddCompileOption(std::string const& option);
   void AddCompileOption(std::string const& option);
+  void AddLinkOption(std::string const& option);
 
 
   /** Create a new imported target with the name and type given.  */
   /** Create a new imported target with the name and type given.  */
   cmTarget* AddImportedTarget(const std::string& name,
   cmTarget* AddImportedTarget(const std::string& name,
@@ -788,6 +789,8 @@ public:
   cmBacktraceRange GetCompileOptionsBacktraces() const;
   cmBacktraceRange GetCompileOptionsBacktraces() const;
   cmStringRange GetCompileDefinitionsEntries() const;
   cmStringRange GetCompileDefinitionsEntries() const;
   cmBacktraceRange GetCompileDefinitionsBacktraces() const;
   cmBacktraceRange GetCompileDefinitionsBacktraces() const;
+  cmStringRange GetLinkOptionsEntries() const;
+  cmBacktraceRange GetLinkOptionsBacktraces() const;
 
 
   std::set<std::string> const& GetSystemIncludeDirectories() const
   std::set<std::string> const& GetSystemIncludeDirectories() const
   {
   {

+ 2 - 12
Source/cmMakefileExecutableTargetGenerator.cxx

@@ -154,12 +154,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
                                              linkLanguage, this->ConfigName);
                                              linkLanguage, this->ConfigName);
 
 
   // Add target-specific linker flags.
   // Add target-specific linker flags.
-  this->LocalGenerator->AppendFlags(
-    linkFlags, this->GeneratorTarget->GetProperty("LINK_FLAGS"));
-  std::string linkFlagsConfig = "LINK_FLAGS_";
-  linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
-  this->LocalGenerator->AppendFlags(
-    linkFlags, this->GeneratorTarget->GetProperty(linkFlagsConfig));
+  this->GetTargetLinkFlags(linkFlags, linkLanguage);
 
 
   // Construct a list of files associated with this executable that
   // Construct a list of files associated with this executable that
   // may need to be cleaned.
   // may need to be cleaned.
@@ -437,12 +432,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
                                              linkLanguage, this->ConfigName);
                                              linkLanguage, this->ConfigName);
 
 
   // Add target-specific linker flags.
   // Add target-specific linker flags.
-  this->LocalGenerator->AppendFlags(
-    linkFlags, this->GeneratorTarget->GetProperty("LINK_FLAGS"));
-  std::string linkFlagsConfig = "LINK_FLAGS_";
-  linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
-  this->LocalGenerator->AppendFlags(
-    linkFlags, this->GeneratorTarget->GetProperty(linkFlagsConfig));
+  this->GetTargetLinkFlags(linkFlags, linkLanguage);
 
 
   {
   {
     std::unique_ptr<cmLinkLineComputer> linkLineComputer(
     std::unique_ptr<cmLinkLineComputer> linkLineComputer(

+ 8 - 34
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -137,10 +137,7 @@ void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
     this->GeneratorTarget->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS");
     this->GeneratorTarget->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS");
   if (hasCUDA && resolveDeviceSymbols) {
   if (hasCUDA && resolveDeviceSymbols) {
     std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
     std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
-    std::string extraFlags;
-    this->LocalGenerator->AppendFlags(
-      extraFlags, this->GeneratorTarget->GetProperty("LINK_FLAGS"));
-    this->WriteDeviceLibraryRules(linkRuleVar, extraFlags, false);
+    this->WriteDeviceLibraryRules(linkRuleVar, false);
   }
   }
 
 
   std::string linkLanguage =
   std::string linkLanguage =
@@ -173,10 +170,7 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
                  cuda_lang) != closure->Languages.end());
                  cuda_lang) != closure->Languages.end());
     if (hasCUDA) {
     if (hasCUDA) {
       std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
       std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
-      std::string extraFlags;
-      this->LocalGenerator->AppendFlags(
-        extraFlags, this->GeneratorTarget->GetProperty("LINK_FLAGS"));
-      this->WriteDeviceLibraryRules(linkRuleVar, extraFlags, relink);
+      this->WriteDeviceLibraryRules(linkRuleVar, relink);
     }
     }
   }
   }
 
 
@@ -187,13 +181,7 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
   linkRuleVar += "_CREATE_SHARED_LIBRARY";
   linkRuleVar += "_CREATE_SHARED_LIBRARY";
 
 
   std::string extraFlags;
   std::string extraFlags;
-  this->LocalGenerator->AppendFlags(
-    extraFlags, this->GeneratorTarget->GetProperty("LINK_FLAGS"));
-  std::string linkFlagsConfig = "LINK_FLAGS_";
-  linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
-  this->LocalGenerator->AppendFlags(
-    extraFlags, this->GeneratorTarget->GetProperty(linkFlagsConfig));
-
+  this->GetTargetLinkFlags(extraFlags, linkLanguage);
   this->LocalGenerator->AddConfigVariableFlags(
   this->LocalGenerator->AddConfigVariableFlags(
     extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->ConfigName);
     extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->ConfigName);
 
 
@@ -223,10 +211,7 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
                  cuda_lang) != closure->Languages.end());
                  cuda_lang) != closure->Languages.end());
     if (hasCUDA) {
     if (hasCUDA) {
       std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
       std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
-      std::string extraFlags;
-      this->LocalGenerator->AppendFlags(
-        extraFlags, this->GeneratorTarget->GetProperty("LINK_FLAGS"));
-      this->WriteDeviceLibraryRules(linkRuleVar, extraFlags, relink);
+      this->WriteDeviceLibraryRules(linkRuleVar, relink);
     }
     }
   }
   }
 
 
@@ -237,12 +222,7 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
   linkRuleVar += "_CREATE_SHARED_MODULE";
   linkRuleVar += "_CREATE_SHARED_MODULE";
 
 
   std::string extraFlags;
   std::string extraFlags;
-  this->LocalGenerator->AppendFlags(
-    extraFlags, this->GeneratorTarget->GetProperty("LINK_FLAGS"));
-  std::string linkFlagsConfig = "LINK_FLAGS_";
-  linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
-  this->LocalGenerator->AppendFlags(
-    extraFlags, this->GeneratorTarget->GetProperty(linkFlagsConfig));
+  this->GetTargetLinkFlags(extraFlags, linkLanguage);
   this->LocalGenerator->AddConfigVariableFlags(
   this->LocalGenerator->AddConfigVariableFlags(
     extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->ConfigName);
     extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->ConfigName);
 
 
@@ -265,12 +245,7 @@ void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink)
   linkRuleVar += "_CREATE_MACOSX_FRAMEWORK";
   linkRuleVar += "_CREATE_MACOSX_FRAMEWORK";
 
 
   std::string extraFlags;
   std::string extraFlags;
-  this->LocalGenerator->AppendFlags(
-    extraFlags, this->GeneratorTarget->GetProperty("LINK_FLAGS"));
-  std::string linkFlagsConfig = "LINK_FLAGS_";
-  linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
-  this->LocalGenerator->AppendFlags(
-    extraFlags, this->GeneratorTarget->GetProperty(linkFlagsConfig));
+  this->GetTargetLinkFlags(extraFlags, linkLanguage);
   this->LocalGenerator->AddConfigVariableFlags(
   this->LocalGenerator->AddConfigVariableFlags(
     extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS", this->ConfigName);
     extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS", this->ConfigName);
 
 
@@ -278,7 +253,7 @@ void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink)
 }
 }
 
 
 void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules(
 void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules(
-  const std::string& linkRuleVar, const std::string& extraFlags, bool relink)
+  const std::string& linkRuleVar, bool relink)
 {
 {
 #ifdef CMAKE_BUILD_WITH_CMAKE
 #ifdef CMAKE_BUILD_WITH_CMAKE
   // TODO: Merge the methods that call this method to avoid
   // TODO: Merge the methods that call this method to avoid
@@ -296,7 +271,7 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules(
 
 
   // Create set of linking flags.
   // Create set of linking flags.
   std::string linkFlags;
   std::string linkFlags;
-  this->LocalGenerator->AppendFlags(linkFlags, extraFlags);
+  this->GetTargetLinkFlags(linkFlags, linkLanguage);
 
 
   // Get the name of the device object to generate.
   // Get the name of the device object to generate.
   std::string const targetOutputReal =
   std::string const targetOutputReal =
@@ -458,7 +433,6 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules(
   this->WriteTargetDriverRule(targetOutputReal, relink);
   this->WriteTargetDriverRule(targetOutputReal, relink);
 #else
 #else
   static_cast<void>(linkRuleVar);
   static_cast<void>(linkRuleVar);
-  static_cast<void>(extraFlags);
   static_cast<void>(relink);
   static_cast<void>(relink);
 #endif
 #endif
 }
 }

+ 1 - 2
Source/cmMakefileLibraryTargetGenerator.h

@@ -27,8 +27,7 @@ protected:
   void WriteSharedLibraryRules(bool relink);
   void WriteSharedLibraryRules(bool relink);
   void WriteModuleLibraryRules(bool relink);
   void WriteModuleLibraryRules(bool relink);
 
 
-  void WriteDeviceLibraryRules(const std::string& linkRule,
-                               const std::string& extraFlags, bool relink);
+  void WriteDeviceLibraryRules(const std::string& linkRule, bool relink);
   void WriteLibraryRules(const std::string& linkRule,
   void WriteLibraryRules(const std::string& linkRule,
                          const std::string& extraFlags, bool relink);
                          const std::string& extraFlags, bool relink);
   // MacOSX Framework support methods
   // MacOSX Framework support methods

+ 17 - 0
Source/cmMakefileTargetGenerator.cxx

@@ -82,6 +82,23 @@ cmMakefileTargetGenerator* cmMakefileTargetGenerator::New(
   return result;
   return result;
 }
 }
 
 
+void cmMakefileTargetGenerator::GetTargetLinkFlags(
+  std::string& flags, const std::string& linkLanguage)
+{
+  this->LocalGenerator->AppendFlags(
+    flags, this->GeneratorTarget->GetProperty("LINK_FLAGS"));
+
+  std::string linkFlagsConfig = "LINK_FLAGS_";
+  linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
+  this->LocalGenerator->AppendFlags(
+    flags, this->GeneratorTarget->GetProperty(linkFlagsConfig));
+
+  std::vector<std::string> opts;
+  this->GeneratorTarget->GetLinkOptions(opts, this->ConfigName, linkLanguage);
+  // LINK_OPTIONS are escaped.
+  this->LocalGenerator->AppendCompileOptions(flags, opts);
+}
+
 void cmMakefileTargetGenerator::CreateRuleFile()
 void cmMakefileTargetGenerator::CreateRuleFile()
 {
 {
   // Create a directory for this target.
   // Create a directory for this target.

+ 2 - 0
Source/cmMakefileTargetGenerator.h

@@ -52,6 +52,8 @@ public:
   cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; }
   cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; }
 
 
 protected:
 protected:
+  void GetTargetLinkFlags(std::string& flags, const std::string& linkLanguage);
+
   // create the file and directory etc
   // create the file and directory etc
   void CreateRuleFile();
   void CreateRuleFile();
 
 

+ 2 - 0
Source/cmState.cxx

@@ -280,6 +280,8 @@ cmStateSnapshot cmState::Reset()
     it->CompileDefinitionsBacktraces.clear();
     it->CompileDefinitionsBacktraces.clear();
     it->CompileOptions.clear();
     it->CompileOptions.clear();
     it->CompileOptionsBacktraces.clear();
     it->CompileOptionsBacktraces.clear();
+    it->LinkOptions.clear();
+    it->LinkOptionsBacktraces.clear();
     it->DirectoryEnd = pos;
     it->DirectoryEnd = pos;
     it->NormalTargetNames.clear();
     it->NormalTargetNames.clear();
     it->Properties.clear();
     it->Properties.clear();

+ 52 - 0
Source/cmStateDirectory.cxx

@@ -360,6 +360,42 @@ void cmStateDirectory::ClearCompileOptions()
                this->Snapshot_.Position->CompileOptionsPosition);
                this->Snapshot_.Position->CompileOptionsPosition);
 }
 }
 
 
+cmStringRange cmStateDirectory::GetLinkOptionsEntries() const
+{
+  return GetPropertyContent(this->DirectoryState->LinkOptions,
+                            this->Snapshot_.Position->LinkOptionsPosition);
+}
+
+cmBacktraceRange cmStateDirectory::GetLinkOptionsEntryBacktraces() const
+{
+  return GetPropertyBacktraces(this->DirectoryState->LinkOptions,
+                               this->DirectoryState->LinkOptionsBacktraces,
+                               this->Snapshot_.Position->LinkOptionsPosition);
+}
+
+void cmStateDirectory::AppendLinkOptionsEntry(const std::string& vec,
+                                              const cmListFileBacktrace& lfbt)
+{
+  AppendEntry(this->DirectoryState->LinkOptions,
+              this->DirectoryState->LinkOptionsBacktraces,
+              this->Snapshot_.Position->LinkOptionsPosition, vec, lfbt);
+}
+
+void cmStateDirectory::SetLinkOptions(const std::string& vec,
+                                      const cmListFileBacktrace& lfbt)
+{
+  SetContent(this->DirectoryState->LinkOptions,
+             this->DirectoryState->LinkOptionsBacktraces,
+             this->Snapshot_.Position->LinkOptionsPosition, vec, lfbt);
+}
+
+void cmStateDirectory::ClearLinkOptions()
+{
+  ClearContent(this->DirectoryState->LinkOptions,
+               this->DirectoryState->LinkOptionsBacktraces,
+               this->Snapshot_.Position->LinkOptionsPosition);
+}
+
 void cmStateDirectory::SetProperty(const std::string& prop, const char* value,
 void cmStateDirectory::SetProperty(const std::string& prop, const char* value,
                                    cmListFileBacktrace const& lfbt)
                                    cmListFileBacktrace const& lfbt)
 {
 {
@@ -387,6 +423,14 @@ void cmStateDirectory::SetProperty(const std::string& prop, const char* value,
     this->SetCompileDefinitions(value, lfbt);
     this->SetCompileDefinitions(value, lfbt);
     return;
     return;
   }
   }
+  if (prop == "LINK_OPTIONS") {
+    if (!value) {
+      this->ClearLinkOptions();
+      return;
+    }
+    this->SetLinkOptions(value, lfbt);
+    return;
+  }
 
 
   this->DirectoryState->Properties.SetProperty(prop, value);
   this->DirectoryState->Properties.SetProperty(prop, value);
 }
 }
@@ -407,6 +451,10 @@ void cmStateDirectory::AppendProperty(const std::string& prop,
     this->AppendCompileDefinitionsEntry(value, lfbt);
     this->AppendCompileDefinitionsEntry(value, lfbt);
     return;
     return;
   }
   }
+  if (prop == "LINK_OPTIONS") {
+    this->AppendLinkOptionsEntry(value, lfbt);
+    return;
+  }
 
 
   this->DirectoryState->Properties.AppendProperty(prop, value, asString);
   this->DirectoryState->Properties.AppendProperty(prop, value, asString);
 }
 }
@@ -490,6 +538,10 @@ const char* cmStateDirectory::GetProperty(const std::string& prop,
     output = cmJoin(this->GetCompileDefinitionsEntries(), ";");
     output = cmJoin(this->GetCompileDefinitionsEntries(), ";");
     return output.c_str();
     return output.c_str();
   }
   }
+  if (prop == "LINK_OPTIONS") {
+    output = cmJoin(this->GetLinkOptionsEntries(), ";");
+    return output.c_str();
+  }
 
 
   const char* retVal = this->DirectoryState->Properties.GetPropertyValue(prop);
   const char* retVal = this->DirectoryState->Properties.GetPropertyValue(prop);
   if (!retVal && chain) {
   if (!retVal && chain) {

+ 7 - 0
Source/cmStateDirectory.h

@@ -58,6 +58,13 @@ public:
                          cmListFileBacktrace const& lfbt);
                          cmListFileBacktrace const& lfbt);
   void ClearCompileOptions();
   void ClearCompileOptions();
 
 
+  cmStringRange GetLinkOptionsEntries() const;
+  cmBacktraceRange GetLinkOptionsEntryBacktraces() const;
+  void AppendLinkOptionsEntry(std::string const& vec,
+                              cmListFileBacktrace const& lfbt);
+  void SetLinkOptions(std::string const& vec, cmListFileBacktrace const& lfbt);
+  void ClearLinkOptions();
+
   void SetProperty(const std::string& prop, const char* value,
   void SetProperty(const std::string& prop, const char* value,
                    cmListFileBacktrace const& lfbt);
                    cmListFileBacktrace const& lfbt);
   void AppendProperty(const std::string& prop, const char* value,
   void AppendProperty(const std::string& prop, const char* value,

+ 4 - 0
Source/cmStatePrivate.h

@@ -42,6 +42,7 @@ struct cmStateDetail::SnapshotDataType
   std::vector<std::string>::size_type IncludeDirectoryPosition;
   std::vector<std::string>::size_type IncludeDirectoryPosition;
   std::vector<std::string>::size_type CompileDefinitionsPosition;
   std::vector<std::string>::size_type CompileDefinitionsPosition;
   std::vector<std::string>::size_type CompileOptionsPosition;
   std::vector<std::string>::size_type CompileOptionsPosition;
+  std::vector<std::string>::size_type LinkOptionsPosition;
 };
 };
 
 
 struct cmStateDetail::PolicyStackEntry : public cmPolicies::PolicyMap
 struct cmStateDetail::PolicyStackEntry : public cmPolicies::PolicyMap
@@ -84,6 +85,9 @@ struct cmStateDetail::BuildsystemDirectoryStateType
   std::vector<std::string> CompileOptions;
   std::vector<std::string> CompileOptions;
   std::vector<cmListFileBacktrace> CompileOptionsBacktraces;
   std::vector<cmListFileBacktrace> CompileOptionsBacktraces;
 
 
+  std::vector<std::string> LinkOptions;
+  std::vector<cmListFileBacktrace> LinkOptionsBacktraces;
+
   std::vector<std::string> NormalTargetNames;
   std::vector<std::string> NormalTargetNames;
 
 
   std::string ProjectName;
   std::string ProjectName;

+ 7 - 0
Source/cmStateSnapshot.cxx

@@ -390,6 +390,13 @@ void cmStateSnapshot::InitializeFromParent()
     this->Position->BuildSystemDirectory->CompileOptionsBacktraces,
     this->Position->BuildSystemDirectory->CompileOptionsBacktraces,
     this->Position->CompileOptionsPosition);
     this->Position->CompileOptionsPosition);
 
 
+  InitializeContentFromParent(
+    parent->BuildSystemDirectory->LinkOptions,
+    this->Position->BuildSystemDirectory->LinkOptions,
+    parent->BuildSystemDirectory->LinkOptionsBacktraces,
+    this->Position->BuildSystemDirectory->LinkOptionsBacktraces,
+    this->Position->LinkOptionsPosition);
+
   const char* include_regex =
   const char* include_regex =
     parent->BuildSystemDirectory->Properties.GetPropertyValue(
     parent->BuildSystemDirectory->Properties.GetPropertyValue(
       "INCLUDE_REGULAR_EXPRESSION");
       "INCLUDE_REGULAR_EXPRESSION");

+ 71 - 6
Source/cmTarget.cxx

@@ -166,6 +166,8 @@ public:
   std::vector<cmListFileBacktrace> CompileDefinitionsBacktraces;
   std::vector<cmListFileBacktrace> CompileDefinitionsBacktraces;
   std::vector<std::string> SourceEntries;
   std::vector<std::string> SourceEntries;
   std::vector<cmListFileBacktrace> SourceBacktraces;
   std::vector<cmListFileBacktrace> SourceBacktraces;
+  std::vector<std::string> LinkOptionsEntries;
+  std::vector<cmListFileBacktrace> LinkOptionsBacktraces;
   std::vector<std::string> LinkImplementationPropertyEntries;
   std::vector<std::string> LinkImplementationPropertyEntries;
   std::vector<cmListFileBacktrace> LinkImplementationPropertyBacktraces;
   std::vector<cmListFileBacktrace> LinkImplementationPropertyBacktraces;
 };
 };
@@ -343,17 +345,29 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
     this->SystemIncludeDirectories.insert(parentSystemIncludes.begin(),
     this->SystemIncludeDirectories.insert(parentSystemIncludes.begin(),
                                           parentSystemIncludes.end());
                                           parentSystemIncludes.end());
 
 
-    const cmStringRange parentOptions =
+    const cmStringRange parentCompileOptions =
       this->Makefile->GetCompileOptionsEntries();
       this->Makefile->GetCompileOptionsEntries();
-    const cmBacktraceRange parentOptionsBts =
+    const cmBacktraceRange parentCompileOptionsBts =
       this->Makefile->GetCompileOptionsBacktraces();
       this->Makefile->GetCompileOptionsBacktraces();
 
 
     this->Internal->CompileOptionsEntries.insert(
     this->Internal->CompileOptionsEntries.insert(
-      this->Internal->CompileOptionsEntries.end(), parentOptions.begin(),
-      parentOptions.end());
+      this->Internal->CompileOptionsEntries.end(),
+      parentCompileOptions.begin(), parentCompileOptions.end());
     this->Internal->CompileOptionsBacktraces.insert(
     this->Internal->CompileOptionsBacktraces.insert(
-      this->Internal->CompileOptionsBacktraces.end(), parentOptionsBts.begin(),
-      parentOptionsBts.end());
+      this->Internal->CompileOptionsBacktraces.end(),
+      parentCompileOptionsBts.begin(), parentCompileOptionsBts.end());
+
+    const cmStringRange parentLinkOptions =
+      this->Makefile->GetLinkOptionsEntries();
+    const cmBacktraceRange parentLinkOptionsBts =
+      this->Makefile->GetLinkOptionsBacktraces();
+
+    this->Internal->LinkOptionsEntries.insert(
+      this->Internal->LinkOptionsEntries.end(), parentLinkOptions.begin(),
+      parentLinkOptions.end());
+    this->Internal->LinkOptionsBacktraces.insert(
+      this->Internal->LinkOptionsBacktraces.end(),
+      parentLinkOptionsBts.begin(), parentLinkOptionsBts.end());
   }
   }
 
 
   if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
   if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
@@ -822,6 +836,16 @@ cmBacktraceRange cmTarget::GetSourceBacktraces() const
   return cmMakeRange(this->Internal->SourceBacktraces);
   return cmMakeRange(this->Internal->SourceBacktraces);
 }
 }
 
 
+cmStringRange cmTarget::GetLinkOptionsEntries() const
+{
+  return cmMakeRange(this->Internal->LinkOptionsEntries);
+}
+
+cmBacktraceRange cmTarget::GetLinkOptionsBacktraces() const
+{
+  return cmMakeRange(this->Internal->LinkOptionsBacktraces);
+}
+
 cmStringRange cmTarget::GetLinkImplementationEntries() const
 cmStringRange cmTarget::GetLinkImplementationEntries() const
 {
 {
   return cmMakeRange(this->Internal->LinkImplementationPropertyEntries);
   return cmMakeRange(this->Internal->LinkImplementationPropertyEntries);
@@ -847,6 +871,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
   MAKE_STATIC_PROP(EXPORT_NAME);
   MAKE_STATIC_PROP(EXPORT_NAME);
   MAKE_STATIC_PROP(IMPORTED_GLOBAL);
   MAKE_STATIC_PROP(IMPORTED_GLOBAL);
   MAKE_STATIC_PROP(INCLUDE_DIRECTORIES);
   MAKE_STATIC_PROP(INCLUDE_DIRECTORIES);
+  MAKE_STATIC_PROP(LINK_OPTIONS);
   MAKE_STATIC_PROP(LINK_LIBRARIES);
   MAKE_STATIC_PROP(LINK_LIBRARIES);
   MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES);
   MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES);
   MAKE_STATIC_PROP(NAME);
   MAKE_STATIC_PROP(NAME);
@@ -925,6 +950,14 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
       cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
       cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
       this->Internal->CompileDefinitionsBacktraces.push_back(lfbt);
       this->Internal->CompileDefinitionsBacktraces.push_back(lfbt);
     }
     }
+  } else if (prop == propLINK_OPTIONS) {
+    this->Internal->LinkOptionsEntries.clear();
+    this->Internal->LinkOptionsBacktraces.clear();
+    if (value) {
+      this->Internal->LinkOptionsEntries.push_back(value);
+      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+      this->Internal->LinkOptionsBacktraces.push_back(lfbt);
+    }
   } else if (prop == propLINK_LIBRARIES) {
   } else if (prop == propLINK_LIBRARIES) {
     this->Internal->LinkImplementationPropertyEntries.clear();
     this->Internal->LinkImplementationPropertyEntries.clear();
     this->Internal->LinkImplementationPropertyBacktraces.clear();
     this->Internal->LinkImplementationPropertyBacktraces.clear();
@@ -1030,6 +1063,12 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value,
       cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
       cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
       this->Internal->CompileDefinitionsBacktraces.push_back(lfbt);
       this->Internal->CompileDefinitionsBacktraces.push_back(lfbt);
     }
     }
+  } else if (prop == "LINK_OPTIONS") {
+    if (value && *value) {
+      this->Internal->LinkOptionsEntries.push_back(value);
+      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+      this->Internal->LinkOptionsBacktraces.push_back(lfbt);
+    }
   } else if (prop == "LINK_LIBRARIES") {
   } else if (prop == "LINK_LIBRARIES") {
     if (value && *value) {
     if (value && *value) {
       cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
       cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
@@ -1111,6 +1150,21 @@ void cmTarget::InsertCompileDefinition(std::string const& entry,
   this->Internal->CompileDefinitionsBacktraces.push_back(bt);
   this->Internal->CompileDefinitionsBacktraces.push_back(bt);
 }
 }
 
 
+void cmTarget::InsertLinkOption(std::string const& entry,
+                                cmListFileBacktrace const& bt, bool before)
+{
+  std::vector<std::string>::iterator position = before
+    ? this->Internal->LinkOptionsEntries.begin()
+    : this->Internal->LinkOptionsEntries.end();
+
+  std::vector<cmListFileBacktrace>::iterator btPosition = before
+    ? this->Internal->LinkOptionsBacktraces.begin()
+    : this->Internal->LinkOptionsBacktraces.end();
+
+  this->Internal->LinkOptionsEntries.insert(position, entry);
+  this->Internal->LinkOptionsBacktraces.insert(btPosition, bt);
+}
+
 static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop,
 static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop,
                                                   const char* value,
                                                   const char* value,
                                                   cmMakefile* context,
                                                   cmMakefile* context,
@@ -1230,6 +1284,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const
   MAKE_STATIC_PROP(COMPILE_FEATURES);
   MAKE_STATIC_PROP(COMPILE_FEATURES);
   MAKE_STATIC_PROP(COMPILE_OPTIONS);
   MAKE_STATIC_PROP(COMPILE_OPTIONS);
   MAKE_STATIC_PROP(COMPILE_DEFINITIONS);
   MAKE_STATIC_PROP(COMPILE_DEFINITIONS);
+  MAKE_STATIC_PROP(LINK_OPTIONS);
   MAKE_STATIC_PROP(IMPORTED);
   MAKE_STATIC_PROP(IMPORTED);
   MAKE_STATIC_PROP(IMPORTED_GLOBAL);
   MAKE_STATIC_PROP(IMPORTED_GLOBAL);
   MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES);
   MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES);
@@ -1245,6 +1300,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const
     specialProps.insert(propCOMPILE_FEATURES);
     specialProps.insert(propCOMPILE_FEATURES);
     specialProps.insert(propCOMPILE_OPTIONS);
     specialProps.insert(propCOMPILE_OPTIONS);
     specialProps.insert(propCOMPILE_DEFINITIONS);
     specialProps.insert(propCOMPILE_DEFINITIONS);
+    specialProps.insert(propLINK_OPTIONS);
     specialProps.insert(propIMPORTED);
     specialProps.insert(propIMPORTED);
     specialProps.insert(propIMPORTED_GLOBAL);
     specialProps.insert(propIMPORTED_GLOBAL);
     specialProps.insert(propMANUALLY_ADDED_DEPENDENCIES);
     specialProps.insert(propMANUALLY_ADDED_DEPENDENCIES);
@@ -1303,6 +1359,15 @@ const char* cmTarget::GetProperty(const std::string& prop) const
       output = cmJoin(this->Internal->CompileDefinitionsEntries, ";");
       output = cmJoin(this->Internal->CompileDefinitionsEntries, ";");
       return output.c_str();
       return output.c_str();
     }
     }
+    if (prop == propLINK_OPTIONS) {
+      if (this->Internal->LinkOptionsEntries.empty()) {
+        return nullptr;
+      }
+
+      static std::string output;
+      output = cmJoin(this->Internal->LinkOptionsEntries, ";");
+      return output.c_str();
+    }
     if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
     if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
       if (this->Utilities.empty()) {
       if (this->Utilities.empty()) {
         return nullptr;
         return nullptr;

+ 6 - 0
Source/cmTarget.h

@@ -239,6 +239,8 @@ public:
                            cmListFileBacktrace const& bt, bool before = false);
                            cmListFileBacktrace const& bt, bool before = false);
   void InsertCompileDefinition(std::string const& entry,
   void InsertCompileDefinition(std::string const& entry,
                                cmListFileBacktrace const& bt);
                                cmListFileBacktrace const& bt);
+  void InsertLinkOption(std::string const& entry,
+                        cmListFileBacktrace const& bt, bool before = false);
 
 
   void AppendBuildInterfaceIncludes();
   void AppendBuildInterfaceIncludes();
 
 
@@ -265,6 +267,10 @@ public:
 
 
   cmStringRange GetSourceEntries() const;
   cmStringRange GetSourceEntries() const;
   cmBacktraceRange GetSourceBacktraces() const;
   cmBacktraceRange GetSourceBacktraces() const;
+
+  cmStringRange GetLinkOptionsEntries() const;
+  cmBacktraceRange GetLinkOptionsBacktraces() const;
+
   cmStringRange GetLinkImplementationEntries() const;
   cmStringRange GetLinkImplementationEntries() const;
   cmBacktraceRange GetLinkImplementationBacktraces() const;
   cmBacktraceRange GetLinkImplementationBacktraces() const;
 
 

+ 41 - 0
Source/cmTargetLinkOptionsCommand.cxx

@@ -0,0 +1,41 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmTargetLinkOptionsCommand.h"
+
+#include <sstream>
+
+#include "cmAlgorithms.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmTarget.h"
+#include "cmake.h"
+
+class cmExecutionStatus;
+
+bool cmTargetLinkOptionsCommand::InitialPass(
+  std::vector<std::string> const& args, cmExecutionStatus&)
+{
+  return this->HandleArguments(args, "LINK_OPTIONS", PROCESS_BEFORE);
+}
+
+void cmTargetLinkOptionsCommand::HandleMissingTarget(const std::string& name)
+{
+  std::ostringstream e;
+  e << "Cannot specify link options for target \"" << name
+    << "\" which is not built by this project.";
+  this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+std::string cmTargetLinkOptionsCommand::Join(
+  const std::vector<std::string>& content)
+{
+  return cmJoin(content, ";");
+}
+
+bool cmTargetLinkOptionsCommand::HandleDirectContent(
+  cmTarget* tgt, const std::vector<std::string>& content, bool, bool)
+{
+  cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+  tgt->InsertLinkOption(this->Join(content), lfbt);
+  return true; // Successfully handled.
+}

+ 41 - 0
Source/cmTargetLinkOptionsCommand.h

@@ -0,0 +1,41 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmTargetLinkOptionsCommand_h
+#define cmTargetLinkOptionsCommand_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+#include "cmTargetPropCommandBase.h"
+
+class cmCommand;
+class cmExecutionStatus;
+class cmTarget;
+
+class cmTargetLinkOptionsCommand : public cmTargetPropCommandBase
+{
+public:
+  /**
+   * This is a virtual constructor for the command.
+   */
+  cmCommand* Clone() override { return new cmTargetLinkOptionsCommand; }
+
+  /**
+   * This is called when the command is first encountered in
+   * the CMakeLists.txt file.
+   */
+  bool InitialPass(std::vector<std::string> const& args,
+                   cmExecutionStatus& status) override;
+
+private:
+  void HandleMissingTarget(const std::string& name) override;
+
+  bool HandleDirectContent(cmTarget* tgt,
+                           const std::vector<std::string>& content,
+                           bool prepend, bool system) override;
+  std::string Join(const std::vector<std::string>& content) override;
+};
+
+#endif

+ 5 - 0
Source/cmVisualStudio10TargetGenerator.cxx

@@ -3234,6 +3234,11 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
     flags += flagsConfig;
     flags += flagsConfig;
   }
   }
 
 
+  std::vector<std::string> opts;
+  this->GeneratorTarget->GetLinkOptions(opts, config, linkLanguage);
+  // LINK_OPTIONS are escaped.
+  this->LocalGenerator->AppendCompileOptions(flags, opts);
+
   cmComputeLinkInformation* pcli =
   cmComputeLinkInformation* pcli =
     this->GeneratorTarget->GetLinkInformation(config);
     this->GeneratorTarget->GetLinkInformation(config);
   if (!pcli) {
   if (!pcli) {

+ 20 - 0
Tests/CMakeCommands/add_link_options/CMakeLists.txt

@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.11)
+
+project(add_link_options LANGUAGES C)
+
+
+add_link_options(-LINK_FLAG)
+
+add_executable(add_link_options EXCLUDE_FROM_ALL LinkOptionsExe.c)
+
+get_target_property(result add_link_options LINK_OPTIONS)
+if (NOT result MATCHES "-LINK_FLAG")
+  message(SEND_ERROR "add_link_options not populated the LINK_OPTIONS target property")
+endif()
+
+
+add_library(imp UNKNOWN IMPORTED)
+get_target_property(result imp LINK_OPTIONS)
+if (result)
+  message(FATAL_ERROR "add_link_options populated the LINK_OPTIONS target property")
+endif()

+ 4 - 0
Tests/CMakeCommands/add_link_options/LinkOptionsExe.c

@@ -0,0 +1,4 @@
+int main(void)
+{
+  return 0;
+}

+ 19 - 0
Tests/CMakeCommands/target_link_options/CMakeLists.txt

@@ -0,0 +1,19 @@
+
+cmake_minimum_required(VERSION 3.11)
+
+project(target_link_options LANGUAGES C)
+
+add_library(target_link_options SHARED LinkOptionsLib.c)
+# Test no items
+target_link_options(target_link_options PRIVATE)
+
+add_library(target_link_options_2 SHARED EXCLUDE_FROM_ALL LinkOptionsLib.c)
+target_link_options(target_link_options_2 PRIVATE -PRIVATE_FLAG INTERFACE -INTERFACE_FLAG)
+get_target_property(result target_link_options_2 LINK_OPTIONS)
+if (NOT result MATCHES "-PRIVATE_FLAG")
+  message(SEND_ERROR "target_link_options not populated the LINK_OPTIONS target property")
+endif()
+get_target_property(result target_link_options_2 INTERFACE_LINK_OPTIONS)
+if (NOT result MATCHES "-INTERFACE_FLAG")
+  message(SEND_ERROR "target_link_options not populated the INTERFACE_LINK_OPTIONS target property")
+endif()

+ 7 - 0
Tests/CMakeCommands/target_link_options/LinkOptionsLib.c

@@ -0,0 +1,7 @@
+#if defined(_WIN32)
+__declspec(dllexport)
+#endif
+  int flags_lib(void)
+{
+  return 0;
+}

+ 3 - 0
Tests/CMakeLists.txt

@@ -2840,6 +2840,9 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
   ADD_TEST_MACRO(CMakeCommands.target_compile_definitions target_compile_definitions)
   ADD_TEST_MACRO(CMakeCommands.target_compile_definitions target_compile_definitions)
   ADD_TEST_MACRO(CMakeCommands.target_compile_options target_compile_options)
   ADD_TEST_MACRO(CMakeCommands.target_compile_options target_compile_options)
 
 
+  ADD_TEST_MACRO(CMakeCommands.add_link_options)
+  ADD_TEST_MACRO(CMakeCommands.target_link_options)
+
   # The cmake server-mode test requires python for a simple client.
   # The cmake server-mode test requires python for a simple client.
   find_package(PythonInterp QUIET)
   find_package(PythonInterp QUIET)
   if(PYTHON_EXECUTABLE)
   if(PYTHON_EXECUTABLE)

+ 10 - 0
Tests/ExportImport/Export/CMakeLists.txt

@@ -597,3 +597,13 @@ install(
   )
   )
 install(DIRECTORY $<1:include/abs>$<0:/wrong> DESTINATION $<1:include>$<0:/wrong>)
 install(DIRECTORY $<1:include/abs>$<0:/wrong> DESTINATION $<1:include>$<0:/wrong>)
 install(EXPORT expAbs NAMESPACE expAbs_ DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/expAbs)
 install(EXPORT expAbs NAMESPACE expAbs_ DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/expAbs)
+
+
+#------------------------------------------------------------------------------
+# test export of INTERFACE_LINK_OPTIONS
+add_library(testLinkOptions INTERFACE)
+target_link_options(testLinkOptions INTERFACE INTERFACE_FLAG)
+
+install(TARGETS testLinkOptions
+        EXPORT RequiredExp DESTINATION lib)
+export(TARGETS testLinkOptions NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake)

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

@@ -472,3 +472,8 @@ if (((CMAKE_C_COMPILER_ID STREQUAL GNU AND CMAKE_C_COMPILER_VERSION VERSION_GREA
     endif()
     endif()
   endif()
   endif()
 endif()
 endif()
+
+#---------------------------------------------------------------------------------
+# check that imported libraries have the expected INTERFACE_LINK_OPTIONS property
+checkForProperty(bld_testLinkOptions "INTERFACE_LINK_OPTIONS" "INTERFACE_FLAG")
+checkForProperty(Req::testLinkOptions "INTERFACE_LINK_OPTIONS" "INTERFACE_FLAG")

+ 8 - 0
Tests/ExportImport/Import/A/imp_testLinkOptions.cpp

@@ -0,0 +1,8 @@
+
+#include "testSharedLibRequired.h"
+
+int foo()
+{
+  TestSharedLibRequired req;
+  return req.foo();
+}

+ 4 - 2
Tests/RunCMake/AndroidMK/AndroidMK.cmake

@@ -5,7 +5,9 @@ add_library(car foo.cxx)
 add_library(bar bar.c)
 add_library(bar bar.c)
 add_library(dog  foo.cxx)
 add_library(dog  foo.cxx)
 target_link_libraries(foo PRIVATE car bar dog debug -lm)
 target_link_libraries(foo PRIVATE car bar dog debug -lm)
-export(TARGETS bar dog car foo  ANDROID_MK
+add_library(foo2  foo.cxx)
+target_link_options(foo2 INTERFACE -lm)
+export(TARGETS bar dog car foo foo2 ANDROID_MK
   ${build_BINARY_DIR}/Android.mk)
   ${build_BINARY_DIR}/Android.mk)
-install(TARGETS bar dog car foo DESTINATION lib EXPORT myexp)
+install(TARGETS bar dog car foo foo2 DESTINATION lib EXPORT myexp)
 install(EXPORT_ANDROID_MK myexp DESTINATION share/ndk-modules)
 install(EXPORT_ANDROID_MK myexp DESTINATION share/ndk-modules)

+ 8 - 0
Tests/RunCMake/AndroidMK/expectedBuildAndroidMK.txt

@@ -24,3 +24,11 @@ LOCAL_STATIC_LIBRARIES.*car bar dog
 LOCAL_EXPORT_LDLIBS := -lm
 LOCAL_EXPORT_LDLIBS := -lm
 LOCAL_HAS_CPP := true
 LOCAL_HAS_CPP := true
 include.*PREBUILT_STATIC_LIBRARY.*
 include.*PREBUILT_STATIC_LIBRARY.*
+.*
+include.*CLEAR_VARS.*
+LOCAL_MODULE.*foo2
+LOCAL_SRC_FILES.*.*foo2.*
+LOCAL_CPP_FEATURES.*rtti exceptions
+LOCAL_EXPORT_LDFLAGS := -lm
+LOCAL_HAS_CPP := true
+include.*PREBUILT_STATIC_LIBRARY.*

+ 8 - 0
Tests/RunCMake/AndroidMK/expectedInstallAndroidMK.txt

@@ -26,3 +26,11 @@ LOCAL_STATIC_LIBRARIES.*car bar dog
 LOCAL_EXPORT_LDLIBS := -lm
 LOCAL_EXPORT_LDLIBS := -lm
 LOCAL_HAS_CPP := true
 LOCAL_HAS_CPP := true
 include.*PREBUILT_STATIC_LIBRARY.*
 include.*PREBUILT_STATIC_LIBRARY.*
+
+include.*CLEAR_VARS.*
+LOCAL_MODULE.*foo2
+LOCAL_SRC_FILES.*_IMPORT_PREFIX\)/lib.*foo2.*
+LOCAL_CPP_FEATURES.*rtti exceptions
+LOCAL_EXPORT_LDFLAGS := -lm
+LOCAL_HAS_CPP := true
+include.*PREBUILT_STATIC_LIBRARY.*

+ 2 - 0
Tests/RunCMake/CMakeLists.txt

@@ -332,6 +332,8 @@ endif()
 add_RunCMake_test(File_Generate)
 add_RunCMake_test(File_Generate)
 add_RunCMake_test(ExportWithoutLanguage)
 add_RunCMake_test(ExportWithoutLanguage)
 add_RunCMake_test(target_link_libraries)
 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_compile_features)
 add_RunCMake_test(target_compile_features)
 add_RunCMake_test(CheckModules)
 add_RunCMake_test(CheckModules)

+ 5 - 0
Tests/RunCMake/add_link_options/CMakeLists.txt

@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.11)
+
+project(${RunCMake_TEST} LANGUAGES NONE)
+
+include(${RunCMake_TEST}.cmake)

+ 2 - 0
Tests/RunCMake/add_link_options/LINKER_SHELL_expansion-build-check.cmake

@@ -0,0 +1,2 @@
+
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake")

+ 4 - 0
Tests/RunCMake/add_link_options/LINKER_SHELL_expansion.cmake

@@ -0,0 +1,4 @@
+
+set (LINKER_OPTION "LINKER:SHELL:-foo bar")
+
+include ("LINKER_expansion-list.cmake")

+ 2 - 0
Tests/RunCMake/add_link_options/LINKER_expansion-build-check.cmake

@@ -0,0 +1,2 @@
+
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake")

+ 36 - 0
Tests/RunCMake/add_link_options/LINKER_expansion-list.cmake

@@ -0,0 +1,36 @@
+
+enable_language(C)
+
+add_executable(dump dump.c)
+
+add_link_options("${LINKER_OPTION}")
+
+# ensure no temp file will be used
+string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}")
+string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}")
+
+add_library(example SHARED LinkOptionsLib.c)
+# use LAUNCH facility to dump linker command
+set_property(TARGET example PROPERTY RULE_LAUNCH_LINK "\"${CMAKE_CURRENT_BINARY_DIR}/dump${CMAKE_EXECUTABLE_SUFFIX}\"")
+
+add_dependencies (example dump)
+
+# generate reference for LINKER flag
+if (CMAKE_C_LINKER_WRAPPER_FLAG)
+  set(linker_flag ${CMAKE_C_LINKER_WRAPPER_FLAG})
+  list(GET linker_flag -1 linker_space)
+  if (linker_space STREQUAL " ")
+    list(REMOVE_AT linker_flag -1)
+  else()
+    set(linker_space)
+  endif()
+  list (JOIN linker_flag " " linker_flag)
+  if (CMAKE_C_LINKER_WRAPPER_FLAG_SEP)
+    string (APPEND  linker_flag "${linker_space}" "-foo${CMAKE_C_LINKER_WRAPPER_FLAG_SEP}bar")
+  else()
+    set (linker_flag "${linker_flag}${linker_space}-foo ${linker_flag}${linker_space}bar")
+  endif()
+else()
+  set(linker_flag "-foo bar")
+endif()
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/LINKER.txt" "${linker_flag}")

+ 15 - 0
Tests/RunCMake/add_link_options/LINKER_expansion-validation.cmake

@@ -0,0 +1,15 @@
+
+if (actual_stdout MATCHES "(LINKER|SHELL):")
+  set (RunCMake_TEST_FAILED "LINKER: prefix was not expanded.")
+  return()
+endif()
+
+if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/LINKER.txt")
+  set (RunCMake_TEST_FAILED "${RunCMake_TEST_BINARY_DIR}/LINKER.txt: Reference file not found.")
+  return()
+endif()
+file(READ "${RunCMake_TEST_BINARY_DIR}/LINKER.txt" linker_flag)
+
+if (NOT actual_stdout MATCHES "${linker_flag}")
+  set (RunCMake_TEST_FAILED "LINKER: was not expanded correctly.")
+endif()

+ 4 - 0
Tests/RunCMake/add_link_options/LINKER_expansion.cmake

@@ -0,0 +1,4 @@
+
+set (LINKER_OPTION "LINKER:-foo,bar")
+
+include ("LINKER_expansion-list.cmake")

+ 7 - 0
Tests/RunCMake/add_link_options/LINK_OPTIONS-exe-check.cmake

@@ -0,0 +1,7 @@
+
+if (NOT actual_stdout MATCHES "BADFLAG_EXECUTABLE_RELEASE")
+  set (RunCMake_TEST_FAILED "Not found expected 'BADFLAG_EXECUTABLE_RELEASE'.")
+endif()
+if (actual_stdout MATCHES "BADFLAG_(SHARED|MODULE)_RELEASE")
+  set (RunCMake_TEST_FAILED "Found unexpected 'BADFLAG_(SHARED|MODULE)_RELEASE'.")
+endif()

+ 1 - 0
Tests/RunCMake/add_link_options/LINK_OPTIONS-exe-result.txt

@@ -0,0 +1 @@
+.*

+ 7 - 0
Tests/RunCMake/add_link_options/LINK_OPTIONS-mod-check.cmake

@@ -0,0 +1,7 @@
+
+if (NOT actual_stdout MATCHES "BADFLAG_MODULE_RELEASE")
+  set (RunCMake_TEST_FAILED "Not found expected 'BADFLAG_MODULE_RELEASE'.")
+endif()
+if (actual_stdout MATCHES "BADFLAG_(SHARED|EXECUTABLE)_RELEASE")
+  set (RunCMake_TEST_FAILED "Found unexpected 'BADFLAG_(SHARED|EXECUTABLE)_RELEASE'.")
+endif()

+ 1 - 0
Tests/RunCMake/add_link_options/LINK_OPTIONS-mod-result.txt

@@ -0,0 +1 @@
+.*

+ 7 - 0
Tests/RunCMake/add_link_options/LINK_OPTIONS-shared-check.cmake

@@ -0,0 +1,7 @@
+
+if (NOT actual_stdout MATCHES "BADFLAG_SHARED_RELEASE")
+  set (RunCMake_TEST_FAILED "Not found expected 'BADFLAG_SHARED_RELEASE'.")
+endif()
+if (actual_stdout MATCHES "BADFLAG_(MODULE|EXECUTABLE)_RELEASE")
+  set (RunCMake_TEST_FAILED "Found unexpected 'BADFLAG_(MODULE|EXECUTABLE)_RELEASE'.")
+endif()

+ 1 - 0
Tests/RunCMake/add_link_options/LINK_OPTIONS-shared-result.txt

@@ -0,0 +1 @@
+.*

+ 17 - 0
Tests/RunCMake/add_link_options/LINK_OPTIONS.cmake

@@ -0,0 +1,17 @@
+
+enable_language(C)
+
+set(obj "${CMAKE_C_OUTPUT_EXTENSION}")
+if(BORLAND)
+  set(pre -)
+endif()
+
+add_link_options($<$<AND:$<STREQUAL:$<TARGET_PROPERTY:TYPE>,SHARED_LIBRARY>,$<CONFIG:Release>>:${pre}BADFLAG_SHARED_RELEASE${obj}>)
+add_link_options($<$<AND:$<STREQUAL:$<TARGET_PROPERTY:TYPE>,MODULE_LIBRARY>,$<CONFIG:Release>>:${pre}BADFLAG_MODULE_RELEASE${obj}>)
+add_link_options($<$<AND:$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>,$<CONFIG:Release>>:${pre}BADFLAG_EXECUTABLE_RELEASE${obj}>)
+
+add_library(LinkOptions_shared SHARED LinkOptionsLib.c)
+
+add_library(LinkOptions_mod MODULE LinkOptionsLib.c)
+
+add_executable(LinkOptions_exe LinkOptionsExe.c)

+ 4 - 0
Tests/RunCMake/add_link_options/LinkOptionsExe.c

@@ -0,0 +1,4 @@
+int main(void)
+{
+  return 0;
+}

+ 7 - 0
Tests/RunCMake/add_link_options/LinkOptionsLib.c

@@ -0,0 +1,7 @@
+#if defined(_WIN32)
+__declspec(dllexport)
+#endif
+  int flags_lib(void)
+{
+  return 0;
+}

+ 38 - 0
Tests/RunCMake/add_link_options/RunCMakeTest.cmake

@@ -0,0 +1,38 @@
+
+include(RunCMake)
+
+macro(run_cmake_target test subtest target)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(${test}-${subtest} ${CMAKE_COMMAND} --build . --target ${target} ${ARGN})
+
+  unset(RunCMake_TEST_BINARY_DIR)
+  unset(RunCMake_TEST_NO_CLEAN)
+endmacro()
+
+if (NOT CMAKE_C_COMPILER_ID STREQUAL "Intel")
+  # Intel compiler does not reject bad flags or objects!
+  set(RunCMake_TEST_OUTPUT_MERGE TRUE)
+  if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+    set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
+  endif()
+
+  run_cmake(LINK_OPTIONS)
+
+  run_cmake_target(LINK_OPTIONS shared LinkOptions_shared --config Release)
+  run_cmake_target(LINK_OPTIONS mod LinkOptions_mod --config Release)
+  run_cmake_target(LINK_OPTIONS exe LinkOptions_exe --config Release)
+
+  unset(RunCMake_TEST_OPTIONS)
+  unset(RunCMake_TEST_OUTPUT_MERGE)
+endif()
+
+run_cmake(bad_SHELL_usage)
+
+if(RunCMake_GENERATOR MATCHES "(Ninja|Makefile)")
+  run_cmake(LINKER_expansion)
+  run_cmake_target(LINKER_expansion build all)
+
+  run_cmake(LINKER_SHELL_expansion)
+  run_cmake_target(LINKER_SHELL_expansion build all)
+endif()

Некоторые файлы не были показаны из-за большого количества измененных файлов