diff options
37 files changed, 1329 insertions, 973 deletions
diff --git a/Help/command/target_sources.rst b/Help/command/target_sources.rst index 4699a08..a079307 100644 --- a/Help/command/target_sources.rst +++ b/Help/command/target_sources.rst @@ -52,10 +52,10 @@ expressions to ensure the sources are correctly assigned to the target. .. code-block:: cmake # WRONG: starts with generator expression, but relative path used - target_sources(MyTarget "$<$<CONFIG:Debug>:dbgsrc.cpp>") + target_sources(MyTarget PRIVATE "$<$<CONFIG:Debug>:dbgsrc.cpp>") # CORRECT: absolute path used inside the generator expression - target_sources(MyTarget "$<$<CONFIG:Debug>:${CMAKE_CURRENT_SOURCE_DIR}/dbgsrc.cpp>") + target_sources(MyTarget PRIVATE "$<$<CONFIG:Debug>:${CMAKE_CURRENT_SOURCE_DIR}/dbgsrc.cpp>") See the :manual:`cmake-buildsystem(7)` manual for more on defining buildsystem properties. diff --git a/Help/guide/tutorial/A Basic Starting Point.rst b/Help/guide/tutorial/A Basic Starting Point.rst index cf1ec01..d57cc35 100644 --- a/Help/guide/tutorial/A Basic Starting Point.rst +++ b/Help/guide/tutorial/A Basic Starting Point.rst @@ -19,8 +19,19 @@ required. This will be the starting point for our tutorial. Create a add_executable(Tutorial tutorial.cxx) -Note that this example uses lower case commands in the ``CMakeLists.txt`` file. -Upper, lower, and mixed case commands are supported by CMake. The source +Any project's top most ``CMakeLists.txt`` must start by specifying +a minimum CMake version using :command:`cmake_minimum_required`. This ensures +that the later CMake functions are run with a compatible version of CMake. + +To start a project, we use :command:`project` to set the project name. This +call is required with every project and should be called soon after +:command:`cmake_minimum_required`. + +Lastly, we use :command:`add_executable` to specify we want an executable +named Tutorial generated using ``tutorial.cxx`` as the source. + +Note that this example uses lower case commands in the ``CMakeLists.txt`` +file. Upper, lower, and mixed case commands are supported by CMake. The source code for ``tutorial.cxx`` is provided in the ``Step1`` directory and can be used to compute the square root of a number. @@ -79,7 +90,7 @@ to set the project name and version number. :language: cmake :end-before: # specify the C++ standard -Then, configure a header file to pass the version number to the source +Then use :command:`configure_file` to pass the version number to the source code: .. literalinclude:: Step2/CMakeLists.txt @@ -91,7 +102,8 @@ code: Since the configured file will be written into the binary tree, we must add that directory to the list of paths to search for include -files. Add the following lines to the end of the ``CMakeLists.txt`` file: +files. Use :command:`target_include_directories` to add the following lines to +the end of the ``CMakeLists.txt`` file: .. literalinclude:: Step2/CMakeLists.txt :caption: CMakeLists.txt @@ -107,9 +119,9 @@ directory with the following contents: :name: TutorialConfig.h.in :language: c++ -When CMake configures this header file the values for +When CMake configures this header file, the values for ``@Tutorial_VERSION_MAJOR@`` and ``@Tutorial_VERSION_MINOR@`` will be -replaced. +replaced with the corresponding version numbers from the project. Next modify ``tutorial.cxx`` to include the configured header file, ``TutorialConfig.h``. @@ -141,7 +153,7 @@ Next let's add some C++11 features to our project by replacing ``atof`` with We will need to explicitly state in the CMake code that it should use the correct flags. The easiest way to enable support for a specific C++ standard in CMake is by using the :variable:`CMAKE_CXX_STANDARD` variable. For this -tutorial, set the :variable:`CMAKE_CXX_STANDARD` variable in the +tutorial, :command:`set` the :variable:`CMAKE_CXX_STANDARD` variable in the ``CMakeLists.txt`` file to ``11`` and :variable:`CMAKE_CXX_STANDARD_REQUIRED` to ``True``. Make sure to add the ``CMAKE_CXX_STANDARD`` declarations above the call to ``add_executable``. diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index 25e581a..9949772 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -11,40 +11,189 @@ Introduction ============ Generator expressions are evaluated during build system generation to produce -information specific to each build configuration. +information specific to each build configuration. They have the form +``$<...>``. For example: + +.. code-block:: cmake + + target_include_directories(tgt PRIVATE /opt/include/$<CXX_COMPILER_ID>) + +This would expand to ``/opt/include/GNU``, ``/opt/include/Clang``, etc. +depending on the C++ compiler used. Generator expressions are allowed in the context of many target properties, such as :prop_tgt:`LINK_LIBRARIES`, :prop_tgt:`INCLUDE_DIRECTORIES`, :prop_tgt:`COMPILE_DEFINITIONS` and others. They may also be used when using commands to populate those properties, such as :command:`target_link_libraries`, :command:`target_include_directories`, :command:`target_compile_definitions` -and others. +and others. They enable conditional linking, conditional definitions used when +compiling, conditional include directories, and more. The conditions may be +based on the build configuration, target properties, platform information, +or any other queryable information. -They enable conditional linking, conditional definitions used when compiling, -conditional include directories, and more. The conditions may be based on -the build configuration, target properties, platform information or any other -queryable information. +Generator expressions can be nested: -Generator expressions have the form ``$<...>``. To avoid confusion, this page -deviates from most of the CMake documentation in that it omits angular brackets -``<...>`` around placeholders like ``condition``, ``string``, ``target``, -among others. +.. code-block:: cmake -Generator expressions can be nested, as shown in most of the examples below. + target_compile_definitions(tgt PRIVATE + $<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,4.2.0>:OLD_COMPILER> + ) -.. _`Boolean Generator Expressions`: +The above would expand to ``OLD_COMPILER`` if the +:variable:`CMAKE_CXX_COMPILER_VERSION <CMAKE_<LANG>_COMPILER_VERSION>` is less +than 4.2.0. -Boolean Generator Expressions -============================= +Whitespace And Quoting +====================== -Boolean expressions evaluate to either ``0`` or ``1``. -They are typically used to construct the condition in a :ref:`conditional -generator expression<Conditional Generator Expressions>`. +Generator expressions are typically parsed after command arguments. +If a generator expression contains spaces, new lines, semicolons or +other characters that may be interpreted as command argument separators, +the whole expression should be surrounded by quotes when passed to a +command. Failure to do so may result in the expression being split and +it may no longer be recognized as a generator expression. -Available boolean expressions are: +When using :command:`add_custom_command` or :command:`add_custom_target`, +use the ``VERBATIM`` and ``COMMAND_EXPAND_LISTS`` options to obtain robust +argument splitting and quoting. -Logical Operators ------------------ +.. code-block:: cmake + + # WRONG: Embedded space will be treated as an argument separator. + # This ends up not being seen as a generator expression at all. + add_custom_target(run_some_tool + COMMAND some_tool -I$<JOIN:$<TARGET_PROPERTY:tgt,INCLUDE_DIRECTORIES>, -I> + VERBATIM + ) + +.. code-block:: cmake + + # Better, but still not robust. Quotes prevent the space from splitting the + # expression. However, the tool will receive the expanded value as a single + # argument. + add_custom_target(run_some_tool + COMMAND some_tool "-I$<JOIN:$<TARGET_PROPERTY:tgt,INCLUDE_DIRECTORIES>, -I>" + VERBATIM + ) + +.. code-block:: cmake + + # Nearly correct. Using a semicolon to separate arguments and adding the + # COMMAND_EXPAND_LISTS option means that paths with spaces will be handled + # correctly. Quoting the whole expression ensures it is seen as a generator + # expression. But if the target property is empty, we will get a bare -I + # with nothing after it. + add_custom_target(run_some_tool + COMMAND some_tool "-I$<JOIN:$<TARGET_PROPERTY:tgt,INCLUDE_DIRECTORIES>,;-I>" + COMMAND_EXPAND_LISTS + VERBATIM + ) + +Using variables to build up a more complex generator expression is also a +good way to reduce errors and improve readability. The above example can be +improved further like so: + +.. code-block:: cmake + + # The $<BOOL:...> check prevents adding anything if the property is empty, + # assuming the property value cannot be one of CMake's false constants. + set(prop "$<TARGET_PROPERTY:tgt,INCLUDE_DIRECTORIES>") + add_custom_target(run_some_tool + COMMAND some_tool "$<$<BOOL:${prop}>:-I$<JOIN:${prop},;-I>>" + COMMAND_EXPAND_LISTS + VERBATIM + ) + +A common mistake is to try to split a generator expression across multiple +lines with indenting: + +.. code-block:: cmake + + # WRONG: New lines and spaces all treated as argument separators, so the + # generator expression is split and not recognized correctly. + target_compile_definitions(tgt PRIVATE + $<$<AND: + $<CXX_COMPILER_ID:GNU>, + $<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,5> + >:HAVE_5_OR_LATER> + ) + +Again, use helper variables with well-chosen names to build up a readable +expression instead: + +.. code-block:: cmake + + set(is_gnu "$<CXX_COMPILER_ID:GNU>") + set(v5_or_later "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,5>") + set(meet_requirements "$<AND:${is_gnu},${v5_or_later}>") + target_compile_definitions(tgt PRIVATE + "$<${meet_requirements}:HAVE_5_OR_LATER>" + ) + +Debugging +========= + +Since generator expressions are evaluated during generation of the buildsystem, +and not during processing of ``CMakeLists.txt`` files, it is not possible to +inspect their result with the :command:`message()` command. One possible way +to generate debug messages is to add a custom target: + +.. code-block:: cmake + + add_custom_target(genexdebug COMMAND ${CMAKE_COMMAND} -E echo "$<...>") + +After running ``cmake``, you can then build the ``genexdebug`` target to print +the result of the ``$<...>`` expression (i.e. run the command +``cmake --build ... --target genexdebug``). + +Another way is to write debug messages to a file with :command:`file(GENERATE)`: + +.. code-block:: cmake + + file(GENERATE OUTPUT filename CONTENT "$<...>") + +Generator Expression Reference +============================== + +.. note:: + + This reference deviates from most of the CMake documentation in that it + omits angular brackets ``<...>`` around placeholders like ``condition``, + ``string``, ``target``, etc. This is to prevent an opportunity for those + placeholders to be misinterpreted as generator expressions. + +.. _`Conditional Generator Expressions`: + +Conditional Expressions +----------------------- + +A fundamental category of generator expressions relates to conditional logic. +Two forms of conditional generator expressions are supported: + +.. genex:: $<condition:true_string> + + Evaluates to ``true_string`` if ``condition`` is ``1``, or an empty string + if ``condition`` evaluates to ``0``. Any other value for ``condition`` + results in an error. + +.. genex:: $<IF:condition,true_string,false_string> + + .. versionadded:: 3.8 + + Evaluates to ``true_string`` if ``condition`` is ``1``, or ``false_string`` + if ``condition`` is ``0``. Any other value for ``condition`` results in an + error. + +Typically, the ``condition`` is itself a generator expression. For instance, +the following expression expands to ``DEBUG_MODE`` when the ``Debug`` +configuration is used, and the empty string for all other configurations: + +.. code-block:: cmake + + $<$<CONFIG:Debug>:DEBUG_MODE> + +Boolean-like ``condition`` values other than ``1`` or ``0`` can be handled +by wrapping them with the ``$<BOOL:...>`` generator expression: .. genex:: $<BOOL:string> @@ -58,49 +207,71 @@ Logical Operators Otherwise evaluates to ``1``. +The ``$<BOOL:...>`` generator expression is often used when a ``condition`` +is provided by a CMake variable: + +.. code-block:: cmake + + $<$<BOOL:${HAVE_SOME_FEATURE}>:-DENABLE_SOME_FEATURE> + + +.. _`Boolean Generator Expressions`: + +Logical Operators +----------------- + +The common boolean logic operators are supported: + .. genex:: $<AND:conditions> - where ``conditions`` is a comma-separated list of boolean expressions. - Evaluates to ``1`` if all conditions are ``1``. - Otherwise evaluates to ``0``. + where ``conditions`` is a comma-separated list of boolean expressions, + all of which must evaluate to either ``1`` or ``0``. The whole expression + evaluates to ``1`` if all conditions are ``1``. If any condition is ``0``, + the whole expression evaluates to ``0``. .. genex:: $<OR:conditions> where ``conditions`` is a comma-separated list of boolean expressions. - Evaluates to ``1`` if at least one of the conditions is ``1``. - Otherwise evaluates to ``0``. + all of which must evaluate to either ``1`` or ``0``. The whole expression + evaluates to ``1`` if at least one of the ``conditions`` is ``1``. If all + ``conditions`` evaluate to ``0``, the whole expression evaluates to ``0``. .. genex:: $<NOT:condition> + ``condition`` must be ``0`` or ``1``. The result of the expression is ``0`` if ``condition`` is ``1``, else ``1``. +.. _`Comparison Expressions`: + +Primary Comparison Expressions +------------------------------ + +CMake supports a variety of generator expressions that compare things. +This section covers the primary and most widely used comparison types. +Other more specific comparison types are documented in their own separate +sections further below. + String Comparisons ------------------- +^^^^^^^^^^^^^^^^^^ .. genex:: $<STREQUAL:string1,string2> ``1`` if ``string1`` and ``string2`` are equal, else ``0``. The comparison is case-sensitive. For a case-insensitive comparison, combine with a :ref:`string transforming generator expression - <String Transforming Generator Expressions>`, + <String Transforming Generator Expressions>`. For example, the following + evaluates to ``1`` if ``${foo}`` is any of ``BAR``, ``Bar``, ``bar``, etc. .. code-block:: cmake - $<STREQUAL:$<UPPER_CASE:${foo}>,"BAR"> # "1" if ${foo} is any of "BAR", "Bar", "bar", ... + $<STREQUAL:$<UPPER_CASE:${foo}>,BAR> .. genex:: $<EQUAL:value1,value2> ``1`` if ``value1`` and ``value2`` are numerically equal, else ``0``. -.. genex:: $<IN_LIST:string,list> - - .. versionadded:: 3.12 - - ``1`` if ``string`` is member of the semicolon-separated ``list``, else ``0``. - Uses case-sensitive comparisons. - Version Comparisons -------------------- +^^^^^^^^^^^^^^^^^^^ .. genex:: $<VERSION_LESS:v1,v2> @@ -126,9 +297,70 @@ Version Comparisons ``1`` if ``v1`` is a version greater than or equal to ``v2``, else ``0``. -Path Comparisons +.. _`String Transforming Generator Expressions`: + +String Transformations +---------------------- + +.. genex:: $<LOWER_CASE:string> + + Content of ``string`` converted to lower case. + +.. genex:: $<UPPER_CASE:string> + + Content of ``string`` converted to upper case. + +.. genex:: $<MAKE_C_IDENTIFIER:...> + + Content of ``...`` converted to a C identifier. The conversion follows the + same behavior as :command:`string(MAKE_C_IDENTIFIER)`. + +List Expressions ---------------- +.. genex:: $<IN_LIST:string,list> + + .. versionadded:: 3.12 + + ``1`` if ``string`` is an item in the semicolon-separated ``list``, else ``0``. + It uses case-sensitive comparisons. + +.. genex:: $<JOIN:list,string> + + Joins the list with the content of ``string`` inserted between each item. + +.. genex:: $<REMOVE_DUPLICATES:list> + + .. versionadded:: 3.15 + + Removes duplicated items in the given ``list``. The relative order of items + is preserved, but if duplicates are encountered, only the first instance is + preserved. + +.. genex:: $<FILTER:list,INCLUDE|EXCLUDE,regex> + + .. versionadded:: 3.15 + + Includes or removes items from ``list`` that match the regular expression + ``regex``. + +Path Expressions +---------------- + +Most of the expressions in this section are closely associated with the +:command:`cmake_path` command, providing the same capabilities, but in +the form of a generator expression. + +For all generator expressions in this section, paths are expected to be in +cmake-style format. The :ref:`$\<PATH:CMAKE_PATH\> <GenEx PATH-CMAKE_PATH>` +generator expression can be used to convert a native path to a cmake-style +one. + +.. _GenEx Path Comparisons: + +Path Comparisons +^^^^^^^^^^^^^^^^ + .. genex:: $<PATH_EQUAL:path1,path2> .. versionadded:: 3.24 @@ -142,18 +374,11 @@ Path Comparisons .. _GenEx Path Queries: Path Queries ------------- +^^^^^^^^^^^^ -The ``$<PATH>`` generator expression offers the same capabilities as the -:command:`cmake_path` command, for the :ref:`Query <Path Query>` options. - -For all ``$<PATH>`` generator expressions, paths are expected in cmake-style -format. The :ref:`$\<PATH:CMAKE_PATH\> <GenEx PATH-CMAKE_PATH>` generator -expression can be used to convert a native path to a cmake-style one. - -The ``$<PATH>`` generator expression can also be used for path -:ref:`Decomposition <GenEx Path Decomposition>` and -:ref:`Transformations <GenEx Path Transformations>`. +These expressions provide the generation-time capabilities equivalent to the +:ref:`Query <Path Query>` options of the :command:`cmake_path` command. +All paths are expected to be in cmake-style format. .. genex:: $<PATH:HAS_*,path> @@ -199,211 +424,421 @@ The ``$<PATH>`` generator expression can also be used for path .. versionadded:: 3.24 - Returns ``1`` if ``path`` is the prefix of ``input``,``0`` otherwise. + Returns ``1`` if ``path`` is the prefix of ``input``, ``0`` otherwise. When the ``NORMALIZE`` option is specified, ``path`` and ``input`` are :ref:`normalized <Normalization>` before the check. -Variable Queries ----------------- +.. _GenEx Path Decomposition: -.. genex:: $<TARGET_EXISTS:target> +Path Decomposition +^^^^^^^^^^^^^^^^^^ - .. versionadded:: 3.12 +These expressions provide the generation-time capabilities equivalent to the +:ref:`Decomposition <Path Decomposition>` options of the :command:`cmake_path` +command. All paths are expected to be in cmake-style format. - ``1`` if ``target`` exists, else ``0``. +.. genex:: $<PATH:GET_*,...> -.. genex:: $<CONFIG:cfgs> + .. versionadded:: 3.24 - ``1`` if config is any one of the entries in comma-separated list - ``cfgs``, else ``0``. This is a case-insensitive comparison. The mapping in - :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` is also considered by this - expression when it is evaluated on a property on an :prop_tgt:`IMPORTED` - target. + The following operations retrieve a different component or group of + components from a path. See :ref:`Path Structure And Terminology` for the + meaning of each path component. -.. genex:: $<PLATFORM_ID:platform_ids> + :: - where ``platform_ids`` is a comma-separated list. - ``1`` if the CMake's platform id matches any one of the entries in - ``platform_ids``, otherwise ``0``. - See also the :variable:`CMAKE_SYSTEM_NAME` variable. + $<PATH:GET_ROOT_NAME,path> + $<PATH:GET_ROOT_DIRECTORY,path> + $<PATH:GET_ROOT_PATH,path> + $<PATH:GET_FILENAME,path> + $<PATH:GET_EXTENSION[,LAST_ONLY],path> + $<PATH:GET_STEM[,LAST_ONLY],path> + $<PATH:GET_RELATIVE_PART,path> + $<PATH:GET_PARENT_PATH,path> -.. genex:: $<C_COMPILER_ID:compiler_ids> + If a requested component is not present in the path, an empty string is + returned. - where ``compiler_ids`` is a comma-separated list. - ``1`` if the CMake's compiler id of the C compiler matches any one - of the entries in ``compiler_ids``, otherwise ``0``. - See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. +.. _GenEx Path Transformations: -.. genex:: $<CXX_COMPILER_ID:compiler_ids> +Path Transformations +^^^^^^^^^^^^^^^^^^^^ - where ``compiler_ids`` is a comma-separated list. - ``1`` if the CMake's compiler id of the CXX compiler matches any one - of the entries in ``compiler_ids``, otherwise ``0``. - See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. +These expressions provide the generation-time capabilities equivalent to the +:ref:`Modification <Path Modification>` and :ref:`Generation <Path Generation>` +options of the :command:`cmake_path` command. All paths are expected to be +in cmake-style format. -.. genex:: $<CUDA_COMPILER_ID:compiler_ids> +.. _GenEx PATH-CMAKE_PATH: - .. versionadded:: 3.15 +.. genex:: $<PATH:CMAKE_PATH[,NORMALIZE],path> - where ``compiler_ids`` is a comma-separated list. - ``1`` if the CMake's compiler id of the CUDA compiler matches any one - of the entries in ``compiler_ids``, otherwise ``0``. - See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. + .. versionadded:: 3.24 -.. genex:: $<OBJC_COMPILER_ID:compiler_ids> + Returns ``path``. If ``path`` is a native path, it is converted into a + cmake-style path with forward-slashes (``/``). On Windows, the long filename + marker is taken into account. - .. versionadded:: 3.16 + When the ``NORMALIZE`` option is specified, the path is :ref:`normalized + <Normalization>` after the conversion. - where ``compiler_ids`` is a comma-separated list. - ``1`` if the CMake's compiler id of the Objective-C compiler matches any one - of the entries in ``compiler_ids``, otherwise ``0``. - See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. +.. genex:: $<PATH:APPEND,path,input,...> -.. genex:: $<OBJCXX_COMPILER_ID:compiler_ids> + .. versionadded:: 3.24 - .. versionadded:: 3.16 + Returns all the ``input`` arguments appended to ``path`` using ``/`` as the + ``directory-separator``. Depending on the ``input``, the value of ``path`` + may be discarded. - where ``compiler_ids`` is a comma-separated list. - ``1`` if the CMake's compiler id of the Objective-C++ compiler matches any one - of the entries in ``compiler_ids``, otherwise ``0``. - See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. + See :ref:`cmake_path(APPEND) <APPEND>` for more details. -.. genex:: $<Fortran_COMPILER_ID:compiler_ids> +.. genex:: $<PATH:REMOVE_FILENAME,path> - where ``compiler_ids`` is a comma-separated list. - ``1`` if the CMake's compiler id of the Fortran compiler matches any one - of the entries in ``compiler_ids``, otherwise ``0``. - See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. + .. versionadded:: 3.24 -.. genex:: $<HIP_COMPILER_ID:compiler_ids> + Returns ``path`` with filename component (as returned by + ``$<PATH:GET_FILENAME>``) removed. After removal, any trailing + ``directory-separator`` is left alone, if present. - .. versionadded:: 3.21 + See :ref:`cmake_path(REMOVE_FILENAME) <REMOVE_FILENAME>` for more details. - where ``compiler_ids`` is a comma-separated list. - ``1`` if the CMake's compiler id of the HIP compiler matches any one - of the entries in ``compiler_ids``, otherwise ``0``. - See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. +.. genex:: $<PATH:REPLACE_FILENAME,path,input> -.. genex:: $<ISPC_COMPILER_ID:compiler_ids> + .. versionadded:: 3.24 - .. versionadded:: 3.19 + Returns ``path`` with the filename component replaced by ``input``. If + ``path`` has no filename component (i.e. ``$<PATH:HAS_FILENAME>`` returns + ``0``), ``path`` is unchanged. - where ``compiler_ids`` is a comma-separated list. - ``1`` if the CMake's compiler id of the ISPC compiler matches any one - of the entries in ``compiler_ids``, otherwise ``0``. - See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. + See :ref:`cmake_path(REPLACE_FILENAME) <REPLACE_FILENAME>` for more details. + +.. genex:: $<PATH:REMOVE_EXTENSION[,LAST_ONLY],path> + + .. versionadded:: 3.24 + + Returns ``path`` with the :ref:`extension <EXTENSION_DEF>` removed, if any. + + See :ref:`cmake_path(REMOVE_EXTENSION) <REMOVE_EXTENSION>` for more details. + +.. genex:: $<PATH:REPLACE_EXTENSION[,LAST_ONLY],path> + + .. versionadded:: 3.24 + + Returns ``path`` with the :ref:`extension <EXTENSION_DEF>` replaced by + ``input``, if any. + + See :ref:`cmake_path(REPLACE_EXTENSION) <REPLACE_EXTENSION>` for more details. + +.. genex:: $<PATH:NORMAL_PATH,path> + + .. versionadded:: 3.24 + + Returns ``path`` normalized according to the steps described in + :ref:`Normalization`. + +.. genex:: $<PATH:RELATIVE_PATH,path,base_directory> + + .. versionadded:: 3.24 + + Returns ``path``, modified to make it relative to the ``base_directory`` + argument. + + See :ref:`cmake_path(RELATIVE_PATH) <cmake_path-RELATIVE_PATH>` for more + details. + +.. genex:: $<PATH:ABSOLUTE_PATH[,NORMALIZE],path,base_directory> + + .. versionadded:: 3.24 + + Returns ``path`` as absolute. If ``path`` is a relative path + (``$<PATH:IS_RELATIVE>`` returns ``1``), it is evaluated relative to the + given base directory specified by ``base_directory`` argument. + + When the ``NORMALIZE`` option is specified, the path is + :ref:`normalized <Normalization>` after the path computation. + + See :ref:`cmake_path(ABSOLUTE_PATH) <ABSOLUTE_PATH>` for more details. + +Shell Paths +^^^^^^^^^^^ + +.. genex:: $<SHELL_PATH:...> + + .. versionadded:: 3.4 + + Content of ``...`` converted to shell path style. For example, slashes are + converted to backslashes in Windows shells and drive letters are converted + to posix paths in MSYS shells. The ``...`` must be an absolute path. + + .. versionadded:: 3.14 + The ``...`` may be a :ref:`semicolon-separated list <CMake Language Lists>` + of paths, in which case each path is converted individually and a result + list is generated using the shell path separator (``:`` on POSIX and + ``;`` on Windows). Be sure to enclose the argument containing this genex + in double quotes in CMake source code so that ``;`` does not split arguments. + +Configuration Expressions +------------------------- + +.. genex:: $<CONFIG> + + Configuration name. Use this instead of the deprecated :genex:`CONFIGURATION` + generator expression. + +.. genex:: $<CONFIG:cfgs> + + ``1`` if config is any one of the entries in comma-separated list + ``cfgs``, else ``0``. This is a case-insensitive comparison. The mapping in + :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` is also considered by this + expression when it is evaluated on a property of an :prop_tgt:`IMPORTED` + target. + +.. genex:: $<OUTPUT_CONFIG:...> + + .. versionadded:: 3.20 + + Only valid in :command:`add_custom_command` and :command:`add_custom_target` + as the outer-most generator expression in an argument. + With the :generator:`Ninja Multi-Config` generator, generator expressions + in ``...`` are evaluated using the custom command's "output config". + With other generators, the content of ``...`` is evaluated normally. + +.. genex:: $<COMMAND_CONFIG:...> + + .. versionadded:: 3.20 + + Only valid in :command:`add_custom_command` and :command:`add_custom_target` + as the outer-most generator expression in an argument. + With the :generator:`Ninja Multi-Config` generator, generator expressions + in ``...`` are evaluated using the custom command's "command config". + With other generators, the content of ``...`` is evaluated normally. + +Toolchain And Language Expressions +---------------------------------- + +Platform +^^^^^^^^ + +.. genex:: $<PLATFORM_ID> + + The current system's CMake platform id. + See also the :variable:`CMAKE_SYSTEM_NAME` variable. + +.. genex:: $<PLATFORM_ID:platform_ids> + + where ``platform_ids`` is a comma-separated list. + ``1`` if CMake's platform id matches any one of the entries in + ``platform_ids``, otherwise ``0``. + See also the :variable:`CMAKE_SYSTEM_NAME` variable. + +Compiler Version +^^^^^^^^^^^^^^^^ + +See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable, which is +closely related to the expressions in this sub-section. + +.. genex:: $<C_COMPILER_VERSION> + + The version of the C compiler used. .. genex:: $<C_COMPILER_VERSION:version> ``1`` if the version of the C compiler matches ``version``, otherwise ``0``. - See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. + +.. genex:: $<CXX_COMPILER_VERSION> + + The version of the CXX compiler used. .. genex:: $<CXX_COMPILER_VERSION:version> ``1`` if the version of the CXX compiler matches ``version``, otherwise ``0``. - See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. + +.. genex:: $<CUDA_COMPILER_VERSION> + + .. versionadded:: 3.15 + + The version of the CUDA compiler used. .. genex:: $<CUDA_COMPILER_VERSION:version> .. versionadded:: 3.15 ``1`` if the version of the CXX compiler matches ``version``, otherwise ``0``. - See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. + +.. genex:: $<OBJC_COMPILER_VERSION> + + .. versionadded:: 3.16 + + The version of the OBJC compiler used. .. genex:: $<OBJC_COMPILER_VERSION:version> .. versionadded:: 3.16 ``1`` if the version of the OBJC compiler matches ``version``, otherwise ``0``. - See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. + +.. genex:: $<OBJCXX_COMPILER_VERSION> + + .. versionadded:: 3.16 + + The version of the OBJCXX compiler used. .. genex:: $<OBJCXX_COMPILER_VERSION:version> .. versionadded:: 3.16 ``1`` if the version of the OBJCXX compiler matches ``version``, otherwise ``0``. - See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. + +.. genex:: $<Fortran_COMPILER_VERSION> + + The version of the Fortran compiler used. .. genex:: $<Fortran_COMPILER_VERSION:version> ``1`` if the version of the Fortran compiler matches ``version``, otherwise ``0``. - See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. + +.. genex:: $<HIP_COMPILER_VERSION> + + .. versionadded:: 3.21 + + The version of the HIP compiler used. .. genex:: $<HIP_COMPILER_VERSION:version> .. versionadded:: 3.21 ``1`` if the version of the HIP compiler matches ``version``, otherwise ``0``. - See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. + +.. genex:: $<ISPC_COMPILER_VERSION> + + .. versionadded:: 3.19 + + The version of the ISPC compiler used. .. genex:: $<ISPC_COMPILER_VERSION:version> .. versionadded:: 3.19 ``1`` if the version of the ISPC compiler matches ``version``, otherwise ``0``. - See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. -.. genex:: $<TARGET_POLICY:policy> +Compiler Language And ID +^^^^^^^^^^^^^^^^^^^^^^^^ - ``1`` if the ``policy`` was NEW when the 'head' target was created, - else ``0``. If the ``policy`` was not set, the warning message for the policy - will be emitted. This generator expression only works for a subset of - policies. +See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable, which is closely +related to most of the expressions in this sub-section. -.. genex:: $<COMPILE_FEATURES:features> +.. genex:: $<C_COMPILER_ID> - .. versionadded:: 3.1 + CMake's compiler id of the C compiler used. - where ``features`` is a comma-spearated list. - Evaluates to ``1`` if all of the ``features`` are available for the 'head' - target, and ``0`` otherwise. If this expression is used while evaluating - the link implementation of a target and if any dependency transitively - increases the required :prop_tgt:`C_STANDARD` or :prop_tgt:`CXX_STANDARD` - for the 'head' target, an error is reported. See the - :manual:`cmake-compile-features(7)` manual for information on - compile features and a list of supported compilers. +.. genex:: $<C_COMPILER_ID:compiler_ids> -.. _`Boolean COMPILE_LANGUAGE Generator Expression`: + where ``compiler_ids`` is a comma-separated list. + ``1`` if CMake's compiler id of the C compiler matches any one + of the entries in ``compiler_ids``, otherwise ``0``. -.. genex:: $<COMPILE_LANG_AND_ID:language,compiler_ids> +.. genex:: $<CXX_COMPILER_ID> + + CMake's compiler id of the CXX compiler used. + +.. genex:: $<CXX_COMPILER_ID:compiler_ids> + + where ``compiler_ids`` is a comma-separated list. + ``1`` if CMake's compiler id of the CXX compiler matches any one + of the entries in ``compiler_ids``, otherwise ``0``. + +.. genex:: $<CUDA_COMPILER_ID> .. versionadded:: 3.15 - ``1`` when the language used for compilation unit matches ``language`` and - the CMake's compiler id of the language compiler matches any one of the - entries in ``compiler_ids``, otherwise ``0``. This expression is a short form - for the combination of ``$<COMPILE_LANGUAGE:language>`` and - ``$<LANG_COMPILER_ID:compiler_ids>``. This expression may be used to specify - compile options, compile definitions, and include directories for source files of a - particular language and compiler combination in a target. For example: + CMake's compiler id of the CUDA compiler used. - .. code-block:: cmake +.. genex:: $<CUDA_COMPILER_ID:compiler_ids> - add_executable(myapp main.cpp foo.c bar.cpp zot.cu) - target_compile_definitions(myapp - PRIVATE $<$<COMPILE_LANG_AND_ID:CXX,AppleClang,Clang>:COMPILING_CXX_WITH_CLANG> - $<$<COMPILE_LANG_AND_ID:CXX,Intel>:COMPILING_CXX_WITH_INTEL> - $<$<COMPILE_LANG_AND_ID:C,Clang>:COMPILING_C_WITH_CLANG> - ) + .. versionadded:: 3.15 - This specifies the use of different compile definitions based on both - the compiler id and compilation language. This example will have a - ``COMPILING_CXX_WITH_CLANG`` compile definition when Clang is the CXX - compiler, and ``COMPILING_CXX_WITH_INTEL`` when Intel is the CXX compiler. - Likewise when the C compiler is Clang it will only see the ``COMPILING_C_WITH_CLANG`` - definition. + where ``compiler_ids`` is a comma-separated list. + ``1`` if CMake's compiler id of the CUDA compiler matches any one + of the entries in ``compiler_ids``, otherwise ``0``. - Without the ``COMPILE_LANG_AND_ID`` generator expression the same logic - would be expressed as: +.. genex:: $<OBJC_COMPILER_ID> - .. code-block:: cmake + .. versionadded:: 3.16 - target_compile_definitions(myapp - PRIVATE $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:AppleClang,Clang>>:COMPILING_CXX_WITH_CLANG> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:Intel>>:COMPILING_CXX_WITH_INTEL> - $<$<AND:$<COMPILE_LANGUAGE:C>,$<C_COMPILER_ID:Clang>>:COMPILING_C_WITH_CLANG> - ) + CMake's compiler id of the OBJC compiler used. + +.. genex:: $<OBJC_COMPILER_ID:compiler_ids> + + .. versionadded:: 3.16 + + where ``compiler_ids`` is a comma-separated list. + ``1`` if CMake's compiler id of the Objective-C compiler matches any one + of the entries in ``compiler_ids``, otherwise ``0``. + +.. genex:: $<OBJCXX_COMPILER_ID> + + .. versionadded:: 3.16 + + CMake's compiler id of the OBJCXX compiler used. + +.. genex:: $<OBJCXX_COMPILER_ID:compiler_ids> + + .. versionadded:: 3.16 + + where ``compiler_ids`` is a comma-separated list. + ``1`` if CMake's compiler id of the Objective-C++ compiler matches any one + of the entries in ``compiler_ids``, otherwise ``0``. + +.. genex:: $<Fortran_COMPILER_ID> + + CMake's compiler id of the Fortran compiler used. + +.. genex:: $<Fortran_COMPILER_ID:compiler_ids> + + where ``compiler_ids`` is a comma-separated list. + ``1`` if CMake's compiler id of the Fortran compiler matches any one + of the entries in ``compiler_ids``, otherwise ``0``. + +.. genex:: $<HIP_COMPILER_ID> + + .. versionadded:: 3.21 + + CMake's compiler id of the HIP compiler used. + +.. genex:: $<HIP_COMPILER_ID:compiler_ids> + + .. versionadded:: 3.21 + + where ``compiler_ids`` is a comma-separated list. + ``1`` if CMake's compiler id of the HIP compiler matches any one + of the entries in ``compiler_ids``, otherwise ``0``. + +.. genex:: $<ISPC_COMPILER_ID> + + .. versionadded:: 3.19 + + CMake's compiler id of the ISPC compiler used. + +.. genex:: $<ISPC_COMPILER_ID:compiler_ids> + + .. versionadded:: 3.19 + + where ``compiler_ids`` is a comma-separated list. + ``1`` if CMake's compiler id of the ISPC compiler matches any one + of the entries in ``compiler_ids``, otherwise ``0``. + +.. genex:: $<COMPILE_LANGUAGE> + + .. versionadded:: 3.3 + + The compile language of source files when evaluating compile options. + See :ref:`the related boolean expression + <Boolean COMPILE_LANGUAGE Generator Expression>` + ``$<COMPILE_LANGUAGE:language>`` + for notes about the portability of this generator expression. + +.. _`Boolean COMPILE_LANGUAGE Generator Expression`: .. genex:: $<COMPILE_LANGUAGE:languages> @@ -411,8 +846,8 @@ Variable Queries ``1`` when the language used for compilation unit matches any of the entries in ``languages``, otherwise ``0``. This expression may be used to specify - compile options, compile definitions, and include directories for source files of a - particular language in a target. For example: + compile options, compile definitions, and include directories for source + files of a particular language in a target. For example: .. code-block:: cmake @@ -451,49 +886,82 @@ Variable Queries add_executable(myapp main.cpp) target_link_libraries(myapp myapp_c myapp_cxx) -.. _`Boolean LINK_LANGUAGE Generator Expression`: - -.. genex:: $<LINK_LANG_AND_ID:language,compiler_ids> +.. genex:: $<COMPILE_LANG_AND_ID:language,compiler_ids> - .. versionadded:: 3.18 + .. versionadded:: 3.15 - ``1`` when the language used for link step matches ``language`` and the - CMake's compiler id of the language linker matches any one of the entries - in ``compiler_ids``, otherwise ``0``. This expression is a short form for the - combination of ``$<LINK_LANGUAGE:language>`` and + ``1`` when the language used for compilation unit matches ``language`` and + CMake's compiler id of the ``language`` compiler matches any one of the + entries in ``compiler_ids``, otherwise ``0``. This expression is a short form + for the combination of ``$<COMPILE_LANGUAGE:language>`` and ``$<LANG_COMPILER_ID:compiler_ids>``. This expression may be used to specify - link libraries, link options, link directories and link dependencies of a - particular language and linker combination in a target. For example: + compile options, compile definitions, and include directories for source + files of a particular language and compiler combination in a target. + For example: .. code-block:: cmake - add_library(libC_Clang ...) - add_library(libCXX_Clang ...) - add_library(libC_Intel ...) - add_library(libCXX_Intel ...) + add_executable(myapp main.cpp foo.c bar.cpp zot.cu) + target_compile_definitions(myapp + PRIVATE $<$<COMPILE_LANG_AND_ID:CXX,AppleClang,Clang>:COMPILING_CXX_WITH_CLANG> + $<$<COMPILE_LANG_AND_ID:CXX,Intel>:COMPILING_CXX_WITH_INTEL> + $<$<COMPILE_LANG_AND_ID:C,Clang>:COMPILING_C_WITH_CLANG> + ) - add_executable(myapp main.c) - if (CXX_CONFIG) - target_sources(myapp PRIVATE file.cxx) - endif() - target_link_libraries(myapp - PRIVATE $<$<LINK_LANG_AND_ID:CXX,Clang,AppleClang>:libCXX_Clang> - $<$<LINK_LANG_AND_ID:C,Clang,AppleClang>:libC_Clang> - $<$<LINK_LANG_AND_ID:CXX,Intel>:libCXX_Intel> - $<$<LINK_LANG_AND_ID:C,Intel>:libC_Intel>) + This specifies the use of different compile definitions based on both + the compiler id and compilation language. This example will have a + ``COMPILING_CXX_WITH_CLANG`` compile definition when Clang is the CXX + compiler, and ``COMPILING_CXX_WITH_INTEL`` when Intel is the CXX compiler. + Likewise, when the C compiler is Clang, it will only see the + ``COMPILING_C_WITH_CLANG`` definition. - This specifies the use of different link libraries based on both the - compiler id and link language. This example will have target ``libCXX_Clang`` - as link dependency when ``Clang`` or ``AppleClang`` is the ``CXX`` - linker, and ``libCXX_Intel`` when ``Intel`` is the ``CXX`` linker. - Likewise when the ``C`` linker is ``Clang`` or ``AppleClang``, target - ``libC_Clang`` will be added as link dependency and ``libC_Intel`` when - ``Intel`` is the ``C`` linker. + Without the ``COMPILE_LANG_AND_ID`` generator expression, the same logic + would be expressed as: - See :ref:`the note related to - <Constraints LINK_LANGUAGE Generator Expression>` - ``$<LINK_LANGUAGE:language>`` for constraints about the usage of this - generator expression. + .. code-block:: cmake + + target_compile_definitions(myapp + PRIVATE $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:AppleClang,Clang>>:COMPILING_CXX_WITH_CLANG> + $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:Intel>>:COMPILING_CXX_WITH_INTEL> + $<$<AND:$<COMPILE_LANGUAGE:C>,$<C_COMPILER_ID:Clang>>:COMPILING_C_WITH_CLANG> + ) + +Compile Features +^^^^^^^^^^^^^^^^ + +.. genex:: $<COMPILE_FEATURES:features> + + .. versionadded:: 3.1 + + where ``features`` is a comma-separated list. + Evaluates to ``1`` if all of the ``features`` are available for the 'head' + target, and ``0`` otherwise. If this expression is used while evaluating + the link implementation of a target and if any dependency transitively + increases the required :prop_tgt:`C_STANDARD` or :prop_tgt:`CXX_STANDARD` + for the 'head' target, an error is reported. See the + :manual:`cmake-compile-features(7)` manual for information on + compile features and a list of supported compilers. + +Linker Language And ID +^^^^^^^^^^^^^^^^^^^^^^ + +.. genex:: $<LINK_LANGUAGE> + + .. versionadded:: 3.18 + + The link language of the target when evaluating link options. + See :ref:`the related boolean expression + <Boolean LINK_LANGUAGE Generator Expression>` ``$<LINK_LANGUAGE:languages>`` + for notes about the portability of this generator expression. + + .. note:: + + This generator expression is not supported by the link libraries + properties to avoid side-effects due to the double evaluation of + these properties. + + +.. _`Boolean LINK_LANGUAGE Generator Expression`: .. genex:: $<LINK_LANGUAGE:languages> @@ -509,7 +977,7 @@ Variable Queries add_library(api_C ...) add_library(api_CXX ...) add_library(api INTERFACE) - target_link_options(api INTERFACE $<$<LINK_LANGUAGE:C>:-opt_c> + target_link_options(api INTERFACE $<$<LINK_LANGUAGE:C>:-opt_c> $<$<LINK_LANGUAGE:CXX>:-opt_cxx>) target_link_libraries(api INTERFACE $<$<LINK_LANGUAGE:C>:api_C> $<$<LINK_LANGUAGE:CXX>:api_CXX>) @@ -560,485 +1028,391 @@ Variable Queries evaluation will give ``C`` as link language, so the second pass will correctly add target ``libother`` as link dependency. -String-Valued Generator Expressions -=================================== - -These expressions expand to some string. -For example, - -.. code-block:: cmake - - include_directories(/usr/include/$<CXX_COMPILER_ID>/) - -expands to ``/usr/include/GNU/`` or ``/usr/include/Clang/`` etc, depending on -the compiler identifier. - -String-valued expressions may also be combined with other expressions. -Here an example for a string-valued expression within a boolean expressions -within a conditional expression: - -.. code-block:: cmake - - $<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,4.2.0>:OLD_COMPILER> - -expands to ``OLD_COMPILER`` if the -:variable:`CMAKE_CXX_COMPILER_VERSION <CMAKE_<LANG>_COMPILER_VERSION>` is less -than 4.2.0. - -And here two nested string-valued expressions: - -.. code-block:: cmake - - -I$<JOIN:$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>, -I> - -generates a string of the entries in the :prop_tgt:`INCLUDE_DIRECTORIES` target -property with each entry preceded by ``-I``. - -Expanding on the previous example, if one first wants to check if the -``INCLUDE_DIRECTORIES`` property is non-empty, then it is advisable to -introduce a helper variable to keep the code readable: - -.. code-block:: cmake - - set(prop "$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>") # helper variable - $<$<BOOL:${prop}>:-I$<JOIN:${prop}, -I>> - -The following string-valued generator expressions are available: - -Escaped Characters ------------------- - -String literals to escape the special meaning a character would otherwise have: - -.. genex:: $<ANGLE-R> - - A literal ``>``. Used for example to compare strings that contain a ``>``. - -.. genex:: $<COMMA> - - A literal ``,``. Used for example to compare strings which contain a ``,``. - -.. genex:: $<SEMICOLON> - - A literal ``;``. Used to prevent list expansion on an argument with ``;``. - -.. _`Conditional Generator Expressions`: - -Conditional Expressions ------------------------ - -Conditional generator expressions depend on a boolean condition -that must be ``0`` or ``1``. - -.. genex:: $<condition:true_string> - - Evaluates to ``true_string`` if ``condition`` is ``1``. - Otherwise evaluates to the empty string. - -.. genex:: $<IF:condition,true_string,false_string> - - .. versionadded:: 3.8 - - Evaluates to ``true_string`` if ``condition`` is ``1``. - Otherwise evaluates to ``false_string``. - -Typically, the ``condition`` is a :ref:`boolean generator expression -<Boolean Generator Expressions>`. For instance, - -.. code-block:: cmake - - $<$<CONFIG:Debug>:DEBUG_MODE> - -expands to ``DEBUG_MODE`` when the ``Debug`` configuration is used, and -otherwise expands to the empty string. - -.. _`String Transforming Generator Expressions`: - -String Transformations ----------------------- - -.. genex:: $<JOIN:list,string> - - Joins the list with the content of ``string``. - -.. genex:: $<REMOVE_DUPLICATES:list> - - .. versionadded:: 3.15 - - Removes duplicated items in the given ``list``. The relative order of items - is preserved, but if duplicates are encountered, only the first instance is - preserved. - -.. genex:: $<FILTER:list,INCLUDE|EXCLUDE,regex> - - .. versionadded:: 3.15 - - Includes or removes items from ``list`` that match the regular expression ``regex``. - -.. genex:: $<LOWER_CASE:string> - - Content of ``string`` converted to lower case. - -.. genex:: $<UPPER_CASE:string> - - Content of ``string`` converted to upper case. - -.. genex:: $<GENEX_EVAL:expr> - - .. versionadded:: 3.12 - - Content of ``expr`` evaluated as a generator expression in the current - context. This enables consumption of generator expressions whose - evaluation results itself in generator expressions. - -.. genex:: $<TARGET_GENEX_EVAL:tgt,expr> - - .. versionadded:: 3.12 - - Content of ``expr`` evaluated as a generator expression in the context of - ``tgt`` target. This enables consumption of custom target properties that - themselves contain generator expressions. - - Having the capability to evaluate generator expressions is very useful when - you want to manage custom properties supporting generator expressions. - For example: - - .. code-block:: cmake - - add_library(foo ...) - - set_property(TARGET foo PROPERTY - CUSTOM_KEYS $<$<CONFIG:DEBUG>:FOO_EXTRA_THINGS> - ) - - add_custom_target(printFooKeys - COMMAND ${CMAKE_COMMAND} -E echo $<TARGET_PROPERTY:foo,CUSTOM_KEYS> - ) +.. genex:: $<LINK_LANG_AND_ID:language,compiler_ids> - This naive implementation of the ``printFooKeys`` custom command is wrong - because ``CUSTOM_KEYS`` target property is not evaluated and the content - is passed as is (i.e. ``$<$<CONFIG:DEBUG>:FOO_EXTRA_THINGS>``). + .. versionadded:: 3.18 - To have the expected result (i.e. ``FOO_EXTRA_THINGS`` if config is - ``Debug``), it is required to evaluate the output of - ``$<TARGET_PROPERTY:foo,CUSTOM_KEYS>``: + ``1`` when the language used for link step matches ``language`` and the + CMake's compiler id of the language linker matches any one of the entries + in ``compiler_ids``, otherwise ``0``. This expression is a short form for the + combination of ``$<LINK_LANGUAGE:language>`` and + ``$<LANG_COMPILER_ID:compiler_ids>``. This expression may be used to specify + link libraries, link options, link directories and link dependencies of a + particular language and linker combination in a target. For example: .. code-block:: cmake - add_custom_target(printFooKeys - COMMAND ${CMAKE_COMMAND} -E - echo $<TARGET_GENEX_EVAL:foo,$<TARGET_PROPERTY:foo,CUSTOM_KEYS>> - ) - -.. _GenEx Path Decomposition: - -Path Decomposition ------------------- - -The ``$<PATH>`` generator expression offers the same capabilities as the -:command:`cmake_path` command, for the -:ref:`Decomposition <Path Decomposition>` options. - -For all ``$<PATH>`` generator expressions, paths are expected in cmake-style -format. The :ref:`$\<PATH:CMAKE_PATH\> <GenEx PATH-CMAKE_PATH>` generator -expression can be used to convert a native path to a cmake-style one. - -The ``$<PATH>`` generator expression can also be used for path -:ref:`Queries <GenEx Path Queries>` and -:ref:`Transformations <GenEx Path Transformations>`. - -.. genex:: $<PATH:GET_*,...> - - .. versionadded:: 3.24 - - The following operations retrieve a different component or group of - components from a path. See :ref:`Path Structure And Terminology` for the - meaning of each path component. - - :: - - $<PATH:GET_ROOT_NAME,path> - $<PATH:GET_ROOT_DIRECTORY,path> - $<PATH:GET_ROOT_PATH,path> - $<PATH:GET_FILENAME,path> - $<PATH:GET_EXTENSION[,LAST_ONLY],path> - $<PATH:GET_STEM[,LAST_ONLY],path> - $<PATH:GET_RELATIVE_PART,path> - $<PATH:GET_PARENT_PATH,path> - - If a requested component is not present in the path, an empty string is - returned. - -.. _GenEx Path Transformations: - -Path Transformations --------------------- + add_library(libC_Clang ...) + add_library(libCXX_Clang ...) + add_library(libC_Intel ...) + add_library(libCXX_Intel ...) -The ``$<PATH>`` generator expression offers the same capabilities as the -:command:`cmake_path` command, for the -:ref:`Modification <Path Modification>` and -:ref:`Generation <Path Generation>` options. + add_executable(myapp main.c) + if (CXX_CONFIG) + target_sources(myapp PRIVATE file.cxx) + endif() + target_link_libraries(myapp + PRIVATE $<$<LINK_LANG_AND_ID:CXX,Clang,AppleClang>:libCXX_Clang> + $<$<LINK_LANG_AND_ID:C,Clang,AppleClang>:libC_Clang> + $<$<LINK_LANG_AND_ID:CXX,Intel>:libCXX_Intel> + $<$<LINK_LANG_AND_ID:C,Intel>:libC_Intel>) -For all ``$<PATH>`` generator expressions, paths are expected in cmake-style -format. The :ref:`$\<PATH:CMAKE_PATH\> <GenEx PATH-CMAKE_PATH>` generator -expression can be used to convert a native path to a cmake-style one. + This specifies the use of different link libraries based on both the + compiler id and link language. This example will have target ``libCXX_Clang`` + as link dependency when ``Clang`` or ``AppleClang`` is the ``CXX`` + linker, and ``libCXX_Intel`` when ``Intel`` is the ``CXX`` linker. + Likewise when the ``C`` linker is ``Clang`` or ``AppleClang``, target + ``libC_Clang`` will be added as link dependency and ``libC_Intel`` when + ``Intel`` is the ``C`` linker. -The ``$<PATH>`` generator expression can also be used for path -:ref:`Queries <GenEx Path Queries>` and -:ref:`Decomposition <GenEx Path Decomposition>`. + See :ref:`the note related to + <Constraints LINK_LANGUAGE Generator Expression>` + ``$<LINK_LANGUAGE:language>`` for constraints about the usage of this + generator expression. -.. _GenEx PATH-CMAKE_PATH: +Link Features +^^^^^^^^^^^^^ -.. genex:: $<PATH:CMAKE_PATH[,NORMALIZE],path> +.. genex:: $<LINK_LIBRARY:feature,library-list> .. versionadded:: 3.24 - Returns ``path``. If ``path`` is a native path, it is converted into a - cmake-style path with forward-slashes (``/``). On Windows, the long filename - marker is taken into account. - - When the ``NORMALIZE`` option is specified, the path is :ref:`normalized - <Normalization>` after the conversion. + Specify a set of libraries to link to a target, along with a ``feature`` + which provides details about *how* they should be linked. For example: -.. genex:: $<PATH:APPEND,path,input,...> + .. code-block:: cmake - .. versionadded:: 3.24 + add_library(lib1 STATIC ...) + add_library(lib2 ...) + target_link_libraries(lib2 PRIVATE "$<LINK_LIBRARY:WHOLE_ARCHIVE,lib1>") - Returns all the ``input`` arguments appended to ``path`` using ``/`` as the - ``directory-separator``. Depending on the ``input``, the value of ``path`` - may be discarded. + This specifies that ``lib2`` should link to ``lib1`` and use the + ``WHOLE_ARCHIVE`` feature when doing so. - See :ref:`cmake_path(APPEND) <APPEND>` for more details. + Feature names are case-sensitive and may only contain letters, numbers and + underscores. Feature names defined in all uppercase are reserved for CMake's + own built-in features. The pre-defined built-in library features are: -.. genex:: $<PATH:REMOVE_FILENAME,path> + .. include:: ../variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt - .. versionadded:: 3.24 + Built-in and custom library features are defined in terms of the following + variables: - Returns ``path`` with filename component (as returned by - ``$<PATH:GET_FILENAME>``) removed. After removal, any trailing - ``directory-separator`` is left alone, if present. + * :variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED` + * :variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>` + * :variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED` + * :variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>` - See :ref:`cmake_path(REMOVE_FILENAME) <REMOVE_FILENAME>` for more details. + The value used for each of these variables is the value as set at the end of + the directory scope in which the target was created. The usage is as follows: -.. genex:: $<PATH:REPLACE_FILENAME,path,input> + 1. If the language-specific + :variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED` variable + is true, the ``feature`` must be defined by the corresponding + :variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>` variable. + 2. If no language-specific ``feature`` is supported, then the + :variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED` variable must be + true and the ``feature`` must be defined by the corresponding + :variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>` variable. - .. versionadded:: 3.24 + The following limitations should be noted: - Returns ``path`` with the filename component replaced by ``input``. If - ``path`` has no filename component (i.e. ``$<PATH:HAS_FILENAME>`` returns - ``0``), ``path`` is unchanged. + * The ``library-list`` can specify CMake targets or libraries. + Any CMake target of type :ref:`OBJECT <Object Libraries>` + or :ref:`INTERFACE <Interface Libraries>` will ignore the feature aspect + of the expression and instead be linked in the standard way. - See :ref:`cmake_path(REPLACE_FILENAME) <REPLACE_FILENAME>` for more details. + * The ``$<LINK_LIBRARY:...>`` generator expression can only be used to + specify link libraries. In practice, this means it can appear in the + :prop_tgt:`LINK_LIBRARIES`, :prop_tgt:`INTERFACE_LINK_LIBRARIES`, and + :prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT` target properties, and be + specified in :command:`target_link_libraries` and :command:`link_libraries` + commands. -.. genex:: $<PATH:REMOVE_EXTENSION[,LAST_ONLY],path> + * If a ``$<LINK_LIBRARY:...>`` generator expression appears in the + :prop_tgt:`INTERFACE_LINK_LIBRARIES` property of a target, it will be + included in the imported target generated by a :command:`install(EXPORT)` + command. It is the responsibility of the environment consuming this + import to define the link feature used by this expression. - .. versionadded:: 3.24 + * Each target or library involved in the link step must have at most only + one kind of library feature. The absence of a feature is also incompatible + with all other features. For example: - Returns ``path`` with the :ref:`extension <EXTENSION_DEF>` removed, if any. + .. code-block:: cmake - See :ref:`cmake_path(REMOVE_EXTENSION) <REMOVE_EXTENSION>` for more details. + add_library(lib1 ...) + add_library(lib2 ...) + add_library(lib3 ...) -.. genex:: $<PATH:REPLACE_EXTENSION[,LAST_ONLY],path> + # lib1 will be associated with feature1 + target_link_libraries(lib2 PUBLIC "$<LINK_LIBRARY:feature1,lib1>") - .. versionadded:: 3.24 + # lib1 is being linked with no feature here. This conflicts with the + # use of feature1 in the line above and would result in an error. + target_link_libraries(lib3 PRIVATE lib1 lib2) - Returns ``path`` with the :ref:`extension <EXTENSION_DEF>` replaced by - ``input``, if any. + Where it isn't possible to use the same feature throughout a build for a + given target or library, the :prop_tgt:`LINK_LIBRARY_OVERRIDE` and + :prop_tgt:`LINK_LIBRARY_OVERRIDE_<LIBRARY>` target properties can be + used to resolve such incompatibilities. - See :ref:`cmake_path(REPLACE_EXTENSION) <REPLACE_EXTENSION>` for more details. + * The ``$<LINK_LIBRARY:...>`` generator expression does not guarantee + that the list of specified targets and libraries will be kept grouped + together. To manage constructs like ``--start-group`` and ``--end-group``, + as supported by the GNU ``ld`` linker, use the :genex:`LINK_GROUP` + generator expression instead. -.. genex:: $<PATH:NORMAL_PATH,path> +.. genex:: $<LINK_GROUP:feature,library-list> .. versionadded:: 3.24 - Returns ``path`` normalized according to the steps described in - :ref:`Normalization`. - -.. genex:: $<PATH:RELATIVE_PATH,path,base_directory> + Specify a group of libraries to link to a target, along with a ``feature`` + which defines how that group should be linked. For example: - .. versionadded:: 3.24 + .. code-block:: cmake - Returns ``path``, modified to make it relative to the ``base_directory`` - argument. + add_library(lib1 STATIC ...) + add_library(lib2 ...) + target_link_libraries(lib2 PRIVATE "$<LINK_GROUP:RESCAN,lib1,external>") - See :ref:`cmake_path(RELATIVE_PATH) <cmake_path-RELATIVE_PATH>` for more - details. + This specifies that ``lib2`` should link to ``lib1`` and ``external``, and + that both of those two libraries should be included on the linker command + line according to the definition of the ``RESCAN`` feature. -.. genex:: $<PATH:ABSOLUTE_PATH[,NORMALIZE],path,base_directory> + Feature names are case-sensitive and may only contain letters, numbers and + underscores. Feature names defined in all uppercase are reserved for CMake's + own built-in features. Currently, there is only one pre-defined built-in + group feature: - .. versionadded:: 3.24 + .. include:: ../variable/LINK_GROUP_PREDEFINED_FEATURES.txt - Returns ``path`` as absolute. If ``path`` is a relative path - (``$<PATH:IS_RELATIVE>`` returns ``1``), it is evaluated relative to the - given base directory specified by ``base_directory`` argument. + Built-in and custom group features are defined in terms of the following + variables: - When the ``NORMALIZE`` option is specified, the path is - :ref:`normalized <Normalization>` after the path computation. + * :variable:`CMAKE_<LANG>_LINK_GROUP_USING_<FEATURE>_SUPPORTED` + * :variable:`CMAKE_<LANG>_LINK_GROUP_USING_<FEATURE>` + * :variable:`CMAKE_LINK_GROUP_USING_<FEATURE>_SUPPORTED` + * :variable:`CMAKE_LINK_GROUP_USING_<FEATURE>` - See :ref:`cmake_path(ABSOLUTE_PATH) <ABSOLUTE_PATH>` for more details. + The value used for each of these variables is the value as set at the end of + the directory scope in which the target was created. The usage is as follows: -Variable Queries ----------------- + 1. If the language-specific + :variable:`CMAKE_<LANG>_LINK_GROUP_USING_<FEATURE>_SUPPORTED` variable + is true, the ``feature`` must be defined by the corresponding + :variable:`CMAKE_<LANG>_LINK_GROUP_USING_<FEATURE>` variable. + 2. If no language-specific ``feature`` is supported, then the + :variable:`CMAKE_LINK_GROUP_USING_<FEATURE>_SUPPORTED` variable must be + true and the ``feature`` must be defined by the corresponding + :variable:`CMAKE_LINK_GROUP_USING_<FEATURE>` variable. -.. genex:: $<CONFIG> + The ``LINK_GROUP`` generator expression is compatible with the + :genex:`LINK_LIBRARY` generator expression. The libraries involved in a + group can be specified using the :genex:`LINK_LIBRARY` generator expression. - Configuration name. + Each target or external library involved in the link step is allowed to be + part of multiple groups, but only if all the groups involved specify the + same ``feature``. Such groups will not be merged on the linker command line, + the individual groups will still be preserved. Mixing different group + features for the same target or library is forbidden. -.. genex:: $<CONFIGURATION> + .. code-block:: cmake - Configuration name. Deprecated since CMake 3.0. Use ``CONFIG`` instead. + add_library(lib1 ...) + add_library(lib2 ...) + add_library(lib3 ...) + add_library(lib4 ...) + add_library(lib5 ...) -.. genex:: $<PLATFORM_ID> + target_link_libraries(lib3 PUBLIC "$<LINK_GROUP:feature1,lib1,lib2>") + target_link_libraries(lib4 PRIVATE "$<LINK_GROUP:feature1,lib1,lib3>") + # lib4 will be linked with the groups {lib1,lib2} and {lib1,lib3}. + # Both groups specify the same feature, so this is fine. - The current system's CMake platform id. - See also the :variable:`CMAKE_SYSTEM_NAME` variable. + target_link_libraries(lib5 PRIVATE "$<LINK_GROUP:feature2,lib1,lib3>") + # An error will be raised here because both lib1 and lib3 are part of two + # groups with different features. -.. genex:: $<C_COMPILER_ID> + When a target or an external library is involved in the link step as part of + a group and also as not part of any group, any occurrence of the non-group + link item will be replaced by the groups it belongs to. - The CMake's compiler id of the C compiler used. - See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. + .. code-block:: cmake -.. genex:: $<CXX_COMPILER_ID> + add_library(lib1 ...) + add_library(lib2 ...) + add_library(lib3 ...) + add_library(lib4 ...) - The CMake's compiler id of the CXX compiler used. - See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. + target_link_libraries(lib3 PUBLIC lib1) -.. genex:: $<CUDA_COMPILER_ID> + target_link_libraries(lib4 PRIVATE lib3 "$<LINK_GROUP:feature1,lib1,lib2>") + # lib4 will only be linked with lib3 and the group {lib1,lib2} - The CMake's compiler id of the CUDA compiler used. - See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. + Because ``lib1`` is part of the group defined for ``lib4``, that group then + gets applied back to the use of ``lib1`` for ``lib3``. The end result will + be as though the linking relationship for ``lib3`` had been specified as: -.. genex:: $<OBJC_COMPILER_ID> + .. code-block:: cmake - .. versionadded:: 3.16 + target_link_libraries(lib3 PUBLIC "$<LINK_GROUP:feature1,lib1,lib2>") - The CMake's compiler id of the OBJC compiler used. - See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. + Be aware that the precedence of the group over the non-group link item can + result in circular dependencies between groups. If this occurs, a fatal + error is raised because circular dependencies are not allowed for groups. -.. genex:: $<OBJCXX_COMPILER_ID> + .. code-block:: cmake - .. versionadded:: 3.16 + add_library(lib1A ...) + add_library(lib1B ...) + add_library(lib2A ...) + add_library(lib2B ...) + add_library(lib3 ...) - The CMake's compiler id of the OBJCXX compiler used. - See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. + # Non-group linking relationships, these are non-circular so far + target_link_libraries(lib1A PUBLIC lib2A) + target_link_libraries(lib2B PUBLIC lib1B) -.. genex:: $<Fortran_COMPILER_ID> + # The addition of these groups creates circular dependencies + target_link_libraries(lib3 PRIVATE + "$<LINK_GROUP:feat,lib1A,lib1B>" + "$<LINK_GROUP:feat,lib2A,lib2B>" + ) - The CMake's compiler id of the Fortran compiler used. - See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. + Because of the groups defined for ``lib3``, the linking relationships for + ``lib1A`` and ``lib2B`` effectively get expanded to the equivalent of: -.. genex:: $<HIP_COMPILER_ID> + .. code-block:: cmake - .. versionadded:: 3.21 + target_link_libraries(lib1A PUBLIC "$<LINK_GROUP:feat,lib2A,lib2B>") + target_link_libraries(lib2B PUBLIC "$<LINK_GROUP:feat,lib1A,lib1B>") - The CMake's compiler id of the HIP compiler used. - See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. + This creates a circular dependency between groups: + ``lib1A --> lib2B --> lib1A``. -.. genex:: $<ISPC_COMPILER_ID> + The following limitations should also be noted: - .. versionadded:: 3.19 + * The ``library-list`` can specify CMake targets or libraries. + Any CMake target of type :ref:`OBJECT <Object Libraries>` + or :ref:`INTERFACE <Interface Libraries>` will ignore the feature aspect + of the expression and instead be linked in the standard way. - The CMake's compiler id of the ISPC compiler used. - See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. + * The ``$<LINK_GROUP:...>`` generator expression can only be used to + specify link libraries. In practice, this means it can appear in the + :prop_tgt:`LINK_LIBRARIES`, :prop_tgt:`INTERFACE_LINK_LIBRARIES`,and + :prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT` target properties, and be + specified in :command:`target_link_libraries` and :command:`link_libraries` + commands. -.. genex:: $<C_COMPILER_VERSION> + * If a ``$<LINK_GROUP:...>`` generator expression appears in the + :prop_tgt:`INTERFACE_LINK_LIBRARIES` property of a target, it will be + included in the imported target generated by a :command:`install(EXPORT)` + command. It is the responsibility of the environment consuming this + import to define the link feature used by this expression. - The version of the C compiler used. - See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. +Link Context +^^^^^^^^^^^^ -.. genex:: $<CXX_COMPILER_VERSION> +.. genex:: $<LINK_ONLY:...> - The version of the CXX compiler used. - See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. + .. versionadded:: 3.1 -.. genex:: $<CUDA_COMPILER_VERSION> + Content of ``...``, except while collecting :ref:`Target Usage Requirements`, + in which case it is the empty string. This is intended for use in an + :prop_tgt:`INTERFACE_LINK_LIBRARIES` target property, typically populated + via the :command:`target_link_libraries` command, to specify private link + dependencies without other usage requirements. - The version of the CUDA compiler used. - See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. + .. versionadded:: 3.24 + ``LINK_ONLY`` may also be used in a :prop_tgt:`LINK_LIBRARIES` target + property. See policy :policy:`CMP0131`. -.. genex:: $<OBJC_COMPILER_VERSION> +.. genex:: $<DEVICE_LINK:list> - .. versionadded:: 3.16 + .. versionadded:: 3.18 - The version of the OBJC compiler used. - See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. + Returns the list if it is the device link step, an empty list otherwise. + The device link step is controlled by :prop_tgt:`CUDA_SEPARABLE_COMPILATION` + and :prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` properties and + policy :policy:`CMP0105`. This expression can only be used to specify link + options. -.. genex:: $<OBJCXX_COMPILER_VERSION> +.. genex:: $<HOST_LINK:list> - .. versionadded:: 3.16 + .. versionadded:: 3.18 - The version of the OBJCXX compiler used. - See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. + Returns the list if it is the normal link step, an empty list otherwise. + This expression is mainly useful when a device link step is also involved + (see :genex:`$<DEVICE_LINK:list>` generator expression). This expression can + only be used to specify link options. -.. genex:: $<Fortran_COMPILER_VERSION> - The version of the Fortran compiler used. - See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. +.. _`Target-Dependent Queries`: -.. genex:: $<HIP_COMPILER_VERSION> +Target-Dependent Expressions +---------------------------- - .. versionadded:: 3.21 +These queries refer to a target ``tgt``. Unless otherwise stated, this can +be any runtime artifact, namely: - The version of the HIP compiler used. - See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. +* An executable target created by :command:`add_executable`. +* A shared library target (``.so``, ``.dll`` but not their ``.lib`` import + library) created by :command:`add_library`. +* A static library target created by :command:`add_library`. -.. genex:: $<ISPC_COMPILER_VERSION> +In the following, the phrase "the ``tgt`` filename" means the name of the +``tgt`` binary file. This has to be distinguished from the phrase +"the target name", which is just the string ``tgt``. - .. versionadded:: 3.19 +.. genex:: $<TARGET_EXISTS:tgt> - The version of the ISPC compiler used. - See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. + .. versionadded:: 3.12 -.. genex:: $<COMPILE_LANGUAGE> + ``1`` if ``tgt`` exists as a CMake target, else ``0``. - .. versionadded:: 3.3 +.. genex:: $<TARGET_NAME_IF_EXISTS:tgt> - The compile language of source files when evaluating compile options. - See :ref:`the related boolean expression - <Boolean COMPILE_LANGUAGE Generator Expression>` - ``$<COMPILE_LANGUAGE:language>`` - for notes about the portability of this generator expression. + .. versionadded:: 3.12 -.. genex:: $<LINK_LANGUAGE> + The target name ``tgt`` if the target exists, an empty string otherwise. - .. versionadded:: 3.18 + Note that ``tgt`` is not added as a dependency of the target this + expression is evaluated on. - The link language of target when evaluating link options. - See :ref:`the related boolean expression - <Boolean LINK_LANGUAGE Generator Expression>` ``$<LINK_LANGUAGE:language>`` - for notes about the portability of this generator expression. +.. genex:: $<TARGET_NAME:...> - .. note:: + Marks ``...`` as being the name of a target. This is required if exporting + targets to multiple dependent export sets. The ``...`` must be a literal + name of a target, it may not contain generator expressions. - This generator expression is not supported by the link libraries - properties to avoid side-effects due to the double evaluation of - these properties. +.. genex:: $<TARGET_PROPERTY:tgt,prop> -.. _`Target-Dependent Queries`: + Value of the property ``prop`` on the target ``tgt``. -Target-Dependent Queries ------------------------- + Note that ``tgt`` is not added as a dependency of the target this + expression is evaluated on. -These queries refer to a target ``tgt``. This can be any runtime artifact, -namely: +.. genex:: $<TARGET_PROPERTY:prop> -* an executable target created by :command:`add_executable` -* a shared library target (``.so``, ``.dll`` but not their ``.lib`` import library) - created by :command:`add_library` -* a static library target created by :command:`add_library` + Value of the property ``prop`` on the target for which the expression + is being evaluated. Note that for generator expressions in + :ref:`Target Usage Requirements` this is the consuming target rather + than the target specifying the requirement. -In the following, "the ``tgt`` filename" means the name of the ``tgt`` -binary file. This has to be distinguished from "the target name", -which is just the string ``tgt``. +.. genex:: $<TARGET_OBJECTS:tgt> -.. genex:: $<TARGET_NAME_IF_EXISTS:tgt> + .. versionadded:: 3.1 - .. versionadded:: 3.12 + List of objects resulting from building ``tgt``. This would typically be + used on :ref:`object library <Object Libraries>` targets. - The target name ``tgt`` if the target exists, an empty string otherwise. +.. genex:: $<TARGET_POLICY:policy> - Note that ``tgt`` is not added as a dependency of the target this - expression is evaluated on. + ``1`` if the ``policy`` was ``NEW`` when the 'head' target was created, + else ``0``. If the ``policy`` was not set, the warning message for the policy + will be emitted. This generator expression only works for a subset of + policies. .. genex:: $<TARGET_FILE:tgt> @@ -1273,20 +1647,6 @@ which is just the string ``tgt``. Note that ``tgt`` is not added as a dependency of the target this expression is evaluated on (see policy :policy:`CMP0112`). -.. genex:: $<TARGET_PROPERTY:tgt,prop> - - Value of the property ``prop`` on the target ``tgt``. - - Note that ``tgt`` is not added as a dependency of the target this - expression is evaluated on. - -.. genex:: $<TARGET_PROPERTY:prop> - - Value of the property ``prop`` on the target for which the expression - is being evaluated. Note that for generator expressions in - :ref:`Target Usage Requirements` this is the consuming target rather - than the target specifying the requirement. - .. genex:: $<TARGET_RUNTIME_DLLS:tgt> .. versionadded:: 3.21 @@ -1294,8 +1654,8 @@ which is just the string ``tgt``. List of DLLs that the target depends on at runtime. This is determined by the locations of all the ``SHARED`` targets in the target's transitive dependencies. Using this generator expression on targets other than - executables, ``SHARED`` libraries, and ``MODULE`` libraries is an error. On - non-DLL platforms, it evaluates to an empty string. + executables, ``SHARED`` libraries, and ``MODULE`` libraries is an error. + **On non-DLL platforms, this expression always evaluates to an empty string**. This generator expression can be used to copy all of the DLLs that a target depends on into its output directory in a ``POST_BUILD`` custom command. For @@ -1310,7 +1670,7 @@ which is just the string ``tgt``. add_custom_command(TARGET exe POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:exe> $<TARGET_FILE_DIR:exe> COMMAND_EXPAND_LISTS - ) + ) .. note:: @@ -1321,368 +1681,100 @@ which is just the string ``tgt``. section for details. Many :ref:`Find Modules` produce imported targets with the ``UNKNOWN`` type and therefore will be ignored. -.. genex:: $<INSTALL_PREFIX> - - Content of the install prefix when the target is exported via - :command:`install(EXPORT)`, or when evaluated in the - :prop_tgt:`INSTALL_NAME_DIR` property or the ``INSTALL_NAME_DIR`` argument of - :command:`install(RUNTIME_DEPENDENCY_SET)`, and empty otherwise. - -Output-Related Expressions --------------------------- - -.. genex:: $<TARGET_NAME:...> - - Marks ``...`` as being the name of a target. This is required if exporting - targets to multiple dependent export sets. The ``...`` must be a literal - name of a target- it may not contain generator expressions. - -.. genex:: $<LINK_ONLY:...> - - .. versionadded:: 3.1 - - Content of ``...``, except while collecting :ref:`Target Usage Requirements`, - in which case it is the empty string. This is intended for use in an - :prop_tgt:`INTERFACE_LINK_LIBRARIES` target property, typically populated - via the :command:`target_link_libraries` command, to specify private link - dependencies without other usage requirements. - - .. versionadded:: 3.24 - ``LINK_ONLY`` may also be used in a :prop_tgt:`LINK_LIBRARIES` target - property. See policy :policy:`CMP0131`. - -.. genex:: $<DEVICE_LINK:list> - - .. versionadded:: 3.18 - - Returns the list if it is the device link step, an empty list otherwise. - The device link step is controlled by :prop_tgt:`CUDA_SEPARABLE_COMPILATION` - and :prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` properties and - policy :policy:`CMP0105`. This expression can only be used to specify link - options. - -.. genex:: $<HOST_LINK:list> - - .. versionadded:: 3.18 - - Returns the list if it is the normal link step, an empty list otherwise. - This expression is mainly useful when a device link step is also involved - (see :genex:`$<DEVICE_LINK:list>` generator expression). This expression can - only be used to specify link options. - -.. genex:: $<LINK_LIBRARY:feature,library-list> - - .. versionadded:: 3.24 - - Specify a set of libraries to link to a target, along with a ``feature`` - which provides details about *how* they should be linked. For example: - - .. code-block:: cmake - - add_library(lib1 STATIC ...) - add_library(lib2 ...) - target_link_libraries(lib2 PRIVATE "$<LINK_LIBRARY:WHOLE_ARCHIVE,lib1>") - - This specifies that ``lib2`` should link to ``lib1`` and use the - ``WHOLE_ARCHIVE`` feature when doing so. - Feature names are case-sensitive and may only contain letters, numbers and - underscores. Feature names defined in all uppercase are reserved for CMake's - own built-in features. The pre-defined built-in library features are: - - .. include:: ../variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt - - Built-in and custom library features are defined in terms of the following - variables: - - * :variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED` - * :variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>` - * :variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED` - * :variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>` - - The value used for each of these variables is the value as set at the end of - the directory scope in which the target was created. The usage is as follows: - - 1. If the language-specific - :variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED` variable - is true, the ``feature`` must be defined by the corresponding - :variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>` variable. - 2. If no language-specific ``feature`` is supported, then the - :variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>_SUPPORTED` variable must be - true and the ``feature`` must be defined by the corresponding - :variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>` variable. +Export And Install Expressions +------------------------------ - The following limitations should be noted: - - * The ``library-list`` can specify CMake targets or libraries. - Any CMake target of type :ref:`OBJECT <Object Libraries>` - or :ref:`INTERFACE <Interface Libraries>` will ignore the feature aspect - of the expression and instead be linked in the standard way. - - * The ``$<LINK_LIBRARY:...>`` generator expression can only be used to - specify link libraries. In practice, this means it can appear in the - :prop_tgt:`LINK_LIBRARIES`, :prop_tgt:`INTERFACE_LINK_LIBRARIES`, and - :prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT` target properties, and be - specified in :command:`target_link_libraries` and :command:`link_libraries` - commands. - - * If a ``$<LINK_LIBRARY:...>`` generator expression appears in the - :prop_tgt:`INTERFACE_LINK_LIBRARIES` property of a target, it will be - included in the imported target generated by a :command:`install(EXPORT)` - command. It is the responsibility of the environment consuming this - import to define the link feature used by this expression. - - * Each target or library involved in the link step must have at most only - one kind of library feature. The absence of a feature is also incompatible - with all other features. For example: - - .. code-block:: cmake - - add_library(lib1 ...) - add_library(lib2 ...) - add_library(lib3 ...) - - # lib1 will be associated with feature1 - target_link_libraries(lib2 PUBLIC "$<LINK_LIBRARY:feature1,lib1>") - - # lib1 is being linked with no feature here. This conflicts with the - # use of feature1 in the line above and would result in an error. - target_link_libraries(lib3 PRIVATE lib1 lib2) - - Where it isn't possible to use the same feature throughout a build for a - given target or library, the :prop_tgt:`LINK_LIBRARY_OVERRIDE` and - :prop_tgt:`LINK_LIBRARY_OVERRIDE_<LIBRARY>` target properties can be - used to resolve such incompatibilities. - - * The ``$<LINK_LIBRARY:...>`` generator expression does not guarantee - that the list of specified targets and libraries will be kept grouped - together. To manage constructs like ``--start-group`` and ``--end-group``, - as supported by the GNU ``ld`` linker, use the :genex:`LINK_GROUP` - generator expression instead. - -.. genex:: $<LINK_GROUP:feature,library-list> - - .. versionadded:: 3.24 - - Specify a group of libraries to link to a target, along with a ``feature`` - which defines how that group should be linked. For example: - - .. code-block:: cmake - - add_library(lib1 STATIC ...) - add_library(lib2 ...) - target_link_libraries(lib2 PRIVATE "$<LINK_GROUP:RESCAN,lib1,external>") +.. genex:: $<INSTALL_INTERFACE:...> - This specifies that ``lib2`` should link to ``lib1`` and ``external``, and - that both of those two libraries should be included on the linker command - line according to the definition of the ``RESCAN`` feature. + Content of ``...`` when the property is exported using + :command:`install(EXPORT)`, and empty otherwise. - Feature names are case-sensitive and may only contain letters, numbers and - underscores. Feature names defined in all uppercase are reserved for CMake's - own built-in features. Currently, there is only one pre-defined built-in - group feature: +.. genex:: $<BUILD_INTERFACE:...> - .. include:: ../variable/LINK_GROUP_PREDEFINED_FEATURES.txt + Content of ``...`` when the property is exported using :command:`export`, or + when the target is used by another target in the same buildsystem. Expands to + the empty string otherwise. - Built-in and custom group features are defined in terms of the following - variables: +.. genex:: $<INSTALL_PREFIX> - * :variable:`CMAKE_<LANG>_LINK_GROUP_USING_<FEATURE>_SUPPORTED` - * :variable:`CMAKE_<LANG>_LINK_GROUP_USING_<FEATURE>` - * :variable:`CMAKE_LINK_GROUP_USING_<FEATURE>_SUPPORTED` - * :variable:`CMAKE_LINK_GROUP_USING_<FEATURE>` + Content of the install prefix when the target is exported via + :command:`install(EXPORT)`, or when evaluated in the + :prop_tgt:`INSTALL_NAME_DIR` property or the ``INSTALL_NAME_DIR`` argument of + :command:`install(RUNTIME_DEPENDENCY_SET)`, and empty otherwise. - The value used for each of these variables is the value as set at the end of - the directory scope in which the target was created. The usage is as follows: +Multi-level Expression Evaluation +--------------------------------- - 1. If the language-specific - :variable:`CMAKE_<LANG>_LINK_GROUP_USING_<FEATURE>_SUPPORTED` variable - is true, the ``feature`` must be defined by the corresponding - :variable:`CMAKE_<LANG>_LINK_GROUP_USING_<FEATURE>` variable. - 2. If no language-specific ``feature`` is supported, then the - :variable:`CMAKE_LINK_GROUP_USING_<FEATURE>_SUPPORTED` variable must be - true and the ``feature`` must be defined by the corresponding - :variable:`CMAKE_LINK_GROUP_USING_<FEATURE>` variable. - - The ``LINK_GROUP`` generator expression is compatible with the - :genex:`LINK_LIBRARY` generator expression. The libraries involved in a - group can be specified using the :genex:`LINK_LIBRARY` generator expression. +.. genex:: $<GENEX_EVAL:expr> - Each target or external library involved in the link step is allowed to be - part of multiple groups, but only if all the groups involved specify the - same ``feature``. Such groups will not be merged on the linker command line, - the individual groups will still be preserved. Mixing different group - features for the same target or library is forbidden. + .. versionadded:: 3.12 - .. code-block:: cmake + Content of ``expr`` evaluated as a generator expression in the current + context. This enables consumption of generator expressions whose + evaluation results itself in generator expressions. - add_library(lib1 ...) - add_library(lib2 ...) - add_library(lib3 ...) - add_library(lib4 ...) - add_library(lib5 ...) +.. genex:: $<TARGET_GENEX_EVAL:tgt,expr> - target_link_libraries(lib3 PUBLIC "$<LINK_GROUP:feature1,lib1,lib2>") - target_link_libraries(lib4 PRIVATE "$<LINK_GROUP:feature1,lib1,lib3>") - # lib4 will be linked with the groups {lib1,lib2} and {lib1,lib3}. - # Both groups specify the same feature, so this is fine. + .. versionadded:: 3.12 - target_link_libraries(lib5 PRIVATE "$<LINK_GROUP:feature2,lib1,lib3>") - # An error will be raised here because both lib1 and lib3 are part of two - # groups with different features. + Content of ``expr`` evaluated as a generator expression in the context of + ``tgt`` target. This enables consumption of custom target properties that + themselves contain generator expressions. - When a target or an external library is involved in the link step as part of - a group and also as not part of any group, any occurrence of the non-group - link item will be replaced by the groups it belongs to. + Having the capability to evaluate generator expressions is very useful when + you want to manage custom properties supporting generator expressions. + For example: .. code-block:: cmake - add_library(lib1 ...) - add_library(lib2 ...) - add_library(lib3 ...) - add_library(lib4 ...) - - target_link_libraries(lib3 PUBLIC lib1) - - target_link_libraries(lib4 PRIVATE lib3 "$<LINK_GROUP:feature1,lib1,lib2>") - # lib4 will only be linked with lib3 and the group {lib1,lib2} + add_library(foo ...) - Because ``lib1`` is part of the group defined for ``lib4``, that group then - gets applied back to the use of ``lib1`` for ``lib3``. The end result will - be as though the linking relationship for ``lib3`` had been specified as: + set_property(TARGET foo PROPERTY + CUSTOM_KEYS $<$<CONFIG:DEBUG>:FOO_EXTRA_THINGS> + ) - .. code-block:: cmake + add_custom_target(printFooKeys + COMMAND ${CMAKE_COMMAND} -E echo $<TARGET_PROPERTY:foo,CUSTOM_KEYS> + ) - target_link_libraries(lib3 PUBLIC "$<LINK_GROUP:feature1,lib1,lib2>") + This naive implementation of the ``printFooKeys`` custom command is wrong + because ``CUSTOM_KEYS`` target property is not evaluated and the content + is passed as is (i.e. ``$<$<CONFIG:DEBUG>:FOO_EXTRA_THINGS>``). - Be aware that the precedence of the group over the non-group link item can - result in circular dependencies between groups. If this occurs, a fatal - error is raised because circular dependencies are not allowed for groups. + To have the expected result (i.e. ``FOO_EXTRA_THINGS`` if config is + ``Debug``), it is required to evaluate the output of + ``$<TARGET_PROPERTY:foo,CUSTOM_KEYS>``: .. code-block:: cmake - add_library(lib1A ...) - add_library(lib1B ...) - add_library(lib2A ...) - add_library(lib2B ...) - add_library(lib3 ...) - - # Non-group linking relationships, these are non-circular so far - target_link_libraries(lib1A PUBLIC lib2A) - target_link_libraries(lib2B PUBLIC lib1B) - - # The addition of these groups creates circular dependencies - target_link_libraries(lib3 PRIVATE - "$<LINK_GROUP:feat,lib1A,lib1B>" - "$<LINK_GROUP:feat,lib2A,lib2B>" + add_custom_target(printFooKeys + COMMAND ${CMAKE_COMMAND} -E + echo $<TARGET_GENEX_EVAL:foo,$<TARGET_PROPERTY:foo,CUSTOM_KEYS>> ) - Because of the groups defined for ``lib3``, the linking relationships for - ``lib1A`` and ``lib2B`` effectively get expanded to the equivalent of: - - .. code-block:: cmake - - target_link_libraries(lib1A PUBLIC "$<LINK_GROUP:feat,lib2A,lib2B>") - target_link_libraries(lib2B PUBLIC "$<LINK_GROUP:feat,lib1A,lib1B>") - - This creates a circular dependency between groups: - ``lib1A --> lib2B --> lib1A``. - - The following limitations should also be noted: - - * The ``library-list`` can specify CMake targets or libraries. - Any CMake target of type :ref:`OBJECT <Object Libraries>` - or :ref:`INTERFACE <Interface Libraries>` will ignore the feature aspect - of the expression and instead be linked in the standard way. - - * The ``$<LINK_GROUP:...>`` generator expression can only be used to - specify link libraries. In practice, this means it can appear in the - :prop_tgt:`LINK_LIBRARIES`, :prop_tgt:`INTERFACE_LINK_LIBRARIES`,and - :prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT` target properties, and be - specified in :command:`target_link_libraries` and :command:`link_libraries` - commands. - - * If a ``$<LINK_GROUP:...>`` generator expression appears in the - :prop_tgt:`INTERFACE_LINK_LIBRARIES` property of a target, it will be - included in the imported target generated by a :command:`install(EXPORT)` - command. It is the responsibility of the environment consuming this - import to define the link feature used by this expression. - -.. genex:: $<INSTALL_INTERFACE:...> - - Content of ``...`` when the property is exported using :command:`install(EXPORT)`, - and empty otherwise. - -.. genex:: $<BUILD_INTERFACE:...> - - Content of ``...`` when the property is exported using :command:`export`, or - when the target is used by another target in the same buildsystem. Expands to - the empty string otherwise. - -.. genex:: $<MAKE_C_IDENTIFIER:...> - - Content of ``...`` converted to a C identifier. The conversion follows the - same behavior as :command:`string(MAKE_C_IDENTIFIER)`. - -.. genex:: $<TARGET_OBJECTS:objLib> - - .. versionadded:: 3.1 - - List of objects resulting from build of ``objLib``. - -.. genex:: $<SHELL_PATH:...> - - .. versionadded:: 3.4 - - Content of ``...`` converted to shell path style. For example, slashes are - converted to backslashes in Windows shells and drive letters are converted - to posix paths in MSYS shells. The ``...`` must be an absolute path. - - .. versionadded:: 3.14 - The ``...`` may be a :ref:`semicolon-separated list <CMake Language Lists>` - of paths, in which case each path is converted individually and a result - list is generated using the shell path separator (``:`` on POSIX and - ``;`` on Windows). Be sure to enclose the argument containing this genex - in double quotes in CMake source code so that ``;`` does not split arguments. - -.. genex:: $<OUTPUT_CONFIG:...> - - .. versionadded:: 3.20 - - Only valid in :command:`add_custom_command` and :command:`add_custom_target` - as the outer-most generator expression in an argument. - With the :generator:`Ninja Multi-Config` generator, generator expressions - in ``...`` are evaluated using the custom command's "output config". - With other generators, the content of ``...`` is evaluated normally. - -.. genex:: $<COMMAND_CONFIG:...> - - .. versionadded:: 3.20 +Escaped Characters +------------------ - Only valid in :command:`add_custom_command` and :command:`add_custom_target` - as the outer-most generator expression in an argument. - With the :generator:`Ninja Multi-Config` generator, generator expressions - in ``...`` are evaluated using the custom command's "command config". - With other generators, the content of ``...`` is evaluated normally. +These expressions evaluate to specific string literals. Use them in place of +the actual string literal where you need to prevent them from having their +special meaning. -Debugging -========= +.. genex:: $<ANGLE-R> -Since generator expressions are evaluated during generation of the buildsystem, -and not during processing of ``CMakeLists.txt`` files, it is not possible to -inspect their result with the :command:`message()` command. + A literal ``>``. Used for example to compare strings that contain a ``>``. -One possible way to generate debug messages is to add a custom target, +.. genex:: $<COMMA> -.. code-block:: cmake + A literal ``,``. Used for example to compare strings which contain a ``,``. - add_custom_target(genexdebug COMMAND ${CMAKE_COMMAND} -E echo "$<...>") +.. genex:: $<SEMICOLON> -The shell command ``make genexdebug`` (invoked after execution of ``cmake``) -would then print the result of ``$<...>``. + A literal ``;``. Used to prevent list expansion on an argument with ``;``. -Another way is to write debug messages to a file: +Deprecated Expressions +---------------------- -.. code-block:: cmake +.. genex:: $<CONFIGURATION> - file(GENERATE OUTPUT filename CONTENT "$<...>") + Configuration name. Deprecated since CMake 3.0. Use :genex:`CONFIG` instead. diff --git a/Help/prop_tgt/LINK_LIBRARIES_ONLY_TARGETS.rst b/Help/prop_tgt/LINK_LIBRARIES_ONLY_TARGETS.rst index a9af74d..0749c6f 100644 --- a/Help/prop_tgt/LINK_LIBRARIES_ONLY_TARGETS.rst +++ b/Help/prop_tgt/LINK_LIBRARIES_ONLY_TARGETS.rst @@ -8,6 +8,8 @@ Enforce that link items that can be target names are actually existing targets. Set this property to a true value to enable additional checks on the contents of the :prop_tgt:`LINK_LIBRARIES` and :prop_tgt:`INTERFACE_LINK_LIBRARIES` target properties, typically populated by :command:`target_link_libraries`. +Checks are also applied to libraries added to a target through the +:prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT` properties of its dependencies. CMake will verify that link items that might be target names actually name existing targets. An item is considered a possible target name if: diff --git a/Help/release/dev/finddoxygen-better-version-checking.rst b/Help/release/dev/finddoxygen-better-version-checking.rst new file mode 100644 index 0000000..3c2215d --- /dev/null +++ b/Help/release/dev/finddoxygen-better-version-checking.rst @@ -0,0 +1,11 @@ +finddoxygen-better-version-checking +----------------------------------- + +* The :module:`FindDoxygen` module now evaluates as many candidate + Doxygen installs as are necessary to satisfy version constraints, + with the package considered to be not found if none are available. + +* The :module:`FindDoxygen` module now handles version ranges. + +* The :module:`FindDoxygen` module now ignores non-semantic portions + of the output from Doxygen's `--version` option. diff --git a/Modules/FindDoxygen.cmake b/Modules/FindDoxygen.cmake index 4a16e31..23b7107 100644 --- a/Modules/FindDoxygen.cmake +++ b/Modules/FindDoxygen.cmake @@ -432,9 +432,44 @@ endif() # or use something like homebrew. # ============== End OSX stuff ================ +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) + # # Find Doxygen... # +function(_Doxygen_get_version doxy_version result_var doxy_path) + execute_process( + COMMAND "${doxy_path}" --version + OUTPUT_VARIABLE full_doxygen_version + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE version_result + ) + + # Ignore any commit hashes, etc. + string(REGEX MATCH [[^[0-9]+\.[0-9]+\.[0-9]+]] sem_doxygen_version "${full_doxygen_version}") + + set(${result_var} ${version_result} PARENT_SCOPE) + set(${doxy_version} ${sem_doxygen_version} PARENT_SCOPE) +endfunction() + +function(_Doxygen_version_validator version_match doxy_path) + if(NOT DEFINED Doxygen_FIND_VERSION) + set(${is_valid_version} TRUE PARENT_SCOPE) + else() + _Doxygen_get_version(candidate_version version_result "${doxy_path}") + + if(version_result) + message(DEBUG "Unable to determine candidate doxygen version at ${doxy_path}: ${version_result}") + endif() + + find_package_check_version("${candidate_version}" valid_doxy_version + HANDLE_VERSION_RANGE + ) + + set(${version_match} "${valid_doxy_version}" PARENT_SCOPE) + endif() +endfunction() + macro(_Doxygen_find_doxygen) find_program( DOXYGEN_EXECUTABLE @@ -446,16 +481,13 @@ macro(_Doxygen_find_doxygen) /Applications/Utilities/Doxygen.app/Contents/Resources /Applications/Utilities/Doxygen.app/Contents/MacOS DOC "Doxygen documentation generation tool (http://www.doxygen.org)" + VALIDATOR _Doxygen_version_validator ) mark_as_advanced(DOXYGEN_EXECUTABLE) if(DOXYGEN_EXECUTABLE) - execute_process( - COMMAND "${DOXYGEN_EXECUTABLE}" --version - OUTPUT_VARIABLE DOXYGEN_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE _Doxygen_version_result - ) + _Doxygen_get_version(DOXYGEN_VERSION _Doxygen_version_result "${DOXYGEN_EXECUTABLE}") + if(_Doxygen_version_result) message(WARNING "Unable to determine doxygen version: ${_Doxygen_version_result}") endif() @@ -642,11 +674,11 @@ endforeach() unset(_comp) # Verify find results -include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) find_package_handle_standard_args( Doxygen REQUIRED_VARS DOXYGEN_EXECUTABLE VERSION_VAR DOXYGEN_VERSION + HANDLE_VERSION_RANGE HANDLE_COMPONENTS ) diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake index 53519ba..7a127e4 100644 --- a/Modules/FindPython/Support.cmake +++ b/Modules/FindPython/Support.cmake @@ -2871,7 +2871,15 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) while (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR) - if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS + set (_${_PYTHON_PREFIX}_LIBRARY_REQUIRED TRUE) + foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Module Embed) + string (TOUPPER "${_${_PYTHON_PREFIX}_COMPONENT}" _${_PYTHON_PREFIX}_ID) + if ("Development.${_${_PYTHON_PREFIX}_COMPONENT}" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS + AND NOT "LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${_${_PYTHON_PREFIX}_ID}_ARTIFACTS) + set (_${_PYTHON_PREFIX}_LIBRARY_REQUIRED FALSE) + endif() + endforeach() + if (_${_PYTHON_PREFIX}_LIBRARY_REQUIRED AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE) # Don't search for include dir if no library was founded break() diff --git a/Modules/Platform/AIX-GNU.cmake b/Modules/Platform/AIX-GNU.cmake index 5a532c7..a9aa8e0 100644 --- a/Modules/Platform/AIX-GNU.cmake +++ b/Modules/Platform/AIX-GNU.cmake @@ -23,11 +23,11 @@ macro(__aix_compiler_gnu lang) # Construct the export list ourselves to pass only the object files so # that we export only the symbols actually provided by the sources. set(CMAKE_${lang}_CREATE_SHARED_LIBRARY - "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/exports.exp <AIX_EXPORTS> <OBJECTS>" + "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/exports.exp -c <CMAKE_${lang}_COMPILER> <AIX_EXPORTS> <OBJECTS>" "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/exports.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" ) set(CMAKE_${lang}_LINK_EXECUTABLE_WITH_EXPORTS - "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -l . <AIX_EXPORTS> <OBJECTS>" + "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -c <CMAKE_${lang}_COMPILER> -l . <AIX_EXPORTS> <OBJECTS>" "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> -Wl,-bE:<TARGET_IMPLIB> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>") endmacro() diff --git a/Modules/Platform/AIX-XL.cmake b/Modules/Platform/AIX-XL.cmake index 2a8c159..902cbb3 100644 --- a/Modules/Platform/AIX-XL.cmake +++ b/Modules/Platform/AIX-XL.cmake @@ -29,12 +29,12 @@ macro(__aix_compiler_xl lang) # Construct the export list ourselves to pass only the object files so # that we export only the symbols actually provided by the sources. set(CMAKE_${lang}_CREATE_SHARED_LIBRARY - "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/exports.exp <AIX_EXPORTS>${_OBJECTS}" + "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/exports.exp -c <CMAKE_${lang}_COMPILER> <AIX_EXPORTS>${_OBJECTS}" "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/exports.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" ) set(CMAKE_${lang}_LINK_EXECUTABLE_WITH_EXPORTS - "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -l . <AIX_EXPORTS> <OBJECTS>" + "\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -c <CMAKE_${lang}_COMPILER> -l . <AIX_EXPORTS> <OBJECTS>" "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> -Wl,-bE:<TARGET_IMPLIB> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>") unset(_OBJECTS) diff --git a/Modules/Platform/AIX/ExportImportList b/Modules/Platform/AIX/ExportImportList index 891bce7..5e16fcb 100755 --- a/Modules/Platform/AIX/ExportImportList +++ b/Modules/Platform/AIX/ExportImportList @@ -5,7 +5,7 @@ # This script is internal to CMake and meant only to be # invoked by CMake-generated build systems on AIX. -usage='usage: ExportImportList -o <out-file> [-l <lib>] [-n] [--] <objects>...' +usage='usage: ExportImportList -o <out-file> -c <compiler> [-l <lib>] [-n] [--] <objects>...' die() { echo "$@" 1>&2; exit 1 @@ -15,11 +15,13 @@ die() { out='' lib='' no_objects='' +compiler='' while test "$#" != 0; do case "$1" in -l) shift; lib="$1" ;; -o) shift; out="$1" ;; -n) no_objects='1' ;; + -c) shift; compiler="$1" ;; --) shift; break ;; -*) die "$usage" ;; *) break ;; @@ -27,27 +29,47 @@ while test "$#" != 0; do shift done test -n "$out" || die "$usage" +# We need the compiler executable to resolve where the ibm-llvm-nm executable is +test -n "$compiler" || die "$usage" # Build a temporary file that atomically replaces the output later. out_tmp="$out.tmp$$" trap 'rm -f "$out_tmp"' EXIT INT TERM > "$out_tmp" +# If IPA was enabled and a compiler from the IBMClang family is used, then +# the object files contain LLVM bitcode[0] rather than XCOFF objects and so +# need to be handled differently. +# +# [0]: https://www.ibm.com/docs/en/openxl-c-and-cpp-aix/17.1.0?topic=compatibility-link-time-optimization-lto +NM="$(dirname "$compiler")/../libexec/ibm-llvm-nm" + +function IsBitcode { + # N4 = first 4 bytes, -tx = output in hexadecimal, -An = don't display offset + # cut: trim off the preceding whitespace where the offset would be + # 4243code is the hexadecimal magic number for LLVM bitcode + [ "$(od -N4 -tx -An $1 | cut -d ' ' -f 2)" == "4243c0de" ]; +} + # Collect symbols exported from all object files. if test -z "$no_objects"; then for f in "$@"; do - dump -tov -X 32_64 "$f" | - awk ' - BEGIN { - V["EXPORTED"]=" export" - V["PROTECTED"]=" protected" - } - /^\[[0-9]+\]\tm +[^ ]+ +\.(text|data|bss) +[^ ]+ +(extern|weak) +(EXPORTED|PROTECTED| ) / { - if (!match($NF,/^(\.|__sinit|__sterm|__[0-9]+__)/)) { - print $NF V[$(NF-1)] + if IsBitcode "$f"; then + "$NM" "$f" --defined-only --extern-only --just-symbol-name 2>/dev/null + else + dump -tov -X 32_64 "$f" | + awk ' + BEGIN { + V["EXPORTED"]=" export" + V["PROTECTED"]=" protected" + } + /^\[[0-9]+\]\tm +[^ ]+ +\.(text|data|bss) +[^ ]+ +(extern|weak) +(EXPORTED|PROTECTED| ) / { + if (!match($NF,/^(\.|__sinit|__sterm|__[0-9]+__)/)) { + print $NF V[$(NF-1)] + } } - } - ' + ' + fi done >> "$out_tmp" fi diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 23ca43b..82e1f62 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 24) -set(CMake_VERSION_PATCH 20220708) +set(CMake_VERSION_PATCH 20220720) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 4cb541a..5113a46 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1399,7 +1399,9 @@ void cmGlobalGenerator::CreateGenerationObjects(TargetTypes targetTypes) this->CheckTargetProperties(); } this->CreateGeneratorTargets(targetTypes); - this->ComputeBuildFileGenerators(); + if (targetTypes == TargetTypes::AllTargets) { + this->ComputeBuildFileGenerators(); + } } void cmGlobalGenerator::CreateImportedGenerationObjects( diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 155efde..dec0858 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -1294,6 +1294,14 @@ bool cmGlobalVisualStudio10Generator::IsInSolution( gt->GetName() == CMAKE_CHECK_BUILD_SYSTEM_TARGET); } +bool cmGlobalVisualStudio10Generator::IsDepInSolution( + const std::string& targetName) const +{ + return !targetName.empty() && + !(this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS16 && + targetName == CMAKE_CHECK_BUILD_SYSTEM_TARGET); +} + bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf) { if (this->DefaultPlatformToolset == "v100") { diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index 2203f71..12fd7a8 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -120,6 +120,8 @@ public: bool IsInSolution(const cmGeneratorTarget* gt) const override; + bool IsDepInSolution(const std::string& targetName) const override; + /** Return true if building for WindowsCE */ bool TargetsWindowsCE() const override { return this->SystemIsWindowsCE; } diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index ce943a2..758ce83 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -180,7 +180,7 @@ void cmGlobalVisualStudio71Generator::WriteExternalProject( fout << "\tProjectSection(ProjectDependencies) = postProject\n"; for (BT<std::pair<std::string, bool>> const& it : depends) { std::string const& dep = it.Value.first; - if (!dep.empty()) { + if (this->IsDepInSolution(dep)) { fout << "\t\t{" << this->GetGUID(dep) << "} = {" << this->GetGUID(dep) << "}\n"; } diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index cddaaa4..c6af20a 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -843,6 +843,12 @@ bool cmGlobalVisualStudioGenerator::IsInSolution( return gt->IsInBuildSystem(); } +bool cmGlobalVisualStudioGenerator::IsDepInSolution( + const std::string& targetName) const +{ + return !targetName.empty(); +} + bool cmGlobalVisualStudioGenerator::TargetCompare::operator()( cmGeneratorTarget const* l, cmGeneratorTarget const* r) const { diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index 4f5f100..f45b4d4 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -101,6 +101,9 @@ public: // return true if target should be included in solution. virtual bool IsInSolution(const cmGeneratorTarget* gt) const; + // return true if project dependency should be included in solution. + virtual bool IsDepInSolution(const std::string& targetName) const; + /** Get the top-level registry key for this VS version. */ std::string GetRegistryBase(); diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 86ae45d..a4080d8 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -1343,9 +1343,11 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( } } - this->ExportObjectCompileCommand( - language, sourceFilePath, objectDir, objectFileName, objectFileDir, - vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"], config); + if (firstForConfig) { + this->ExportObjectCompileCommand( + language, sourceFilePath, objectDir, objectFileName, objectFileDir, + vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"], config); + } objBuild.Outputs.push_back(objectFileName); if (firstForConfig) { diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index a7460e8..2356869 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2930,7 +2930,7 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions( Elem& e0) { cmStateEnums::TargetType ttype = this->GeneratorTarget->GetType(); - if (ttype > cmStateEnums::GLOBAL_TARGET) { + if (ttype > cmStateEnums::INTERFACE_LIBRARY) { return; } if (this->ProjectType == VsProjectType::csproj) { diff --git a/Templates/MSBuild/FlagTables/v10_CSharp.json b/Templates/MSBuild/FlagTables/v10_CSharp.json index 9f21d9a..5341841 100644 --- a/Templates/MSBuild/FlagTables/v10_CSharp.json +++ b/Templates/MSBuild/FlagTables/v10_CSharp.json @@ -201,6 +201,13 @@ "flags": [] }, { + "name": "DebugType", + "switch": "debug:embedded", + "comment": "", + "value": "embedded", + "flags": [] + }, + { "name": "Optimize", "switch": "optimize", "comment": "", diff --git a/Templates/MSBuild/FlagTables/v11_CSharp.json b/Templates/MSBuild/FlagTables/v11_CSharp.json index 9f21d9a..5341841 100644 --- a/Templates/MSBuild/FlagTables/v11_CSharp.json +++ b/Templates/MSBuild/FlagTables/v11_CSharp.json @@ -201,6 +201,13 @@ "flags": [] }, { + "name": "DebugType", + "switch": "debug:embedded", + "comment": "", + "value": "embedded", + "flags": [] + }, + { "name": "Optimize", "switch": "optimize", "comment": "", diff --git a/Templates/MSBuild/FlagTables/v12_CSharp.json b/Templates/MSBuild/FlagTables/v12_CSharp.json index 9f21d9a..5341841 100644 --- a/Templates/MSBuild/FlagTables/v12_CSharp.json +++ b/Templates/MSBuild/FlagTables/v12_CSharp.json @@ -201,6 +201,13 @@ "flags": [] }, { + "name": "DebugType", + "switch": "debug:embedded", + "comment": "", + "value": "embedded", + "flags": [] + }, + { "name": "Optimize", "switch": "optimize", "comment": "", diff --git a/Templates/MSBuild/FlagTables/v140_CSharp.json b/Templates/MSBuild/FlagTables/v140_CSharp.json index 9f21d9a..5341841 100644 --- a/Templates/MSBuild/FlagTables/v140_CSharp.json +++ b/Templates/MSBuild/FlagTables/v140_CSharp.json @@ -201,6 +201,13 @@ "flags": [] }, { + "name": "DebugType", + "switch": "debug:embedded", + "comment": "", + "value": "embedded", + "flags": [] + }, + { "name": "Optimize", "switch": "optimize", "comment": "", diff --git a/Templates/MSBuild/FlagTables/v141_CSharp.json b/Templates/MSBuild/FlagTables/v141_CSharp.json index 9f21d9a..5341841 100644 --- a/Templates/MSBuild/FlagTables/v141_CSharp.json +++ b/Templates/MSBuild/FlagTables/v141_CSharp.json @@ -201,6 +201,13 @@ "flags": [] }, { + "name": "DebugType", + "switch": "debug:embedded", + "comment": "", + "value": "embedded", + "flags": [] + }, + { "name": "Optimize", "switch": "optimize", "comment": "", diff --git a/Templates/MSBuild/FlagTables/v142_CSharp.json b/Templates/MSBuild/FlagTables/v142_CSharp.json index ae1bd47..9ea8f4b 100644 --- a/Templates/MSBuild/FlagTables/v142_CSharp.json +++ b/Templates/MSBuild/FlagTables/v142_CSharp.json @@ -208,6 +208,13 @@ "flags": [] }, { + "name": "DebugType", + "switch": "debug:embedded", + "comment": "", + "value": "embedded", + "flags": [] + }, + { "name": "Optimize", "switch": "optimize", "comment": "", diff --git a/Templates/MSBuild/FlagTables/v143_CSharp.json b/Templates/MSBuild/FlagTables/v143_CSharp.json index ae1bd47..9ea8f4b 100644 --- a/Templates/MSBuild/FlagTables/v143_CSharp.json +++ b/Templates/MSBuild/FlagTables/v143_CSharp.json @@ -208,6 +208,13 @@ "flags": [] }, { + "name": "DebugType", + "switch": "debug:embedded", + "comment": "", + "value": "embedded", + "flags": [] + }, + { "name": "Optimize", "switch": "optimize", "comment": "", diff --git a/Tests/RunCMake/NinjaMultiConfig/CompileCommands-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CompileCommands-check.cmake new file mode 100644 index 0000000..a1ae6ac --- /dev/null +++ b/Tests/RunCMake/NinjaMultiConfig/CompileCommands-check.cmake @@ -0,0 +1,28 @@ +set(expected_compile_commands +[==[^\[ +{ + "directory": "[^ +]*(/Tests/RunCMake/NinjaMultiConfig/CompileCommands-build|\\\\Tests\\\\RunCMake\\\\NinjaMultiConfig\\\\CompileCommands-build)", + "command": "[^ +]*Debug[^ +]*", + "file": "[^ +]*(/Tests/RunCMake/NinjaMultiConfig/main\.c|\\\\Tests\\\\RunCMake\\\\NinjaMultiConfig\\\\main\.c)" +}, +{ + "directory": "[^ +]*(/Tests/RunCMake/NinjaMultiConfig/CompileCommands-build|\\\\Tests\\\\RunCMake\\\\NinjaMultiConfig\\\\CompileCommands-build)", + "command": "[^ +]*Release[^ +]*", + "file": "[^ +]*(/Tests/RunCMake/NinjaMultiConfig/main\.c|\\\\Tests\\\\RunCMake\\\\NinjaMultiConfig\\\\main\.c)" +} +]$]==]) + +file(READ "${RunCMake_TEST_BINARY_DIR}/compile_commands.json" actual_compile_commands) +if(NOT actual_compile_commands MATCHES "${expected_compile_commands}") + string(REPLACE "\n" "\n " expected_compile_commands_formatted "${expected_compile_commands}") + string(REPLACE "\n" "\n " actual_compile_commands_formatted "${actual_compile_commands}") + string(APPEND RunCMake_TEST_FAILED "Expected compile_commands.json to match:\n ${expected_compile_commands_formatted}\nActual compile_commands.json:\n ${actual_compile_commands_formatted}\n") +endif() diff --git a/Tests/RunCMake/NinjaMultiConfig/CompileCommands.cmake b/Tests/RunCMake/NinjaMultiConfig/CompileCommands.cmake new file mode 100644 index 0000000..fc44d5a --- /dev/null +++ b/Tests/RunCMake/NinjaMultiConfig/CompileCommands.cmake @@ -0,0 +1,3 @@ +enable_language(C) + +add_executable(exe main.c) diff --git a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake index 738bc6c..c040e8f 100644 --- a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake +++ b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake @@ -453,6 +453,11 @@ run_cmake_command(NoUnusedVariables ${CMAKE_COMMAND} ${CMAKE_CURRENT_LIST_DIR} "-DCMAKE_DEFAULT_BUILD_TYPE=Debug" "-DCMAKE_DEFAULT_CONFIGS=all" ) +unset(RunCMake_TEST_BINARY_DIR) + +set(RunCMake_TEST_OPTIONS "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release;-DCMAKE_CROSS_CONFIGS=all;-DCMAKE_EXPORT_COMPILE_COMMANDS=ON") +run_cmake(CompileCommands) +unset(RunCMake_TEST_OPTIONS) # CudaSimple uses separable compilation, which is currently only supported on NVCC. if(CMake_TEST_CUDA) diff --git a/Tests/RunCMake/VS10Project/InterfaceLibSources-check.cmake b/Tests/RunCMake/VS10Project/InterfaceLibSources-check.cmake index bcdc101..1701a36 100644 --- a/Tests/RunCMake/VS10Project/InterfaceLibSources-check.cmake +++ b/Tests/RunCMake/VS10Project/InterfaceLibSources-check.cmake @@ -5,6 +5,7 @@ if(NOT EXISTS "${vcProjectFile}") endif() set(found_iface_h 0) +set(found_int_dir 0) file(STRINGS "${vcProjectFile}" lines) foreach(line IN LISTS lines) if(line MATCHES "<([A-Za-z0-9_]+) +Include=.*iface\\.h") @@ -19,7 +20,15 @@ foreach(line IN LISTS lines) endif() set(found_iface_h 1) endif() + if(line MATCHES "^ *<IntDir [^<>]+>[^<>]+</IntDir>") + set(found_int_dir 1) + endif() endforeach() if(NOT found_iface_h) set(RunCMake_TEST_FAILED "iface.h not referenced in\n ${vcProjectFile}") + return() +endif() +if(NOT found_int_dir) + set(RunCMake_TEST_FAILED "No references to IntDir in\n ${vcProjectFile}") + return() endif() diff --git a/Tests/RunCMake/export/RunCMakeTest.cmake b/Tests/RunCMake/export/RunCMakeTest.cmake index 0e6020f..ee00b27 100644 --- a/Tests/RunCMake/export/RunCMakeTest.cmake +++ b/Tests/RunCMake/export/RunCMakeTest.cmake @@ -18,3 +18,4 @@ run_cmake(DependOnDoubleExport) run_cmake(UnknownExport) run_cmake(NamelinkOnlyExport) run_cmake(SeparateNamelinkExport) +run_cmake(TryCompileExport) diff --git a/Tests/RunCMake/export/TryCompileExport.cmake b/Tests/RunCMake/export/TryCompileExport.cmake new file mode 100644 index 0000000..5ad7c6e --- /dev/null +++ b/Tests/RunCMake/export/TryCompileExport.cmake @@ -0,0 +1,9 @@ +enable_language(CXX) + +add_library(interface INTERFACE) +install(TARGETS interface EXPORT export) +export(EXPORT export) + +add_library(imported IMPORTED INTERFACE) + +try_compile(tc "${CMAKE_CURRENT_BINARY_DIR}/tc" "${CMAKE_CURRENT_SOURCE_DIR}/empty.cpp" LINK_LIBRARIES imported) diff --git a/Tests/RunCMake/include_external_msproject/Program.cs b/Tests/RunCMake/include_external_msproject/Program.cs new file mode 100644 index 0000000..5ed58c8 --- /dev/null +++ b/Tests/RunCMake/include_external_msproject/Program.cs @@ -0,0 +1,9 @@ +namespace ConsoleApp +{ + internal class Program + { + static void Main(string[] args) + { + } + } +} diff --git a/Tests/RunCMake/include_external_msproject/RunCMakeTest.cmake b/Tests/RunCMake/include_external_msproject/RunCMakeTest.cmake index cb0eb18..4fbf147 100644 --- a/Tests/RunCMake/include_external_msproject/RunCMakeTest.cmake +++ b/Tests/RunCMake/include_external_msproject/RunCMakeTest.cmake @@ -10,3 +10,14 @@ if(RunCMake_GENERATOR MATCHES "Visual Studio ([^9]|9[0-9])") run_cmake(SkipGetTargetFrameworkProperties) run_cmake(VSCSharpReference) endif() + +if(RunCMake_GENERATOR MATCHES "^Visual Studio (1[6-9]|[2-9][0-9])") + function(run_VSCSharpOnlyProject) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/VSCSharpOnlyProject-build) + run_cmake(VSCSharpOnlyProject) + set(RunCMake_TEST_NO_CLEAN 1) + set(build_flags /restore) + run_cmake_command(VSCSharpOnlyProject-build ${CMAKE_COMMAND} --build . -- ${build_flags}) + endfunction() + run_VSCSharpOnlyProject() +endif() diff --git a/Tests/RunCMake/include_external_msproject/VSCSharpOnlyProject.cmake b/Tests/RunCMake/include_external_msproject/VSCSharpOnlyProject.cmake new file mode 100644 index 0000000..e7e0b99 --- /dev/null +++ b/Tests/RunCMake/include_external_msproject/VSCSharpOnlyProject.cmake @@ -0,0 +1,9 @@ +project(VSCSharpOnlyProject) + +file(COPY + ${CMAKE_CURRENT_SOURCE_DIR}/Program.cs + ${CMAKE_CURRENT_SOURCE_DIR}/consoleapp.csproj + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + +include_external_msproject( + test "${CMAKE_CURRENT_BINARY_DIR}/consoleapp.csproj") diff --git a/Tests/RunCMake/include_external_msproject/consoleapp.csproj b/Tests/RunCMake/include_external_msproject/consoleapp.csproj new file mode 100644 index 0000000..2894848 --- /dev/null +++ b/Tests/RunCMake/include_external_msproject/consoleapp.csproj @@ -0,0 +1,14 @@ +<Project Sdk="Microsoft.NET.Sdk"> + <PropertyGroup> + <OutputType>Exe</OutputType> + <TargetFramework>net472</TargetFramework> + <RootNamespace>ConsoleApp</RootNamespace> + <AssemblyName>ConsoleApp</AssemblyName> + <PlatformTarget>x64</PlatformTarget> + <EnableDefaultItems>false</EnableDefaultItems> + </PropertyGroup> + + <ItemGroup> + <Compile Include="Program.cs" /> + </ItemGroup> +</Project> diff --git a/Utilities/Release/macos/sign-notarize.bash b/Utilities/Release/macos/sign-notarize.bash index fe27afe..55ed591 100755 --- a/Utilities/Release/macos/sign-notarize.bash +++ b/Utilities/Release/macos/sign-notarize.bash @@ -1,6 +1,6 @@ #!/usr/bin/env bash set -e -readonly usage='usage: sign-notarize.bash -i <id> -d <dev-acct> -k <key-item> [-p <provider>] [--] <package>.dmg +readonly usage='usage: sign-notarize.bash -i <id> -k <keychain-profile> [--] <package>.dmg Sign and notarize the "CMake.app" bundle inside the given "<package>.dmg" disk image. Also produce a "<package>.tar.gz" tarball containing the same "CMake.app". @@ -8,9 +8,22 @@ Also produce a "<package>.tar.gz" tarball containing the same "CMake.app". Options: -i <id> Signing Identity - -d <dev-acct> Developer account name - -k <key-item> Keychain item containing account credentials - -p <provider> Provider short name + -k <keychain-profile> Keychain profile containing stored credentials + +Create the keychain profile ahead of time using + + xcrun notarytool store-credentials <keychain-profile> \ + --apple-id <dev-acct> --team-id <team-id> [--password <app-specific-password>] + +where: + + <dev-acct> is an Apple ID of a developer account + <team-id> is from https://developer.apple.com/account/#!/membership + <app-specific-password> is generated via https://support.apple.com/en-us/HT204397 + If --password is omitted, notarytool will prompt for it. + +This creates a keychain item called "com.apple.gke.notary.tool" with an +account name "com.apple.gke.notary.tool.saved-creds.<keychain-profile>". ' cleanup() { @@ -29,15 +42,11 @@ die() { } id='' -dev_acct='' -key_item='' -provider='' +keychain_profile='' while test "$#" != 0; do case "$1" in -i) shift; id="$1" ;; - -d) shift; dev_acct="$1" ;; - -k) shift; key_item="$1" ;; - -p) shift; provider="$1" ;; + -k) shift; keychain_profile="$1" ;; --) shift ; break ;; -*) die "$usage" ;; *) break ;; @@ -51,18 +60,14 @@ esac test "$#" = 0 || die "$usage" # Verify arguments. -if test -z "$id" -o -z "$dev_acct" -o -z "$key_item"; then +if test -z "$id" -o -z "$keychain_profile"; then die "$usage" fi -if test -n "$provider"; then - provider="--provider $provider" -fi # Verify environment. -if ! xcnotary="$(type -p xcnotary)"; then - die "'xcnotary' not found in PATH" +if ! xcrun --find notarytool 2>/dev/null; then + die "'xcrun notarytool' not found" fi -readonly xcnotary readonly tmpdir="$(mktemp -d)" @@ -95,7 +100,9 @@ codesign --verify --timestamp --options=runtime --verbose --deep \ "$vol_path/CMake.app/Contents/bin/cpack" \ "$vol_path/CMake.app" -xcnotary notarize "$vol_path/CMake.app" -d "$dev_acct" -k "$key_item" $provider +ditto -c -k --keepParent "$vol_path/CMake.app" "$tmpdir/CMake.app.zip" +xcrun notarytool submit "$tmpdir/CMake.app.zip" --keychain-profile "$keychain_profile" --wait +xcrun stapler staple "$vol_path/CMake.app" # Create a tarball of the volume next to the original disk image. readonly tar_gz="${dmg/%.dmg/.tar.gz}" |