diff options
author | Brad King <brad.king@kitware.com> | 2018-06-08 13:37:35 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2018-06-08 13:37:48 (GMT) |
commit | 812eaa465ca026ff0413f8c78b41edccd7eefdc7 (patch) | |
tree | 4804a2e64f9a24679ce1b7c1bee6bf65086671e2 | |
parent | e9f2a29fee7fb67d6a3eafa396f4f630795a99ec (diff) | |
parent | 66ea1a3795f76ce921bc48f82ff228bcceed4524 (diff) | |
download | CMake-812eaa465ca026ff0413f8c78b41edccd7eefdc7.zip CMake-812eaa465ca026ff0413f8c78b41edccd7eefdc7.tar.gz CMake-812eaa465ca026ff0413f8c78b41edccd7eefdc7.tar.bz2 |
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 <kwrobot@kitware.com>
Acked-by: Alex Turbov <i.zaufi@gmail.com>
Merge-request: !2033
130 files changed, 1321 insertions, 77 deletions
diff --git a/Help/command/LINK_OPTIONS_LINKER.txt b/Help/command/LINK_OPTIONS_LINKER.txt new file mode 100644 index 0000000..76927be --- /dev/null +++ b/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``. diff --git a/Help/command/COMPILE_OPTIONS_SHELL.txt b/Help/command/OPTIONS_SHELL.txt index a1316c8..530c012 100644 --- a/Help/command/COMPILE_OPTIONS_SHELL.txt +++ b/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 it dependencies. The set of options is de-duplicated to avoid repetition. While beneficial for individual options, the de-duplication step can break diff --git a/Help/command/add_compile_options.rst b/Help/command/add_compile_options.rst index c445608..350a1c0 100644 --- a/Help/command/add_compile_options.rst +++ b/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 more on defining buildsystem properties. -.. include:: COMPILE_OPTIONS_SHELL.txt +.. include:: OPTIONS_SHELL.txt diff --git a/Help/command/add_link_options.rst b/Help/command/add_link_options.rst new file mode 100644 index 0000000..821198d --- /dev/null +++ b/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 diff --git a/Help/command/target_compile_options.rst b/Help/command/target_compile_options.rst index 194d008..88b7f15 100644 --- a/Help/command/target_compile_options.rst +++ b/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 more on defining buildsystem properties. -.. include:: COMPILE_OPTIONS_SHELL.txt +.. include:: OPTIONS_SHELL.txt diff --git a/Help/command/target_link_libraries.rst b/Help/command/target_link_libraries.rst index 6379730..edf38cf 100644 --- a/Help/command/target_link_libraries.rst +++ b/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 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 flag position in the link command. diff --git a/Help/command/target_link_options.rst b/Help/command/target_link_options.rst new file mode 100644 index 0000000..8f47180 --- /dev/null +++ b/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 diff --git a/Help/manual/cmake-commands.7.rst b/Help/manual/cmake-commands.7.rst index 408a3a0..753647d 100644 --- a/Help/manual/cmake-commands.7.rst +++ b/Help/manual/cmake-commands.7.rst @@ -78,6 +78,7 @@ These commands are available only in CMake projects. /command/add_dependencies /command/add_executable /command/add_library + /command/add_link_options /command/add_subdirectory /command/add_test /command/aux_source_directory @@ -111,6 +112,7 @@ These commands are available only in CMake projects. /command/target_compile_options /command/target_include_directories /command/target_link_libraries + /command/target_link_options /command/target_sources /command/try_compile /command/try_run diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 9f9c53f..db900e8 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -77,6 +77,7 @@ Properties on Directories /prop_dir/INTERPROCEDURAL_OPTIMIZATION /prop_dir/LABELS /prop_dir/LINK_DIRECTORIES + /prop_dir/LINK_OPTIONS /prop_dir/LISTFILE_STACK /prop_dir/MACROS /prop_dir/PARENT_DIRECTORY @@ -225,6 +226,7 @@ Properties on Targets /prop_tgt/INTERFACE_COMPILE_OPTIONS /prop_tgt/INTERFACE_INCLUDE_DIRECTORIES /prop_tgt/INTERFACE_LINK_LIBRARIES + /prop_tgt/INTERFACE_LINK_OPTIONS /prop_tgt/INTERFACE_POSITION_INDEPENDENT_CODE /prop_tgt/INTERFACE_SOURCES /prop_tgt/INTERFACE_SYSTEM_INCLUDE_DIRECTORIES @@ -254,6 +256,7 @@ Properties on Targets /prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG /prop_tgt/LINK_INTERFACE_MULTIPLICITY /prop_tgt/LINK_LIBRARIES + /prop_tgt/LINK_OPTIONS /prop_tgt/LINK_SEARCH_END_STATIC /prop_tgt/LINK_SEARCH_START_STATIC /prop_tgt/LINK_WHAT_YOU_USE diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index edfff6c..fde1aab 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -460,6 +460,8 @@ Variables for Languages /variable/CMAKE_LANG_LIBRARY_ARCHITECTURE /variable/CMAKE_LANG_LINKER_PREFERENCE /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_OUTPUT_EXTENSION /variable/CMAKE_LANG_PLATFORM_ID diff --git a/Help/prop_dir/LINK_OPTIONS.rst b/Help/prop_dir/LINK_OPTIONS.rst new file mode 100644 index 0000000..04b9e08 --- /dev/null +++ b/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. diff --git a/Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst b/Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst new file mode 100644 index 0000000..c293b98 --- /dev/null +++ b/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 diff --git a/Help/prop_tgt/LINK_FLAGS.rst b/Help/prop_tgt/LINK_FLAGS.rst index b09e7c1..e0b72b5 100644 --- a/Help/prop_tgt/LINK_FLAGS.rst +++ b/Help/prop_tgt/LINK_FLAGS.rst @@ -3,7 +3,11 @@ LINK_FLAGS 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``, ``MINSIZEREL``, ``RELWITHDEBINFO``, ... + +.. note:: + + This property has been superseded by :prop_tgt:`LINK_OPTIONS` property. diff --git a/Help/prop_tgt/LINK_FLAGS_CONFIG.rst b/Help/prop_tgt/LINK_FLAGS_CONFIG.rst index ba7adc8..1f2910b 100644 --- a/Help/prop_tgt/LINK_FLAGS_CONFIG.rst +++ b/Help/prop_tgt/LINK_FLAGS_CONFIG.rst @@ -4,3 +4,7 @@ LINK_FLAGS_<CONFIG> Per-configuration linker flags for a target. This is the configuration-specific version of LINK_FLAGS. + +.. note:: + + This property has been superseded by :prop_tgt:`LINK_OPTIONS` property. diff --git a/Help/prop_tgt/LINK_OPTIONS.rst b/Help/prop_tgt/LINK_OPTIONS.rst new file mode 100644 index 0000000..c5263a2 --- /dev/null +++ b/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. diff --git a/Help/release/dev/LINK_OPTIONS.rst b/Help/release/dev/LINK_OPTIONS.rst new file mode 100644 index 0000000..e40dab2 --- /dev/null +++ b/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. diff --git a/Help/variable/CMAKE_LANG_LINKER_WRAPPER_FLAG.rst b/Help/variable/CMAKE_LANG_LINKER_WRAPPER_FLAG.rst new file mode 100644 index 0000000..0e52282 --- /dev/null +++ b/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``. diff --git a/Help/variable/CMAKE_LANG_LINKER_WRAPPER_FLAG_SEP.rst b/Help/variable/CMAKE_LANG_LINKER_WRAPPER_FLAG_SEP.rst new file mode 100644 index 0000000..faf1481 --- /dev/null +++ b/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. diff --git a/Modules/Compiler/ARMCC.cmake b/Modules/Compiler/ARMCC.cmake index 250a8f4..f949568 100644 --- a/Modules/Compiler/ARMCC.cmake +++ b/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_DEPFILE_FLAGS_${lang} "--depend=<DEPFILE> --depend_single_line --no_depend_system_headers") + + set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Xlinker" " ") endmacro() diff --git a/Modules/Compiler/Absoft-Fortran.cmake b/Modules/Compiler/Absoft-Fortran.cmake index da1fc80..76502dc 100644 --- a/Modules/Compiler/Absoft-Fortran.cmake +++ b/Modules/Compiler/Absoft-Fortran.cmake @@ -8,3 +8,4 @@ set(CMAKE_Fortran_MODPATH_FLAG "-p") set(CMAKE_Fortran_VERBOSE_FLAG "-v") set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed") set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree") +set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-X") diff --git a/Modules/Compiler/Bruce-C.cmake b/Modules/Compiler/Bruce-C.cmake index cfabe65..6b64e58 100644 --- a/Modules/Compiler/Bruce-C.cmake +++ b/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_RELEASE_INIT " -DNDEBUG") string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -g -DNDEBUG") + +set(CMAKE_C_LINKER_WRAPPER_FLAG "-X") diff --git a/Modules/Compiler/Clang.cmake b/Modules/Compiler/Clang.cmake index 7ce1adb..1653b55 100644 --- a/Modules/Compiler/Clang.cmake +++ b/Modules/Compiler/Clang.cmake @@ -30,6 +30,8 @@ else() set(CMAKE_${lang}_COMPILE_OPTIONS_TARGET "--target=") set(CMAKE_${lang}_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN "--gcc-toolchain=") 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_MAY_BE_SUPPORTED_BY_COMPILER YES) diff --git a/Modules/Compiler/G95-Fortran.cmake b/Modules/Compiler/G95-Fortran.cmake index 2c83fb8..03b7e08 100644 --- a/Modules/Compiler/G95-Fortran.cmake +++ b/Modules/Compiler/G95-Fortran.cmake @@ -7,3 +7,5 @@ set(CMAKE_Fortran_MODDIR_FLAG "-fmod=") set(CMAKE_Fortran_VERBOSE_FLAG "-v") set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form") set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form") +set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,") +set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",") diff --git a/Modules/Compiler/GNU.cmake b/Modules/Compiler/GNU.cmake index a3ef2bc..9f4c8d1 100644 --- a/Modules/Compiler/GNU.cmake +++ b/Modules/Compiler/GNU.cmake @@ -24,6 +24,9 @@ macro(__compiler_gnu lang) set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared") 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 # header file as a warning if depfiles are enabled, causing check_header_file # tests to always succeed. Work around this by disabling dependency tracking diff --git a/Modules/Compiler/HP-C.cmake b/Modules/Compiler/HP-C.cmake index b42ba2b..8fa4c08 100644 --- a/Modules/Compiler/HP-C.cmake +++ b/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_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 ",") diff --git a/Modules/Compiler/HP-CXX.cmake b/Modules/Compiler/HP-CXX.cmake index 7548754..5726b64 100644 --- a/Modules/Compiler/HP-CXX.cmake +++ b/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_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 # 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 diff --git a/Modules/Compiler/HP-Fortran.cmake b/Modules/Compiler/HP-Fortran.cmake index a6ca2c2..63a0331 100644 --- a/Modules/Compiler/HP-Fortran.cmake +++ b/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_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 ",") diff --git a/Modules/Compiler/PGI.cmake b/Modules/Compiler/PGI.cmake index d5a57ee..4f8b90b 100644 --- a/Modules/Compiler/PGI.cmake +++ b/Modules/Compiler/PGI.cmake @@ -25,6 +25,9 @@ macro(__compiler_pgi lang) string(APPEND CMAKE_${lang}_FLAGS_INIT " -Bdynamic") endif() + set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,") + set(CMAKE_${lang}_LINKER_WRAPPER_FLAG ",") + 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)) set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES) diff --git a/Modules/Compiler/QCC.cmake b/Modules/Compiler/QCC.cmake index 0da7050..5cdedeb 100644 --- a/Modules/Compiler/QCC.cmake +++ b/Modules/Compiler/QCC.cmake @@ -13,6 +13,9 @@ macro(__compiler_qcc lang) set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-Wp,-isystem,") 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_MAY_BE_SUPPORTED_BY_COMPILER NO) diff --git a/Modules/Compiler/SCO.cmake b/Modules/Compiler/SCO.cmake index c55a048..7f643d9 100644 --- a/Modules/Compiler/SCO.cmake +++ b/Modules/Compiler/SCO.cmake @@ -15,4 +15,7 @@ macro(__compiler_sco lang) set(CMAKE_${lang}_COMPILE_OPTIONS_DLL -belf) set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-Kpic -belf") 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() diff --git a/Modules/Compiler/SunPro-C.cmake b/Modules/Compiler/SunPro-C.cmake index 8d0e6d6..047de43 100644 --- a/Modules/Compiler/SunPro-C.cmake +++ b/Modules/Compiler/SunPro-C.cmake @@ -29,6 +29,9 @@ foreach(type SHARED_LIBRARY SHARED_MODULE EXE) set(CMAKE_${type}_LINK_DYNAMIC_C_FLAGS "-Bdynamic") 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) set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c89") set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=c89") diff --git a/Modules/Compiler/SunPro-CXX.cmake b/Modules/Compiler/SunPro-CXX.cmake index 14196b7..4c1ac5b 100644 --- a/Modules/Compiler/SunPro-CXX.cmake +++ b/Modules/Compiler/SunPro-CXX.cmake @@ -29,6 +29,9 @@ foreach(type SHARED_LIBRARY SHARED_MODULE EXE) set(CMAKE_${type}_LINK_DYNAMIC_CXX_FLAGS "-Bdynamic") 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_ASSEMBLY_SOURCE "<CMAKE_CXX_COMPILER> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>") diff --git a/Modules/Compiler/SunPro-Fortran.cmake b/Modules/Compiler/SunPro-Fortran.cmake index 9b25c0b..2247dd0 100644 --- a/Modules/Compiler/SunPro-Fortran.cmake +++ b/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_MODPATH_FLAG "-M") +set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Qoption" "ld" " ") +set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",") + set(CMAKE_Fortran_PREPROCESS_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -F -fpp <SOURCE> -o <PREPROCESSED_SOURCE>") diff --git a/Modules/Compiler/TinyCC-C.cmake b/Modules/Compiler/TinyCC-C.cmake index fbd2841..6367695 100644 --- a/Modules/Compiler/TinyCC-C.cmake +++ b/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_RELEASE_INIT " -DNDEBUG") string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO_INIT " -g -DNDEBUG") + +set(CMAKE_C_LINKER_WRAPPER_FLAG "-Wl,") +set(CMAKE_C_LINKER_WRAPPER_FLAG_SEP ",") diff --git a/Modules/Compiler/XL.cmake b/Modules/Compiler/XL.cmake index 3361f8f..a1d7ca1 100644 --- a/Modules/Compiler/XL.cmake +++ b/Modules/Compiler/XL.cmake @@ -23,6 +23,9 @@ macro(__compiler_xl lang) set(CMAKE_${lang}_RESPONSE_FILE_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_RELEASE_INIT " -O") string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -O") diff --git a/Modules/Platform/Apple-Intel.cmake b/Modules/Platform/Apple-Intel.cmake index 2d4f7e5..a854be9 100644 --- a/Modules/Platform/Apple-Intel.cmake +++ b/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_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) set(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY "-fvisibility=") endif() diff --git a/Modules/Platform/Generic-ADSP-C.cmake b/Modules/Platform/Generic-ADSP-C.cmake index de1cee2..c8597cd 100644 --- a/Modules/Platform/Generic-ADSP-C.cmake +++ b/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_RELWITHDEBINFO_INIT " ") +set(CMAKE_C_LINKER_WRAPPER_FLAG "-flags-link" " ") +set(CMAKE_C_LINKER_WRAPPER_FLAG_SEP ",") + 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>") @@ -17,4 +20,3 @@ set(CMAKE_C_LINK_EXECUTABLE set(CMAKE_C_CREATE_SHARED_LIBRARY) set(CMAKE_C_CREATE_MODULE_LIBRARY) - diff --git a/Modules/Platform/Generic-ADSP-CXX.cmake b/Modules/Platform/Generic-ADSP-CXX.cmake index 0cde8f2..d76bb66 100644 --- a/Modules/Platform/Generic-ADSP-CXX.cmake +++ b/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_RELWITHDEBINFO_INIT " ") +set(CMAKE_CXX_LINKER_WRAPPER_FLAG "-flags-link" " ") +set(CMAKE_CXX_LINKER_WRAPPER_FLAG_SEP ",") + 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>") @@ -15,4 +18,3 @@ set(CMAKE_CXX_LINK_EXECUTABLE set(CMAKE_CXX_CREATE_SHARED_LIBRARY) set(CMAKE_CXX_CREATE_MODULE_LIBRARY) - diff --git a/Modules/Platform/Generic-SDCC-C.cmake b/Modules/Platform/Generic-SDCC-C.cmake index 4b3912a..aef4abf 100644 --- a/Modules/Platform/Generic-SDCC-C.cmake +++ b/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) endif() +set(CMAKE_C_LINKER_WRAPPER_FLAG "-Wl" ",") + # compile a C file into an object file 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 set(CMAKE_C_CREATE_SHARED_LIBRARY "") set(CMAKE_C_CREATE_MODULE_LIBRARY "") - diff --git a/Modules/Platform/Linux-Intel.cmake b/Modules/Platform/Linux-Intel.cmake index ee9aac2..f712e2b 100644 --- a/Modules/Platform/Linux-Intel.cmake +++ b/Modules/Platform/Linux-Intel.cmake @@ -30,6 +30,9 @@ macro(__linux_compiler_intel lang) # executables that use dlopen but do not set ENABLE_EXPORTS. 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) if(XIAR) diff --git a/Modules/Platform/Windows-Embarcadero.cmake b/Modules/Platform/Windows-Embarcadero.cmake index f8e1c9e..48b936e 100644 --- a/Modules/Platform/Windows-Embarcadero.cmake +++ b/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_${lang}_USE_RESPONSE_FILE_FOR_INCLUDES 1) + set (CMAKE_${lang}_LINKER_WRAPPER_FLAG "-l") + # compile a source file into an object file # place <DEFINES> outside the response file because Borland refuses # to parse quotes from the response file. diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 30bef74..6623ba4 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -379,6 +379,8 @@ set(SRCS cmAddCompileDefinitionsCommand.h cmAddCompileOptionsCommand.cxx cmAddCompileOptionsCommand.h + cmAddLinkOptionsCommand.cxx + cmAddLinkOptionsCommand.h cmAddCustomCommandCommand.cxx cmAddCustomCommandCommand.h cmAddCustomTargetCommand.cxx @@ -574,6 +576,8 @@ set(SRCS cmTargetCompileOptionsCommand.h cmTargetIncludeDirectoriesCommand.cxx cmTargetIncludeDirectoriesCommand.h + cmTargetLinkOptionsCommand.cxx + cmTargetLinkOptionsCommand.h cmTargetLinkLibrariesCommand.cxx cmTargetLinkLibrariesCommand.h cmTargetPropCommandBase.cxx diff --git a/Source/cmAddLinkOptionsCommand.cxx b/Source/cmAddLinkOptionsCommand.cxx new file mode 100644 index 0000000..10ebd12 --- /dev/null +++ b/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; +} diff --git a/Source/cmAddLinkOptionsCommand.h b/Source/cmAddLinkOptionsCommand.h new file mode 100644 index 0000000..30fff00 --- /dev/null +++ b/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 diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx index dc9318e..15fbd40 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -82,6 +82,7 @@ #if defined(CMAKE_BUILD_WITH_CMAKE) # include "cmAddCompileOptionsCommand.h" +# include "cmAddLinkOptionsCommand.h" # include "cmAuxSourceDirectoryCommand.h" # include "cmBuildNameCommand.h" # include "cmCMakeHostSystemInformationCommand.h" @@ -100,6 +101,7 @@ # include "cmRemoveDefinitionsCommand.h" # include "cmSourceGroupCommand.h" # include "cmSubdirDependsCommand.h" +# include "cmTargetLinkOptionsCommand.h" # include "cmUseMangledMesaCommand.h" # include "cmUtilitySourceCommand.h" # include "cmVariableRequiresCommand.h" @@ -272,7 +274,10 @@ void GetProjectCommands(cmState* state) state->AddBuiltinCommand("include_external_msproject", new cmIncludeExternalMSProjectCommand); state->AddBuiltinCommand("install_programs", new cmInstallProgramsCommand); + state->AddBuiltinCommand("add_link_options", new cmAddLinkOptionsCommand); state->AddBuiltinCommand("link_libraries", new cmLinkLibrariesCommand); + state->AddBuiltinCommand("target_link_options", + new cmTargetLinkOptionsCommand); state->AddBuiltinCommand("load_cache", new cmLoadCacheCommand); state->AddBuiltinCommand("qt_wrap_cpp", new cmQTWrapCPPCommand); state->AddBuiltinCommand("qt_wrap_ui", new cmQTWrapUICommand); diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx index 0ceac85..bb370c4 100644 --- a/Source/cmExportBuildAndroidMKGenerator.cxx +++ b/Source/cmExportBuildAndroidMKGenerator.cxx @@ -7,6 +7,7 @@ #include <sstream> #include <utility> +#include "cmAlgorithms.h" #include "cmGeneratorExpression.h" #include "cmGeneratorExpressionDAGChecker.h" #include "cmGeneratorTarget.h" @@ -169,6 +170,11 @@ void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( end = "\\\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 { os << "# " << property.first << " " << (property.second) << "\n"; } diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 47636cd..9f2e01d 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -95,6 +95,9 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gte, cmGeneratorExpression::BuildInterface, properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gte, + cmGeneratorExpression::BuildInterface, + properties, missingTargets); this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte, properties); diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 02686f3..1db76ac 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -103,6 +103,9 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gt, cmGeneratorExpression::InstallInterface, properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gt, + cmGeneratorExpression::InstallInterface, + properties, missingTargets); std::string errorMessage; if (!this->PopulateExportProperties(gt, properties, errorMessage)) { diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index a3a8f69..cfe31f1 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -25,7 +25,8 @@ struct cmGeneratorExpressionContext; SELECT(F, EvaluatingCompileOptions, COMPILE_OPTIONS) \ SELECT(F, EvaluatingAutoUicOptions, AUTOUIC_OPTIONS) \ 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) \ CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_BOTH) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index b223c5e..41e55a5 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -102,6 +102,7 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) , DebugCompileOptionsDone(false) , DebugCompileFeaturesDone(false) , DebugCompileDefinitionsDone(false) + , DebugLinkOptionsDone(false) , DebugSourcesDone(false) , LinkImplementationLanguageIsContextDependent(true) , UtilityItemsDone(false) @@ -128,6 +129,10 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) t->GetCompileDefinitionsBacktraces(), this->CompileDefinitionsEntries); + CreatePropertyGeneratorExpressions(t->GetLinkOptionsEntries(), + t->GetLinkOptionsBacktraces(), + this->LinkOptionsEntries); + CreatePropertyGeneratorExpressions(t->GetSourceEntries(), t->GetSourceBacktraces(), this->SourceEntries, true); @@ -145,6 +150,7 @@ cmGeneratorTarget::~cmGeneratorTarget() cmDeleteAll(this->CompileOptionsEntries); cmDeleteAll(this->CompileFeaturesEntries); cmDeleteAll(this->CompileDefinitionsEntries); + cmDeleteAll(this->LinkOptionsEntries); cmDeleteAll(this->SourceEntries); cmDeleteAll(this->LinkInformation); } @@ -2633,7 +2639,7 @@ enum class OptionsParse Shell }; -static void processCompileOptionsInternal( +static void processOptionsInternal( cmGeneratorTarget const* tgt, const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, std::vector<std::string>& options, @@ -2665,7 +2671,7 @@ static void processCompileOptionsInternal( if (!usedOptions.empty()) { tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage( cmake::LOG, - std::string("Used compile ") + logName + std::string(" for target ") + + std::string("Used ") + logName + std::string(" for target ") + tgt->GetName() + ":\n" + usedOptions, entry->ge->GetBacktrace()); } @@ -2680,9 +2686,9 @@ static void processCompileOptions( cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, 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, @@ -2734,9 +2740,9 @@ static void processCompileFeatures( cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, 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, @@ -2784,9 +2790,9 @@ static void processCompileDefinitions( cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, 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( @@ -2855,6 +2861,153 @@ void cmGeneratorTarget::GetCompileDefinitions( 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 { if (this->IsImported()) { diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 2132b15..aa36823 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -418,6 +418,10 @@ public: const std::string& config, 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, const std::string& config, const std::string& language) const; @@ -803,6 +807,7 @@ private: std::vector<TargetPropertyEntry*> CompileOptionsEntries; std::vector<TargetPropertyEntry*> CompileFeaturesEntries; std::vector<TargetPropertyEntry*> CompileDefinitionsEntries; + std::vector<TargetPropertyEntry*> LinkOptionsEntries; std::vector<TargetPropertyEntry*> SourceEntries; mutable std::set<std::string> LinkImplicitNullProperties; @@ -851,6 +856,7 @@ private: mutable bool DebugCompileOptionsDone; mutable bool DebugCompileFeaturesDone; mutable bool DebugCompileDefinitionsDone; + mutable bool DebugLinkOptionsDone; mutable bool DebugSourcesDone; mutable bool LinkImplementationLanguageIsContextDependent; mutable bool UtilityItemsDone; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 47741f9..b461598 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1817,6 +1817,10 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, 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. diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index a3f4a8f..072b958 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1042,6 +1042,10 @@ void cmLocalGenerator::GetTargetFlags( linkFlags += " "; } } + std::vector<std::string> opts; + target->GetLinkOptions(opts, config, linkLanguage); + // LINK_OPTIONS are escaped. + this->AppendCompileOptions(linkFlags, opts); if (pcli) { this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, frameworkPath, linkPath); @@ -1113,6 +1117,10 @@ void cmLocalGenerator::GetTargetFlags( linkFlags += " "; } } + std::vector<std::string> opts; + target->GetLinkOptions(opts, config, linkLanguage); + // LINK_OPTIONS are escaped. + this->AppendCompileOptions(linkFlags, opts); } break; default: break; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 3460289..4b0b66d 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -977,6 +977,13 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( extraLinkOptions += " "; 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); if (this->FortranProject) { linkOptions.AddTable(cmLocalVisualStudio7GeneratorFortranLinkFlagTable); diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 3c7a4cf..a9b0b78 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -216,6 +216,16 @@ cmBacktraceRange cmMakefile::GetCompileDefinitionsBacktraces() const .GetCompileDefinitionsEntryBacktraces(); } +cmStringRange cmMakefile::GetLinkOptionsEntries() const +{ + return this->StateSnapshot.GetDirectory().GetLinkOptionsEntries(); +} + +cmBacktraceRange cmMakefile::GetLinkOptionsBacktraces() const +{ + return this->StateSnapshot.GetDirectory().GetLinkOptionsEntryBacktraces(); +} + cmListFileBacktrace cmMakefile::GetBacktrace() const { return this->Backtrace; @@ -1205,6 +1215,11 @@ void cmMakefile::AddCompileOption(std::string const& option) 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) { // Create a regular expression to match valid definitions. diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index a7c8df5..616a37f 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -171,6 +171,7 @@ public: void RemoveDefineFlag(std::string const& definition); void AddCompileDefinition(std::string const& definition); void AddCompileOption(std::string const& option); + void AddLinkOption(std::string const& option); /** Create a new imported target with the name and type given. */ cmTarget* AddImportedTarget(const std::string& name, @@ -788,6 +789,8 @@ public: cmBacktraceRange GetCompileOptionsBacktraces() const; cmStringRange GetCompileDefinitionsEntries() const; cmBacktraceRange GetCompileDefinitionsBacktraces() const; + cmStringRange GetLinkOptionsEntries() const; + cmBacktraceRange GetLinkOptionsBacktraces() const; std::set<std::string> const& GetSystemIncludeDirectories() const { diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 1e59f44..82f4683 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -154,12 +154,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( linkLanguage, this->ConfigName); // 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 // may need to be cleaned. @@ -437,12 +432,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) linkLanguage, this->ConfigName); // 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( diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index c538992..036acc7 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -137,10 +137,7 @@ void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules() this->GeneratorTarget->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS"); if (hasCUDA && resolveDeviceSymbols) { 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 = @@ -173,10 +170,7 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink) cuda_lang) != closure->Languages.end()); if (hasCUDA) { 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"; 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( extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->ConfigName); @@ -223,10 +211,7 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink) cuda_lang) != closure->Languages.end()); if (hasCUDA) { 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"; 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( extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->ConfigName); @@ -265,12 +245,7 @@ void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink) linkRuleVar += "_CREATE_MACOSX_FRAMEWORK"; 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( extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS", this->ConfigName); @@ -278,7 +253,7 @@ void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink) } void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( - const std::string& linkRuleVar, const std::string& extraFlags, bool relink) + const std::string& linkRuleVar, bool relink) { #ifdef CMAKE_BUILD_WITH_CMAKE // TODO: Merge the methods that call this method to avoid @@ -296,7 +271,7 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( // Create set of linking flags. std::string linkFlags; - this->LocalGenerator->AppendFlags(linkFlags, extraFlags); + this->GetTargetLinkFlags(linkFlags, linkLanguage); // Get the name of the device object to generate. std::string const targetOutputReal = @@ -458,7 +433,6 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( this->WriteTargetDriverRule(targetOutputReal, relink); #else static_cast<void>(linkRuleVar); - static_cast<void>(extraFlags); static_cast<void>(relink); #endif } diff --git a/Source/cmMakefileLibraryTargetGenerator.h b/Source/cmMakefileLibraryTargetGenerator.h index 02fa029..35e4327 100644 --- a/Source/cmMakefileLibraryTargetGenerator.h +++ b/Source/cmMakefileLibraryTargetGenerator.h @@ -27,8 +27,7 @@ protected: void WriteSharedLibraryRules(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, const std::string& extraFlags, bool relink); // MacOSX Framework support methods diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 1f65f08..08fcd8f 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -82,6 +82,23 @@ cmMakefileTargetGenerator* cmMakefileTargetGenerator::New( 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() { // Create a directory for this target. diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index 7af3cf3..4d1c9ec 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -52,6 +52,8 @@ public: cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; } protected: + void GetTargetLinkFlags(std::string& flags, const std::string& linkLanguage); + // create the file and directory etc void CreateRuleFile(); diff --git a/Source/cmState.cxx b/Source/cmState.cxx index a57be4d..dcf6ea0 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -280,6 +280,8 @@ cmStateSnapshot cmState::Reset() it->CompileDefinitionsBacktraces.clear(); it->CompileOptions.clear(); it->CompileOptionsBacktraces.clear(); + it->LinkOptions.clear(); + it->LinkOptionsBacktraces.clear(); it->DirectoryEnd = pos; it->NormalTargetNames.clear(); it->Properties.clear(); diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx index 85e6366..6eac8e2 100644 --- a/Source/cmStateDirectory.cxx +++ b/Source/cmStateDirectory.cxx @@ -360,6 +360,42 @@ void cmStateDirectory::ClearCompileOptions() 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, cmListFileBacktrace const& lfbt) { @@ -387,6 +423,14 @@ void cmStateDirectory::SetProperty(const std::string& prop, const char* value, this->SetCompileDefinitions(value, lfbt); return; } + if (prop == "LINK_OPTIONS") { + if (!value) { + this->ClearLinkOptions(); + return; + } + this->SetLinkOptions(value, lfbt); + return; + } this->DirectoryState->Properties.SetProperty(prop, value); } @@ -407,6 +451,10 @@ void cmStateDirectory::AppendProperty(const std::string& prop, this->AppendCompileDefinitionsEntry(value, lfbt); return; } + if (prop == "LINK_OPTIONS") { + this->AppendLinkOptionsEntry(value, lfbt); + return; + } this->DirectoryState->Properties.AppendProperty(prop, value, asString); } @@ -490,6 +538,10 @@ const char* cmStateDirectory::GetProperty(const std::string& prop, output = cmJoin(this->GetCompileDefinitionsEntries(), ";"); return output.c_str(); } + if (prop == "LINK_OPTIONS") { + output = cmJoin(this->GetLinkOptionsEntries(), ";"); + return output.c_str(); + } const char* retVal = this->DirectoryState->Properties.GetPropertyValue(prop); if (!retVal && chain) { diff --git a/Source/cmStateDirectory.h b/Source/cmStateDirectory.h index 79bb369..bc96cc9 100644 --- a/Source/cmStateDirectory.h +++ b/Source/cmStateDirectory.h @@ -58,6 +58,13 @@ public: cmListFileBacktrace const& lfbt); 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, cmListFileBacktrace const& lfbt); void AppendProperty(const std::string& prop, const char* value, diff --git a/Source/cmStatePrivate.h b/Source/cmStatePrivate.h index f36ee37..7177221 100644 --- a/Source/cmStatePrivate.h +++ b/Source/cmStatePrivate.h @@ -42,6 +42,7 @@ struct cmStateDetail::SnapshotDataType std::vector<std::string>::size_type IncludeDirectoryPosition; std::vector<std::string>::size_type CompileDefinitionsPosition; std::vector<std::string>::size_type CompileOptionsPosition; + std::vector<std::string>::size_type LinkOptionsPosition; }; struct cmStateDetail::PolicyStackEntry : public cmPolicies::PolicyMap @@ -84,6 +85,9 @@ struct cmStateDetail::BuildsystemDirectoryStateType std::vector<std::string> CompileOptions; std::vector<cmListFileBacktrace> CompileOptionsBacktraces; + std::vector<std::string> LinkOptions; + std::vector<cmListFileBacktrace> LinkOptionsBacktraces; + std::vector<std::string> NormalTargetNames; std::string ProjectName; diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx index 8f5f58c..ec428a6 100644 --- a/Source/cmStateSnapshot.cxx +++ b/Source/cmStateSnapshot.cxx @@ -390,6 +390,13 @@ void cmStateSnapshot::InitializeFromParent() this->Position->BuildSystemDirectory->CompileOptionsBacktraces, 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 = parent->BuildSystemDirectory->Properties.GetPropertyValue( "INCLUDE_REGULAR_EXPRESSION"); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 1868816..1a6e1d1 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -166,6 +166,8 @@ public: std::vector<cmListFileBacktrace> CompileDefinitionsBacktraces; std::vector<std::string> SourceEntries; std::vector<cmListFileBacktrace> SourceBacktraces; + std::vector<std::string> LinkOptionsEntries; + std::vector<cmListFileBacktrace> LinkOptionsBacktraces; std::vector<std::string> LinkImplementationPropertyEntries; std::vector<cmListFileBacktrace> LinkImplementationPropertyBacktraces; }; @@ -343,17 +345,29 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->SystemIncludeDirectories.insert(parentSystemIncludes.begin(), parentSystemIncludes.end()); - const cmStringRange parentOptions = + const cmStringRange parentCompileOptions = this->Makefile->GetCompileOptionsEntries(); - const cmBacktraceRange parentOptionsBts = + const cmBacktraceRange parentCompileOptionsBts = this->Makefile->GetCompileOptionsBacktraces(); 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.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 && @@ -822,6 +836,16 @@ cmBacktraceRange cmTarget::GetSourceBacktraces() const 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 { 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(IMPORTED_GLOBAL); MAKE_STATIC_PROP(INCLUDE_DIRECTORIES); + MAKE_STATIC_PROP(LINK_OPTIONS); MAKE_STATIC_PROP(LINK_LIBRARIES); MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES); MAKE_STATIC_PROP(NAME); @@ -925,6 +950,14 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); 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) { this->Internal->LinkImplementationPropertyEntries.clear(); this->Internal->LinkImplementationPropertyBacktraces.clear(); @@ -1030,6 +1063,12 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value, cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); 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") { if (value && *value) { cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); @@ -1111,6 +1150,21 @@ void cmTarget::InsertCompileDefinition(std::string const& entry, 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, const char* value, cmMakefile* context, @@ -1230,6 +1284,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const MAKE_STATIC_PROP(COMPILE_FEATURES); MAKE_STATIC_PROP(COMPILE_OPTIONS); MAKE_STATIC_PROP(COMPILE_DEFINITIONS); + MAKE_STATIC_PROP(LINK_OPTIONS); MAKE_STATIC_PROP(IMPORTED); MAKE_STATIC_PROP(IMPORTED_GLOBAL); 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_OPTIONS); specialProps.insert(propCOMPILE_DEFINITIONS); + specialProps.insert(propLINK_OPTIONS); specialProps.insert(propIMPORTED); specialProps.insert(propIMPORTED_GLOBAL); specialProps.insert(propMANUALLY_ADDED_DEPENDENCIES); @@ -1303,6 +1359,15 @@ const char* cmTarget::GetProperty(const std::string& prop) const output = cmJoin(this->Internal->CompileDefinitionsEntries, ";"); 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 (this->Utilities.empty()) { return nullptr; diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 3abb47e..5f0b33c 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -239,6 +239,8 @@ public: cmListFileBacktrace const& bt, bool before = false); void InsertCompileDefinition(std::string const& entry, cmListFileBacktrace const& bt); + void InsertLinkOption(std::string const& entry, + cmListFileBacktrace const& bt, bool before = false); void AppendBuildInterfaceIncludes(); @@ -265,6 +267,10 @@ public: cmStringRange GetSourceEntries() const; cmBacktraceRange GetSourceBacktraces() const; + + cmStringRange GetLinkOptionsEntries() const; + cmBacktraceRange GetLinkOptionsBacktraces() const; + cmStringRange GetLinkImplementationEntries() const; cmBacktraceRange GetLinkImplementationBacktraces() const; diff --git a/Source/cmTargetLinkOptionsCommand.cxx b/Source/cmTargetLinkOptionsCommand.cxx new file mode 100644 index 0000000..f0f13fd --- /dev/null +++ b/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. +} diff --git a/Source/cmTargetLinkOptionsCommand.h b/Source/cmTargetLinkOptionsCommand.h new file mode 100644 index 0000000..a1fc9fc --- /dev/null +++ b/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 diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 1768c57..549c8af 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -3234,6 +3234,11 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( flags += flagsConfig; } + std::vector<std::string> opts; + this->GeneratorTarget->GetLinkOptions(opts, config, linkLanguage); + // LINK_OPTIONS are escaped. + this->LocalGenerator->AppendCompileOptions(flags, opts); + cmComputeLinkInformation* pcli = this->GeneratorTarget->GetLinkInformation(config); if (!pcli) { diff --git a/Tests/CMakeCommands/add_link_options/CMakeLists.txt b/Tests/CMakeCommands/add_link_options/CMakeLists.txt new file mode 100644 index 0000000..bb7dcbb --- /dev/null +++ b/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() diff --git a/Tests/CMakeCommands/add_link_options/LinkOptionsExe.c b/Tests/CMakeCommands/add_link_options/LinkOptionsExe.c new file mode 100644 index 0000000..8488f4e --- /dev/null +++ b/Tests/CMakeCommands/add_link_options/LinkOptionsExe.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/Tests/CMakeCommands/target_link_options/CMakeLists.txt b/Tests/CMakeCommands/target_link_options/CMakeLists.txt new file mode 100644 index 0000000..c66cd37 --- /dev/null +++ b/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() diff --git a/Tests/CMakeCommands/target_link_options/LinkOptionsLib.c b/Tests/CMakeCommands/target_link_options/LinkOptionsLib.c new file mode 100644 index 0000000..9bbd24c --- /dev/null +++ b/Tests/CMakeCommands/target_link_options/LinkOptionsLib.c @@ -0,0 +1,7 @@ +#if defined(_WIN32) +__declspec(dllexport) +#endif + int flags_lib(void) +{ + return 0; +} diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 886e392..aa72d44 100644 --- a/Tests/CMakeLists.txt +++ b/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_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. find_package(PythonInterp QUIET) if(PYTHON_EXECUTABLE) diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt index 0f1a556..a1c4993 100644 --- a/Tests/ExportImport/Export/CMakeLists.txt +++ b/Tests/ExportImport/Export/CMakeLists.txt @@ -597,3 +597,13 @@ install( ) install(DIRECTORY $<1:include/abs>$<0:/wrong> DESTINATION $<1:include>$<0:/wrong>) 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) diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt index 39a89dc..f8eb721 100644 --- a/Tests/ExportImport/Import/A/CMakeLists.txt +++ b/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() + +#--------------------------------------------------------------------------------- +# 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") diff --git a/Tests/ExportImport/Import/A/imp_testLinkOptions.cpp b/Tests/ExportImport/Import/A/imp_testLinkOptions.cpp new file mode 100644 index 0000000..2b18b2e --- /dev/null +++ b/Tests/ExportImport/Import/A/imp_testLinkOptions.cpp @@ -0,0 +1,8 @@ + +#include "testSharedLibRequired.h" + +int foo() +{ + TestSharedLibRequired req; + return req.foo(); +} diff --git a/Tests/RunCMake/AndroidMK/AndroidMK.cmake b/Tests/RunCMake/AndroidMK/AndroidMK.cmake index 3fbb2cf..9137f2b 100644 --- a/Tests/RunCMake/AndroidMK/AndroidMK.cmake +++ b/Tests/RunCMake/AndroidMK/AndroidMK.cmake @@ -5,7 +5,9 @@ add_library(car foo.cxx) add_library(bar bar.c) add_library(dog foo.cxx) 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) -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) diff --git a/Tests/RunCMake/AndroidMK/expectedBuildAndroidMK.txt b/Tests/RunCMake/AndroidMK/expectedBuildAndroidMK.txt index bbf67a5..a0e5044 100644 --- a/Tests/RunCMake/AndroidMK/expectedBuildAndroidMK.txt +++ b/Tests/RunCMake/AndroidMK/expectedBuildAndroidMK.txt @@ -24,3 +24,11 @@ LOCAL_STATIC_LIBRARIES.*car bar dog LOCAL_EXPORT_LDLIBS := -lm LOCAL_HAS_CPP := true 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.* diff --git a/Tests/RunCMake/AndroidMK/expectedInstallAndroidMK.txt b/Tests/RunCMake/AndroidMK/expectedInstallAndroidMK.txt index 3515fb9..28b1c21 100644 --- a/Tests/RunCMake/AndroidMK/expectedInstallAndroidMK.txt +++ b/Tests/RunCMake/AndroidMK/expectedInstallAndroidMK.txt @@ -26,3 +26,11 @@ LOCAL_STATIC_LIBRARIES.*car bar dog LOCAL_EXPORT_LDLIBS := -lm LOCAL_HAS_CPP := true 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.* diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index bb46144..daf3940 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -332,6 +332,8 @@ endif() add_RunCMake_test(File_Generate) add_RunCMake_test(ExportWithoutLanguage) 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(CheckModules) diff --git a/Tests/RunCMake/add_link_options/CMakeLists.txt b/Tests/RunCMake/add_link_options/CMakeLists.txt new file mode 100644 index 0000000..14ef56e --- /dev/null +++ b/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) diff --git a/Tests/RunCMake/add_link_options/LINKER_SHELL_expansion-build-check.cmake b/Tests/RunCMake/add_link_options/LINKER_SHELL_expansion-build-check.cmake new file mode 100644 index 0000000..d0ef8de --- /dev/null +++ b/Tests/RunCMake/add_link_options/LINKER_SHELL_expansion-build-check.cmake @@ -0,0 +1,2 @@ + +include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake") diff --git a/Tests/RunCMake/add_link_options/LINKER_SHELL_expansion.cmake b/Tests/RunCMake/add_link_options/LINKER_SHELL_expansion.cmake new file mode 100644 index 0000000..7316ef5 --- /dev/null +++ b/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") diff --git a/Tests/RunCMake/add_link_options/LINKER_expansion-build-check.cmake b/Tests/RunCMake/add_link_options/LINKER_expansion-build-check.cmake new file mode 100644 index 0000000..d0ef8de --- /dev/null +++ b/Tests/RunCMake/add_link_options/LINKER_expansion-build-check.cmake @@ -0,0 +1,2 @@ + +include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake") diff --git a/Tests/RunCMake/add_link_options/LINKER_expansion-list.cmake b/Tests/RunCMake/add_link_options/LINKER_expansion-list.cmake new file mode 100644 index 0000000..34dcc67 --- /dev/null +++ b/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}") diff --git a/Tests/RunCMake/add_link_options/LINKER_expansion-validation.cmake b/Tests/RunCMake/add_link_options/LINKER_expansion-validation.cmake new file mode 100644 index 0000000..bebd6c7 --- /dev/null +++ b/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() diff --git a/Tests/RunCMake/add_link_options/LINKER_expansion.cmake b/Tests/RunCMake/add_link_options/LINKER_expansion.cmake new file mode 100644 index 0000000..42b286d --- /dev/null +++ b/Tests/RunCMake/add_link_options/LINKER_expansion.cmake @@ -0,0 +1,4 @@ + +set (LINKER_OPTION "LINKER:-foo,bar") + +include ("LINKER_expansion-list.cmake") diff --git a/Tests/RunCMake/add_link_options/LINK_OPTIONS-exe-check.cmake b/Tests/RunCMake/add_link_options/LINK_OPTIONS-exe-check.cmake new file mode 100644 index 0000000..4a22d7e --- /dev/null +++ b/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() diff --git a/Tests/RunCMake/add_link_options/LINK_OPTIONS-exe-result.txt b/Tests/RunCMake/add_link_options/LINK_OPTIONS-exe-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/add_link_options/LINK_OPTIONS-exe-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/add_link_options/LINK_OPTIONS-mod-check.cmake b/Tests/RunCMake/add_link_options/LINK_OPTIONS-mod-check.cmake new file mode 100644 index 0000000..d695761 --- /dev/null +++ b/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() diff --git a/Tests/RunCMake/add_link_options/LINK_OPTIONS-mod-result.txt b/Tests/RunCMake/add_link_options/LINK_OPTIONS-mod-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/add_link_options/LINK_OPTIONS-mod-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/add_link_options/LINK_OPTIONS-shared-check.cmake b/Tests/RunCMake/add_link_options/LINK_OPTIONS-shared-check.cmake new file mode 100644 index 0000000..eaac8e3 --- /dev/null +++ b/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() diff --git a/Tests/RunCMake/add_link_options/LINK_OPTIONS-shared-result.txt b/Tests/RunCMake/add_link_options/LINK_OPTIONS-shared-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/add_link_options/LINK_OPTIONS-shared-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/add_link_options/LINK_OPTIONS.cmake b/Tests/RunCMake/add_link_options/LINK_OPTIONS.cmake new file mode 100644 index 0000000..802ff4f --- /dev/null +++ b/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) diff --git a/Tests/RunCMake/add_link_options/LinkOptionsExe.c b/Tests/RunCMake/add_link_options/LinkOptionsExe.c new file mode 100644 index 0000000..8488f4e --- /dev/null +++ b/Tests/RunCMake/add_link_options/LinkOptionsExe.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/Tests/RunCMake/add_link_options/LinkOptionsLib.c b/Tests/RunCMake/add_link_options/LinkOptionsLib.c new file mode 100644 index 0000000..9bbd24c --- /dev/null +++ b/Tests/RunCMake/add_link_options/LinkOptionsLib.c @@ -0,0 +1,7 @@ +#if defined(_WIN32) +__declspec(dllexport) +#endif + int flags_lib(void) +{ + return 0; +} diff --git a/Tests/RunCMake/add_link_options/RunCMakeTest.cmake b/Tests/RunCMake/add_link_options/RunCMakeTest.cmake new file mode 100644 index 0000000..4f5df72 --- /dev/null +++ b/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() diff --git a/Tests/RunCMake/add_link_options/bad_SHELL_usage-result.txt b/Tests/RunCMake/add_link_options/bad_SHELL_usage-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/add_link_options/bad_SHELL_usage-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/add_link_options/bad_SHELL_usage-stderr.txt b/Tests/RunCMake/add_link_options/bad_SHELL_usage-stderr.txt new file mode 100644 index 0000000..02d09f3 --- /dev/null +++ b/Tests/RunCMake/add_link_options/bad_SHELL_usage-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at bad_SHELL_usage.cmake:6 \(add_library\): + 'SHELL:' prefix is not supported as part of 'LINKER:' arguments. +Call Stack \(most recent call first\): + CMakeLists.txt:5 \(include\) diff --git a/Tests/RunCMake/add_link_options/bad_SHELL_usage.cmake b/Tests/RunCMake/add_link_options/bad_SHELL_usage.cmake new file mode 100644 index 0000000..324893d --- /dev/null +++ b/Tests/RunCMake/add_link_options/bad_SHELL_usage.cmake @@ -0,0 +1,6 @@ + +enable_language(C) + +add_link_options("LINKER:-foo,SHELL:-bar") + +add_library(example SHARED LinkOptionsLib.c) diff --git a/Tests/RunCMake/add_link_options/dump.c b/Tests/RunCMake/add_link_options/dump.c new file mode 100644 index 0000000..8baa313 --- /dev/null +++ b/Tests/RunCMake/add_link_options/dump.c @@ -0,0 +1,13 @@ + +#include "stdio.h" + +int main(int argc, char* argv[]) +{ + int i; + + for (i = 1; i < argc; i++) + printf("%s ", argv[i]); + printf("\n"); + + return 0; +} diff --git a/Tests/RunCMake/set_property/LINK_OPTIONS-stdout.txt b/Tests/RunCMake/set_property/LINK_OPTIONS-stdout.txt new file mode 100644 index 0000000..033792a --- /dev/null +++ b/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' diff --git a/Tests/RunCMake/set_property/LINK_OPTIONS.cmake b/Tests/RunCMake/set_property/LINK_OPTIONS.cmake new file mode 100644 index 0000000..6daf41b --- /dev/null +++ b/Tests/RunCMake/set_property/LINK_OPTIONS.cmake @@ -0,0 +1,3 @@ +include(Common.cmake) +test_target_property(LINK_OPTIONS) +test_directory_property(LINK_OPTIONS) diff --git a/Tests/RunCMake/set_property/RunCMakeTest.cmake b/Tests/RunCMake/set_property/RunCMakeTest.cmake index b966e89..77da703 100644 --- a/Tests/RunCMake/set_property/RunCMakeTest.cmake +++ b/Tests/RunCMake/set_property/RunCMakeTest.cmake @@ -5,6 +5,7 @@ run_cmake(COMPILE_FEATURES) run_cmake(COMPILE_OPTIONS) run_cmake(IMPORTED_GLOBAL) run_cmake(INCLUDE_DIRECTORIES) +run_cmake(LINK_OPTIONS) run_cmake(LINK_LIBRARIES) run_cmake(SOURCES) run_cmake(TYPE) diff --git a/Tests/RunCMake/target_link_options/CMakeLists.txt b/Tests/RunCMake/target_link_options/CMakeLists.txt new file mode 100644 index 0000000..14ef56e --- /dev/null +++ b/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) diff --git a/Tests/RunCMake/target_link_options/LINKER_expansion-LINKER-check.cmake b/Tests/RunCMake/target_link_options/LINKER_expansion-LINKER-check.cmake new file mode 100644 index 0000000..d0ef8de --- /dev/null +++ b/Tests/RunCMake/target_link_options/LINKER_expansion-LINKER-check.cmake @@ -0,0 +1,2 @@ + +include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake") diff --git a/Tests/RunCMake/target_link_options/LINKER_expansion-LINKER_SHELL-check.cmake b/Tests/RunCMake/target_link_options/LINKER_expansion-LINKER_SHELL-check.cmake new file mode 100644 index 0000000..d0ef8de --- /dev/null +++ b/Tests/RunCMake/target_link_options/LINKER_expansion-LINKER_SHELL-check.cmake @@ -0,0 +1,2 @@ + +include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake") diff --git a/Tests/RunCMake/target_link_options/LINKER_expansion-validation.cmake b/Tests/RunCMake/target_link_options/LINKER_expansion-validation.cmake new file mode 100644 index 0000000..1af8f13 --- /dev/null +++ b/Tests/RunCMake/target_link_options/LINKER_expansion-validation.cmake @@ -0,0 +1,15 @@ + +if (actual_stdout MATCHES "LINKER:") + 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() diff --git a/Tests/RunCMake/target_link_options/LINKER_expansion.cmake b/Tests/RunCMake/target_link_options/LINKER_expansion.cmake new file mode 100644 index 0000000..b344867 --- /dev/null +++ b/Tests/RunCMake/target_link_options/LINKER_expansion.cmake @@ -0,0 +1,49 @@ + +enable_language(C) + +add_executable(dump dump.c) + +# 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}") + + +# Use LINKER alone +add_library(linker SHARED LinkOptionsLib.c) +target_link_options(linker PRIVATE "LINKER:-foo,bar") + +# use LAUNCH facility to dump linker command +set_property(TARGET linker PROPERTY RULE_LAUNCH_LINK "\"${CMAKE_CURRENT_BINARY_DIR}/dump${CMAKE_EXECUTABLE_SUFFIX}\"") + +add_dependencies (linker dump) + + +# Use LINKER with SHELL +add_library(linker_shell SHARED LinkOptionsLib.c) +target_link_options(linker_shell PRIVATE "LINKER:SHELL:-foo bar") + +# use LAUNCH facility to dump linker command +set_property(TARGET linker_shell PROPERTY RULE_LAUNCH_LINK "\"${CMAKE_CURRENT_BINARY_DIR}/dump${CMAKE_EXECUTABLE_SUFFIX}\"") + +add_dependencies (linker_shell 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}") diff --git a/Tests/RunCMake/target_link_options/LINK_OPTIONS-basic-check.cmake b/Tests/RunCMake/target_link_options/LINK_OPTIONS-basic-check.cmake new file mode 100644 index 0000000..7799506 --- /dev/null +++ b/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() diff --git a/Tests/RunCMake/target_link_options/LINK_OPTIONS-basic-result.txt b/Tests/RunCMake/target_link_options/LINK_OPTIONS-basic-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_options/LINK_OPTIONS-basic-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_options/LINK_OPTIONS-exe-check.cmake b/Tests/RunCMake/target_link_options/LINK_OPTIONS-exe-check.cmake new file mode 100644 index 0000000..a686de9 --- /dev/null +++ b/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() diff --git a/Tests/RunCMake/target_link_options/LINK_OPTIONS-exe-result.txt b/Tests/RunCMake/target_link_options/LINK_OPTIONS-exe-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_options/LINK_OPTIONS-exe-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_options/LINK_OPTIONS-interface-check.cmake b/Tests/RunCMake/target_link_options/LINK_OPTIONS-interface-check.cmake new file mode 100644 index 0000000..6c5ffdb --- /dev/null +++ b/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() diff --git a/Tests/RunCMake/target_link_options/LINK_OPTIONS-interface-result.txt b/Tests/RunCMake/target_link_options/LINK_OPTIONS-interface-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_options/LINK_OPTIONS-interface-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_options/LINK_OPTIONS-mod-check.cmake b/Tests/RunCMake/target_link_options/LINK_OPTIONS-mod-check.cmake new file mode 100644 index 0000000..a686de9 --- /dev/null +++ b/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() diff --git a/Tests/RunCMake/target_link_options/LINK_OPTIONS-mod-result.txt b/Tests/RunCMake/target_link_options/LINK_OPTIONS-mod-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_options/LINK_OPTIONS-mod-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_options/LINK_OPTIONS-shared-check.cmake b/Tests/RunCMake/target_link_options/LINK_OPTIONS-shared-check.cmake new file mode 100644 index 0000000..a686de9 --- /dev/null +++ b/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() diff --git a/Tests/RunCMake/target_link_options/LINK_OPTIONS-shared-result.txt b/Tests/RunCMake/target_link_options/LINK_OPTIONS-shared-result.txt new file mode 100644 index 0000000..8d98f9d --- /dev/null +++ b/Tests/RunCMake/target_link_options/LINK_OPTIONS-shared-result.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/target_link_options/LINK_OPTIONS.cmake b/Tests/RunCMake/target_link_options/LINK_OPTIONS.cmake new file mode 100644 index 0000000..f17195d --- /dev/null +++ b/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}>) diff --git a/Tests/RunCMake/target_link_options/LinkOptionsExe.c b/Tests/RunCMake/target_link_options/LinkOptionsExe.c new file mode 100644 index 0000000..8488f4e --- /dev/null +++ b/Tests/RunCMake/target_link_options/LinkOptionsExe.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/Tests/RunCMake/target_link_options/LinkOptionsLib.c b/Tests/RunCMake/target_link_options/LinkOptionsLib.c new file mode 100644 index 0000000..9bbd24c --- /dev/null +++ b/Tests/RunCMake/target_link_options/LinkOptionsLib.c @@ -0,0 +1,7 @@ +#if defined(_WIN32) +__declspec(dllexport) +#endif + int flags_lib(void) +{ + return 0; +} diff --git a/Tests/RunCMake/target_link_options/RunCMakeTest.cmake b/Tests/RunCMake/target_link_options/RunCMakeTest.cmake new file mode 100644 index 0000000..121a0ce --- /dev/null +++ b/Tests/RunCMake/target_link_options/RunCMakeTest.cmake @@ -0,0 +1,39 @@ + +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() + +run_cmake(bad_SHELL_usage) + +if(RunCMake_GENERATOR MATCHES "(Ninja|Makefile)") + run_cmake(LINKER_expansion) + + run_cmake_target(LINKER_expansion LINKER linker) + run_cmake_target(LINKER_expansion LINKER_SHELL linker_shell) +endif() diff --git a/Tests/RunCMake/target_link_options/bad_SHELL_usage-result.txt b/Tests/RunCMake/target_link_options/bad_SHELL_usage-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/target_link_options/bad_SHELL_usage-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/target_link_options/bad_SHELL_usage-stderr.txt b/Tests/RunCMake/target_link_options/bad_SHELL_usage-stderr.txt new file mode 100644 index 0000000..bffd80a --- /dev/null +++ b/Tests/RunCMake/target_link_options/bad_SHELL_usage-stderr.txt @@ -0,0 +1,4 @@ +CMake Error at bad_SHELL_usage.cmake:4 \(add_library\): + 'SHELL:' prefix is not supported as part of 'LINKER:' arguments. +Call Stack \(most recent call first\): + CMakeLists.txt:5 \(include\) diff --git a/Tests/RunCMake/target_link_options/bad_SHELL_usage.cmake b/Tests/RunCMake/target_link_options/bad_SHELL_usage.cmake new file mode 100644 index 0000000..b0adf19 --- /dev/null +++ b/Tests/RunCMake/target_link_options/bad_SHELL_usage.cmake @@ -0,0 +1,5 @@ + +enable_language(C) + +add_library(example SHARED LinkOptionsLib.c) +target_link_options(example PRIVATE "LINKER:-foo,SHELL:-bar") diff --git a/Tests/RunCMake/target_link_options/dump.c b/Tests/RunCMake/target_link_options/dump.c new file mode 100644 index 0000000..8baa313 --- /dev/null +++ b/Tests/RunCMake/target_link_options/dump.c @@ -0,0 +1,13 @@ + +#include "stdio.h" + +int main(int argc, char* argv[]) +{ + int i; + + for (i = 1; i < argc; i++) + printf("%s ", argv[i]); + printf("\n"); + + return 0; +} |