Spec-Zone.ru › CMake 3.29

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_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>...
  [EXCLUDE_FROM_ALL]
  [SYSTEM]
  [OVERRIDE_FIND_PACKAGE |
   FIND_PACKAGE_ARGS args...]
)

Функция FetchContent_Declare() записывает параметры, описывающие, как заполнить указанный контент. Если такие данные уже были записаны ранее в этом проекте (независимо от места в иерархии проекта), этот и все последующие вызовы для того же контента <name> игнорируются. Такой подход «первый записавший побеждает» позволяет родительским проектам в иерархических проектах переопределять детали контента дочерних проектов.

Контент <name> может быть любой строкой без пробелов, но рекомендуется использовать только буквы, цифры и нижние подчёркивания. Имя будет обрабатываться без учёта регистра и должно быть очевидным для представляемого контента, часто являясь именем дочернего проекта или значением, заданным для его команды верхнего уровня project() (если это проект CMake). Для известных публичных проектов имя обычно должно соответствовать официальному названию проекта. Выбор необычного имени делает маловероятным, что другие проекты, нуждающиеся в том же контенте, будут использовать то же имя, что приведёт к многократному заполнению контента.

Параметры <contentOptions> могут быть любыми параметрами загрузки, обновления или исправления, которые понимает команда ExternalProject_Add(). Шаги конфигурации, сборки, установки и тестирования явно отключены, и поэтому параметры, связанные с ними, будут проигнорированы. Параметр SOURCE_SUBDIR является исключением, см. FetchContent_MakeAvailable() для деталей о том, как это влияет на поведение.

В большинстве случаев <contentOptions> будет содержать всего пару параметров, определяющих метод загрузки и детали, специфичные для метода, такие как тег коммита или хэш архива. Например:

FetchContent_Declare(
  googletest
  GIT_REPOSITORY https://github.com/google/googletest.git
  GIT_TAG        703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
)

FetchContent_Declare(
  myCompanyIcons
  URL      https://intranet.mycompany.com/assets/iconset_1.12.tar.gz
  URL_HASH MD5=5588a7b18261c20068beabfb4f530b87
)

FetchContent_Declare(
  myCompanyCertificates
  SVN_REPOSITORY svn+ssh://svn.mycompany.com/srv/svn/trunk/certs
  SVN_REVISION   -r12345
)

Если контент извлекается из удалённого места, и вы не контролируете этот сервер, рекомендуется использовать хэш для GIT_TAG вместо имени ветки или тега. Хэш коммита более безопасен и помогает подтвердить, что загруженный контент соответствует вашим ожиданиям.

Изменено в версии 3.14: Команды для шагов загрузки, обновления или исправления могут получить доступ к терминалу. Это может потребоваться для таких задач, как запросы паролей или отображение прогресса команд в реальном времени.

Добавлена в версии 3.22: Переменные CMAKE_TLS_VERIFY, CMAKE_TLS_CAINFO, CMAKE_NETRC и CMAKE_NETRC_FILE теперь предоставляют значения по умолчанию для соответствующих параметров контента, как и для команды ExternalProject_Add(). Ранее эти переменные игнорировались модулем FetchContent.

Добавлена в версии 3.24:

FIND_PACKAGE_ARGS

Этот параметр предназначен для сценариев, когда команда FetchContent_MakeAvailable() может сначала выполнить вызов find_package() для удовлетворения зависимости для <name>. По умолчанию такой вызов был бы просто find_package(<name>), но FIND_PACKAGE_ARGS может быть использован для добавления дополнительных аргументов, которые будут добавлены после <name>. FIND_PACKAGE_ARGS также может быть использован без последующих аргументов, что указывает на то, что find_package() по-прежнему может быть вызван, если FETCHCONTENT_TRY_FIND_PACKAGE_MODE установлен в значение OPT_IN или не задан.

Не следует обычно указывать 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. См. документацию аргумента add_subdirectory() 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 установлена в значение «истина» при вызове 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 будут установлены в значение «истина». Это гарантирует, что все последующие вызовы 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().

END_OF_DOCUMENT_MARKER

