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со значением «true» при заполнении командойFetchContent_MakeAvailable(). Элементы в их свойствеINTERFACE_INCLUDE_DIRECTORIESбудут рассматриваться как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в его верхнем каталоге.
Проекты должны стремиться объявить детали всех зависимостей, которые они могут использовать, до вызова
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отключает только этап обновления. Поэтому, если содержимое не было загружено ранее, оно всё ещё будет загружено, когда включена эта опция. Это может ускорить этап конфигурации, но не так сильно, какFETCHCONTENT_FULLY_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указывает на это расположение. Это даёт разработчикам возможность иметь отдельный checkout содержимого, которое они могут свободно изменять без вмешательства сборки. Сборка просто использует этот существующий исходный код, но все равно определяет<lowercaseName>_BINARY_DIRдля указания места внутри своей собственной области сборки. Разработчикам настоятельно рекомендуется использовать этот механизм вместо редактирования исходных кодов в стандартном расположении, поскольку изменения в исходных кодах по умолчанию могут быть потеряны при изменении информации о конфигурации содержимого проектом.
-
FETCHCONTENT_UPDATES_DISCONNECTED_<uppercaseName> -
Это эквивалент
FETCHCONTENT_UPDATES_DISCONNECTEDна уровне содержимого. Если глобальный параметр или этот параметрON, тогда обновления будут отключены для указанного содержимого. Отключение обновлений для отдельных содержимых может быть полезно для содержимого, которое редко изменяется, при этом другие часто изменяемые содержимые остаются с включёнными обновлениями.
Примеры
Типичный случай
Этот первый довольно простой пример гарантирует, что некоторые популярные фреймворки тестирования доступны для основной сборки:
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 de6fe184a9ac1a06895cdd1c9b437f0a0bdf14ad # v2.13.4 ) # 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 de6fe184a9ac1a06895cdd1c9b437f0a0bdf14ad # v2.13.4 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 de6fe184a9ac1a06895cdd1c9b437f0a0bdf14ad # v2.13.4 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 каждого проекта может содержать такие разделы:
projA:
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)
projB:
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)
projC:
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
Этот последний пример демонстрирует, как можно загрузить и распаковать архив firmware tar с помощью script mode CMake. Вызов FetchContent_Populate() указывает все детали контента, и распакованный firmware будет помещён в каталог 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–2022 Kitware, Inc. and Contributors
Licensed under the BSD 3-clause License.
https://cmake.org/cmake/help/v3.25/module/FetchContent.html