Spec-Zone.ru › CMake 3.30

FetchContent

Новые в версии 3.11.

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

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

Примечание

Руководство Using Dependencies Guide предоставляет общее введение в эту тему. Оно содержит более широкий обзор того, как модуль FetchContent вписывается в общую картину, включая его взаимосвязь с командой find_package(). Рекомендуется ознакомиться с руководством перед изучением деталей ниже.

Обзор

Этот модуль позволяет заполнять контент на этапе конфигурации любым способом, поддерживаемым модулем ExternalProject. В то время как ExternalProject_Add() загружает контент на этапе сборки, модуль FetchContent делает его доступным сразу, позволяя шагу конфигурации использовать контент в командах, таких как add_subdirectory(), include() или операциях file().

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

Следующий пример демонстрирует типичный случай объявления деталей контента для некоторых зависимостей и последующего его заполнения отдельным вызовом:

FetchContent_Declare(
  googletest
  GIT_REPOSITORY https://github.com/google/googletest.git
  GIT_TAG        703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
)
FetchContent_Declare(
  myCompanyIcons
  URL      https://intranet.mycompany.com/assets/iconset_1.12.tar.gz
  URL_HASH MD5=5588a7b18261c20068beabfb4f530b87
)

FetchContent_MakeAvailable(googletest myCompanyIcons)

Команда FetchContent_MakeAvailable() гарантирует, что указанные зависимости были заполнены, либо предыдущим вызовом, либо путем заполнения их самостоятельно. При выполнении заполнения она также добавит их в основную сборку, если это возможно, чтобы основная сборка могла использовать целевые объекты и т.д. См. документацию команды для получения информации о том, как выполняются эти шаги.

При использовании иерархической структуры проекта, проекты на более высоких уровнях иерархии могут переопределить объявленные детали контента, указанные на более низких уровнях проекта. Первые объявленные детали для данной зависимости имеют приоритет, независимо от того, где в иерархии проекта это происходит. Аналогично, первый вызов, пытающийся заполнить зависимость, «выигрывает», а последующие заполнения используют результат первого, вместо повторного заполнения. См. Примеры, которые демонстрируют этот сценарий.

Модуль FetchContent также поддерживает определение и заполнение контента в одном вызове без проверки того, заполнен ли контент где-либо еще. Это не следует делать в проектах, но может быть уместно для заполнения контента в режиме сценариев CMake script mode. См. FetchContent_Populate() для получения подробной информации.

Команды

FetchContent_Declare
FetchContent_Declare(
  <name>
  <contentOptions>...
  [EXCLUDE_FROM_ALL]
  [SYSTEM]
  [OVERRIDE_FIND_PACKAGE |
   FIND_PACKAGE_ARGS args...]
)

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

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

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

Изменено в версии 3.30: Когда политика CMP0168 установлена в NEW, некоторые параметры, связанные с выводом и каталогами, игнорируются. Подробности см. в документации по политике.

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

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

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

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

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

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

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

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

FIND_PACKAGE_ARGS

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

Обычно не следует указывать REQUIRED в качестве одного из дополнительных аргументов после FIND_PACKAGE_ARGS. Это означает, что вызов find_package() должен быть успешным, поэтому ни одна из других деталей, указанных в вызове FetchContent_Declare(), не получит возможности быть использована как резервный вариант.

Все, что следует за ключевым словом FIND_PACKAGE_ARGS, добавляется к вызову find_package(), поэтому все остальные <contentOptions> должны предшествовать ключевому слову FIND_PACKAGE_ARGS. Если переменная CMAKE_FIND_PACKAGE_TARGETS_GLOBAL установлена в true во время вызова FetchContent_Declare(), ключевое слово GLOBAL будет добавлено к аргументам find_package(), если оно еще не было указано. Он также будет добавлен, если FIND_PACKAGE_ARGS не был задан, но FETCHCONTENT_TRY_FIND_PACKAGE_MODE был установлен в ALWAYS.

OVERRIDE_FIND_PACKAGE не может использоваться, когда указано FIND_PACKAGE_ARGS.

Поставщики зависимостей описывает другой способ перенаправления вызовов FetchContent_MakeAvailable(). FIND_PACKAGE_ARGS предназначен для управления проектом, тогда как поставщики зависимостей позволяют пользователям переопределять поведение проекта.

OVERRIDE_FIND_PACKAGE

Когда в вызове FetchContent_Declare(<name> ...) включен этот параметр, последующие вызовы find_package(<name> ...) будут гарантировать, что FetchContent_MakeAvailable(<name>) был вызван, затем будут использоваться конфигурационные файлы пакета в каталоге CMAKE_FIND_PACKAGE_REDIRECTS_DIR (обычно созданные FetchContent_MakeAvailable()). Это фактически заставляет FetchContent_MakeAvailable() переопределять find_package() для указанной зависимости, позволяя первому удовлетворять требования к пакету последнего. FIND_PACKAGE_ARGS не может использоваться, когда указано OVERRIDE_FIND_PACKAGE.

