瀏覽代碼

LINK_OPTIONS: Add new family of properties

This family enable to manage link flags

Three new properties:
* directory property: LINK_OPTIONS
* target properties: LINK_OPTIONS and INTERFACE_LINK_OPTIONS

Two new commands
* add_link_options(): to populate directory property
* target_link_options(): to populate target properties

Fixes: #16543
Marc Chevrier 7 年之前
父節點
當前提交
c1f5a44b28
共有 84 個文件被更改,包括 921 次插入34 次删除
  1. 1 1
      Help/command/OPTIONS_SHELL.txt
  2. 1 1
      Help/command/add_compile_options.rst
  3. 24 0
      Help/command/add_link_options.rst
  4. 1 1
      Help/command/target_compile_options.rst
  5. 2 1
      Help/command/target_link_libraries.rst
  6. 40 0
      Help/command/target_link_options.rst
  7. 2 0
      Help/manual/cmake-commands.7.rst
  8. 3 0
      Help/manual/cmake-properties.7.rst
  9. 16 0
      Help/prop_dir/LINK_OPTIONS.rst
  10. 9 0
      Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst
  11. 6 2
      Help/prop_tgt/LINK_FLAGS.rst
  12. 4 0
      Help/prop_tgt/LINK_FLAGS_CONFIG.rst
  13. 21 0
      Help/prop_tgt/LINK_OPTIONS.rst
  14. 11 0
      Help/release/dev/LINK_OPTIONS.rst
  15. 4 0
      Source/CMakeLists.txt
  16. 20 0
      Source/cmAddLinkOptionsCommand.cxx
  17. 31 0
      Source/cmAddLinkOptionsCommand.h
  18. 5 0
      Source/cmCommands.cxx
  19. 6 0
      Source/cmExportBuildAndroidMKGenerator.cxx
  20. 3 0
      Source/cmExportBuildFileGenerator.cxx
  21. 3 0
      Source/cmExportInstallFileGenerator.cxx
  22. 2 1
      Source/cmGeneratorExpressionDAGChecker.h
  23. 70 11
      Source/cmGeneratorTarget.cxx
  24. 6 0
      Source/cmGeneratorTarget.h
  25. 4 0
      Source/cmGlobalXCodeGenerator.cxx
  26. 8 0
      Source/cmLocalGenerator.cxx
  27. 7 0
      Source/cmLocalVisualStudio7Generator.cxx
  28. 15 0
      Source/cmMakefile.cxx
  29. 3 0
      Source/cmMakefile.h
  30. 2 2
      Source/cmMakefileExecutableTargetGenerator.cxx
  31. 4 4
      Source/cmMakefileLibraryTargetGenerator.cxx
  32. 7 1
      Source/cmMakefileTargetGenerator.cxx
  33. 1 1
      Source/cmMakefileTargetGenerator.h
  34. 2 0
      Source/cmState.cxx
  35. 52 0
      Source/cmStateDirectory.cxx
  36. 7 0
      Source/cmStateDirectory.h
  37. 4 0
      Source/cmStatePrivate.h
  38. 7 0
      Source/cmStateSnapshot.cxx
  39. 71 6
      Source/cmTarget.cxx
  40. 6 0
      Source/cmTarget.h
  41. 41 0
      Source/cmTargetLinkOptionsCommand.cxx
  42. 41 0
      Source/cmTargetLinkOptionsCommand.h
  43. 5 0
      Source/cmVisualStudio10TargetGenerator.cxx
  44. 20 0
      Tests/CMakeCommands/add_link_options/CMakeLists.txt
  45. 4 0
      Tests/CMakeCommands/add_link_options/LinkOptionsExe.c
  46. 19 0
      Tests/CMakeCommands/target_link_options/CMakeLists.txt
  47. 7 0
      Tests/CMakeCommands/target_link_options/LinkOptionsLib.c
  48. 3 0
      Tests/CMakeLists.txt
  49. 10 0
      Tests/ExportImport/Export/CMakeLists.txt
  50. 5 0
      Tests/ExportImport/Import/A/CMakeLists.txt
  51. 8 0
      Tests/ExportImport/Import/A/imp_testLinkOptions.cpp
  52. 4 2
      Tests/RunCMake/AndroidMK/AndroidMK.cmake
  53. 8 0
      Tests/RunCMake/AndroidMK/expectedBuildAndroidMK.txt
  54. 8 0
      Tests/RunCMake/AndroidMK/expectedInstallAndroidMK.txt
  55. 2 0
      Tests/RunCMake/CMakeLists.txt
  56. 5 0
      Tests/RunCMake/add_link_options/CMakeLists.txt
  57. 7 0
      Tests/RunCMake/add_link_options/LINK_OPTIONS-exe-check.cmake
  58. 1 0
      Tests/RunCMake/add_link_options/LINK_OPTIONS-exe-result.txt
  59. 7 0
      Tests/RunCMake/add_link_options/LINK_OPTIONS-mod-check.cmake
  60. 1 0
      Tests/RunCMake/add_link_options/LINK_OPTIONS-mod-result.txt
  61. 7 0
      Tests/RunCMake/add_link_options/LINK_OPTIONS-shared-check.cmake
  62. 1 0
      Tests/RunCMake/add_link_options/LINK_OPTIONS-shared-result.txt
  63. 17 0
      Tests/RunCMake/add_link_options/LINK_OPTIONS.cmake
  64. 4 0
      Tests/RunCMake/add_link_options/LinkOptionsExe.c
  65. 7 0
      Tests/RunCMake/add_link_options/LinkOptionsLib.c
  66. 28 0
      Tests/RunCMake/add_link_options/RunCMakeTest.cmake
  67. 2 0
      Tests/RunCMake/set_property/LINK_OPTIONS-stdout.txt
  68. 3 0
      Tests/RunCMake/set_property/LINK_OPTIONS.cmake
  69. 1 0
      Tests/RunCMake/set_property/RunCMakeTest.cmake
  70. 5 0
      Tests/RunCMake/target_link_options/CMakeLists.txt
  71. 7 0
      Tests/RunCMake/target_link_options/LINK_OPTIONS-basic-check.cmake
  72. 1 0
      Tests/RunCMake/target_link_options/LINK_OPTIONS-basic-result.txt
  73. 7 0
      Tests/RunCMake/target_link_options/LINK_OPTIONS-exe-check.cmake
  74. 1 0
      Tests/RunCMake/target_link_options/LINK_OPTIONS-exe-result.txt
  75. 4 0
      Tests/RunCMake/target_link_options/LINK_OPTIONS-interface-check.cmake
  76. 1 0
      Tests/RunCMake/target_link_options/LINK_OPTIONS-interface-result.txt
  77. 7 0
      Tests/RunCMake/target_link_options/LINK_OPTIONS-mod-check.cmake
  78. 1 0
      Tests/RunCMake/target_link_options/LINK_OPTIONS-mod-result.txt
  79. 7 0
      Tests/RunCMake/target_link_options/LINK_OPTIONS-shared-check.cmake
  80. 1 0
      Tests/RunCMake/target_link_options/LINK_OPTIONS-shared-result.txt
  81. 39 0
      Tests/RunCMake/target_link_options/LINK_OPTIONS.cmake
  82. 4 0
      Tests/RunCMake/target_link_options/LinkOptionsExe.c
  83. 7 0
      Tests/RunCMake/target_link_options/LinkOptionsLib.c
  84. 62 0
      Tests/RunCMake/target_link_options/RunCMakeTest.cmake

