Введение
Конфигурация CMake-проекта под несколько целевых платформ (Windows MSVC, Linux GCC, macOS Clang, кросс-компиляция под embedded) исторически решалась через длинные команды с десятками флагов -D, которые передавались вручную или прятались в shell-скриптах. CMake Presets (начиная с CMake 3.19+) формализует эти конфигурации в декларативный JSON-файл, который хранится в репозитории и понимается современными IDE (CLion, Visual Studio, VS Code) без дополнительной настройки. В статье разберём, как описать несколько профилей сборки Qt-проекта через presets.
Концепция
Файл CMakePresets.json в корне проекта описывает именованные presets для конфигурации (configurePresets) и сборки (buildPresets). Каждый preset может задавать генератор, переменные CMake (включая CMAKE_TOOLCHAIN_FILE, CMAKE_PREFIX_PATH для Qt и vcpkg), тип сборки (Debug/Release) и условия применимости (condition), например — preset активен только на конкретной ОС. Presets могут наследовать друг от друга через inherits, что позволяет выносить общие настройки в базовый preset и переопределять только различающиеся параметры.
Это устраняет необходимость в платформо-специфичных bat/sh скриптах и делает процесс сборки воспроизводимым одной командой cmake --preset <name> независимо от того, кто и на какой машине её запускает.
Пример кода: Сборка Qt-проекта под
{
"version": 6,
"configurePresets": [
{
"name": "base",
"hidden": true,
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
}
},
{
"name": "windows-msvc-debug",
"inherits": "base",
"generator": "Visual Studio 17 2022",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_PREFIX_PATH": "C:/Qt/6.7.0/msvc2019_64"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "linux-gcc-release",
"inherits": "base",
"generator": "Ninja",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_PREFIX_PATH": "/opt/Qt/6.7.0/gcc_64",
"CMAKE_CXX_COMPILER": "g++"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
}
},
{
"name": "macos-clang-release",
"inherits": "base",
"generator": "Ninja",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_PREFIX_PATH": "/opt/homebrew/opt/qt"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
}
}
],
"buildPresets": [
{ "name": "windows-msvc-debug", "configurePreset": "windows-msvc-debug" },
{ "name": "linux-gcc-release", "configurePreset": "linux-gcc-release" },
{ "name": "macos-clang-release", "configurePreset": "macos-clang-release" }
]
}
# Использование presets
cmake --preset linux-gcc-release
cmake --build --preset linux-gcc-release
Пояснения к коду
Preset base помечен как hidden: true — он не предназначен для прямого использования, а служит общим набором настроек (директория сборки, экспорт compile_commands.json для языковых серверов и IDE), от которого наследуются платформо-специфичные presets через inherits. Каждый конкретный preset задаёт генератор, путь к нужной сборке Qt через CMAKE_PREFIX_PATH и условие condition, ограничивающее его применимость конкретной ОС — это предотвращает случайный выбор неподходящего preset на чужой платформе.
Команды cmake --preset и cmake --build --preset заменяют длинные ручные вызовы с флагами, делая процесс сборки идентичным для любого разработчика и CI-агента, использующего этот файл.
Подводные камни
CMakePresets.jsonверсионируется в Git, а пользовательские локальные пути (например, специфичный путь к Qt на конкретной машине разработчика) — нет. Для индивидуальных переопределений путей существуетCMakeUserPresets.json, который должен быть в.gitignoreи наследовать общие presets изCMakePresets.json.- Несовпадение версии схемы (
"version") с установленной версией CMake. Новые возможности presets (например,condition) появились не в первой версии формата — слишком старая версия CMake в CI может не поддерживать нужную версию схемы, выдавая неясную ошибку парсинга. - Жёстко прописанные абсолютные пути к Qt в самом
CMakePresets.jsonломают переносимость между машинами с разной структурой каталогов — там, где путь действительно различается у каждого разработчика, его стоит выносить вCMakeUserPresets.jsonили передавать через переменные окружения внутри preset ("environment"). - Condition не означает автоматический выбор подходящего preset. Если запустить
cmake --preset windows-msvc-debugна Linux, CMake выдаст ошибку валидации condition — это защита от ошибки, а не автоматический подбор платформы; правильный preset для CI всё равно нужно выбирать явно по имени, соответствующему агенту.