Если поставщик зависимостей был установлен, и проект вызывает find_package() для зависимости <name>, OVERRIDE_FIND_PACKAGE не помешает поставщику увидеть этот вызов. Поставщики зависимостей всегда имеют возможность перехватить любой прямой вызов find_package(), за исключением случая, когда этот вызов содержит параметр BYPASS_PROVIDER.

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

SYSTEM

Если указан аргумент SYSTEM, свойство каталога SYSTEM подкаталога, добавленного командой FetchContent_MakeAvailable(), будет установлено в true. Это повлияет на неимпортированные цели, созданные в рамках этой команды. См. документацию по свойству цели SYSTEM для более подробного обсуждения последствий.

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

EXCLUDE_FROM_ALL

Если указан аргумент EXCLUDE_FROM_ALL, цели в подкаталоге, добавленном командой FetchContent_MakeAvailable(), по умолчанию не будут включены в цель ALL и могут быть исключены из файлов проекта IDE. См. документацию по свойству каталога EXCLUDE_FROM_ALL для подробного обсуждения последствий.

FetchContent_MakeAvailable

Новое в версии 3.14.

FetchContent_MakeAvailable(<name1> [<name2>...])

Эта команда гарантирует, что каждый из перечисленных зависимостей будет доступен проекту к моменту его возвращения. Должна была быть вызвана команда FetchContent_Declare() для каждой зависимости, и первый такой вызов будет управлять тем, как эта зависимость будет сделана доступной, как описано ниже.

Если <lowercaseName>_SOURCE_DIR не установлено:

  • Новое в версии 3.24: Если установлено предоставление зависимостей, вызовите команду поставщика с FETCHCONTENT_MAKEAVAILABLE_SERIAL в качестве первого аргумента, за которым следуют аргументы первого вызова FetchContent_Declare() для <name>. Если SOURCE_DIR или BINARY_DIR не были частью исходных объявленных аргументов, они будут добавлены со своими значениями по умолчанию. Если FETCHCONTENT_TRY_FIND_PACKAGE_MODE было установлено в значение NEVER при объявлении деталей, любые FIND_PACKAGE_ARGS будут опушены. Ключевое слово OVERRIDE_FIND_PACKAGE также всегда опущено. Если поставщик выполнил запрос, FetchContent_MakeAvailable() посчитает эту зависимость обработанной, пропустит оставшиеся шаги ниже и перейдёт к следующей зависимости в списке.

  • Новое в версии 3.24: Если разрешено, будет вызван find_package(<name> [<args>...]), где <args>... может быть предоставлено параметром FIND_PACKAGE_ARGS в FetchContent_Declare(). Значение переменной FETCHCONTENT_TRY_FIND_PACKAGE_MODE на момент вызова FetchContent_Declare() определяет, может ли FetchContent_MakeAvailable() вызвать find_package(). Если переменная CMAKE_FIND_PACKAGE_TARGETS_GLOBAL установлена в значение true во время вызова FetchContent_MakeAvailable(), она всё ещё влияет на любые импортированные цели, созданные, когда этот вызов в свою очередь вызывает find_package(), даже если эта переменная была false при объявлении соответствующих деталей.

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

  • Если зависимость уже была обработана ранее в этом запуске, установите переменные <lowercaseName>_POPULATED, <lowercaseName>_SOURCE_DIR, и <lowercaseName>_BINARY_DIR таким же образом, как при вызове FetchContent_GetProperties(), затем пропустите оставшиеся шаги ниже и перейдите к следующей зависимости в списке.
  • Обработайте зависимость, используя детали, записанные при предыдущем вызове FetchContent_Declare(). Прекратите выполнение с ошибкой, если такие детали не были записаны. FETCHCONTENT_SOURCE_DIR_<uppercaseName> может быть использована для переопределения объявленных деталей и использования содержимого, предоставленного по указанному пути вместо этого.
  • Новое в версии 3.24: Убедитесь, что в каталоге CMAKE_FIND_PACKAGE_REDIRECTS_DIR содержатся файлы <lowercaseName>-config.cmake и <lowercaseName>-config-version.cmake (или, аналогично, <name>Config.cmake и <name>ConfigVersion.cmake). Каталог, на который указывает переменная CMAKE_FIND_PACKAGE_REDIRECTS_DIR, очищается в начале каждого запуска CMake. Если после обработки зависимости на предыдущем шаге файла конфигурации не существует, будет создан минимальный файл, который includes любой файл <lowercaseName>-extra.cmake или <name>Extra.cmake с флагом OPTIONAL (так что файлы могут отсутствовать и не будут генерировать предупреждение). Аналогично, если файла версии конфигурации не существует, будет создан очень простой файл, который установит PACKAGE_VERSION_COMPATIBLE и PACKAGE_VERSION_EXACT в значение true. Это гарантирует, что все последующие вызовы find_package() для зависимости будут использовать перенаправленный файл конфигурации, независимо от каких-либо требований к версии. CMake не может автоматически определить версию произвольной зависимости, поэтому он не может установить PACKAGE_VERSION. Когда зависимость подключается через add_subdirectory() на следующем шаге, она может выбрать переопределение сгенерированного файла версии конфигурации в CMAKE_FIND_PACKAGE_REDIRECTS_DIR на тот, который также устанавливает PACKAGE_VERSION. Зависимость также может записать файлы <lowercaseName>-extra.cmake или <name>Extra.cmake для выполнения пользовательской обработки или определения переменных, которые обычно определяет файл конфигурации их стандартного (установленного) пакета (многие проекты не выполняют пользовательскую обработку или не определяют переменные и поэтому в этом нет необходимости). При необходимости основной проект может записать эти файлы вместо этого, если проект зависимости этого не сделает. Это позволяет основному проекту добавить недостающие детали из более старых зависимостей, которые не были или не могут быть обновлены для поддержки этой функциональности. Примеры см. в разделе Интеграция с find_package().

  • Если в корневой папке обработанного содержимого находится файл CMakeLists.txt, вызовите add_subdirectory() для добавления его в основной сборке. Отсутствие файла CMakeLists.txt не является ошибкой, что позволяет использовать эту команду для зависимостей, которые делают загруженное содержимое доступным по известному пути, но которые не нуждаются или не поддерживают прямое добавление в сборку.

    Новое в версии 3.18: Параметр SOURCE_SUBDIR может быть указан в объявленных деталях, чтобы найти что-то ниже корневой директории вместо этого (то есть, так же, как SOURCE_SUBDIR используется командой ExternalProject_Add()). Путь, указанный с SOURCE_SUBDIR, должен быть относительным, и он будет обрабатываться как относительный к корневой директории. Он также может указывать на каталог, не содержащий файл CMakeLists.txt, или даже на несуществующий каталог. Это может быть использовано, чтобы избежать добавления проекта, который содержит файл CMakeLists.txt в своей корневой директории.

    Новое в версии 3.25: Если ключевое слово SYSTEM было включено в вызов FetchContent_Declare(), ключевое слово SYSTEM будет добавлено к команде add_subdirectory().

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

    Новое в версии 3.29: CMAKE_EXPORT_FIND_PACKAGE_NAME устанавливается в имя зависимости перед вызовом add_subdirectory().