+ 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

+ 24 - 0
Help/command/add_link_options.rst

@@ -0,0 +1,24 @@
+add_link_options
+----------------
+
+Adds options to the link of targets.
+
+::
+
+  add_link_options(<option> ...)
+
+Adds options to the linker command line 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 command
+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:: 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.
 
 

+ 40 - 0
Help/command/target_link_options.rst

@@ -0,0 +1,40 @@
+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 compile 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:: 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

+ 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

+ 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)

+ 70 - 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,59 @@ void cmGeneratorTarget::GetCompileDefinitions(
   cmDeleteAll(linkInterfaceCompileDefinitionsEntries);
   cmDeleteAll(linkInterfaceCompileDefinitionsEntries);
 }
 }
 
 
+static 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);
+}
+
 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 - 2
Source/cmMakefileExecutableTargetGenerator.cxx

@@ -154,7 +154,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
                                              linkLanguage, this->ConfigName);
                                              linkLanguage, this->ConfigName);
 
 
   // Add target-specific linker flags.
   // Add target-specific linker flags.
-  this->GetTargetLinkFlags(linkFlags);
+  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.
@@ -432,7 +432,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
                                              linkLanguage, this->ConfigName);
                                              linkLanguage, this->ConfigName);
 
 
   // Add target-specific linker flags.
   // Add target-specific linker flags.
