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>... [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установлена в 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для более подробного обсуждения последствий.
-
-
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()также.
Проекты должны стремиться объявлять детали всех зависимостей, которые они могут использовать, до того, как вызовут
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 могут остановить работу с ошибкой в таких случаях.
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_DISCONNECTEDпо умолчанию.
-
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
)
# 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, он загрузит и распакует архив tar в _deps/mycompany_toolchains-src относительно каталога сборки. Переменная CMAKE_TOOLCHAIN_FILE не используется до тех пор, пока не будет достигнут вызов команды project(), в этот момент CMake ищет указанный файл инструментальной цепочки относительно каталога сборки. Поскольку архив tar уже загружен и распакован к этому моменту, файл инструментальной цепочки будет доступен, даже в первый раз, когда cmake запускается в каталоге сборки.
Заполнение содержимого в режиме сценария CMake
Этот последний пример демонстрирует, как можно загрузить и распаковать архив tar с прошивкой с помощью 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.27/module/FetchContent.html