Проекты должны стремиться объявлять подробности всех зависимостей, которые они могут использовать, до вызова FetchContent_MakeAvailable() для любой из них. Это гарантирует, что если какие-либо зависимости также являются подзависимостями одной или нескольких других, основной проект по-прежнему контролирует подробности, которые будут использоваться (потому что он объявляет их первым, прежде чем у зависимостей появится возможность). В следующих примерах кода предположим, что зависимость uses_other также использует FetchContent для добавления зависимости other внутри:

# WRONG: Should declare all details first
FetchContent_Declare(uses_other ...)
FetchContent_MakeAvailable(uses_other)

FetchContent_Declare(other ...)    # Will be ignored, uses_other beat us to it
FetchContent_MakeAvailable(other)  # Would use details declared by uses_other
# CORRECT: All details declared first, so they will take priority
FetchContent_Declare(uses_other ...)
FetchContent_Declare(other ...)
FetchContent_MakeAvailable(uses_other other)

Обратите внимание, что CMAKE_VERIFY_INTERFACE_HEADER_SETS явно устанавливается в значение false при входе в FetchContent_MakeAvailable(), и восстанавливается до исходного значения перед возвратом команды. Разработчики обычно хотят проверить только наборы заголовков из основного проекта, а не из зависимостей. Эта локальная манипуляция переменной CMAKE_VERIFY_INTERFACE_HEADER_SETS обеспечивает это интуитивное поведение. Вы можете использовать переменные, такие как CMAKE_PROJECT_INCLUDE или CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE, чтобы включить проверку для всех или некоторых зависимостей. Вы также можете установить свойство VERIFY_INTERFACE_HEADER_SETS отдельных целевых объектов.

FetchContent_Populate

Команда FetchContent_Populate() — это автономный вызов, который можно использовать для выполнения заполнения контента как изолированной операции. Редко используется, проекты почти всегда должны использовать FetchContent_Declare() и FetchContent_MakeAvailable() вместо нее. Основной случай использования FetchContent_Populate() — в режиме сценариев CMake в рамках реализации некоторой другой пользовательской функции более высокого уровня.

FetchContent_Populate(
  <name>
  [QUIET]
  [SUBBUILD_DIR <subBuildDir>]
  [SOURCE_DIR <srcDir>]
  [BINARY_DIR <binDir>]
  ...
)

