| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- cmake_language
- --------------
- .. versionadded:: 3.18
- Call meta-operations on CMake commands.
- Synopsis
- ^^^^^^^^
- .. parsed-literal::
- cmake_language(`CALL`_ <command> [<arg>...])
- cmake_language(`EVAL`_ CODE <code>...)
- cmake_language(`DEFER`_ <options>... CALL <command> [<arg>...])
- cmake_language(`SET_DEPENDENCY_PROVIDER`_ <command> SUPPORTED_METHODS <methods>...)
- Introduction
- ^^^^^^^^^^^^
- This command will call meta-operations on built-in CMake commands or
- those created via the :command:`macro` or :command:`function` commands.
- ``cmake_language`` does not introduce a new variable or policy scope.
- Calling Commands
- ^^^^^^^^^^^^^^^^
- .. _CALL:
- .. code-block:: cmake
- cmake_language(CALL <command> [<arg>...])
- Calls the named ``<command>`` with the given arguments (if any).
- For example, the code:
- .. code-block:: cmake
- set(message_command "message")
- cmake_language(CALL ${message_command} STATUS "Hello World!")
- is equivalent to
- .. code-block:: cmake
- message(STATUS "Hello World!")
- .. note::
- To ensure consistency of the code, the following commands are not allowed:
- * ``if`` / ``elseif`` / ``else`` / ``endif``
- * ``while`` / ``endwhile``
- * ``foreach`` / ``endforeach``
- * ``function`` / ``endfunction``
- * ``macro`` / ``endmacro``
- Evaluating Code
- ^^^^^^^^^^^^^^^
- .. _EVAL:
- .. code-block:: cmake
- cmake_language(EVAL CODE <code>...)
- Evaluates the ``<code>...`` as CMake code.
- For example, the code:
- .. code-block:: cmake
- set(A TRUE)
- set(B TRUE)
- set(C TRUE)
- set(condition "(A AND B) OR C")
- cmake_language(EVAL CODE "
- if (${condition})
- message(STATUS TRUE)
- else()
- message(STATUS FALSE)
- endif()"
- )
- is equivalent to
- .. code-block:: cmake
- set(A TRUE)
- set(B TRUE)
- set(C TRUE)
- set(condition "(A AND B) OR C")
- file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/eval.cmake "
- if (${condition})
- message(STATUS TRUE)
- else()
- message(STATUS FALSE)
- endif()"
- )
- include(${CMAKE_CURRENT_BINARY_DIR}/eval.cmake)
- Deferring Calls
- ^^^^^^^^^^^^^^^
- .. versionadded:: 3.19
- .. _DEFER:
- .. code-block:: cmake
- cmake_language(DEFER <options>... CALL <command> [<arg>...])
- Schedules a call to the named ``<command>`` with the given arguments (if any)
- to occur at a later time. By default, deferred calls are executed as if
- written at the end of the current directory's ``CMakeLists.txt`` file,
- except that they run even after a :command:`return` call. Variable
- references in arguments are evaluated at the time the deferred call is
- executed.
- The options are:
- ``DIRECTORY <dir>``
- Schedule the call for the end of the given directory instead of the
- current directory. The ``<dir>`` may reference either a source
- directory or its corresponding binary directory. Relative paths are
- treated as relative to the current source directory.
- The given directory must be known to CMake, being either the top-level
- directory or one added by :command:`add_subdirectory`. Furthermore,
- the given directory must not yet be finished processing. This means
- it can be the current directory or one of its ancestors.
- ``ID <id>``
- Specify an identification for the deferred call.
- The ``<id>`` may not be empty and may not begin with a capital letter ``A-Z``.
- The ``<id>`` may begin with an underscore (``_``) only if it was generated
- automatically by an earlier call that used ``ID_VAR`` to get the id.
- ``ID_VAR <var>``
- Specify a variable in which to store the identification for the
- deferred call. If ``ID <id>`` is not given, a new identification
- will be generated and the generated id will start with an underscore (``_``).
- The currently scheduled list of deferred calls may be retrieved:
- .. code-block:: cmake
- cmake_language(DEFER [DIRECTORY <dir>] GET_CALL_IDS <var>)
- This will store in ``<var>`` a :ref:`semicolon-separated list <CMake Language
- Lists>` of deferred call ids. The ids are for the directory scope in which
- the calls have been deferred to (i.e. where they will be executed), which can
- be different to the scope in which they were created. The ``DIRECTORY``
- option can be used to specify the scope for which to retrieve the call ids.
- If that option is not given, the call ids for the current directory scope will
- be returned.
- Details of a specific call may be retrieved from its id:
- .. code-block:: cmake
- cmake_language(DEFER [DIRECTORY <dir>] GET_CALL <id> <var>)
- This will store in ``<var>`` a :ref:`semicolon-separated list <CMake Language
- Lists>` in which the first element is the name of the command to be
- called, and the remaining elements are its unevaluated arguments (any
- contained ``;`` characters are included literally and cannot be distinguished
- from multiple arguments). If multiple calls are scheduled with the same id,
- this retrieves the first one. If no call is scheduled with the given id in
- the specified ``DIRECTORY`` scope (or the current directory scope if no
- ``DIRECTORY`` option is given), this stores an empty string in the variable.
- Deferred calls may be canceled by their id:
- .. code-block:: cmake
- cmake_language(DEFER [DIRECTORY <dir>] CANCEL_CALL <id>...)
- This cancels all deferred calls matching any of the given ids in the specified
- ``DIRECTORY`` scope (or the current directory scope if no ``DIRECTORY`` option
- is given). Unknown ids are silently ignored.
- Deferred Call Examples
- """"""""""""""""""""""
- For example, the code:
- .. code-block:: cmake
- cmake_language(DEFER CALL message "${deferred_message}")
- cmake_language(DEFER ID_VAR id CALL message "Canceled Message")
- cmake_language(DEFER CANCEL_CALL ${id})
- message("Immediate Message")
- set(deferred_message "Deferred Message")
- prints::
- Immediate Message
- Deferred Message
- The ``Cancelled Message`` is never printed because its command is
- canceled. The ``deferred_message`` variable reference is not evaluated
- until the call site, so it can be set after the deferred call is scheduled.
- In order to evaluate variable references immediately when scheduling a
- deferred call, wrap it using ``cmake_language(EVAL)``. However, note that
- arguments will be re-evaluated in the deferred call, though that can be
- avoided by using bracket arguments. For example:
- .. code-block:: cmake
- set(deferred_message "Deferred Message 1")
- set(re_evaluated [[${deferred_message}]])
- cmake_language(EVAL CODE "
- cmake_language(DEFER CALL message [[${deferred_message}]])
- cmake_language(DEFER CALL message \"${re_evaluated}\")
- ")
- message("Immediate Message")
- set(deferred_message "Deferred Message 2")
- also prints::
- Immediate Message
- Deferred Message 1
- Deferred Message 2
- .. _SET_DEPENDENCY_PROVIDER:
- .. _dependency_providers:
- Dependency Providers
- ^^^^^^^^^^^^^^^^^^^^
- .. versionadded:: 3.24
- .. note:: A high-level introduction to this feature can be found in the
- :ref:`Using Dependencies Guide <dependency_providers_overview>`.
- .. code-block:: cmake
- cmake_language(SET_DEPENDENCY_PROVIDER <command>
- SUPPORTED_METHODS <methods>...)
- When a call is made to :command:`find_package` or
- :command:`FetchContent_MakeAvailable`, the call may be forwarded to a
- dependency provider which then has the opportunity to fulfill the request.
- If the request is for one of the ``<methods>`` specified when the provider
- was set, CMake calls the provider's ``<command>`` with a set of
- method-specific arguments. If the provider does not fulfill the request,
- or if the provider doesn't support the request's method, or no provider
- is set, the built-in :command:`find_package` or
- :command:`FetchContent_MakeAvailable` implementation is used to fulfill
- the request in the usual way.
- One or more of the following values can be specified for the ``<methods>``
- when setting the provider:
- ``FIND_PACKAGE``
- The provider command accepts :command:`find_package` requests.
- ``FETCHCONTENT_MAKEAVAILABLE_SERIAL``
- The provider command accepts :command:`FetchContent_MakeAvailable`
- requests. It expects each dependency to be fed to the provider command
- one at a time, not the whole list in one go.
- Only one provider can be set at any point in time. If a provider is already
- set when ``cmake_language(SET_DEPENDENCY_PROVIDER)`` is called, the new
- provider replaces the previously set one. The specified ``<command>`` must
- already exist when ``cmake_language(SET_DEPENDENCY_PROVIDER)`` is called.
- As a special case, providing an empty string for the ``<command>`` and no
- ``<methods>`` will discard any previously set provider.
- The dependency provider can only be set while processing one of the files
- specified by the :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variable.
- Thus, dependency providers can only be set as part of the first call to
- :command:`project`. Calling ``cmake_language(SET_DEPENDENCY_PROVIDER)``
- outside of that context will result in an error.
- .. note::
- The choice of dependency provider should always be under the user's control.
- As a convenience, a project may choose to provide a file that users can
- list in their :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variable, but
- the use of such a file should always be the user's choice.
- Provider commands
- """""""""""""""""
- Providers define a single ``<command>`` to accept requests. The name of
- the command should be specific to that provider, not something overly
- generic that another provider might also use. This enables users to compose
- different providers in their own custom provider. The recommended form is
- ``xxx_provide_dependency()``, where ``xxx`` is the provider-specific part
- (e.g. ``vcpkg_provide_dependency()``, ``conan_provide_dependency()``,
- ``ourcompany_provide_dependency()``, and so on).
- .. code-block:: cmake
- xxx_provide_dependency(<method> [<method-specific-args>...])
- Because some methods expect certain variables to be set in the calling scope,
- the provider command should typically be implemented as a macro rather than a
- function. This ensures it does not introduce a new variable scope.
- The arguments CMake passes to the dependency provider depend on the type of
- request. The first argument is always the method, and it will only ever
- be one of the ``<methods>`` that was specified when setting the provider.
- ``FIND_PACKAGE``
- The ``<method-specific-args>`` will be everything passed to the
- :command:`find_package` call that requested the dependency. The first of
- these ``<method-specific-args>`` will therefore always be the name of the
- dependency. Dependency names are case-sensitive for this method because
- :command:`find_package` treats them case-sensitively too.
- If the provider command fulfills the request, it must set the same variable
- that :command:`find_package` expects to be set. For a dependency named
- ``depName``, the provider must set ``depName_FOUND`` to true if it fulfilled
- the request. If the provider returns without setting this variable, CMake
- will assume the request was not fulfilled and will fall back to the
- built-in implementation.
- If the provider needs to call the built-in :command:`find_package`
- implementation as part of its processing, it can do so by including the
- ``BYPASS_PROVIDER`` keyword as one of the arguments.
- ``FETCHCONTENT_MAKEAVAILABE_SERIAL``
- The ``<method-specific-args>`` will be everything passed to the
- :command:`FetchContent_Declare` call that corresponds to the requested
- dependency, with the following exceptions:
- * If ``SOURCE_DIR`` or ``BINARY_DIR`` were not part of the original
- declared arguments, they will be added with their default values.
- * If :variable:`FETCHCONTENT_TRY_FIND_PACKAGE_MODE` is set to ``NEVER``,
- any ``FIND_PACKAGE_ARGS`` will be omitted.
- * The ``OVERRIDE_FIND_PACKAGE`` keyword is always omitted.
- The first of the ``<method-specific-args>`` will always be the name of the
- dependency. Dependency names are case-insensitive for this method because
- :module:`FetchContent` also treats them case-insensitively.
- If the provider fulfills the request, it should call
- :command:`FetchContent_SetPopulated`, passing the name of the dependency as
- the first argument. The ``SOURCE_DIR`` and ``BINARY_DIR`` arguments to that
- command should only be given if the provider makes the dependency's source
- and build directories available in exactly the same way as the built-in
- :command:`FetchContent_MakeAvailable` command.
- If the provider returns without calling :command:`FetchContent_SetPopulated`
- for the named dependency, CMake will assume the request was not fulfilled
- and will fall back to the built-in implementation.
- Note that empty arguments may be significant for this method (e.g. an empty
- string following a ``GIT_SUBMODULES`` keyword). Therefore, if forwarding
- these arguments on to another command, extra care must be taken to avoid such
- arguments being silently dropped.
- If ``FETCHCONTENT_SOURCE_DIR_<uppercaseDepName>`` is set, then the
- dependency provider will never see requests for the ``<depName>`` dependency
- for this method. When the user sets such a variable, they are explicitly
- overriding where to get that dependency from and are taking on the
- responsibility that their overriding version meets any requirements for that
- dependency and is compatible with whatever else in the project uses it.
- Depending on the value of :variable:`FETCHCONTENT_TRY_FIND_PACKAGE_MODE`
- and whether the ``OVERRIDE_FIND_PACKAGE`` option was given to
- :command:`FetchContent_Declare`, having
- ``FETCHCONTENT_SOURCE_DIR_<uppercaseDepName>`` set may also prevent the
- dependency provider from seeing requests for a ``find_package(depName)``
- call too.
- Provider Examples
- """""""""""""""""
- This first example only intercepts :command:`find_package` calls. The
- provider command runs an external tool which copies the relevant artifacts
- into a provider-specific directory, if that tool knows about the dependency.
- It then relies on the built-in implementation to then find those artifacts.
- :command:`FetchContent_MakeAvailable` calls would not go through the provider.
- .. code-block:: cmake
- :caption: mycomp_provider.cmake
- # Always ensure we have the policy settings this provider expects
- cmake_minimum_required(VERSION 3.24)
- set(MYCOMP_PROVIDER_INSTALL_DIR ${CMAKE_BINARY_DIR}/mycomp_packages
- CACHE PATH "The directory this provider installs packages to"
- )
- # Tell the built-in implementation to look in our area first, unless
- # the find_package() call uses NO_..._PATH options to exclude it
- list(APPEND CMAKE_MODULE_PATH ${MYCOMP_PROVIDER_INSTALL_DIR}/cmake)
- list(APPEND CMAKE_PREFIX_PATH ${MYCOMP_PROVIDER_INSTALL_DIR})
- macro(mycomp_provide_dependency method package_name)
- execute_process(
- COMMAND some_tool ${package_name} --installdir ${MYCOMP_PROVIDER_INSTALL_DIR}
- COMMAND_ERROR_IS_FATAL ANY
- )
- endmacro()
- cmake_language(
- SET_DEPENDENCY_PROVIDER mycomp_provide_dependency
- SUPPORTED_METHODS FIND_PACKAGE
- )
- The user would then typically use the above file like so::
- cmake -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=/path/to/mycomp_provider.cmake ...
- The next example demonstrates a provider that accepts both methods, but
- only handles one specific dependency. It enforces providing Google Test
- using :module:`FetchContent`, but leaves all other dependencies to be
- fulfilled by CMake's built-in implementation. It accepts a few different
- names, which demonstrates one way of working around projects that hard-code
- an unusual or undesirable way of adding this particular dependency to the
- build. The example also demonstrates how to use the :command:`list` command
- to preserve variables that may be overwritten by a call to
- :command:`FetchContent_MakeAvailable`.
- .. code-block:: cmake
- :caption: mycomp_provider.cmake
- cmake_minimum_required(VERSION 3.24)
- # Because we declare this very early, it will take precedence over any
- # details the project might declare later for the same thing
- include(FetchContent)
- FetchContent_Declare(
- googletest
- GIT_REPOSITORY https://github.com/google/googletest.git
- GIT_TAG e2239ee6043f73722e7aa812a459f54a28552929 # release-1.11.0
- )
- # Both FIND_PACKAGE and FETCHCONTENT_MAKEAVAILABLE_SERIAL methods provide
- # the package or dependency name as the first method-specific argument.
- macro(mycomp_provide_dependency method dep_name)
- if("${dep_name}" MATCHES "^(gtest|googletest)$")
- # Save our current command arguments in case we are called recursively
- list(APPEND mycomp_provider_args ${method} ${dep_name})
- # This will forward to the built-in FetchContent implementation,
- # which detects a recursive call for the same thing and avoids calling
- # the provider again if dep_name is the same as the current call.
- FetchContent_MakeAvailable(googletest)
- # Restore our command arguments
- list(POP_BACK mycomp_provider_args dep_name method)
- # Tell the caller we fulfilled the request
- if("${method}" STREQUAL "FIND_PACKAGE")
- # We need to set this if we got here from a find_package() call
- # since we used a different method to fulfill the request.
- # This example assumes projects only use the gtest targets,
- # not any of the variables the FindGTest module may define.
- set(${dep_name}_FOUND TRUE)
- elseif(NOT "${dep_name}" STREQUAL "googletest")
- # We used the same method, but were given a different name to the
- # one we populated with. Tell the caller about the name it used.
- FetchContent_SetPopulated(${dep_name}
- SOURCE_DIR "${googletest_SOURCE_DIR}"
- BINARY_DIR "${googletest_BINARY_DIR}"
- )
- endif()
- endif()
- endmacro()
- cmake_language(
- SET_DEPENDENCY_PROVIDER mycomp_provide_dependency
- SUPPORTED_METHODS
- FIND_PACKAGE
- FETCHCONTENT_MAKEAVAILABLE_SERIAL
- )
- The final example demonstrates how to modify arguments to a
- :command:`find_package` call. It forces all such calls to have the
- ``QUIET`` keyword. It uses the ``BYPASS_PROVIDER`` keyword to prevent
- calling the provider command recursively for the same dependency.
- .. code-block:: cmake
- :caption: mycomp_provider.cmake
- cmake_minimum_required(VERSION 3.24)
- macro(mycomp_provide_dependency method)
- find_package(${ARGN} BYPASS_PROVIDER QUIET)
- endmacro()
- cmake_language(
- SET_DEPENDENCY_PROVIDER mycomp_provide_dependency
- SUPPORTED_METHODS FIND_PACKAGE
- )
|