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