После <name> должен быть указан как минимум один параметр, в противном случае вызов интерпретируется иначе (см. ниже). Поддерживаемые параметры для FetchContent_Populate() такие же, как для FetchContent_Declare(), за несколькими исключениями. Следующие параметры не относятся к заполнению контента с помощью FetchContent_Populate() и поэтому не поддерживаются:

  • EXCLUDE_FROM_ALL
  • SYSTEM
  • OVERRIDE_FIND_PACKAGE
  • FIND_PACKAGE_ARGS

Несколько параметров, показанных в сигнатуре выше, либо специфичны для FetchContent_Populate(), либо их поведение немного отличается от того, как ExternalProject_Add() обрабатывает их:

QUIET

Параметр QUIET может быть указан для скрытия вывода, связанного с заполнением указанного контента. Если заполнение завершается неудачей, вывод будет показан независимо от того, был ли указан этот параметр или нет, чтобы можно было диагностировать причину сбоя. Переменная FETCHCONTENT_QUIET не влияет на вызовы FetchContent_Populate() с указанными деталями контента напрямую.

Изменено в версии 3.30: Параметр QUIET и переменная FETCHCONTENT_QUIET не влияют, когда политика CMP0168 установлена в NEW. В этом случае вывод по умолчанию остается тихим, но уровень детализации вывода регулируется уровнем ведения журнала сообщений (см. CMAKE_MESSAGE_LOG_LEVEL и --log-level).

SUBBUILD_DIR

Аргумент SUBBUILD_DIR может быть предоставлен для изменения расположения подсборки, созданной для выполнения заполнения. Значение по умолчанию — ${CMAKE_CURRENT_BINARY_DIR}/<lowercaseName>-subbuild, и обычно нет необходимости его изменять. Если указан относительный путь, он будет интерпретироваться относительно CMAKE_CURRENT_BINARY_DIR. Этот параметр не следует путать с параметром SOURCE_SUBDIR , который влияет только на команду FetchContent_MakeAvailable().

Изменено в версии 3.30: SUBBUILD_DIR игнорируется, когда политика CMP0168 установлена в NEW, так как в этом случае подсборка не используется.

SOURCE_DIR, BINARY_DIR

Аргументы SOURCE_DIR и BINARY_DIR поддерживаются ExternalProject_Add(), но FetchContent_Populate() используют разные значения по умолчанию. SOURCE_DIR имеет значение по умолчанию ${CMAKE_CURRENT_BINARY_DIR}/<lowercaseName>-src, а BINARY_DIR имеет значение по умолчанию ${CMAKE_CURRENT_BINARY_DIR}/<lowercaseName>-build. Если указан относительный путь, он будет интерпретироваться относительно CMAKE_CURRENT_BINARY_DIR.

Помимо вышеуказанных явных параметров, все другие нераспознанные параметры передаются без изменений в ExternalProject_Add() для настройки шагов загрузки, исправления и обновления. Следующие параметры явно запрещены (они отключены командой FetchContent_Populate()):

  • CONFIGURE_COMMAND
  • BUILD_COMMAND
  • INSTALL_COMMAND
  • TEST_COMMAND

В этом формате переменные FETCHCONTENT_FULLY_DISCONNECTED и FETCHCONTENT_UPDATES_DISCONNECTED и политика CMP0170 игнорируются.

После возврата этой формы FetchContent_Populate() в области вызывающей программы будут установлены следующие переменные:

<lowercaseName>_SOURCE_DIR

Расположение, где можно найти заполненный контент по возвращении.

<lowercaseName>_BINARY_DIR

Директория, изначально предназначенная для использования в качестве соответствующей директории сборки, но маловероятно, что она будет актуальна при использовании этой формы команды.

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

Изменено в версии 3.30: Если политика CMP0168 установлена в NEW, подсборка не используется. В режиме сценариев CMake это позволяет вызвать FetchContent_Populate() без инструмента сборки или генератора CMake.

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

Команда поддерживает другую форму, хотя ее использование больше не рекомендуется:

FetchContent_Populate(<name>)

Изменено в версии 3.30: Эта форма устарела. Политика CMP0169 обеспечивает обратную совместимость для проектов, которым все еще требуется использовать эту форму, но проекты следует обновить, чтобы использовать FetchContent_MakeAvailable() вместо этого.

В этой форме единственным аргументом, переданным FetchContent_Populate() является <name>. В этом случае команда предполагает, что детали контента были записаны ранее вызовом FetchContent_Declare(). Детали хранятся в глобальной переменной, поэтому они не зависят от таких вещей, как область видимости переменных или каталогов. Поэтому неважно, где в проекте были ранее объявлены детали, достаточно, чтобы они были объявлены до вызова FetchContent_Populate(). Затем эти сохраненные детали используются для заполнения контента с помощью метода, основанного на ExternalProject_Add() (см. политику CMP0168 для важных аспектов поведения этого процесса).

При возвращении этой формы FetchContent_Populate() следующие переменные будут установлены в области видимости вызывающего объекта:

<lowercaseName>_POPULATED

