Общая информация

CMake - это единственная и неповторимая система сборки, которую мы используем. CMake позволяет собрать C++ проект в исполняемый файл, статическую или динамическую библиотеку на разных платформах, компиляторах и операционных системах.

Каждый этап сборки с помощью CMake состоит из трёх шагов:

  • Конфигурация: на этом этапе задаются переменные окружения, компиляторы, конфигурация сборки, шаблоны и прочее. Выполняет роль описание того, как будет собираться проект, но сам процесс компиляции и линковки происходит не здесь.
  • Сборка: на этом этапе происходит компиляция и линковка всех целей CMake (targets) в соответствии с конфигурацией из предыдущего этапа.
  • Установка: готовые бинарные файлы, заголовки и файлы конфигурации собираются в пакет и устанавливаются в указанную директорию (префиксный путь). Это опциональный этап, но хорошим тоном является описывать шаг установки в своих CMake-файлах.

Конфигурация

Для конфигурации проекта необходимо вызвать команду cmake со следующими аргументами:

  • -S - папка, в которой лежит корневой CMakeLists.txt вашего проекта
  • -B - папка, в которой вы хотите произвести сборку
  • -G [Ninja|...] - генератор (подробнее про генераторы здесь). Мы используем Ninja в качестве основного генератора.
  • -DCMAKE_BUILD_TYPE=[Release|Debug|MinSizeRel|RelWithDebugInfo] - шаблон сборки. Для релизных проектов всегда выбирайте Release, для разработки - Debug.
  • -DBUILD_SHARED_LIBS=[ON|OFF] - выбор между статической/динамической версией сборки (только для библиотек). Для сборки динамической библиотеки используйте ON, в противном случае - OFF
  • -DCMAKE_C_COMPILER=$PATH - выбор компилятора для языка C. По умолчанию для генератора Ninja на ОС Linux это gcc, на ОС Windows - mingw-w64-x86_64-gcc (если установлен) или cl.exe (MSVC). Не указывайте этот аргумент в большинстве случаев.
  • -DCMAKE_CXX_COMPILER=$PATH - аналогично предыдущему, выбор компилятора для языка C++. По умолчанию для генератора Ninja на ОС Linux это g++, на ОС Windows - mingw-w64-x86_64-g++ или cl.exe.
  • --preset и -DCMAKE_TOOLCHAIN_PATH - подробнее об этом в статье про Conan. (здесь появится ссылка, когда я ее напишу!).
Примеры конфигурации проекта, лежащего в текущей рабочей директории:
Простая отладочная конфигурация
cmake -S . -B target/debug -G Ninja
Конфигурация динамической библиотеки
cmake -S . -B target/release -G Ninja\
-DCMAKE_BUILD_TYPE="Release"\
-DBUILD_SHARED_LIBS=ON
Конфигурация релизной динамической библиотеки с помощью Clang
cmake -S . -B target/release-clang -G Ninja\
-DCMAKE_BUILD_TYPE="Release"\
-DBUILD_SHARED_LIBS=ON\
-DCMAKE_C_COMPILER="/usr/bin/clang"\
-DCMAKE_CXX_COMPLILER="/usr/bin/clang++"
Конфигурация для кросс-компиляции под Windows из ОС Linux
x86_64-w64-mingw32-cmake -S . -B target/release -G Ninja\
-DCMAKE_BUILD_TYPE="Release"\
-DBUILD_SHARED_LIBS=ON

Примечание

Обратите внимание, что для кросс-компиляции под Windows на этапе конфигурации используется команда x86_64-w64-mingw32-cmake вместо cmake. Это необходимо для корректного выбора компилятора и настройки среды MinGW, Данная команда применяется только к этапу конфигурации. Дальнейшая сборка и установка будет выполняться обычной командой cmake.

Сборка

На этапе сборки проекта исходный код компилируется и линкуется в бинарные файлы. Сборка любого проекта должна осуществляться командой cmake --build.

Замечание

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

Аргументы сборки

  • --target <TARGET> - явно указывает, какая цель будет собрана (в случае если целей сборки в проекте несколько). По умолчанию собираются все цели.
  • --config <Release/Debug/MinSizeRel/ReleaseWithDebugInfo> - конфигурация сборки (аналогично опции -DCMAKE_BUILD_TYPE=<TYPE> на этапе конфигурации.
  • --clean-first - производит очистку кеша предыдущей сборки перед новой.
  • --parallel - выполняет сборку на всех доступных ядрах устройства.
  • -- <...> - прямая передача нативных аргументов в вызываемый генератор.

Примеры

Производит сборку уже сконфигурированного проекта:

cmake --build target --parallel

Производит сборку уже сконфигурированного проекта в режиме Release:

cmake --build target --config "Release" --parallel

Производит сборку только одной цели с именем binary-file:

cmake --build target --target "binary-file" --parallel

Экспорт

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

. 
├── include 
├── bin 
├── lib/ 
│ └── cmake/ 
│     └── <libname> 
└── share

Проект, который был экспортирован, можно подключать в другие проекты с помощью удобного инструмента поиска пакетов CMake - команды find_package(). Также такой проект легко использовать в связке с пакетными менеджерами - Conan, vcpkg и другими.

Экспорт проектных файлов производится с помощью команды cmake --install.

Аргументы экспорта

  • --prefix "<PATH>" - целевая папка, в которую будет экспортирован проект. По умолчанию зависит от системы и равна:
    • C:\Program Files (x86) на ОС Windows;
    • /usr/local или /usr на ОС Linux.

При установке в системные директории команду cmake --install необходимо запускать от имени администратора ОС (т.е. sudo cmake --install на ОС Linux).

Примеры

Установка в подпапку export существующей папки target:

cmake --install target --prefix "target/export"

Установка в системные директории:

sudo cmake --install target # на ОС Linux
cmake --install target      # на ОС Windows, требует запуска консоли от им. адм.

Пример сборки проекта

Простая сборка и установка в локальную подпапку:

cmake -S . -B target -DCMAKE_BUILD_TYPE="Release"
cmake --build target --config "Release" --parallel
cmake --install target --prefix "target/export"

Сборка проекта в режиме Debug:

cmake -S . -B target 
cmake --build target --parallel

Сборка проекта с передачей особого префиксного пути, затем установка в этот же путь:

cmake -S . -B target -DCMAKE_BUILD_TYPE="Release" -DCMAKE_PREFIX_PATH="/usr/local/cmakelibs"
cmake --build target --config "Release" --parallel
sudo cmake --install target --prefix "/usr/local/cmakelibs"