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>... [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.
-
-
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(), даже если эта переменная была ложной при объявлении соответствующих деталей.
Если зависимость не была удовлетворена поставщиком или вызовом
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, возвращаемая вызывающей стороне, указывает на это местоположение. Это даёт разработчикам возможность иметь отдельный чек-аут контента, который они могут свободно изменять без вмешательства сборки. Сборка просто использует этот существующий исходный код, но всё ещё определяет<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 места его расположения. Следующий пример демонстрирует, как использовать эту опцию, а также устанавливает переменную, имеющую смысл для подпроекта перед подключением его к основной сборке:
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) 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
Этот последний пример демонстрирует, как можно загрузить и распаковать архив tar с прошивкой с помощью CMake script mode. Вызов 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–2022 Kitware, Inc. and Contributors
Licensed under the BSD 3-clause License.
https://cmake.org/cmake/help/v3.24/module/FetchContent.html