Это значение всегда будет установлено в TRUE вызовом.

<lowercaseName>_SOURCE_DIR

Расположение, где можно найти заполненный контент по возвращении.

<lowercaseName>_BINARY_DIR

Каталог, предназначенный для использования в качестве соответствующего каталога сборки.

Значения этих трех переменных также можно получить из любого места иерархии проекта, используя команду FetchContent_GetProperties().

Реализация гарантирует, что если контент уже был заполнен в предыдущем запуске CMake, этот контент будет повторно использован, а не повторно заполняться. В общем случае, когда заполнение включает загрузку контента, стоимость загрузки оплачивается только один раз. Однако обратите внимание, что вызов FetchContent_Populate(<name>) с тем же <name> более одного раза в одном запуске CMake является ошибкой. См. FetchContent_GetProperties() для того, как определить, уже ли было выполнено заполнение <name> в текущем запуске.

FetchContent_GetProperties

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

FetchContent_GetProperties(
  <name>
  [SOURCE_DIR <srcDirVar>]
  [BINARY_DIR <binDirVar>]
  [POPULATED <doneVar>]
)

Опции SOURCE_DIR, BINARY_DIR, и POPULATED могут быть использованы для указания свойств, которые необходимо получить. Каждая опция принимает значение, которое является именем переменной, в которой должно храниться это свойство. Однако в большинстве случаев указывается только <name>, в этом случае вызов установит те же переменные, что и вызов FetchContent_MakeAvailable(name) или FetchContent_Populate(name). Обратите внимание, что значения SOURCE_DIR и BINARY_DIR могут быть пустыми, если вызов выполняется поставщиком зависимостей.

Эта команда редко необходима при использовании FetchContent_MakeAvailable(). Она чаще используется в рамках реализации устаревшего шаблона с FetchContent_Populate(), что гарантирует, что соответствующие переменные всегда будут определены независимо от того, было ли выполнено заполнение в другом месте проекта:

# WARNING: This pattern is deprecated, don't use it!
#
# Check if population has already been performed
FetchContent_GetProperties(depname)
if(NOT depname_POPULATED)
  # Fetch the content using previously declared details
  FetchContent_Populate(depname)

  # Set custom variables, policies, etc.
  # ...

  # Bring the populated content into the build
  add_subdirectory(${depname_SOURCE_DIR} ${depname_BINARY_DIR})
endif()
FetchContent_SetPopulated

Новое в версии 3.24.

Примечание

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

FetchContent_SetPopulated(
  <name>
  [SOURCE_DIR <srcDir>]
  [BINARY_DIR <binDir>]
)

Если команда-поставщик выполняет запрос FETCHCONTENT_MAKEAVAILABLE_SERIAL, она должна вызвать эту функцию перед возвратом. Аргументы SOURCE_DIR и BINARY_DIR могут быть использованы для указания значений, которые FetchContent_GetProperties() должен возвращать для соответствующих аргументов. Предоставляйте только SOURCE_DIR и BINARY_DIR если они имеют такое же значение, как если бы они были заполнены встроенной реализацией FetchContent_MakeAvailable().

Переменные

Несколько переменных кеша могут влиять на поведение, когда детали из вызова FetchContent_Declare() используются для заполнения контента.

Примечание

Все эти переменные предназначены для разработчика, чтобы настроить поведение. Их обычно не следует устанавливать проектом.

FETCHCONTENT_BASE_DIR

В большинстве случаев сохраненные детали не указывают никаких параметров, относящихся к каталогам для использования внутренних подсборок, окончательных исходных и сборки. Обычно лучше всего оставить эти решения модулю FetchContent для обработки от имени проекта. Переменная кеша FETCHCONTENT_BASE_DIR управляет точкой, из которой собираются все каталоги заполнения контента, но в большинстве случаев разработчикам не нужно изменять это значение. По умолчанию расположение - ${CMAKE_BINARY_DIR}/_deps, но если разработчики изменят это значение, они должны стремиться поддерживать короткий путь, чуть ниже верхнего уровня дерева сборки, чтобы избежать проблем с длиной пути в Windows.

FETCHCONTENT_QUIET

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

Изменено в версии 3.30: FETCHCONTENT_QUIET игнорируется, если политика CMP0168 установлена в значение NEW. Выходные данные по-прежнему тихие по умолчанию в этом случае, но уровень подробности контролируется уровнем протоколирования сообщений (см. CMAKE_MESSAGE_LOG_LEVEL и --log-level).

FETCHCONTENT_FULLY_DISCONNECTED

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

Примечание

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

Изменено в версии 3.30: Требование о том, что каталог исходного кода уже заполнен, когда FETCHCONTENT_FULLY_DISCONNECTED является истинным, теперь выполняется. См. политику CMP0170.

END_OF_DOCUMENT_MARKER
FETCHCONTENT_UPDATES_DISCONNECTED

