Spec-Zone.ru › CMake 3.31

FetchContent

Добавлен в версии 3.11.

  • Обзор
  • Команды
  • Переменные
  • Примеры

    • Типичный случай
    • Интеграция с find_package()
    • Переопределение места поиска CMakeLists.txt
    • Сложные иерархии зависимостей
    • Заполнение контента без добавления его в сборку
    • Заполнение контента в режиме скрипта CMake

Примечание

В 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_ALL
  • SYSTEM
  • OVERRIDE_FIND_PACKAGE
  • FIND_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_COMMAND
  • BUILD_COMMAND
  • INSTALL_COMMAND
  • TEST_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 каждого проекта может содержать разделы, подобные следующим:

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
)

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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API