cmake_language
Новое в версии 3.18.
Вызов метаопераций на команды CMake.
Синтаксис
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>...) cmake_language(GET_MESSAGE_LOG_LEVEL <out-var>)
Введение
Эта команда вызовет метаоперации на встроенные команды CMake или те, которые были созданы с помощью команд macro() или function().
cmake_language не вводит новую переменную или область политики.
Вызов команд
-
cmake_language(CALL <command> [<arg>...]) -
Вызывает команду с указанным именем
<command>с заданными аргументами (если таковые имеются). Например, код:set(message_command "message") cmake_language(CALL ${message_command} STATUS "Hello World!")эквивалентен
message(STATUS "Hello World!")
Примечание
Для обеспечения согласованности кода запрещены следующие команды:
-
if/elseif/else/endif -
block/endblock -
while/endwhile -
foreach/endforeach -
function/endfunction -
macro/endmacro
-
Вычисление кода
-
cmake_language(EVAL CODE <code>...) -
Вычисляет
<code>...как код 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()" )эквивалентен
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)
Отложенные вызовы
Новое в версии 3.19.
-
cmake_language(DEFER <options>... CALL <command> [<arg>...]) -
Планирует вызов команды с указанным именем
<command>с заданными аргументами (если таковые имеются) на более позднее время. По умолчанию отложенные вызовы выполняются как если бы они были написаны в конце файлаCMakeLists.txtтекущего каталога, за исключением того, что они выполняются даже после вызоваreturn(). Ссылки на переменные в аргументах вычисляются в момент выполнения отложенного вызова.Доступны следующие параметры:
-
DIRECTORY <dir> -
Планирует вызов для конца указанного каталога вместо текущего. Указанный
<dir>может ссылаться на каталог исходников или соответствующий двоичный каталог. Относительные пути рассматриваются как относительные к текущему каталогу исходников.Указанный каталог должен быть известен CMake, являясь либо корневым каталогом, либо добавленным с помощью команды
add_subdirectory(). Кроме того, указанный каталог не должен быть ещё завершен. Это означает, что он может быть текущим каталогом или одним из его предков. -
ID <id> -
Указывает идентификатор для отложенного вызова. Идентификатор
<id>не может быть пустым и не может начинаться с заглавной буквыA-Z. Идентификатор<id>может начинаться с подчеркивания (_) только если он был сгенерирован автоматически предыдущим вызовом, который использовалID_VARдля получения идентификатора. -
ID_VAR <var> -
Указывает переменную, в которой нужно хранить идентификатор для отложенного вызова. Если
ID <id>не указан, будет сгенерирован новый идентификатор, и сгенерированный идентификатор будет начинаться с подчеркивания (_).
Текущий список отложенных вызовов можно получить:
cmake_language(DEFER [DIRECTORY <dir>] GET_CALL_IDS <var>)
Это сохранит в
<var>список отложенных идентификаторов вызовов, разделённых точкой с запятой. Идентификаторы относятся к области каталога, в который отложены вызовы (т. е. где они будут выполнены), которая может отличаться от области, в которой они были созданы. ПараметрDIRECTORYможет использоваться для указания области, для которой нужно получить идентификаторы вызовов. Если этот параметр не указан, будут возвращены идентификаторы вызовов для текущей области каталога.Подробные сведения об определённом вызове можно получить по его идентификатору:
cmake_language(DEFER [DIRECTORY <dir>] GET_CALL <id> <var>)
Это сохранит в
<var>список, разделённый точкой с запятой, в котором первый элемент — имя вызываемой команды, а оставшиеся элементы — её невычисленные аргументы (любые символы;включены буквально и не могут быть отличимы от нескольких аргументов). Если несколько вызовов запланированы с одинаковым идентификатором, это извлекает первый из них. Если в указанной областиDIRECTORY(или текущей области каталога, если параметрDIRECTORYне указан) нет вызовов с заданным идентификатором, в переменную запишется пустая строка.Отложенные вызовы можно отменить по их идентификатору:
cmake_language(DEFER [DIRECTORY <dir>] CANCEL_CALL <id>...)
Это отменяет все отложенные вызовы, соответствующие любому из заданных идентификаторов в указанной области
DIRECTORY(или текущей области каталога, если параметрDIRECTORYне указан). Неизвестные идентификаторы игнорируются без сообщений об ошибках. -
Примеры отложенных вызовов
Например, код:
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")
выводит:
Immediate Message Deferred Message
Переменная Cancelled Message никогда не выводится, потому что её команда отменена. Ссылка на переменную deferred_message не вычисляется до места вызова, поэтому её можно установить после планирования отложенного вызова.
Для немедленного вычисления ссылок на переменные при планировании отложенного вызова оберните его в cmake_language(EVAL). Однако обратите внимание, что аргументы будут перевычисляться в отложенном вызове, хотя это можно избежать, используя аргументы в квадратных скобках. Например:
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")
также выводит:
Immediate Message Deferred Message 1 Deferred Message 2
Поставщики зависимостей
Новое в версии 3.24.
Примечание
Более подробное введение в эту функцию можно найти в Руководстве по использованию зависимостей.
-
cmake_language(SET_DEPENDENCY_PROVIDER <command> SUPPORTED_METHODS <methods>...) -
При вызове
find_package()илиFetchContent_MakeAvailable(), вызов может быть перенаправлен поставщику зависимостей, который затем имеет возможность выполнить запрос. Если запрос относится к одной из зависимостей<methods>, указанных при установке поставщика, CMake вызывает метод<command>поставщика с набором аргументов, специфичных для метода. Если поставщик не выполняет запрос, или если поставщик не поддерживает метод запроса, или поставщик не установлен, используется встроенная реализацияfind_package()илиFetchContent_MakeAvailable()для выполнения запроса обычным способом.Можно указать один или несколько из следующих значений для параметра
<methods>при установке поставщика:-
FIND_PACKAGE - Поставщик команды принимает запросы
find_package(). -
FETCHCONTENT_MAKEAVAILABLE_SERIAL - Поставщик команды принимает запросы
FetchContent_MakeAvailable(). Он ожидает, что каждая зависимость будет подаваться поставщику команды по одной, а не весь список сразу.
Одновременно может быть установлен только один поставщик. Если поставщик уже установлен при вызове
cmake_language(SET_DEPENDENCY_PROVIDER), новый поставщик заменяет предыдущий. Указанный<command>должен уже существовать при вызовеcmake_language(SET_DEPENDENCY_PROVIDER). В качестве специального случая, предоставление пустой строки для<command>и отсутствие<methods>удалит любого ранее установленного поставщика.Поставщик зависимостей может быть установлен только при обработке одного из файлов, указанных в переменной
CMAKE_PROJECT_TOP_LEVEL_INCLUDES. Таким образом, поставщики зависимостей могут быть установлены только как часть первого вызоваproject(). Вызовcmake_language(SET_DEPENDENCY_PROVIDER)вне этого контекста приведёт к ошибке.Примечание
Выбор поставщика зависимостей всегда должен осуществляться под контролем пользователя. Для удобства проект может предоставить файл, который пользователи могут указать в переменной
CMAKE_PROJECT_TOP_LEVEL_INCLUDES, но использование такого файла всегда должно быть выбором пользователя. -
Команды поставщика
Поставщики определяют одну <command> для обработки запросов. Имя команды должно быть специфичным для данного поставщика, а не слишком общим, которое может использовать и другой поставщик. Это позволяет пользователям создавать свои собственные поставщики, комбинируя различные поставщики. Рекомендуемая форма — xxx_provide_dependency(), где xxx — часть, специфичная для поставщика (например, vcpkg_provide_dependency(), conan_provide_dependency(), ourcompany_provide_dependency(), и т. д.).
xxx_provide_dependency(<method> [<method-specific-args>...])
Так как некоторые методы ожидают, что определённые переменные будут установлены в вызывающей области, команда поставщика обычно реализуется как макрос, а не функция. Это гарантирует, что она не вводит новую область переменных.
Аргументы, которые CMake передает поставщику зависимостей, зависят от типа запроса. Первый аргумент всегда — метод, и он может быть только одним из <methods>, который был указан при настройке поставщика.
-
FIND_PACKAGE -
Значение
<method-specific-args>будет представлять собой всё, что было передано в вызовfind_package(), который запросил зависимость. Таким образом, первым из этих<method-specific-args>всегда будет имя зависимости. Имена зависимостей чувствительны к регистру для этого метода, посколькуfind_package()также обрабатывает их как чувствительные к регистру.Если команда-поставщик выполняет запрос, она должна установить ту же переменную, что и
find_package()ожидает для установки. Для зависимости с именемdepName, поставщик должен установитьdepName_FOUNDв значение true, если он выполнил запрос. Если поставщик возвращается без установки этой переменной, CMake предположит, что запрос не был выполнен, и вернётся к встроенной реализации.Если поставщику нужно вызвать встроенную реализацию
find_package()в рамках своей обработки, он может сделать это, включив ключевое словоBYPASS_PROVIDERв качестве одного из аргументов. -
FETCHCONTENT_MAKEAVAILABE_SERIAL -
Значение
<method-specific-args>будет представлять собой всё, что было передано в вызовFetchContent_Declare(), соответствующий запрошенной зависимости, с последующими исключениями:- Если
SOURCE_DIRилиBINARY_DIRне были частью исходных объявленных аргументов, они будут добавлены со своими значениями по умолчанию. - Если
FETCHCONTENT_TRY_FIND_PACKAGE_MODEустановлено вNEVER, любыеFIND_PACKAGE_ARGSбудут опущены. - Ключевое слово
OVERRIDE_FIND_PACKAGEвсегда опускается.
Первый из
<method-specific-args>всегда будет именем зависимости. Имена зависимостей нечувствительны к регистру для этого метода, посколькуFetchContentтакже обрабатывает их как нечувствительные к регистру.Если поставщик выполняет запрос, он должен вызвать
FetchContent_SetPopulated(), передав имя зависимости в качестве первого аргумента. АргументыSOURCE_DIRиBINARY_DIRдля этой команды должны быть указаны только в том случае, если поставщик делает доступными каталоги исходного кода и сборки зависимости точно так же, как и встроенная командаFetchContent_MakeAvailable().Если поставщик возвращается без вызова
FetchContent_SetPopulated()для указанной зависимости, CMake предположит, что запрос не был выполнен, и вернётся к встроенной реализации.Обратите внимание, что пустые аргументы могут быть значимыми для этого метода (например, пустая строка после ключевого слова
GIT_SUBMODULES). Поэтому, если передавать эти аргументы другой команде, необходимо проявлять особую осторожность, чтобы избежать того, что такие аргументы будут безмолвно пропущены.Если
FETCHCONTENT_SOURCE_DIR_<uppercaseDepName>установлено, поставщик зависимостей никогда не увидит запросы для зависимости<depName>для этого метода. Когда пользователь устанавливает такую переменную, он явно переопределяет, откуда получать эту зависимость, и берёт на себя ответственность за то, что его переопределённая версия соответствует всем требованиям к этой зависимости и совместима с другими элементами проекта, использующими её. В зависимости от значенияFETCHCONTENT_TRY_FIND_PACKAGE_MODEи от того, был ли задан параметрOVERRIDE_FIND_PACKAGEдляFetchContent_Declare(), установкаFETCHCONTENT_SOURCE_DIR_<uppercaseDepName>также может предотвратить получение запросов поставщиком зависимостей для вызоваfind_package(depName). - Если
Примеры поставщиков
В этом первом примере перехватываются только вызовы find_package(). Команда поставщика запускает внешнюю утилиту, которая копирует соответствующие артефакты в каталог, специфичный для поставщика, если эта утилита знает о зависимости. Затем она полагается на встроенную реализацию для поиска этих артефактов. Вызовы FetchContent_MakeAvailable() не пройдут через поставщика.
# 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
)
Пользователь обычно будет использовать вышеуказанный файл следующим образом:
cmake -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=/path/to/mycomp_provider.cmake ...
Следующий пример демонстрирует поставщика, который принимает оба метода, но обрабатывает только одну конкретную зависимость. Он обеспечивает предоставление Google Test с помощью FetchContent, но оставляет все остальные зависимости для выполнения встроенной реализацией CMake. Он принимает несколько разных имён, что демонстрирует один из способов решения проблем с проектами, которые жестко кодируют необычный или нежелательный способ добавления этой конкретной зависимости в сборку. Пример также демонстрирует, как использовать команду list() для сохранения переменных, которые могут быть перезаписаны вызовом FetchContent_MakeAvailable().
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
)
Последний пример демонстрирует, как изменить аргументы для вызова find_package(). Он принудительно добавляет ключевое слово QUIET ко всем таким вызовам. Он использует ключевое слово BYPASS_PROVIDER для предотвращения рекурсивного вызова команды поставщика для той же зависимости.
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
)
Получение текущего уровня ведения журнала сообщений
Введено в версии 3.25.
-
cmake_language(GET_MESSAGE_LOG_LEVEL <output_variable>) -
Записывает текущий уровень ведения журнала
message()в указанный<output_variable>.См.
message()для возможных уровней ведения журнала.Текущий уровень ведения журнала сообщений может быть задан либо с помощью параметра командной строки
--log-levelпрограммыcmake(1), либо с помощью переменнойCMAKE_MESSAGE_LOG_LEVEL.Если заданы и параметр командной строки, и переменная, приоритет имеет параметр командной строки. Если ни один из них не задан, возвращается уровень ведения журнала по умолчанию.
© 2000–2024 Kitware, Inc. and Contributors
Licensed under the BSD 3-clause License.
https://cmake.org/cmake/help/v3.27/command/cmake_language.html