Это менее жёсткий контроль загрузки/обновления по сравнению с FETCHCONTENT_FULLY_DISCONNECTED. Вместо полного игнорирования логики загрузки и обновления, FETCHCONTENT_UPDATES_DISCONNECTED блокирует только этап обновления, который устанавливает соединения с удалёнными серверами при использовании методов загрузки git или hg. Обновления всё ещё происходят, если меняются детали этапа обновления, но попытка обновления производится только с информацией, уже доступной локально (поэтому переключение на другой тег или коммит, уже загруженный локально, будет успешным, но переключение на неизвестный хеш коммита — нет). Этап загрузки не затрагивается, поэтому если содержимое ранее не было загружено, оно всё ещё будет загружено, если этот параметр включён. Это может ускорить этап конфигурации, но не так сильно, как FETCHCONTENT_FULLY_DISCONNECTED. FETCHCONTENT_UPDATES_DISCONNECTED по умолчанию OFF.

FETCHCONTENT_TRY_FIND_PACKAGE_MODE

Новая версия 3.24.

Эта переменная изменяет детали, которые FetchContent_Declare() записывает для заданной зависимости. Хотя в конечном итоге она контролирует поведение FetchContent_MakeAvailable(), используется значение переменной во время вызова FetchContent_Declare(). Не имеет значения, какое значение имеет переменная при вызове FetchContent_MakeAvailable(). Поскольку переменная должна устанавливаться только пользователем, а не проектами напрямую, она обычно имеет одинаковое значение, поэтому это различие обычно незаметно.

FETCHCONTENT_TRY_FIND_PACKAGE_MODE в конечном итоге определяет, может ли FetchContent_MakeAvailable() вызывать find_package() для удовлетворения зависимости. Переменная может принимать одно из следующих значений:

OPT_IN

FetchContent_MakeAvailable() будет вызывать find_package() только если вызов FetchContent_Declare() включал ключевое слово FIND_PACKAGE_ARGS. Это также является поведением по умолчанию, если FETCHCONTENT_TRY_FIND_PACKAGE_MODE не установлен.

ALWAYS

find_package() может вызываться FetchContent_MakeAvailable() независимо от того, включал ли вызов FetchContent_Declare() ключевое слово FIND_PACKAGE_ARGS или нет. Если ключевое слово FIND_PACKAGE_ARGS не указано, поведение будет таким, как если бы FIND_PACKAGE_ARGS было указано без дополнительных аргументов после него.

NEVER

FetchContent_MakeAvailable() не будет вызывать find_package(). Любое ключевое слово FIND_PACKAGE_ARGS, заданное в вызове FetchContent_Declare(), будет проигнорировано.

В качестве особого случая, если переменная FETCHCONTENT_SOURCE_DIR_<uppercaseName> имеет ненулевое значение для зависимости, предполагается, что пользователь переопределяет все остальные способы обеспечения этой зависимости. FETCHCONTENT_TRY_FIND_PACKAGE_MODE не повлияет на эту зависимость, и FetchContent_MakeAvailable() не будет пытаться вызвать find_package() для неё.

В дополнение к вышеперечисленному, для каждого имени содержимого также определены следующие переменные:

FETCHCONTENT_SOURCE_DIR_<uppercaseName>

Если это установлено, для указанного содержимого не выполняются шаги загрузки и обновления, и переменная <lowercaseName>_SOURCE_DIR возвращается вызывающей стороне, указывая на это местоположение. Это предоставляет разработчикам способ создать отдельный клон содержимого, который они могут свободно изменять без вмешательства сборки. Сборка просто использует этот существующий исходный код, но всё ещё определяет <lowercaseName>_BINARY_DIR, указывающий внутри своей области сборки. Разработчикам настоятельно рекомендуется использовать этот механизм вместо редактирования исходных кодов по умолчанию, так как изменения в исходных кодах по умолчанию могут быть потеряны, если проект изменит данные о загрузке содержимого.

FETCHCONTENT_UPDATES_DISCONNECTED_<uppercaseName>

Это эквивалент FETCHCONTENT_UPDATES_DISCONNECTED на уровне содержимого. Если глобальный параметр или этот параметр ON, тогда обновления для методов git и hg не будут обращаться к удалённому серверу для указанного содержимого. Они будут использовать только информацию, уже доступную локально. Отключение обновлений для отдельных содержимых элементов может быть полезно для содержимого, детали которого редко меняются, при этом другие часто меняющиеся содержимые элементы остаются с включёнными обновлениями.

Примеры

Типичный случай

Этот достаточно простой пример обеспечивает доступность популярных тестовых фреймворков для основной сборки:

include(FetchContent)
FetchContent_Declare(
  googletest
  GIT_REPOSITORY https://github.com/google/googletest.git
  GIT_TAG        703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
)
FetchContent_Declare(
  Catch2
  GIT_REPOSITORY https://github.com/catchorg/Catch2.git
  GIT_TAG        605a34765aa5d5ecbf476b4598a862ada971b0cc # v3.0.1
)

