FetchContent
Новые в версии 3.11.
Примечание
Руководство Using Dependencies Guide предоставляет общее введение в эту тему. Оно содержит более широкий обзор того, как модуль FetchContent вписывается в общую картину, включая его взаимосвязь с командой find_package(). Рекомендуется ознакомиться с руководством перед изучением деталей ниже.
Обзор
Этот модуль позволяет заполнять контент на этапе конфигурации любым способом, поддерживаемым модулем ExternalProject. В то время как ExternalProject_Add() загружает контент на этапе сборки, модуль FetchContent делает его доступным сразу, позволяя шагу конфигурации использовать контент в командах, таких как add_subdirectory(), include() или операциях file().
Подробности заполнения содержимого должны быть определены отдельно от команды, выполняющей фактическое заполнение. Это разделение гарантирует, что все детали зависимостей будут определены до того, как что-либо попытается использовать их для заполнения контента. Это особенно важно в более сложных иерархиях проектов, где зависимости могут быть общими для нескольких проектов.
Следующий пример демонстрирует типичный случай объявления деталей контента для некоторых зависимостей и последующего его заполнения отдельным вызовом:
FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0 ) FetchContent_Declare( myCompanyIcons URL https://intranet.mycompany.com/assets/iconset_1.12.tar.gz URL_HASH MD5=5588a7b18261c20068beabfb4f530b87 ) FetchContent_MakeAvailable(googletest myCompanyIcons)
Команда FetchContent_MakeAvailable() гарантирует, что указанные зависимости были заполнены, либо предыдущим вызовом, либо путем заполнения их самостоятельно. При выполнении заполнения она также добавит их в основную сборку, если это возможно, чтобы основная сборка могла использовать целевые объекты и т.д. См. документацию команды для получения информации о том, как выполняются эти шаги.
При использовании иерархической структуры проекта, проекты на более высоких уровнях иерархии могут переопределить объявленные детали контента, указанные на более низких уровнях проекта. Первые объявленные детали для данной зависимости имеют приоритет, независимо от того, где в иерархии проекта это происходит. Аналогично, первый вызов, пытающийся заполнить зависимость, «выигрывает», а последующие заполнения используют результат первого, вместо повторного заполнения. См. Примеры, которые демонстрируют этот сценарий.
Модуль FetchContent также поддерживает определение и заполнение контента в одном вызове без проверки того, заполнен ли контент где-либо еще. Это не следует делать в проектах, но может быть уместно для заполнения контента в режиме сценариев CMake script mode. См. FetchContent_Populate() для получения подробной информации.
Команды
-
FetchContent_Declare
-
FetchContent_Declare( <name> <contentOptions>... [EXCLUDE_FROM_ALL] [SYSTEM] [OVERRIDE_FIND_PACKAGE | FIND_PACKAGE_ARGS args...] )
Функция
FetchContent_Declare()записывает параметры, описывающие, как заполнить указанный контент. Если такие детали уже были записаны ранее в этом проекте (независимо от того, где в иерархии проекта), этот и все последующие вызовы для того же контента<name>игнорируются. Этот подход «первый записанный — побеждает» позволяет родительским проектам в иерархических проектах переопределять детали контента дочерних проектов.Контент
<name>может быть любой строкой без пробелов, но хорошей практикой будет использовать только буквы, цифры и символы нижнего подчеркивания. Название будет обрабатываться без учета регистра и должно быть очевидным для представляемого контента. Часто это имя дочернего проекта или значение, заданное для команды верхнего уровняproject()(если это проект CMake). Для известных публичных проектов имя, как правило, должно быть официальным названием проекта. Выбор необычного имени делает маловероятным использование того же имени другими проектами, нуждающимися в том же контенте, что приводит к многократному заполнению контента.Параметры
<contentOptions>могут быть любыми параметрами загрузки, обновления или исправления, которые понимает командаExternalProject_Add(). Шаги конфигурации, сборки, установки и тестирования явно отключены, поэтому параметры, относящиеся к этим шагам, будут проигнорированы. ПараметрSOURCE_SUBDIRявляется исключением, см.FetchContent_MakeAvailable()для получения подробной информации о влиянии этого на поведение.Изменено в версии 3.30: Когда политика
CMP0168установлена вNEW, некоторые параметры, связанные с выводом и каталогами, игнорируются. Подробности см. в документации по политике.В большинстве случаев
<contentOptions>будет просто несколькими параметрами, определяющими метод загрузки и детали метода, такие как тег коммита или хэш архива. Например:FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0 ) FetchContent_Declare( myCompanyIcons URL https://intranet.mycompany.com/assets/iconset_1.12.tar.gz URL_HASH MD5=5588a7b18261c20068beabfb4f530b87 ) FetchContent_Declare( myCompanyCertificates SVN_REPOSITORY svn+ssh://svn.mycompany.com/srv/svn/trunk/certs SVN_REVISION -r12345 )
В случаях, когда контент извлекается из удаленного расположения, и вы не контролируете этот сервер, рекомендуется использовать хэш для
GIT_TAGвместо имени ветки или тега. Хэш коммита более безопасен и помогает подтвердить, что загруженный контент соответствует ожиданиям.Изменено в версии 3.14: Команды для шагов загрузки, обновления или исправления могут получать доступ к терминалу. Это может потребоваться для таких задач, как запросы паролей или отображение прогресса команды в реальном времени.
Добавлена в версии 3.22: Переменные
CMAKE_TLS_VERIFY,CMAKE_TLS_CAINFO,CMAKE_NETRCиCMAKE_NETRC_FILEтеперь предоставляют значения по умолчанию для соответствующих параметров контента, как и дляExternalProject_Add(). Ранее эти переменные игнорировались модулемFetchContent.Добавлена в версии 3.24:
-
FIND_PACKAGE_ARGS -
Этот параметр предназначен для сценариев, когда команда
FetchContent_MakeAvailable()может сначала выполнить вызовfind_package()для удовлетворения зависимости для<name>. По умолчанию такой вызов будет простоfind_package(<name>), ноFIND_PACKAGE_ARGSможно использовать для предоставления дополнительных аргументов, которые будут добавлены после<name>.FIND_PACKAGE_ARGSтакже можно указать без чего-либо после него, что указывает на то, чтоfind_package()по-прежнему может быть вызван, еслиFETCHCONTENT_TRY_FIND_PACKAGE_MODEустановлено вOPT_IN, или не установлено.Обычно не следует указывать
REQUIREDв качестве одного из дополнительных аргументов послеFIND_PACKAGE_ARGS. Это означает, что вызовfind_package()должен быть успешным, поэтому ни одна из других деталей, указанных в вызовеFetchContent_Declare(), не получит возможности быть использована как резервный вариант.Все, что следует за ключевым словом
FIND_PACKAGE_ARGS, добавляется к вызовуfind_package(), поэтому все остальные<contentOptions>должны предшествовать ключевому словуFIND_PACKAGE_ARGS. Если переменнаяCMAKE_FIND_PACKAGE_TARGETS_GLOBALустановлена в true во время вызоваFetchContent_Declare(), ключевое словоGLOBALбудет добавлено к аргументамfind_package(), если оно еще не было указано. Он также будет добавлен, еслиFIND_PACKAGE_ARGSне был задан, ноFETCHCONTENT_TRY_FIND_PACKAGE_MODEбыл установлен вALWAYS.OVERRIDE_FIND_PACKAGEне может использоваться, когда указаноFIND_PACKAGE_ARGS.Поставщики зависимостей описывает другой способ перенаправления вызовов
FetchContent_MakeAvailable().FIND_PACKAGE_ARGSпредназначен для управления проектом, тогда как поставщики зависимостей позволяют пользователям переопределять поведение проекта. -
OVERRIDE_FIND_PACKAGE -
Когда в вызове
FetchContent_Declare(<name> ...)включен этот параметр, последующие вызовыfind_package(<name> ...)будут гарантировать, чтоFetchContent_MakeAvailable(<name>)был вызван, затем будут использоваться конфигурационные файлы пакета в каталогеCMAKE_FIND_PACKAGE_REDIRECTS_DIR(обычно созданныеFetchContent_MakeAvailable()). Это фактически заставляетFetchContent_MakeAvailable()переопределятьfind_package()для указанной зависимости, позволяя первому удовлетворять требования к пакету последнего.FIND_PACKAGE_ARGSне может использоваться, когда указаноOVERRIDE_FIND_PACKAGE.Если поставщик зависимостей был установлен, и проект вызывает
find_package()для зависимости<name>,OVERRIDE_FIND_PACKAGEне помешает поставщику увидеть этот вызов. Поставщики зависимостей всегда имеют возможность перехватить любой прямой вызовfind_package(), за исключением случая, когда этот вызов содержит параметрBYPASS_PROVIDER.
Добавлена в версии 3.25:
-
SYSTEM -
Если указан аргумент
SYSTEM, свойство каталогаSYSTEMподкаталога, добавленного командойFetchContent_MakeAvailable(), будет установлено в true. Это повлияет на неимпортированные цели, созданные в рамках этой команды. См. документацию по свойству целиSYSTEMдля более подробного обсуждения последствий.
Добавлена в версии 3.28:
-
EXCLUDE_FROM_ALL -
Если указан аргумент
EXCLUDE_FROM_ALL, цели в подкаталоге, добавленном командойFetchContent_MakeAvailable(), по умолчанию не будут включены в цельALLи могут быть исключены из файлов проекта IDE. См. документацию по свойству каталогаEXCLUDE_FROM_ALLдля подробного обсуждения последствий.
-
-
FetchContent_MakeAvailable -
Новое в версии 3.14.
FetchContent_MakeAvailable(<name1> [<name2>...])
Эта команда гарантирует, что каждый из перечисленных зависимостей будет доступен проекту к моменту его возвращения. Должна была быть вызвана команда
FetchContent_Declare()для каждой зависимости, и первый такой вызов будет управлять тем, как эта зависимость будет сделана доступной, как описано ниже.Если
<lowercaseName>_SOURCE_DIRне установлено:-
Новое в версии 3.24: Если установлено предоставление зависимостей, вызовите команду поставщика с
FETCHCONTENT_MAKEAVAILABLE_SERIALв качестве первого аргумента, за которым следуют аргументы первого вызоваFetchContent_Declare()для<name>. ЕслиSOURCE_DIRилиBINARY_DIRне были частью исходных объявленных аргументов, они будут добавлены со своими значениями по умолчанию. ЕслиFETCHCONTENT_TRY_FIND_PACKAGE_MODEбыло установлено в значениеNEVERпри объявлении деталей, любыеFIND_PACKAGE_ARGSбудут опушены. Ключевое словоOVERRIDE_FIND_PACKAGEтакже всегда опущено. Если поставщик выполнил запрос,FetchContent_MakeAvailable()посчитает эту зависимость обработанной, пропустит оставшиеся шаги ниже и перейдёт к следующей зависимости в списке. -
Новое в версии 3.24: Если разрешено, будет вызван
find_package(<name> [<args>...]), где<args>...может быть предоставлено параметромFIND_PACKAGE_ARGSвFetchContent_Declare(). Значение переменнойFETCHCONTENT_TRY_FIND_PACKAGE_MODEна момент вызоваFetchContent_Declare()определяет, может лиFetchContent_MakeAvailable()вызватьfind_package(). Если переменнаяCMAKE_FIND_PACKAGE_TARGETS_GLOBALустановлена в значение true во время вызоваFetchContent_MakeAvailable(), она всё ещё влияет на любые импортированные цели, созданные, когда этот вызов в свою очередь вызываетfind_package(), даже если эта переменная была false при объявлении соответствующих деталей.
Если зависимость не была удовлетворена поставщиком или вызовом
find_package(),FetchContent_MakeAvailable()использует следующий алгоритм для обеспечения доступности зависимости:- Если зависимость уже была обработана ранее в этом запуске, установите переменные
<lowercaseName>_POPULATED,<lowercaseName>_SOURCE_DIR, и<lowercaseName>_BINARY_DIRтаким же образом, как при вызовеFetchContent_GetProperties(), затем пропустите оставшиеся шаги ниже и перейдите к следующей зависимости в списке. - Обработайте зависимость, используя детали, записанные при предыдущем вызове
FetchContent_Declare(). Прекратите выполнение с ошибкой, если такие детали не были записаны.FETCHCONTENT_SOURCE_DIR_<uppercaseName>может быть использована для переопределения объявленных деталей и использования содержимого, предоставленного по указанному пути вместо этого. -
Новое в версии 3.24: Убедитесь, что в каталоге
CMAKE_FIND_PACKAGE_REDIRECTS_DIRсодержатся файлы<lowercaseName>-config.cmakeи<lowercaseName>-config-version.cmake(или, аналогично,<name>Config.cmakeи<name>ConfigVersion.cmake). Каталог, на который указывает переменнаяCMAKE_FIND_PACKAGE_REDIRECTS_DIR, очищается в начале каждого запуска CMake. Если после обработки зависимости на предыдущем шаге файла конфигурации не существует, будет создан минимальный файл, которыйincludesлюбой файл<lowercaseName>-extra.cmakeили<name>Extra.cmakeс флагомOPTIONAL(так что файлы могут отсутствовать и не будут генерировать предупреждение). Аналогично, если файла версии конфигурации не существует, будет создан очень простой файл, который установитPACKAGE_VERSION_COMPATIBLEиPACKAGE_VERSION_EXACTв значение true. Это гарантирует, что все последующие вызовыfind_package()для зависимости будут использовать перенаправленный файл конфигурации, независимо от каких-либо требований к версии. CMake не может автоматически определить версию произвольной зависимости, поэтому он не может установитьPACKAGE_VERSION. Когда зависимость подключается черезadd_subdirectory()на следующем шаге, она может выбрать переопределение сгенерированного файла версии конфигурации вCMAKE_FIND_PACKAGE_REDIRECTS_DIRна тот, который также устанавливаетPACKAGE_VERSION. Зависимость также может записать файлы<lowercaseName>-extra.cmakeили<name>Extra.cmakeдля выполнения пользовательской обработки или определения переменных, которые обычно определяет файл конфигурации их стандартного (установленного) пакета (многие проекты не выполняют пользовательскую обработку или не определяют переменные и поэтому в этом нет необходимости). При необходимости основной проект может записать эти файлы вместо этого, если проект зависимости этого не сделает. Это позволяет основному проекту добавить недостающие детали из более старых зависимостей, которые не были или не могут быть обновлены для поддержки этой функциональности. Примеры см. в разделе Интеграция с find_package(). -
Если в корневой папке обработанного содержимого находится файл
CMakeLists.txt, вызовитеadd_subdirectory()для добавления его в основной сборке. Отсутствие файлаCMakeLists.txtне является ошибкой, что позволяет использовать эту команду для зависимостей, которые делают загруженное содержимое доступным по известному пути, но которые не нуждаются или не поддерживают прямое добавление в сборку.Новое в версии 3.18: Параметр
SOURCE_SUBDIRможет быть указан в объявленных деталях, чтобы найти что-то ниже корневой директории вместо этого (то есть, так же, какSOURCE_SUBDIRиспользуется командойExternalProject_Add()). Путь, указанный сSOURCE_SUBDIR, должен быть относительным, и он будет обрабатываться как относительный к корневой директории. Он также может указывать на каталог, не содержащий файлCMakeLists.txt, или даже на несуществующий каталог. Это может быть использовано, чтобы избежать добавления проекта, который содержит файлCMakeLists.txtв своей корневой директории.Новое в версии 3.25: Если ключевое слово
SYSTEMбыло включено в вызовFetchContent_Declare(), ключевое словоSYSTEMбудет добавлено к командеadd_subdirectory().Новое в версии 3.28: Если ключевое слово
EXCLUDE_FROM_ALLбыло включено в вызовFetchContent_Declare(), ключевое словоEXCLUDE_FROM_ALLбудет добавлено к командеadd_subdirectory().Новое в версии 3.29:
CMAKE_EXPORT_FIND_PACKAGE_NAMEустанавливается в имя зависимости перед вызовомadd_subdirectory().
-
Проекты должны стремиться объявлять подробности всех зависимостей, которые они могут использовать, до вызова
FetchContent_MakeAvailable()для любой из них. Это гарантирует, что если какие-либо зависимости также являются подзависимостями одной или нескольких других, основной проект по-прежнему контролирует подробности, которые будут использоваться (потому что он объявляет их первым, прежде чем у зависимостей появится возможность). В следующих примерах кода предположим, что зависимостьuses_otherтакже используетFetchContentдля добавления зависимостиotherвнутри:# WRONG: Should declare all details first FetchContent_Declare(uses_other ...) FetchContent_MakeAvailable(uses_other) FetchContent_Declare(other ...) # Will be ignored, uses_other beat us to it FetchContent_MakeAvailable(other) # Would use details declared by uses_other
# CORRECT: All details declared first, so they will take priority FetchContent_Declare(uses_other ...) FetchContent_Declare(other ...) FetchContent_MakeAvailable(uses_other other)
Обратите внимание, что
CMAKE_VERIFY_INTERFACE_HEADER_SETSявно устанавливается в значение false при входе вFetchContent_MakeAvailable(), и восстанавливается до исходного значения перед возвратом команды. Разработчики обычно хотят проверить только наборы заголовков из основного проекта, а не из зависимостей. Эта локальная манипуляция переменнойCMAKE_VERIFY_INTERFACE_HEADER_SETSобеспечивает это интуитивное поведение. Вы можете использовать переменные, такие какCMAKE_PROJECT_INCLUDEилиCMAKE_PROJECT_<PROJECT-NAME>_INCLUDE, чтобы включить проверку для всех или некоторых зависимостей. Вы также можете установить свойствоVERIFY_INTERFACE_HEADER_SETSотдельных целевых объектов.
-
FetchContent_Populate -
Команда
FetchContent_Populate()— это автономный вызов, который можно использовать для выполнения заполнения контента как изолированной операции. Редко используется, проекты почти всегда должны использоватьFetchContent_Declare()иFetchContent_MakeAvailable()вместо нее. Основной случай использованияFetchContent_Populate()— в режиме сценариев CMake в рамках реализации некоторой другой пользовательской функции более высокого уровня.FetchContent_Populate( <name> [QUIET] [SUBBUILD_DIR <subBuildDir>] [SOURCE_DIR <srcDir>] [BINARY_DIR <binDir>] ... )
После
<name>должен быть указан как минимум один параметр, в противном случае вызов интерпретируется иначе (см. ниже). Поддерживаемые параметры дляFetchContent_Populate()такие же, как дляFetchContent_Declare(), за несколькими исключениями. Следующие параметры не относятся к заполнению контента с помощьюFetchContent_Populate()и поэтому не поддерживаются:EXCLUDE_FROM_ALLSYSTEMOVERRIDE_FIND_PACKAGEFIND_PACKAGE_ARGS
Несколько параметров, показанных в сигнатуре выше, либо специфичны для
FetchContent_Populate(), либо их поведение немного отличается от того, какExternalProject_Add()обрабатывает их:-
QUIET -
Параметр
QUIETможет быть указан для скрытия вывода, связанного с заполнением указанного контента. Если заполнение завершается неудачей, вывод будет показан независимо от того, был ли указан этот параметр или нет, чтобы можно было диагностировать причину сбоя. ПеременнаяFETCHCONTENT_QUIETне влияет на вызовыFetchContent_Populate()с указанными деталями контента напрямую.Изменено в версии 3.30: Параметр
QUIETи переменнаяFETCHCONTENT_QUIETне влияют, когда политикаCMP0168установлена вNEW. В этом случае вывод по умолчанию остается тихим, но уровень детализации вывода регулируется уровнем ведения журнала сообщений (см.CMAKE_MESSAGE_LOG_LEVELи--log-level). -
SUBBUILD_DIR -
Аргумент
SUBBUILD_DIRможет быть предоставлен для изменения расположения подсборки, созданной для выполнения заполнения. Значение по умолчанию —${CMAKE_CURRENT_BINARY_DIR}/<lowercaseName>-subbuild, и обычно нет необходимости его изменять. Если указан относительный путь, он будет интерпретироваться относительноCMAKE_CURRENT_BINARY_DIR. Этот параметр не следует путать с параметромSOURCE_SUBDIR, который влияет только на командуFetchContent_MakeAvailable().Изменено в версии 3.30:
SUBBUILD_DIRигнорируется, когда политикаCMP0168установлена вNEW, так как в этом случае подсборка не используется. -
SOURCE_DIR, BINARY_DIR -
Аргументы
SOURCE_DIRиBINARY_DIRподдерживаютсяExternalProject_Add(), ноFetchContent_Populate()используют разные значения по умолчанию.SOURCE_DIRимеет значение по умолчанию${CMAKE_CURRENT_BINARY_DIR}/<lowercaseName>-src, аBINARY_DIRимеет значение по умолчанию${CMAKE_CURRENT_BINARY_DIR}/<lowercaseName>-build. Если указан относительный путь, он будет интерпретироваться относительноCMAKE_CURRENT_BINARY_DIR.
Помимо вышеуказанных явных параметров, все другие нераспознанные параметры передаются без изменений в
ExternalProject_Add()для настройки шагов загрузки, исправления и обновления. Следующие параметры явно запрещены (они отключены командойFetchContent_Populate()):CONFIGURE_COMMANDBUILD_COMMANDINSTALL_COMMANDTEST_COMMAND
В этом формате переменные
FETCHCONTENT_FULLY_DISCONNECTEDиFETCHCONTENT_UPDATES_DISCONNECTEDи политикаCMP0170игнорируются.После возврата этой формы
FetchContent_Populate()в области вызывающей программы будут установлены следующие переменные:-
<lowercaseName>_SOURCE_DIR -
Расположение, где можно найти заполненный контент по возвращении.
-
<lowercaseName>_BINARY_DIR -
Директория, изначально предназначенная для использования в качестве соответствующей директории сборки, но маловероятно, что она будет актуальна при использовании этой формы команды.
Если использовать
FetchContent_Populate()в режиме сценариев CMake, имейте в виду, что реализация настраивает подсборку, а следовательно, требует наличия генератора CMake и инструмента сборки. Если эти компоненты не могут быть найдены по умолчанию, то переменныеCMAKE_GENERATORи, возможно,CMAKE_MAKE_PROGRAMдолжны быть установлены соответствующим образом в командной строке, вызывающей сценарий.Изменено в версии 3.30: Если политика
CMP0168установлена вNEW, подсборка не используется. В режиме сценариев CMake это позволяет вызватьFetchContent_Populate()без инструмента сборки или генератора CMake.Добавлена в версии 3.18: Добавлена поддержка параметра
DOWNLOAD_NO_EXTRACT.
Команда поддерживает другую форму, хотя ее использование больше не рекомендуется:
FetchContent_Populate(<name>)
Изменено в версии 3.30: Эта форма устарела. Политика CMP0169 обеспечивает обратную совместимость для проектов, которым все еще требуется использовать эту форму, но проекты следует обновить, чтобы использовать FetchContent_MakeAvailable() вместо этого.
В этой форме единственным аргументом, переданным FetchContent_Populate() является <name>. В этом случае команда предполагает, что детали контента были записаны ранее вызовом FetchContent_Declare(). Детали хранятся в глобальной переменной, поэтому они не зависят от таких вещей, как область видимости переменных или каталогов. Поэтому неважно, где в проекте были ранее объявлены детали, достаточно, чтобы они были объявлены до вызова FetchContent_Populate(). Затем эти сохраненные детали используются для заполнения контента с помощью метода, основанного на ExternalProject_Add() (см. политику CMP0168 для важных аспектов поведения этого процесса).
При возвращении этой формы FetchContent_Populate() следующие переменные будут установлены в области видимости вызывающего объекта:
-
<lowercaseName>_POPULATED -
Это значение всегда будет установлено в
TRUEвызовом. -
<lowercaseName>_SOURCE_DIR -
Расположение, где можно найти заполненный контент по возвращении.
-
<lowercaseName>_BINARY_DIR -
Каталог, предназначенный для использования в качестве соответствующего каталога сборки.
Значения этих трех переменных также можно получить из любого места иерархии проекта, используя команду FetchContent_GetProperties().
Реализация гарантирует, что если контент уже был заполнен в предыдущем запуске CMake, этот контент будет повторно использован, а не повторно заполняться. В общем случае, когда заполнение включает загрузку контента, стоимость загрузки оплачивается только один раз. Однако обратите внимание, что вызов FetchContent_Populate(<name>) с тем же <name> более одного раза в одном запуске CMake является ошибкой. См. FetchContent_GetProperties() для того, как определить, уже ли было выполнено заполнение <name> в текущем запуске.
-
FetchContent_GetProperties -
При использовании сохраненных деталей контента, вызов
FetchContent_MakeAvailable()илиFetchContent_Populate()записывает информацию в глобальные переменные, которую можно запросить в любое время. Эта информация может включать каталоги исходного кода и бинарных файлов, связанных с контентом, а также информацию о том, был ли контент заполнен во время текущего запуска конфигурации.FetchContent_GetProperties( <name> [SOURCE_DIR <srcDirVar>] [BINARY_DIR <binDirVar>] [POPULATED <doneVar>] )
Опции
SOURCE_DIR,BINARY_DIR, иPOPULATEDмогут быть использованы для указания свойств, которые необходимо получить. Каждая опция принимает значение, которое является именем переменной, в которой должно храниться это свойство. Однако в большинстве случаев указывается только<name>, в этом случае вызов установит те же переменные, что и вызовFetchContent_MakeAvailable(name)илиFetchContent_Populate(name). Обратите внимание, что значенияSOURCE_DIRиBINARY_DIRмогут быть пустыми, если вызов выполняется поставщиком зависимостей.Эта команда редко необходима при использовании
FetchContent_MakeAvailable(). Она чаще используется в рамках реализации устаревшего шаблона сFetchContent_Populate(), что гарантирует, что соответствующие переменные всегда будут определены независимо от того, было ли выполнено заполнение в другом месте проекта:# WARNING: This pattern is deprecated, don't use it! # # Check if population has already been performed FetchContent_GetProperties(depname) if(NOT depname_POPULATED) # Fetch the content using previously declared details FetchContent_Populate(depname) # Set custom variables, policies, etc. # ... # Bring the populated content into the build add_subdirectory(${depname_SOURCE_DIR} ${depname_BINARY_DIR}) endif()
-
FetchContent_SetPopulated -
Новое в версии 3.24.
Примечание
Эта команда должна вызываться только поставщиками зависимостей. Вызов ее в любом другом контексте не поддерживается, и в будущих версиях CMake может возникнуть ошибка в таких случаях.
FetchContent_SetPopulated( <name> [SOURCE_DIR <srcDir>] [BINARY_DIR <binDir>] )
Если команда-поставщик выполняет запрос
FETCHCONTENT_MAKEAVAILABLE_SERIAL, она должна вызвать эту функцию перед возвратом. АргументыSOURCE_DIRиBINARY_DIRмогут быть использованы для указания значений, которыеFetchContent_GetProperties()должен возвращать для соответствующих аргументов. Предоставляйте толькоSOURCE_DIRиBINARY_DIRесли они имеют такое же значение, как если бы они были заполнены встроенной реализациейFetchContent_MakeAvailable().
Переменные
Несколько переменных кеша могут влиять на поведение, когда детали из вызова FetchContent_Declare() используются для заполнения контента.
Примечание
Все эти переменные предназначены для разработчика, чтобы настроить поведение. Их обычно не следует устанавливать проектом.
-
FETCHCONTENT_BASE_DIR -
В большинстве случаев сохраненные детали не указывают никаких параметров, относящихся к каталогам для использования внутренних подсборок, окончательных исходных и сборки. Обычно лучше всего оставить эти решения модулю
FetchContentдля обработки от имени проекта. Переменная кешаFETCHCONTENT_BASE_DIRуправляет точкой, из которой собираются все каталоги заполнения контента, но в большинстве случаев разработчикам не нужно изменять это значение. По умолчанию расположение -${CMAKE_BINARY_DIR}/_deps, но если разработчики изменят это значение, они должны стремиться поддерживать короткий путь, чуть ниже верхнего уровня дерева сборки, чтобы избежать проблем с длиной пути в Windows.
-
FETCHCONTENT_QUIET -
Выходные данные протоколирования во время заполнения могут быть достаточно подробными, что делает этап конфигурации довольно шумным. Эта переменная кеша (по умолчанию
ON) скрывает все выходные данные заполнения, за исключением случаев возникновения ошибки. Если возникают проблемы с зависающими загрузками, временное отключение этой опции может помочь в диагностике, какой процесс заполнения контента вызывает проблему.Изменено в версии 3.30:
FETCHCONTENT_QUIETигнорируется, если политикаCMP0168установлена в значениеNEW. Выходные данные по-прежнему тихие по умолчанию в этом случае, но уровень подробности контролируется уровнем протоколирования сообщений (см.CMAKE_MESSAGE_LOG_LEVELи--log-level).
-
FETCHCONTENT_FULLY_DISCONNECTED -
Когда эта опция включена, попытки загрузить или обновить любой контент не предпринимаются. Предполагается, что весь контент уже был заполнен в предыдущем запуске или каталоги исходных файлов были указаны на существующий контент, предоставленный разработчиком вручную (используя опции, описанные ниже). Если разработчик знает, что никаких изменений в деталях контента не было, включение этой опции
ONможет ускорить этап конфигурации. ОнаOFFпо умолчанию.Примечание
Переменная
FETCHCONTENT_FULLY_DISCONNECTEDне является подходящим способом предотвращения любого сетевого доступа в первом запуске в каталоге сборки. Это может нарушить работу проектов, привести к вводящим в заблуждение сообщениям об ошибках и скрыть неявные сбои в процессе заполнения. Эта переменная предназначена только для включения после первого запуска CMake. Если вы хотите предотвратить сетевой доступ даже в первом запуске, используйте поставщика зависимостей и заполняйте зависимость из локального контента.Изменено в версии 3.30: Требование о том, что каталог исходного кода уже заполнен, когда
FETCHCONTENT_FULLY_DISCONNECTEDявляется истинным, теперь выполняется. См. политикуCMP0170.
-
FETCHCONTENT_UPDATES_DISCONNECTED -
Это менее жёсткий контроль загрузки/обновления по сравнению с
FETCHCONTENT_FULLY_DISCONNECTED. Вместо полного игнорирования логики загрузки и обновления,FETCHCONTENT_UPDATES_DISCONNECTEDблокирует только этап обновления, который устанавливает соединения с удалёнными серверами при использовании методов загрузки git или hg. Обновления всё ещё происходят, если меняются детали этапа обновления, но попытка обновления производится только с информацией, уже доступной локально (поэтому переключение на другой тег или коммит, уже загруженный локально, будет успешным, но переключение на неизвестный хеш коммита — нет). Этап загрузки не затрагивается, поэтому если содержимое ранее не было загружено, оно всё ещё будет загружено, если этот параметр включён. Это может ускорить этап конфигурации, но не так сильно, какFETCHCONTENT_FULLY_DISCONNECTED.FETCHCONTENT_UPDATES_DISCONNECTEDпо умолчаниюOFF.
-
FETCHCONTENT_TRY_FIND_PACKAGE_MODE -
Новая версия 3.24.
Эта переменная изменяет детали, которые
FetchContent_Declare()записывает для заданной зависимости. Хотя в конечном итоге она контролирует поведениеFetchContent_MakeAvailable(), используется значение переменной во время вызоваFetchContent_Declare(). Не имеет значения, какое значение имеет переменная при вызовеFetchContent_MakeAvailable(). Поскольку переменная должна устанавливаться только пользователем, а не проектами напрямую, она обычно имеет одинаковое значение, поэтому это различие обычно незаметно.FETCHCONTENT_TRY_FIND_PACKAGE_MODEв конечном итоге определяет, может лиFetchContent_MakeAvailable()вызыватьfind_package()для удовлетворения зависимости. Переменная может принимать одно из следующих значений:-
OPT_IN -
FetchContent_MakeAvailable()будет вызыватьfind_package()только если вызовFetchContent_Declare()включал ключевое словоFIND_PACKAGE_ARGS. Это также является поведением по умолчанию, еслиFETCHCONTENT_TRY_FIND_PACKAGE_MODEне установлен. -
ALWAYS -
find_package()может вызыватьсяFetchContent_MakeAvailable()независимо от того, включал ли вызовFetchContent_Declare()ключевое словоFIND_PACKAGE_ARGSили нет. Если ключевое словоFIND_PACKAGE_ARGSне указано, поведение будет таким, как если быFIND_PACKAGE_ARGSбыло указано без дополнительных аргументов после него. -
NEVER -
FetchContent_MakeAvailable()не будет вызыватьfind_package(). Любое ключевое словоFIND_PACKAGE_ARGS, заданное в вызовеFetchContent_Declare(), будет проигнорировано.
В качестве особого случая, если переменная
FETCHCONTENT_SOURCE_DIR_<uppercaseName>имеет ненулевое значение для зависимости, предполагается, что пользователь переопределяет все остальные способы обеспечения этой зависимости.FETCHCONTENT_TRY_FIND_PACKAGE_MODEне повлияет на эту зависимость, иFetchContent_MakeAvailable()не будет пытаться вызватьfind_package()для неё. -
В дополнение к вышеперечисленному, для каждого имени содержимого также определены следующие переменные:
-
FETCHCONTENT_SOURCE_DIR_<uppercaseName> -
Если это установлено, для указанного содержимого не выполняются шаги загрузки и обновления, и переменная
<lowercaseName>_SOURCE_DIRвозвращается вызывающей стороне, указывая на это местоположение. Это предоставляет разработчикам способ создать отдельный клон содержимого, который они могут свободно изменять без вмешательства сборки. Сборка просто использует этот существующий исходный код, но всё ещё определяет<lowercaseName>_BINARY_DIR, указывающий внутри своей области сборки. Разработчикам настоятельно рекомендуется использовать этот механизм вместо редактирования исходных кодов по умолчанию, так как изменения в исходных кодах по умолчанию могут быть потеряны, если проект изменит данные о загрузке содержимого.
-
FETCHCONTENT_UPDATES_DISCONNECTED_<uppercaseName> -
Это эквивалент
FETCHCONTENT_UPDATES_DISCONNECTEDна уровне содержимого. Если глобальный параметр или этот параметрON, тогда обновления для методов git и hg не будут обращаться к удалённому серверу для указанного содержимого. Они будут использовать только информацию, уже доступную локально. Отключение обновлений для отдельных содержимых элементов может быть полезно для содержимого, детали которого редко меняются, при этом другие часто меняющиеся содержимые элементы остаются с включёнными обновлениями.
Примеры
Типичный случай
Этот достаточно простой пример обеспечивает доступность популярных тестовых фреймворков для основной сборки:
include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0 ) FetchContent_Declare( Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG 605a34765aa5d5ecbf476b4598a862ada971b0cc # v3.0.1 ) # After the following call, the CMake targets defined by googletest and # Catch2 will be available to the rest of the build FetchContent_MakeAvailable(googletest Catch2)
Интеграция с find_package()
В предыдущем примере, если пользователь хотел сначала попробовать найти googletest и Catch2 через find_package(), а затем попробовать загрузить и собрать их из исходного кода, он мог бы установить переменную FETCHCONTENT_TRY_FIND_PACKAGE_MODE в значение ALWAYS. Это также повлияет на любые другие вызовы FetchContent_Declare() в рамках проекта, что может быть неприемлемо. Вместо этого поведение можно включить только для этих двух зависимостей, добавив FIND_PACKAGE_ARGS к объявленным деталям и оставив FETCHCONTENT_TRY_FIND_PACKAGE_MODE не заданной или в значении OPT_IN.
include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0 FIND_PACKAGE_ARGS NAMES GTest ) FetchContent_Declare( Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG 605a34765aa5d5ecbf476b4598a862ada971b0cc # v3.0.1 FIND_PACKAGE_ARGS ) # This will try calling find_package() first for both dependencies FetchContent_MakeAvailable(googletest Catch2)
Для Catch2, дополнительные аргументы к find_package() не нужны, поэтому дополнительные аргументы после ключевого слова FIND_PACKAGE_ARGS не указываются. Для googletest, его пакет чаще называют GTest, поэтому добавляются аргументы для поддержки поиска по этому имени.
Если пользователь хотел отключить FetchContent_MakeAvailable() от вызова find_package() для любой зависимости, даже если она предоставила FIND_PACKAGE_ARGS в своих объявленных деталях, он мог бы установить FETCHCONTENT_TRY_FIND_PACKAGE_MODE в значение NEVER.
Если проект хотел указать, что эти две зависимости должны быть загружены и собраны из исходного кода, и что вызовы find_package() должны быть перенаправлены на использование собранных зависимостей, необходимо использовать параметр OVERRIDE_FIND_PACKAGE при объявлении деталей содержимого:
include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0 OVERRIDE_FIND_PACKAGE ) FetchContent_Declare( Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG 605a34765aa5d5ecbf476b4598a862ada971b0cc # v3.0.1 OVERRIDE_FIND_PACKAGE ) # The following will automatically forward through to FetchContent_MakeAvailable() find_package(googletest) find_package(Catch2)
CMake предоставляет модуль FindGTest, который определяет некоторые переменные, которые могут использоваться более старыми проектами вместо связывания с импортированными целевыми объектами. Для поддержки таких случаев мы можем предоставить дополнительный файл. Согласно философии "первое определение побеждает" FetchContent, мы записываем этот файл только если этого ещё не сделал кто-то другой.
FetchContent_MakeAvailable(googletest)
if(NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/googletest-extra.cmake AND
NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/googletestExtra.cmake)
file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/googletest-extra.cmake
[=[
if("${GTEST_LIBRARIES}" STREQUAL "" AND TARGET GTest::gtest)
set(GTEST_LIBRARIES GTest::gtest)
endif()
if("${GTEST_MAIN_LIBRARIES}" STREQUAL "" AND TARGET GTest::gtest_main)
set(GTEST_MAIN_LIBRARIES GTest::gtest_main)
endif()
if("${GTEST_BOTH_LIBRARIES}" STREQUAL "")
set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
endif()
]=])
endif()
Проекты, скорее всего, будут использовать find_package(GTest) вместо find_package(googletest), но можно использовать область CMAKE_FIND_PACKAGE_REDIRECTS_DIR, чтобы включить последнюю как зависимость первой. Это, вероятно, будет достаточно для типичного вызова find_package(GTest).
FetchContent_MakeAvailable(googletest)
if(NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/gtest-config.cmake AND
NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/GTestConfig.cmake)
file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/gtest-config.cmake
[=[
include(CMakeFindDependencyMacro)
find_dependency(googletest)
]=])
endif()
if(NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/gtest-config-version.cmake AND
NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/GTestConfigVersion.cmake)
file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/gtest-config-version.cmake
[=[
include(${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/googletest-config-version.cmake OPTIONAL)
if(NOT PACKAGE_VERSION_COMPATIBLE)
include(${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/googletestConfigVersion.cmake OPTIONAL)
endif()
]=])
endif()
Переопределение местоположения CMakeLists.txt
Если файл CMakeLists.txt подпроекта не находится в корне его дерева исходных кодов, можно использовать опцию SOURCE_SUBDIR для указания FetchContent, где его найти. Следующий пример демонстрирует использование этой опции, а также устанавливает переменную, имеющую значение для подпроекта перед включением его в основной сборке (установлено как INTERNAL переменная кеша, чтобы избежать проблем с политикой CMP0077):
include(FetchContent) FetchContent_Declare( protobuf GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git GIT_TAG ae50d9b9902526efd6c7a1907d09739f959c6297 # v3.15.0 SOURCE_SUBDIR cmake ) set(protobuf_BUILD_TESTS OFF CACHE INTERNAL "") FetchContent_MakeAvailable(protobuf)
Сложные иерархии зависимостей
В более сложных иерархиях проектов отношения зависимостей могут быть более сложными. Рассмотрим иерархию, где projA является проектом верхнего уровня и напрямую зависит от проектов projB и projC. Оба проекта projB и projC могут быть построены автономно, и оба также зависят от другого проекта projD. projB дополнительно зависит от projE. Этот пример предполагает, что все пять проектов доступны на сервере компании Git. Файлы CMakeLists.txt каждого проекта могут содержать разделы, подобные следующим:
include(FetchContent) FetchContent_Declare( projB GIT_REPOSITORY git@mycompany.com:git/projB.git GIT_TAG 4a89dc7e24ff212a7b5167bef7ab079d ) FetchContent_Declare( projC GIT_REPOSITORY git@mycompany.com:git/projC.git GIT_TAG 4ad4016bd1d8d5412d135cf8ceea1bb9 ) FetchContent_Declare( projD GIT_REPOSITORY git@mycompany.com:git/projD.git GIT_TAG origin/integrationBranch ) FetchContent_Declare( projE GIT_REPOSITORY git@mycompany.com:git/projE.git GIT_TAG v2.3-rc1 ) # Order is important, see notes in the discussion further below FetchContent_MakeAvailable(projD projB projC)
include(FetchContent) FetchContent_Declare( projD GIT_REPOSITORY git@mycompany.com:git/projD.git GIT_TAG 20b415f9034bbd2a2e8216e9a5c9e632 ) FetchContent_Declare( projE GIT_REPOSITORY git@mycompany.com:git/projE.git GIT_TAG 68e20f674a48be38d60e129f600faf7d ) FetchContent_MakeAvailable(projD projE)
include(FetchContent) FetchContent_Declare( projD GIT_REPOSITORY git@mycompany.com:git/projD.git GIT_TAG 7d9a17ad2c962aa13e2fbb8043fb6b8a ) FetchContent_MakeAvailable(projD)
Несколько ключевых моментов следует отметить в вышеприведённом:
-
projBиprojCопределяют разные детали содержимого дляprojD, ноprojAтакже определяет набор деталей содержимого дляprojD. ПосколькуprojAопределит их в первую очередь, детали изprojBиprojCне будут использованы. Детали переопределения, определенныеprojA, не обязаны совпадать ни с одним из этих деталей изprojBилиprojC, но проект верхнего уровня должен убедиться, что определенные им детали всё ещё имеют смысл для дочерних проектов. - В вызове
projAкFetchContent_MakeAvailable(),projDуказан передprojBиprojC, поэтому он будет заполнен передprojBилиprojC. Это не обязательно дляprojA, но это гарантирует, чтоprojAполностью контролирует среду, в которойprojDвключен в сборку (свойства каталогов особенно важны). - Хотя
projAопределяет детали содержимого дляprojE, он не обязан явным образом вызыватьFetchContent_MakeAvailable(projE)илиFetchContent_Populate(projD)сам. Вместо этого он оставляет это дочернимprojB. Для проектов верхнего уровня часто достаточно просто определить детали переопределённого содержимого и оставить фактическое заполнение дочерним проектам. Это экономит повторное указание одного и того же на каждом уровне иерархии проекта, но это следует делать только в том случае, если свойства каталогов, установленные зависимостями, не должны влиять на заполнение общей зависимости (projEв этом случае).
Заполнение содержимого без добавления его в сборку
Проектам не всегда нужно добавлять заполненное содержимое в сборку. Иногда проект просто хочет сделать загруженное содержимое доступным в предсказуемом месте. Следующий пример гарантирует, что набор стандартных файлов инструментальной цепочки компании (и, возможно, даже сами двоичные файлы инструментальной цепочки) доступны достаточно рано, чтобы их можно было использовать в той же сборке.
cmake_minimum_required(VERSION 3.14) include(FetchContent) FetchContent_Declare( mycom_toolchains URL https://intranet.mycompany.com//toolchains_1.3.2.tar.gz ) FetchContent_MakeAvailable(mycom_toolchains) project(CrossCompileExample)
Проект можно настроить на использование одного из загруженных наборов инструментов следующим образом:
cmake -DCMAKE_TOOLCHAIN_FILE=_deps/mycom_toolchains-src/toolchain_arm.cmake /path/to/src
Когда CMake обрабатывает файл CMakeLists.txt, он загрузит и распакует архив в _deps/mycompany_toolchains-src относительно каталога сборки. Переменная CMAKE_TOOLCHAIN_FILE не используется до достижения команды project(), в этот момент CMake ищет файл инструментальной цепочки с указанным именем относительно каталога сборки. Так как архив уже загружен и распакован к тому моменту, файл инструментальной цепочки будет на месте, даже при первом запуске cmake в каталоге сборки.
Заполнение содержимого в режиме обработки сценариев CMake
Этот последний пример демонстрирует, как можно загрузить и распаковать архив с прошивкой с помощью режима обработки сценариев CMake. Вызов FetchContent_Populate() указывает все детали содержимого, а распакованная прошивка будет помещена в каталог firmware ниже текущего рабочего каталога.
getFirmware.cmake# NOTE: Intended to be run in script mode with cmake -P include(FetchContent) FetchContent_Populate( firmware URL https://mycompany.com/assets/firmware-1.23-arm.tar.gz URL_HASH MD5=68247684da89b608d466253762b0ff11 SOURCE_DIR firmware )
© 2000–2024 Kitware, Inc. and Contributors
Licensed under the BSD 3-clause License.
https://cmake.org/cmake/help/v3.30/module/FetchContent.html