Spec-Zone.ru › CMake

FetchContent

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

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

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

Этот модуль предоставляет команды для получения содержимого на этапе конфигурирования или в составе вызывающего скрипта.

Загрузите этот модуль в CMake с помощью:

include(FetchContent)

Примечание

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(), к аргументам find_package() будет добавлено ключевое слово GLOBAL, если оно еще не указано. Оно также будет добавлено, если 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(); первый такой вызов определяет, как эта зависимость будет предоставлена, как описано ниже.

Если FETCHCONTENT_SOURCE_DIR_<uppercaseName> не задана:

  • Добавлено в версии 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() также всегда пропускается. Если поставщик выполнил запрос, find_package(<name> [<args>...]) считает эту зависимость обработанной, пропускает оставшиеся шаги ниже и переходит к следующей зависимости в списке.

  • Добавлено в версии 3.24: Если это разрешено, будет вызвана команда <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() установлена в true, это по-прежнему влияет на любые импортированные цели, созданные при вызове find_package(), даже если при объявлении соответствующих сведений эта переменная имела значение false.

Если поставщик или вызов FetchContent_MakeAvailable() не удовлетворил зависимость, <lowercaseName>_POPULATED использует следующую логику, чтобы сделать её доступной:

  • Если зависимость уже была заполнена ранее в этом запуске, установите переменные <lowercaseName>_SOURCE_DIR, <lowercaseName>_BINARY_DIR и FetchContent_GetProperties() так же, как при вызове FetchContent_Declare(), затем пропустите оставшиеся шаги ниже и перейдите к следующей зависимости в списке.
  • Заполните зависимость, используя сведения, сохранённые предыдущим вызовом FETCHCONTENT_SOURCE_DIR_<uppercaseName>. Если такие сведения не были сохранены, завершите выполнение с критической ошибкой. CMAKE_FIND_PACKAGE_REDIRECTS_DIR можно использовать, чтобы переопределить объявленные сведения и вместо этого использовать содержимое из указанного расположения.
  • Добавлено в версии 3.24: Убедитесь, что каталог <lowercaseName>-config.cmake содержит файл <lowercaseName>-config-version.cmake и файл <name>Config.cmake (или, что эквивалентно, <name>ConfigVersion.cmake и CMAKE_FIND_PACKAGE_REDIRECTS_DIR). Каталог, на который указывает переменная includes, очищается в начале каждого запуска CMake. Если после заполнения зависимости на предыдущем шаге файл конфигурации отсутствует, будет создан минимальный файл, который подключает с флагом <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: Если при вызове FetchContent_Declare() было включено ключевое слово SYSTEM, в команду add_subdirectory() будет добавлено ключевое слово SYSTEM.

    Добавлено в версии 3.28: Если при вызове FetchContent_Declare() было включено ключевое слово EXCLUDE_FROM_ALL, в команду add_subdirectory() будет добавлено ключевое слово EXCLUDE_FROM_ALL.

    Добавлено в версии 3.29: Перед вызовом add_subdirectory() переменной CMAKE_EXPORT_FIND_PACKAGE_NAME присваивается имя зависимости.

Проектам следует объявлять сведения обо всех зависимостях, которые они могут использовать, до вызова 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)

Обратите внимание, что при входе в FetchContent_MakeAvailable() переменным CMAKE_VERIFY_INTERFACE_HEADER_SETS и CMAKE_VERIFY_PRIVATE_HEADER_SETS явно присваивается значение false, а перед возвратом команды восстанавливаются их исходные значения. Обычно разработчики хотят проверять наборы заголовков только основного проекта, а не его зависимостей. Такое локальное изменение переменных CMAKE_VERIFY_INTERFACE_HEADER_SETS и CMAKE_VERIFY_PRIVATE_HEADER_SETS обеспечивает такое ожидаемое поведение. Можно использовать переменные, такие как CMAKE_PROJECT_INCLUDE или CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE, чтобы снова включить проверку для всех или некоторых зависимостей. Также можно задать свойства VERIFY_INTERFACE_HEADER_SETS и VERIFY_PRIVATE_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 является ошибкой. Информацию о том, как определить, выполнялось ли заполнение <name> в текущем запуске, см. в разделе FetchContent_GetProperties().

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, однако проект верхнего уровня должен убедиться, что заданные им сведения по-прежнему подходят дочерним проектам.
  • В вызове FetchContent_MakeAvailable() из проекта projA элемент 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

При обработке файла CMakeLists.txt CMake загрузит и распакует архив tar в _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–2026 Kitware, Inc. and Contributors
Licensed under the BSD 3-clause License.
https://cmake.org/cmake/help/latest/module/FetchContent.html

Spec-Zone.ru

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