-  this->GetTargetLinkFlags(linkFlags);
+  this->GetTargetLinkFlags(linkFlags, linkLanguage);
 
 
   {
   {
     std::unique_ptr<cmLinkLineComputer> linkLineComputer(
     std::unique_ptr<cmLinkLineComputer> linkLineComputer(

+ 4 - 4
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -181,7 +181,7 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
   linkRuleVar += "_CREATE_SHARED_LIBRARY";
   linkRuleVar += "_CREATE_SHARED_LIBRARY";
 
 
   std::string extraFlags;
   std::string extraFlags;
-  this->GetTargetLinkFlags(extraFlags);
+  this->GetTargetLinkFlags(extraFlags, linkLanguage);
   this->LocalGenerator->AddConfigVariableFlags(
   this->LocalGenerator->AddConfigVariableFlags(
     extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->ConfigName);
     extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->ConfigName);
 
 
@@ -222,7 +222,7 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
   linkRuleVar += "_CREATE_SHARED_MODULE";
   linkRuleVar += "_CREATE_SHARED_MODULE";
 
 
   std::string extraFlags;
   std::string extraFlags;
-  this->GetTargetLinkFlags(extraFlags);
+  this->GetTargetLinkFlags(extraFlags, linkLanguage);
   this->LocalGenerator->AddConfigVariableFlags(
   this->LocalGenerator->AddConfigVariableFlags(
     extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->ConfigName);
     extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->ConfigName);
 
 
@@ -245,7 +245,7 @@ void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink)
   linkRuleVar += "_CREATE_MACOSX_FRAMEWORK";
   linkRuleVar += "_CREATE_MACOSX_FRAMEWORK";
 
 
   std::string extraFlags;
   std::string extraFlags;
-  this->GetTargetLinkFlags(extraFlags);
+  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);
 
 
@@ -271,7 +271,7 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules(
 
 
   // Create set of linking flags.
   // Create set of linking flags.
   std::string linkFlags;
   std::string linkFlags;
-  this->GetTargetLinkFlags(linkFlags);
+  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 =

+ 7 - 1
Source/cmMakefileTargetGenerator.cxx

@@ -82,7 +82,8 @@ cmMakefileTargetGenerator* cmMakefileTargetGenerator::New(
   return result;
   return result;
 }
 }
 
 
-void cmMakefileTargetGenerator::GetTargetLinkFlags(std::string& flags)
+void cmMakefileTargetGenerator::GetTargetLinkFlags(
+  std::string& flags, const std::string& linkLanguage)
 {
 {
   this->LocalGenerator->AppendFlags(
   this->LocalGenerator->AppendFlags(
     flags, this->GeneratorTarget->GetProperty("LINK_FLAGS"));
     flags, this->GeneratorTarget->GetProperty("LINK_FLAGS"));
@@ -91,6 +92,11 @@ void cmMakefileTargetGenerator::GetTargetLinkFlags(std::string& flags)
   linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
   linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
   this->LocalGenerator->AppendFlags(
   this->LocalGenerator->AppendFlags(
     flags, this->GeneratorTarget->GetProperty(linkFlagsConfig));
     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()

+ 1 - 1
Source/cmMakefileTargetGenerator.h

@@ -52,7 +52,7 @@ public:
   cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; }
   cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; }
 
 
 protected:
 protected:
-  void GetTargetLinkFlags(std::string& flags);
+  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)

+ 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;
+}

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

@@ -0,0 +1,28 @@
+
+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()

+ 2 - 0
Tests/RunCMake/set_property/LINK_OPTIONS-stdout.txt

@@ -0,0 +1,2 @@
+-- Target LINK_OPTIONS is 'a;b;c;d;;e'
+-- Directory LINK_OPTIONS is 'a;b;c;d;;e'

+ 3 - 0
Tests/RunCMake/set_property/LINK_OPTIONS.cmake

@@ -0,0 +1,3 @@
+include(Common.cmake)
+test_target_property(LINK_OPTIONS)
+test_directory_property(LINK_OPTIONS)

+ 1 - 0
Tests/RunCMake/set_property/RunCMakeTest.cmake

@@ -5,6 +5,7 @@ run_cmake(COMPILE_FEATURES)
 run_cmake(COMPILE_OPTIONS)
 run_cmake(COMPILE_OPTIONS)
 run_cmake(IMPORTED_GLOBAL)
 run_cmake(IMPORTED_GLOBAL)
 run_cmake(INCLUDE_DIRECTORIES)
 run_cmake(INCLUDE_DIRECTORIES)
+run_cmake(LINK_OPTIONS)
 run_cmake(LINK_LIBRARIES)
 run_cmake(LINK_LIBRARIES)
 run_cmake(SOURCES)
 run_cmake(SOURCES)
 run_cmake(TYPE)
 run_cmake(TYPE)

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

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

+ 7 - 0
Tests/RunCMake/target_link_options/LINK_OPTIONS-basic-check.cmake

@@ -0,0 +1,7 @@
+
+if (NOT actual_stdout MATCHES "BADFLAG_PRIVATE")
+  set (RunCMake_TEST_FAILED "Not found expected 'BADFLAG_PRIVATE'.")
+endif()
+if (actual_stdout MATCHES "BADFLAG_INTERFACE")
+  string (APPEND RunCMake_TEST_FAILED "\nFound unexpected 'BADFLAG_INTERFACE'.")
+endif()

+ 1 - 0
Tests/RunCMake/target_link_options/LINK_OPTIONS-basic-result.txt

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

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

@@ -0,0 +1,7 @@
+
+if (NOT actual_stdout MATCHES "BADFLAG_RELEASE")
+  set (RunCMake_TEST_FAILED "Not found expected 'BADFLAG_RELEASE'.")
+endif()
+if (actual_stdout MATCHES "SHELL:")
+  string (APPEND RunCMake_TEST_FAILED "\nFound unexpected prefix 'SHELL:'.")
+endif()

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

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

+ 4 - 0
Tests/RunCMake/target_link_options/LINK_OPTIONS-interface-check.cmake

@@ -0,0 +1,4 @@
+
+if (NOT actual_stdout MATCHES "BADFLAG_INTERFACE")
+  set (RunCMake_TEST_FAILED "Not found expected 'BADFLAG_INTERFACE'.")
+endif()

+ 1 - 0
Tests/RunCMake/target_link_options/LINK_OPTIONS-interface-result.txt

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

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

@@ -0,0 +1,7 @@
+
+if (NOT actual_stdout MATCHES "BADFLAG_RELEASE")
+  set (RunCMake_TEST_FAILED "Not found expected 'BADFLAG_RELEASE'.")
+endif()
+if (actual_stdout MATCHES "SHELL:")
+  string (APPEND RunCMake_TEST_FAILED "\nFound unexpected prefix 'SHELL:'.")
+endif()

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

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

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

@@ -0,0 +1,7 @@
+
+if (NOT actual_stdout MATCHES "BADFLAG_RELEASE")
+  set (RunCMake_TEST_FAILED "Not found expected 'BADFLAG_RELEASE'.")
+endif()
+if (actual_stdout MATCHES "SHELL:")
+  string (APPEND RunCMake_TEST_FAILED "\nFound unexpected prefix 'SHELL:'.")
+endif()

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

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

+ 39 - 0
Tests/RunCMake/target_link_options/LINK_OPTIONS.cmake

@@ -0,0 +1,39 @@
+
+enable_language(C)
+
+set(obj "${CMAKE_C_OUTPUT_EXTENSION}")
+if(BORLAND)
+  set(pre -)
+endif()
+
+# basic configuration
+add_library(LinkOptions SHARED LinkOptionsLib.c)
+target_link_options(LinkOptions
+  PRIVATE ${pre}BADFLAG_PRIVATE${obj}
+  INTERFACE ${pre}BADFLAG_INTERFACE${obj})
+
+
+# INTERFACE_LINK_OPTIONS
+add_library(LinkOptions_producer SHARED LinkOptionsLib.c)
+target_link_options(LinkOptions_producer
+  INTERFACE ${pre}BADFLAG_INTERFACE${obj})
+
+add_executable(LinkOptions_consumer LinkOptionsExe.c)
+target_link_libraries(LinkOptions_consumer PRIVATE LinkOptions_producer)
+
+
+# shared library with generator expression
+add_library(LinkOptions_shared SHARED LinkOptionsLib.c)
+target_link_options(LinkOptions_shared PRIVATE $<$<CONFIG:Release>:${pre}BADFLAG_RELEASE${obj}>
+  "SHELL:" # produces no options
+  )
+
+
+# module library with generator expression
+add_library(LinkOptions_mod MODULE LinkOptionsLib.c)
+target_link_options(LinkOptions_mod PRIVATE $<$<CONFIG:Release>:${pre}BADFLAG_RELEASE${obj}>)
+
+
+# executable with generator expression
+add_executable(LinkOptions_exe LinkOptionsExe.c)
+target_link_options(LinkOptions_exe PRIVATE $<$<CONFIG:Release>:${pre}BADFLAG_RELEASE${obj}>)

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

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

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

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

+ 62 - 0
Tests/RunCMake/target_link_options/RunCMakeTest.cmake

@@ -0,0 +1,62 @@
+
+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 basic LinkOptions)
+  run_cmake_target(LINK_OPTIONS interface LinkOptions_consumer)
+  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()
+
+
+# include(RunCMake)
+
+# macro(run_cmake_build test)
+#   run_cmake(${test})
+
+#   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
+#   set(RunCMake_TEST_NO_CLEAN 1)
+#   run_cmake_command(${test}-build ${CMAKE_COMMAND} --build . ${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)
+
+#   run_cmake_build(LINK_OPTIONS)
+#   run_cmake_build(INTERFACE_LINK_OPTIONS)
+
+#   if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+#     set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
+#   endif()
+#   run_cmake_build(LINK_OPTIONS_shared --config Release)
+#   run_cmake_build(LINK_OPTIONS_mod --config Release)
+#   run_cmake_build(LINK_OPTIONS_exe --config Release)
+#   unset(RunCMake_TEST_OPTIONS)
+
+#   unset(RunCMake_TEST_OUTPUT_MERGE)
+# endif()