FetchContent
Новое в версии 3.11.
Обзор
Этот модуль позволяет заполнять контент во время настройки с помощью любого метода, поддерживаемого модулем ExternalProject. В то время как ExternalProject_Add() загружает контент во время сборки, модуль FetchContent делает контент доступным сразу, позволяя шагу настройки использовать контент в командах, таких как add_subdirectory(), include() или операциях file().
Подробности заполнения контента обычно определяются отдельно от команды, выполняющей фактическое заполнение. Это разделение гарантирует, что все данные о зависимостях будут определены до того, как что-либо попытается использовать эти данные для заполнения контента. Это особенно важно в более сложных иерархиях проектов, где зависимости могут быть общими для нескольких проектов.
Ниже приведён типичный пример объявления деталей контента:
FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG release-1.8.0 )
В большинстве типичных случаев заполнение контента может быть выполнено одной командой следующим образом:
FetchContent_MakeAvailable(googletest)
Вышеприведённая команда не только заполняет контент, но также добавляет его в основную сборку (если это возможно), чтобы основная сборка могла использовать цели заполненного проекта и т. д. В некоторых случаях основному проекту может потребоваться более точный контроль над заполнением или ему может потребоваться явно определить шаги заполнения (например, если необходимо поддерживать версии CMake, предшествующие 3.14). Типичный шаблон таких пользовательских шагов выглядит так:
FetchContent_GetProperties(googletest)
if(NOT googletest_POPULATED)
FetchContent_Populate(googletest)
add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
endif()
Независимо от того, какой метод заполнения используется, при использовании шаблона объявления-заполнения с иерархической структурой проекта, проекты на более высоких уровнях иерархии могут переопределять данные заполнения контента, указанного где-либо ниже в иерархии проекта. Возможность определять, был ли контент уже заполнен, гарантирует, что даже если несколько дочерних проектов хотят сделать определённый контент доступным, тот, кто его заполнил первым, побеждает. Другой дочерний проект может просто использовать уже доступный контент, а не повторять заполнение для себя. См. раздел Примеры, который демонстрирует этот сценарий.
Модуль FetchContent также поддерживает определение и заполнение контента в одном вызове, без проверки, был ли контент уже заполнен где-либо ещё в проекте. Это более низкоуровневая операция, и обычно модуль не используется таким образом, но иногда это полезно в рамках реализации каких-либо функций более высокого уровня или для заполнения контента в режиме скриптов CMake.
Изменено в версии 3.14: Команды FetchContent могут получить доступ к терминалу. Это необходимо для работы запросов паролей и отображения прогресса в реальном времени.
Команды
Объявление деталей контента
-
FetchContent_Declare -
FetchContent_Declare(<name> <contentOptions>...)
Функция
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 release-1.8.0 ) FetchContent_Declare( myCompanyIcons URL https://intranet.mycompany.com/assets/iconset_1.12.tar.gz URL_HASH 5588a7b18261c20068beabfb4f530b87 ) FetchContent_Declare( myCompanyCertificates SVN_REPOSITORY svn+ssh://svn.mycompany.com/srv/svn/trunk/certs SVN_REVISION -r12345 )
Заполнение контента
В большинстве распространённых сценариев заполнение означает обеспечение доступности контента для основной сборки в соответствии с ранее объявленными данными для этой зависимости. Существует два основных шаблона заполнения контента, один основан на вызове FetchContent_GetProperties() и FetchContent_Populate() для более точного контроля, а другой — на вызове FetchContent_MakeAvailable() для более простого и автоматизированного подхода. Первый вариант, как правило, следует этому каноническому шаблону:
# Check if population has already been performed
FetchContent_GetProperties(<name>)
string(TOLOWER "<name>" lcName)
if(NOT ${lcName}_POPULATED)
# Fetch the content using previously declared details
FetchContent_Populate(<name>)
# Set custom variables, policies, etc.
# ...
# Bring the populated content into the build
add_subdirectory(${${lcName}_SOURCE_DIR} ${${lcName}_BINARY_DIR})
endif()
Вышеупомянутый шаблон настолько распространён, что там, где между вызовами FetchContent_Populate() и add_subdirectory() не нужны пользовательские шаги, эквивалентный код может быть получен с помощью вызова FetchContent_MakeAvailable() вместо этого. Где это соответствует потребностям проекта, FetchContent_MakeAvailable() следует предпочитать, так как он проще и предоставляет дополнительные возможности по сравнению с шаблоном выше.
-
FetchContent_Populate -
FetchContent_Populate( <name> )
В большинстве случаев единственным аргументом, передаваемым в
FetchContent_Populate(), является<name>. В таком случае команда предполагает, что данные о содержимом были записаны ранее в ходе вызоваFetchContent_Declare(). Данные хранятся в глобальной переменной, поэтому они не зависят от таких факторов, как область видимости переменных или каталогов. Следовательно, не имеет значения, где в проекте были ранее объявлены данные, если они были объявлены до вызоваFetchContent_Populate(). Эти сохранённые данные затем используются для построения вызоваExternalProject_Add()в частном подпроекте для немедленного заполнения содержимого. РеализацияExternalProject_Add()гарантирует, что если содержимое уже было заполнено в предыдущем запуске CMake, это содержимое будет повторно использовано, а не заполнено заново. В общем случае, когда заполнение включает в себя загрузку содержимого, затраты на загрузку оплачиваются только один раз.Внутренняя глобальная переменная фиксирует, когда был обработан определённый запрос на заполнение содержимого. Если
FetchContent_Populate()вызывается более одного раза для одного и того же имени содержимого в ходе конфигурации, второй вызов завершится с ошибкой. Проекты могут и должны проверять, была ли уже обработана загрузка содержимого с помощью командыFetchContent_GetProperties()перед вызовомFetchContent_Populate().FetchContent_Populate()установит три переменные в области видимости вызывающей программы:<lcName>_POPULATED,<lcName>_SOURCE_DIRи<lcName>_BINARY_DIR, где<lcName>— это строка<name>в нижнем регистре.<lcName>_POPULATEDвсегда будет установлено вTrueв ходе вызова.<lcName>_SOURCE_DIR— это местоположение, где содержимое можно найти после возврата (оно уже будет заполнено), а<lcName>_BINARY_DIR— каталог, предназначенный для использования в качестве соответствующего каталога сборки. Основной сценарий использования двух переменных каталога заключается в вызовеadd_subdirectory()сразу после заполнения, например:FetchContent_Populate(FooBar ...) add_subdirectory(${foobar_SOURCE_DIR} ${foobar_BINARY_DIR})Значения трёх переменных также могут быть получены из любой точки иерархии проекта с помощью команды
FetchContent_GetProperties().Несколько переменных кэша влияют на поведение всех операций заполнения содержимого, выполняемых с помощью данных, сохранённых в ходе вызова
FetchContent_Declare():-
FETCHCONTENT_BASE_DIR -
В большинстве случаев сохранённые данные не содержат каких-либо параметров, относящихся к каталогам, которые нужно использовать для внутреннего подпроекта, конечных областей исходного кода и сборки. Обычно лучше оставить эти решения модулю
FetchContentдля обработки от имени проекта. Переменная кэшаFETCHCONTENT_BASE_DIRуправляет точкой, в которой собираются все каталоги заполнения содержимого, но в большинстве случаев разработчикам не нужно будет это изменять. По умолчанию используется${CMAKE_BINARY_DIR}/_deps, но если разработчики изменят это значение, они должны стремиться поддерживать короткий путь, расположенный непосредственно ниже верхнего уровня дерева сборки, чтобы избежать проблем с длиной пути в Windows. -
FETCHCONTENT_QUIET -
Выходные данные логов во время заполнения могут быть достаточно подробными, делая этап конфигурации довольно шумным. Этот параметр кэша (
ONпо умолчанию) скрывает все выходные данные заполнения, если только не возникнет ошибка. Если у вас возникают проблемы с зависанием загрузок, временное отключение этого параметра может помочь в диагностике проблемы с конкретным заполнением содержимого. -
FETCHCONTENT_FULLY_DISCONNECTED -
При включении этого параметра не предпринимаются никакие попытки загрузить или обновить содержимое. Предполагается, что всё содержимое уже было заполнено в предыдущем запуске, или каталоги исходного кода указывают на существующее содержимое, предоставленное разработчиком вручную (с помощью параметров, описанных ниже). Когда разработчик знает, что никакие изменения в данных о содержимом не вносились, включение этого параметра
ONможет существенно ускорить этап конфигурации. По умолчанию онOFF. -
FETCHCONTENT_UPDATES_DISCONNECTED -
Это менее жёсткий контроль загрузки/обновления по сравнению с
FETCHCONTENT_FULLY_DISCONNECTED. Вместо того, чтобы обойти всю логику загрузки и обновления,FETCHCONTENT_UPDATES_DISCONNECTEDотключает только этап обновления. Следовательно, если содержимое ранее не загружалось, оно всё равно будет загружено, когда этот параметр включён. Это может ускорить этап конфигурации, но не так сильно, какFETCHCONTENT_FULLY_DISCONNECTED. По умолчанию онOFF.
В дополнение к вышеуказанным переменным кэша, для каждого имени содержимого также определены следующие переменные кэша (
<ucName>— это значение<name>в верхнем регистре):-
FETCHCONTENT_SOURCE_DIR_<ucName> -
Если это значение установлено, для указанного содержимого не выполняются шаги загрузки или обновления, и переменная
<lcName>_SOURCE_DIRвозвращаемая вызывающей программе, указывает на это местоположение. Это даёт разработчикам возможность иметь отдельный набор содержимого, который они могут свободно изменять без вмешательства процесса сборки. Сборка просто использует этот существующий исходный код, но всё равно определяет<lcName>_BINARY_DIRдля указания на свою область сборки. Разработчикам настоятельно рекомендуется использовать этот механизм, а не изменять исходный код, заполненный по умолчанию, так как изменения исходного кода в каталоге по умолчанию могут быть потеряны, когда данные о заполнении содержимого меняются в проекте. -
FETCHCONTENT_UPDATES_DISCONNECTED_<ucName> -
Это эквивалент
FETCHCONTENT_UPDATES_DISCONNECTEDдля каждого содержимого. Если глобальный параметр или этот параметрON, то обновления будут отключены для указанного содержимого. Отключение обновлений для отдельных содержимых может быть полезно для содержимого, данные о котором редко меняются, в то время как другие часто изменяемые содержимые могут оставаться с включенными обновлениями.
Команда
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игнорируются.
Переменные
<lcName>_SOURCE_DIRи<lcName>_BINARY_DIRвсё равно возвращаются вызывающей программе, но поскольку эти места не сохраняются как глобальные переменные при использовании этого формата, они доступны только вызывающей программе и её подпрограммам, а не всей иерархии проекта. Переменная<lcName>_POPULATEDне устанавливается в области видимости вызывающей программы в этом формате.Поддерживаемые параметры для
FetchContent_Populate()такие же, как и дляFetchContent_Declare(). Эти немногие параметры, показанные выше, либо специфичны дляFetchContent_Populate(), либо их поведение немного отличается от того, какExternalProject_Add()их обрабатывает.-
QUIET -
Параметр
QUIETможет быть задан для скрытия вывода, связанного с заполнением указанного содержимого. Если заполнение завершится неудачей, вывод будет отображаться независимо от того, был ли задан этот параметр или нет, чтобы можно было диагностировать причину сбоя. Глобальная переменная кэшаFETCHCONTENT_QUIETне влияет на вызовыFetchContent_Populate()с прямым указанием данных содержимого. -
SUBBUILD_DIR -
Аргумент
SUBBUILD_DIRможет быть предоставлен для изменения расположения подпроекта, созданного для заполнения. Значение по умолчанию${CMAKE_CURRENT_BINARY_DIR}/<lcName>-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}/<lcName>-src, аBINARY_DIRимеет значение по умолчанию${CMAKE_CURRENT_BINARY_DIR}/<lcName>-build. Если указан относительный путь, он будет интерпретироваться относительноCMAKE_CURRENT_BINARY_DIR.
В дополнение к вышеуказанным явным параметрам, любые другие нераспознанные параметры передаются без изменений в
ExternalProject_Add()для выполнения шагов загрузки, применения исправлений и обновления. Следующие параметры явно запрещены (они отключены командойFetchContent_Populate()): -
CONFIGURE_COMMANDBUILD_COMMANDINSTALL_COMMANDTEST_COMMAND
Если использовать
FetchContent_Populate()в режиме сценариев CMake, следует учитывать, что реализация создаёт подсборку, которая, следовательно, требует наличия генератора CMake и инструмента сборки. Если эти компоненты не могут быть найдены по умолчанию, то переменныеCMAKE_GENERATORи/илиCMAKE_MAKE_PROGRAMнеобходимо будет установить соответствующим образом в командной строке, вызывающей сценарий.Добавлено в версии 3.18: Добавлена поддержка
DOWNLOAD_NO_EXTRACTиSOURCE_SUBDIRопций.
-
FetchContent_GetProperties -
При использовании сохранённых данных о содержимом, вызов
FetchContent_Populate()записывает информацию в глобальные свойства, которые могут быть запрошены в любое время. Эта информация включает каталоги исходников и библиотек, связанные с содержимым, а также то, обрабатывалась ли популяция содержимого во время текущего выполнения конфигурации.FetchContent_GetProperties( <name> [SOURCE_DIR <srcDirVar>] [BINARY_DIR <binDirVar>] [POPULATED <doneVar>] )
Опции
SOURCE_DIR,BINARY_DIRиPOPULATEDмогут быть использованы для указания свойств, которые должны быть извлечены. Каждая опция принимает значение, представляющее имя переменной, в которую следует сохранить данное свойство. Чаще всего используется только<name>, в этом случае вызов установит те же переменные, что и вызовFetchContent_Populate(name). Это позволяет использовать следующий канонический шаблон, гарантирующий определение необходимых переменных независимо от того, выполнялась ли популяция в другом месте проекта:FetchContent_GetProperties(foobar) if(NOT foobar_POPULATED) FetchContent_Populate(foobar) ... endif()
Вышеупомянутый шаблон позволяет другим частям общей иерархии проекта повторно использовать то же содержимое и гарантировать его заполнение только один раз.
-
FetchContent_MakeAvailable -
FetchContent_MakeAvailable( <name1> [<name2>...] )
Добавлено в версии 3.14.
Эта команда реализует общий шаблон, обычно необходимый для большинства зависимостей. Она итерирует по каждой из указанных зависимостей и для каждой из них приблизительно следует каноническому шаблону, представленному в начале этого раздела. Важное отличие заключается в том, что
add_subdirectory()будет вызван только для заполненного содержимого, если в верхнем каталоге исходников существует файлCMakeLists.txt. Это позволяет использовать команду для зависимостей, которые делают загруженное содержимое доступным в известном месте, но не нуждаются или не поддерживают прямое добавление в сборку.Опция
SOURCE_SUBDIRможет быть указана в объявленных деталях, чтобы направитьFetchContent_MakeAvailable()искать файлCMakeLists.txtв подкаталоге ниже верхнего уровня (то есть, таким же образом, какSOURCE_SUBDIRиспользуется командойExternalProject_Add()).SOURCE_SUBDIRдолжен всегда быть относительным путём. См. следующий раздел для примера использования этой опции.
Примеры
Этот первый довольно простой пример гарантирует доступность некоторых популярных фреймворков тестирования для основной сборки:
include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG release-1.8.0 ) FetchContent_Declare( Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG v2.5.0 ) # After the following call, the CMake targets defined by googletest and # Catch2 will be defined and available to the rest of the build FetchContent_MakeAvailable(googletest Catch2)
Если файл CMakeLists.txt подпроекта не находится на верхнем уровне его дерева исходных кодов, опция SOURCE_SUBDIR может использоваться для указания FetchContent местонахождения этого файла. Следующий пример демонстрирует использование этой опции, а также задаёт переменную, имеющую значение для подпроекта перед его включением в основную сборку:
include(FetchContent) FetchContent_Declare( protobuf GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git GIT_TAG v3.12.0 SOURCE_SUBDIR cmake ) set(protobuf_BUILD_TESTS OFF) 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 origin/release/2.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 запускается в каталоге сборки.
Наконец, следующий пример демонстрирует, как можно загрузить и распаковать архив прошивки с помощью 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–2021 Kitware, Inc. and Contributors
Licensed under the BSD 3-clause License.
https://cmake.org/cmake/help/v3.20/module/FetchContent.html