Проекты должны стремиться объявлять детали всех зависимостей, которые они могут использовать, прежде чем вызывать 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_COMMAND
    • BUILD_COMMAND
    • INSTALL_COMMAND
    • TEST_COMMAND

    Если использовать FetchContent_Populate() в режиме сценариев CMake, следует учитывать, что реализация создаёт подстрое, а это требует наличия генератора CMake и инструмента построения. Если их нельзя найти по умолчанию, переменные CMAKE_GENERATOR и/или CMAKE_MAKE_PROGRAM необходимо установить в командной строке, запускающей сценарий.

    Новое в версии 3.18: Добавлена поддержка параметра DOWNLOAD_NO_EXTRACT.

    FetchContent_GetProperties

    При использовании сохранённых данных о содержимом, вызов FetchContent_MakeAvailable() или FetchContent_Populate() записывает информацию в глобальные свойства, которые можно запросить в любое время. Эта информация может включать каталоги исходного кода и бинарных файлов, связанных с содержимым, а также информацию о том, было ли выполнено заполнение содержимого во время текущего выполнения configure.

    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

    Выходные данные протоколирования во время заполнения могут быть довольно объёмными, что делает этап configure довольно шумным. Эта опция кэша (по умолчанию ON) скрывает все выходные данные заполнения, за исключением случаев возникновения ошибки. Если возникают проблемы с зависанием загрузок, временное отключение этой опции может помочь диагностировать, какая операция заполнения содержимого вызывает проблему.

    FETCHCONTENT_FULLY_DISCONNECTED

    При включении этой опции не предпринимается попытка загрузить или обновить какое-либо содержимое. Предполагается, что всё содержимое уже было заполнено в предыдущей операции или каталоги исходных файлов указывают на существующее содержимое, предоставленное разработчиком вручную (используя описанные ниже параметры). Если разработчик знает, что изменения в данных о содержимом не вносились, включение этой опции ON может значительно ускорить этап configure. По умолчанию она OFF.

    Примечание

    Переменная FETCHCONTENT_FULLY_DISCONNECTED не является надлежащим способом предотвращения доступа к сети при первой операции сборки в каталоге. Это может нарушить работу проектов, привести к вводящим в заблуждение сообщениям об ошибках и скрыть незаметные ошибки заполнения. Эта переменная предназначена для включения только после первого запуска CMake. Если вы хотите предотвратить доступ к сети даже при первом запуске, используйте поставщика зависимостей и заполните зависимость локальным содержимым.

    FETCHCONTENT_UPDATES_DISCONNECTED

    Это менее жёсткий контроль за загрузкой/обновлением по сравнению с FETCHCONTENT_FULLY_DISCONNECTED. Вместо того, чтобы полностью игнорировать логику загрузки и обновления, FETCHCONTENT_UPDATES_DISCONNECTED предотвращает подключение к удалённым серверам на шаге обновления при использовании методов загрузки git или hg. Обновления всё ещё происходят, если данные о шаге обновления изменятся, но обновление пытается выполнить с использованием только доступной локально информации (следовательно, переключение на другую метку или коммит, который уже загружен локально, будет успешным, но переключение на неизвестный хеш коммита завершится неудачей). Шаг загрузки не затронут, поэтому, если содержимое не было загружено ранее, оно всё равно будет загружено, когда эта опция включена. Это может ускорить этап configure, но не так сильно, как 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
    )
    
    # 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
    

    При обработке файла CMakeLists.txt CMake загрузит и распакует архив в _deps/mycompany_toolchains-src относительно каталога сборки. Переменная CMAKE_TOOLCHAIN_FILE не используется до тех пор, пока не будет достигнут вызов команды project(), в этот момент CMake ищет указанный файл инструментальной цепочки относительно каталога сборки. Поскольку архив уже загружен и распакован к этому моменту, файл инструментальной цепочки будет на месте, даже в первый раз, когда cmake запускается в каталоге сборки.

    Заполнение содержимого в режиме сценариев CMake

    Этот последний пример демонстрирует, как можно загрузить и распаковать архив с прошивкой с помощью script mode CMake. Вызов FetchContent_Populate() определяет все детали содержимого, и распакованная прошивка будет помещена в каталог firmware ниже текущего каталога.

    getFirmware.cmake
    # NOTE: Intended to be run in script mode with cmake -P
    include(FetchContent)
    FetchContent_Populate(
      firmware
      URL        https://mycompany.com/assets/firmware-1.23-arm.tar.gz
      URL_HASH   MD5=68247684da89b608d466253762b0ff11
      SOURCE_DIR firmware
    )
    

    © 2000–2024 Kitware, Inc. and Contributors
    Licensed under the BSD 3-clause License.
    https://cmake.org/cmake/help/v3.29/module/FetchContent.html

    Spec-Zone.ru

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