# After the following call, the CMake targets defined by googletest and
# Catch2 will be available to the rest of the build
FetchContent_MakeAvailable(googletest Catch2)

Интеграция с find_package()

В предыдущем примере, если пользователь хотел сначала попробовать найти googletest и Catch2 через find_package(), а затем попробовать загрузить и собрать их из исходного кода, он мог бы установить переменную FETCHCONTENT_TRY_FIND_PACKAGE_MODE в значение ALWAYS. Это также повлияет на любые другие вызовы FetchContent_Declare() в рамках проекта, что может быть неприемлемо. Вместо этого поведение можно включить только для этих двух зависимостей, добавив FIND_PACKAGE_ARGS к объявленным деталям и оставив FETCHCONTENT_TRY_FIND_PACKAGE_MODE не заданной или в значении OPT_IN.

include(FetchContent)
FetchContent_Declare(
  googletest
  GIT_REPOSITORY https://github.com/google/googletest.git
  GIT_TAG        703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
  FIND_PACKAGE_ARGS NAMES GTest
)
FetchContent_Declare(
  Catch2
  GIT_REPOSITORY https://github.com/catchorg/Catch2.git
  GIT_TAG        605a34765aa5d5ecbf476b4598a862ada971b0cc # v3.0.1
  FIND_PACKAGE_ARGS
)

# This will try calling find_package() first for both dependencies
FetchContent_MakeAvailable(googletest Catch2)

Для Catch2, дополнительные аргументы к find_package() не нужны, поэтому дополнительные аргументы после ключевого слова FIND_PACKAGE_ARGS не указываются. Для googletest, его пакет чаще называют GTest, поэтому добавляются аргументы для поддержки поиска по этому имени.

Если пользователь хотел отключить FetchContent_MakeAvailable() от вызова find_package() для любой зависимости, даже если она предоставила FIND_PACKAGE_ARGS в своих объявленных деталях, он мог бы установить FETCHCONTENT_TRY_FIND_PACKAGE_MODE в значение NEVER.

Если проект хотел указать, что эти две зависимости должны быть загружены и собраны из исходного кода, и что вызовы find_package() должны быть перенаправлены на использование собранных зависимостей, необходимо использовать параметр OVERRIDE_FIND_PACKAGE при объявлении деталей содержимого:

include(FetchContent)
FetchContent_Declare(
  googletest
  GIT_REPOSITORY https://github.com/google/googletest.git
  GIT_TAG        703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
  OVERRIDE_FIND_PACKAGE
)
FetchContent_Declare(
  Catch2
  GIT_REPOSITORY https://github.com/catchorg/Catch2.git
  GIT_TAG        605a34765aa5d5ecbf476b4598a862ada971b0cc # v3.0.1
  OVERRIDE_FIND_PACKAGE
)

# The following will automatically forward through to FetchContent_MakeAvailable()
find_package(googletest)
find_package(Catch2)

CMake предоставляет модуль FindGTest, который определяет некоторые переменные, которые могут использоваться более старыми проектами вместо связывания с импортированными целевыми объектами. Для поддержки таких случаев мы можем предоставить дополнительный файл. Согласно философии "первое определение побеждает" FetchContent, мы записываем этот файл только если этого ещё не сделал кто-то другой.

FetchContent_MakeAvailable(googletest)

if(NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/googletest-extra.cmake AND
   NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/googletestExtra.cmake)
  file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/googletest-extra.cmake
[=[
if("${GTEST_LIBRARIES}" STREQUAL "" AND TARGET GTest::gtest)
  set(GTEST_LIBRARIES GTest::gtest)
endif()
if("${GTEST_MAIN_LIBRARIES}" STREQUAL "" AND TARGET GTest::gtest_main)
  set(GTEST_MAIN_LIBRARIES GTest::gtest_main)
endif()
if("${GTEST_BOTH_LIBRARIES}" STREQUAL "")
  set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
endif()
]=])
endif()

Проекты, скорее всего, будут использовать find_package(GTest) вместо find_package(googletest), но можно использовать область CMAKE_FIND_PACKAGE_REDIRECTS_DIR, чтобы включить последнюю как зависимость первой. Это, вероятно, будет достаточно для типичного вызова find_package(GTest).

FetchContent_MakeAvailable(googletest)

if(NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/gtest-config.cmake AND
   NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/GTestConfig.cmake)
  file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/gtest-config.cmake
[=[
include(CMakeFindDependencyMacro)
find_dependency(googletest)
]=])
endif()

if(NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/gtest-config-version.cmake AND
   NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/GTestConfigVersion.cmake)
  file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/gtest-config-version.cmake
