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_GetProperties() и FetchContent_Populate() более низкого уровня. Однако у них отсутствуют более богатые возможности, предоставляемые FetchContent_MakeAvailable(), поэтому их непосредственное использование следует рассматривать в крайних случаях. Типичный шаблон таких пользовательских шагов выглядит так:
# NOTE: Where possible, prefer to use FetchContent_MakeAvailable()
# instead of custom logic like this
# 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 также поддерживает определение и заполнение контента в одном вызове, без проверки того, уже ли заполнен этот контент в другом месте. Это не следует делать в проектах, но может быть уместно для заполнения контента в режиме сценариев CMake. См. 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()для получения подробностей о влиянии на поведение.В большинстве случаев
<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или не задан.Всё после ключевого слова
FIND_PACKAGE_ARGSдобавляется к вызовуfind_package(), поэтому все другие<contentOptions>должны идти перед ключевым словомFIND_PACKAGE_ARGS. Если переменнаяCMAKE_FIND_PACKAGE_TARGETS_GLOBALустановлена в значение «истина» во время вызова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(), будет установлено в значение «истина». Это повлияет на неимпортированные цели, созданные в рамках этой команды. Подробнее об эффектах см. в документации к свойству целиSYSTEM.
Добавлена в версии 3.28:
-
EXCLUDE_FROM_ALL -
Если указан аргумент
EXCLUDE_FROM_ALL, цели в подкаталоге, добавленном командойFetchContent_MakeAvailable(), по умолчанию не будут включены в цельALL, и могут быть исключены из файлов проекта IDE. Подробнее об эффектах см. в документации к аргументуEXCLUDE_FROM_ALLкомандыadd_subdirectory().
-
-
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_Populate()для заполнения зависимости, используя данные, записанные в предыдущем вызове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. Если конфигурационный файл не существует, когдаFetchContent_Populate()возвращает результат, будет создан минимальный файл, который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().
Проекты должны стремиться объявлять детали всех зависимостей, которые они могут использовать, прежде чем вызывать
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_MakeAvailable()вместо ручной реализации заполнения с помощью этой команды.FetchContent_Populate(<name>)
В большинстве случаев единственный аргумент, передаваемый
FetchContent_Populate(), — это<name>. В этом случае команда предполагает, что детали содержимого были записаны в предыдущем вызовеFetchContent_Declare(). Детали хранятся в глобальном свойстве, поэтому они не зависят от области действия переменных или каталогов. Поэтому неважно, где в проекте были ранее объявлены детали, главное, чтобы они были объявлены до вызоваFetchContent_Populate(). Эти сохраненные детали затем используются для построения вызоваExternalProject_Add()в частном подпроекте для немедленного заполнения содержимого. РеализацияExternalProject_Add()гарантирует, что если содержимое уже было заполнено в предыдущем запуске CMake, это содержимое будет повторно использовано, а не заполнено заново. В общем случае, когда заполнение включает загрузку содержимого, затраты на загрузку осуществляются только один раз.Внутреннее глобальное свойство записывает, когда запрос на заполнение определённого содержимого был обработан. Если
FetchContent_Populate()вызывается более одного раза для одного и того же имени содержимого в рамках выполнения конфигурации, второй вызов завершится ошибкой. Проекты могут и должны проверять, было ли содержимое уже обработано, с помощью командыFetchContent_GetProperties()перед вызовомFetchContent_Populate().FetchContent_Populate()установит три переменные в области вызывающей стороны:-
<lowercaseName>_POPULATED -
Это всегда будет установлено в
TRUEвызовом. -
<lowercaseName>_SOURCE_DIR -
Расположение, где можно найти заполненное содержимое по завершении.
-
<lowercaseName>_BINARY_DIR -
Каталог, предназначенный для использования в качестве соответствующего каталога построения.
Основное использование переменных
<lowercaseName>_SOURCE_DIRи<lowercaseName>_BINARY_DIR— вызватьadd_subdirectory()сразу после заполнения:FetchContent_Populate(FooBar) add_subdirectory(${foobar_SOURCE_DIR} ${foobar_BINARY_DIR})Значения трех переменных также могут быть извлечены из любой точки иерархии проекта с помощью команды
FetchContent_GetProperties().Команда
FetchContent_Populate()также поддерживает синтаксис, позволяющий указывать детали содержимого непосредственно, а не использовать сохранённые данные. Это более низкий уровень, и использование этого формата обычно следует избегать в пользу использования сохранённых данных о содержимом, как описано выше. Тем не менее, в определенных ситуациях это может быть полезно для вызова заполнения содержимого как изолированной операции (обычно как часть реализации какой-либо другой функции более высокого уровня или при использовании CMake в режиме скрипта):FetchContent_Populate( <name> [QUIET] [SUBBUILD_DIR <subBuildDir>] [SOURCE_DIR <srcDir>] [BINARY_DIR <binDir>] ... )
У этого формата есть ряд ключевых отличий от варианта, где указан только
<name>:- Предполагается, что все необходимые детали заполнения были предоставлены непосредственно в вызове
FetchContent_Populate(). Любые сохранённые данные для<name>игнорируются. - Не проверяется, было ли содержимое
<name>уже заполнено. - Не устанавливается глобальное свойство, регистрирующее выполнение заполнения.
- Не сохраняются глобальные свойства для источника или каталога библиотек заполненного содержимого.
- Переменные кэша
FETCHCONTENT_FULLY_DISCONNECTEDиFETCHCONTENT_UPDATES_DISCONNECTEDигнорируются.
Переменные
<lowercaseName>_SOURCE_DIRи<lowercaseName>_BINARY_DIRвсё ещё возвращаются вызывающей стороне, но поскольку эти расположения не сохраняются в глобальных свойствах при использовании этого формата, они доступны только в вызывающей области и ниже, а не во всей иерархии проекта. Переменная<lowercaseName>_POPULATEDне устанавливается в области вызывающей стороны в этом формате.Поддерживаемые параметры для
FetchContent_Populate()такие же, как и дляFetchContent_Declare(). Эти несколько вариантов, представленные выше, либо специфичны дляFetchContent_Populate(), либо их поведение немного отличается от того, какExternalProject_Add()обрабатывает их:-
QUIET -
Параметр
QUIETможет быть указан для скрытия вывода, связанного с заполнением указанного содержимого. Если заполнение завершается неудачно, вывод будет показан независимо от того, был ли указан этот параметр или нет, чтобы можно было диагностировать причину сбоя. Глобальная переменная кэшаFETCHCONTENT_QUIETне влияет на вызовыFetchContent_Populate(), где детали содержимого предоставляются напрямую. -
SUBBUILD_DIR -
Аргумент
SUBBUILD_DIRможет быть указан для изменения расположения подпроекта, созданного для выполнения заполнения. Значение по умолчанию —${CMAKE_CURRENT_BINARY_DIR}/<lowercaseName>-subbuild, и редко возникает необходимость его переопределять. Если указан относительный путь, он будет интерпретирован относительноCMAKE_CURRENT_BINARY_DIR. Этот параметр не следует путать с параметромSOURCE_SUBDIR, который влияет только на командуFetchContent_MakeAvailable(). -
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_Populate()в режиме скрипта CMake имейте в виду, что реализация создаёт подпроект, который, следовательно, требует наличия генератора CMake и инструмента построения. Если их нельзя найти по умолчанию, то переменныеCMAKE_GENERATORи/илиCMAKE_MAKE_PROGRAMнеобходимо задать в командной строке вызова скрипта.В версии 3.18: Добавлена поддержка параметра
DOWNLOAD_NO_EXTRACT. -
-
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(), что гарантирует, что соответствующие переменные будут всегда определены независимо от того, выполнялась ли популяция в другом месте проекта:# 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 могут завершиться с ошибкой fatal в таких случаях.
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по умолчанию) скрывает все выходные данные заполнения, если не возникает ошибка. Если возникают проблемы с зависающими загрузками, временное отключение этого параметра может помочь в диагностике, какая популяция содержимого вызывает проблему.
-
FETCHCONTENT_FULLY_DISCONNECTED -
Когда этот параметр включен, не предпринимается попыток загрузить или обновить какое-либо содержимое. Предполагается, что всё содержимое уже было заполнено в предыдущем запуске или исходные каталоги указывали на существующее содержимое, которое разработчик предоставил вручную (используя параметры, описанные ниже). Если разработчик знает, что изменения в данных о содержимом не вносились, включение этого параметра
ONможет значительно ускорить этап конфигурации. ОнOFFпо умолчанию.
-
FETCHCONTENT_UPDATES_DISCONNECTED -
Это менее строгий контроль за загрузкой/обновлением по сравнению с
FETCHCONTENT_FULLY_DISCONNECTED. Вместо того, чтобы игнорировать всю логику загрузки и обновления,FETCHCONTENT_UPDATES_DISCONNECTEDтолько предотвращает выполнение шага обновления, устанавливающего соединения с удалёнными серверами при использовании методов загрузки git или hg. Обновления всё ещё происходят, если меняются данные о шаге обновления, но попытка обновления выполняется только с информацией, уже имеющейся локально (так, переход к другому тегу или коммиту, который уже загружен локально, будет успешным, но переход к неизвестному хэшу коммита завершится ошибкой). Шаг загрузки не затрагивается, поэтому, если содержимое не было загружено ранее, оно по-прежнему будет загружено, когда этот параметр включен. Это может ускорить этап конфигурации, но не так сильно, какFETCHCONTENT_FULLY_DISCONNECTED.FETCHCONTENT_UPDATES_DISCONNECTEDOFFпо умолчанию.
-
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.
Для 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
)
# This particular version of projD requires workarounds
FetchContent_GetProperties(projD)
if(NOT projd_POPULATED)
FetchContent_Populate(projD)
# Copy an additional/replacement file into the populated source
file(COPY someFile.c DESTINATION ${projd_SOURCE_DIR}/src)
add_subdirectory(${projd_SOURCE_DIR} ${projd_BINARY_DIR})
endif()
Несколько ключевых моментов следует отметить выше:
-
projBиprojCопределяют различные детали контента дляprojD, ноprojAтакже определяет набор деталей контента дляprojD. ПосколькуprojAопределит их первым, детали изprojBиprojCне будут использоваться. Детали переопределения, определённыеprojA, не обязательно должны совпадать ни с одной из деталей изprojBилиprojC, но проект верхнего уровня должен убедиться, что определённые им детали всё ещё имеют смысл для дочерних проектов. - В вызове
projAкFetchContent_MakeAvailable(),projDуказан передprojBиprojC, чтобы гарантировать, чтоprojAконтролирует, как заполняетсяprojD. - Хотя
projAопределяет детали контента дляprojE, ему не нужно явно вызыватьFetchContent_MakeAvailable(projE)илиFetchContent_Populate(projD)сам. Вместо этого он оставляет это дочернимprojB. Для проектов верхнего уровня часто достаточно просто определить детали переопределённого контента и оставить фактическое заполнение дочерним проектам. Это позволяет избежать ненужного повторения одних и тех же действий на каждом уровне иерархии проекта.
Заполнение контента без добавления его в сборку
Проекты не всегда нуждаются в добавлении заполненного контента в сборку. Иногда проект просто хочет сделать загруженный контент доступным в предсказуемом месте. Следующий пример гарантирует, что набор стандартных файлов инструментальной цепочки компании (и, возможно, даже сами двоичные файлы инструментальной цепочки) будут доступны достаточно рано, чтобы их можно было использовать для той же сборки.
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
Этот последний пример демонстрирует, как можно загрузить и распаковать архив с прошивкой с помощью script mode 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.28/module/FetchContent.html