[=[
include(${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/googletest-config-version.cmake OPTIONAL)
if(NOT PACKAGE_VERSION_COMPATIBLE)
  include(${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/googletestConfigVersion.cmake OPTIONAL)
endif()
]=])
endif()

Переопределение местоположения CMakeLists.txt

Если файл CMakeLists.txt подпроекта не находится в корне его дерева исходных кодов, можно использовать опцию SOURCE_SUBDIR для указания FetchContent, где его найти. Следующий пример демонстрирует использование этой опции, а также устанавливает переменную, имеющую значение для подпроекта перед включением его в основной сборке (установлено как INTERNAL переменная кеша, чтобы избежать проблем с политикой CMP0077):

include(FetchContent)
FetchContent_Declare(
  protobuf
  GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git
  GIT_TAG        ae50d9b9902526efd6c7a1907d09739f959c6297 # v3.15.0
  SOURCE_SUBDIR  cmake
)
set(protobuf_BUILD_TESTS OFF CACHE INTERNAL "")
FetchContent_MakeAvailable(protobuf)

Сложные иерархии зависимостей

В более сложных иерархиях проектов отношения зависимостей могут быть более сложными. Рассмотрим иерархию, где projA является проектом верхнего уровня и напрямую зависит от проектов projB и projC. Оба проекта projB и projC могут быть построены автономно, и оба также зависят от другого проекта projD. projB дополнительно зависит от projE. Этот пример предполагает, что все пять проектов доступны на сервере компании Git. Файлы CMakeLists.txt каждого проекта могут содержать разделы, подобные следующим:

projA
include(FetchContent)
FetchContent_Declare(
  projB
  GIT_REPOSITORY git@mycompany.com:git/projB.git
  GIT_TAG        4a89dc7e24ff212a7b5167bef7ab079d
)
FetchContent_Declare(
  projC
  GIT_REPOSITORY git@mycompany.com:git/projC.git
  GIT_TAG        4ad4016bd1d8d5412d135cf8ceea1bb9
)
FetchContent_Declare(
  projD
  GIT_REPOSITORY git@mycompany.com:git/projD.git
  GIT_TAG        origin/integrationBranch
)
FetchContent_Declare(
  projE
  GIT_REPOSITORY git@mycompany.com:git/projE.git
  GIT_TAG        v2.3-rc1
)

# Order is important, see notes in the discussion further below
FetchContent_MakeAvailable(projD projB projC)
projB
include(FetchContent)
FetchContent_Declare(
  projD
  GIT_REPOSITORY git@mycompany.com:git/projD.git
  GIT_TAG        20b415f9034bbd2a2e8216e9a5c9e632
)
FetchContent_Declare(
  projE
  GIT_REPOSITORY git@mycompany.com:git/projE.git
  GIT_TAG        68e20f674a48be38d60e129f600faf7d
)

FetchContent_MakeAvailable(projD projE)
projC
include(FetchContent)
FetchContent_Declare(
  projD
  GIT_REPOSITORY git@mycompany.com:git/projD.git
  GIT_TAG        7d9a17ad2c962aa13e2fbb8043fb6b8a
)

FetchContent_MakeAvailable(projD)

Несколько ключевых моментов следует отметить в вышеприведённом:

  • projB и projC определяют разные детали содержимого для projD, но projA также определяет набор деталей содержимого для projD. Поскольку projA определит их в первую очередь, детали из projB и projC не будут использованы. Детали переопределения, определенные projA, не обязаны совпадать ни с одним из этих деталей из projB или projC, но проект верхнего уровня должен убедиться, что определенные им детали всё ещё имеют смысл для дочерних проектов.
  • В вызове projA к FetchContent_MakeAvailable(), projD указан перед projB и projC, поэтому он будет заполнен перед projB или projC. Это не обязательно для projA, но это гарантирует, что projA полностью контролирует среду, в которой projD включен в сборку (свойства каталогов особенно важны).
  • Хотя projA определяет детали содержимого для projE, он не обязан явным образом вызывать FetchContent_MakeAvailable(projE) или FetchContent_Populate(projD) сам. Вместо этого он оставляет это дочерним projB. Для проектов верхнего уровня часто достаточно просто определить детали переопределённого содержимого и оставить фактическое заполнение дочерним проектам. Это экономит повторное указание одного и того же на каждом уровне иерархии проекта, но это следует делать только в том случае, если свойства каталогов, установленные зависимостями, не должны влиять на заполнение общей зависимости (projE в этом случае).

Заполнение содержимого без добавления его в сборку

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

cmake_minimum_required(VERSION 3.14)

include(FetchContent)
FetchContent_Declare(
  mycom_toolchains
  URL  https://intranet.mycompany.com//toolchains_1.3.2.tar.gz
)
FetchContent_MakeAvailable(mycom_toolchains)

project(CrossCompileExample)

Проект можно настроить на использование одного из загруженных наборов инструментов следующим образом:

cmake -DCMAKE_TOOLCHAIN_FILE=_deps/mycom_toolchains-src/toolchain_arm.cmake /path/to/src

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

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

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

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

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

Spec-Zone.ru

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