Основы CMake

Тема дорожной карты · Modern C++ Developer

CMake — де-факто стандартная система сборки в мире C++. Это не сборщик, а генератор: по описанию проекта в CMakeLists.txt он создаёт файлы для Make, Ninja, Visual Studio или Xcode. Практически каждая современная библиотека поставляется с поддержкой CMake, а менеджеры пакетов Conan и vcpkg опираются на его механизм поиска зависимостей. Без уверенного владения «современным CMake» (target-based подход, версии 3.15+) невозможно поддерживать кроссплатформенный проект.

Как это работает

Проект описывается декларативно: команда project() задаёт имя и языки, add_executable() и add_library() объявляют цели, а target_link_libraries() связывает их между собой. Ключевая идея современного CMake — свойства привязаны к целям, а не к каталогам. Флаги компиляции, пути к заголовкам и определения макросов задаются через target_compile_options, target_include_directories, target_compile_definitions с указанием области видимости: PRIVATE — только для самой цели, INTERFACE — только для потребителей, PUBLIC — для обоих.

Сборка проходит в два этапа. Конфигурация (cmake -S . -B build -G Ninja) выполняет скрипт, находит компилятор, проверяет зависимости через find_package() и генерирует build-файлы в отдельном каталоге. Затем cmake --build build запускает выбранный генератор. Такое разделение позволяет держать несколько конфигураций (Debug, Release, разные компиляторы) рядом с одним исходным деревом.

Зависимости подключаются через find_package() для установленных библиотек или FetchContent для загрузки из Git во время конфигурации. Библиотека, экспортирующая цели вида fmt::fmt, автоматически передаёт потребителю свои заголовки и флаги — достаточно одной строки target_link_libraries(app PRIVATE fmt::fmt).

Когда применять

CMake стоит использовать для любого проекта, который должен собираться более чем на одной машине или платформе, публиковаться как библиотека или подключать сторонние зависимости. Для однофайлового эксперимента достаточно вызова компилятора, но уже при появлении тестов, нескольких целей и внешних библиотек выгоднее сразу завести CMakeLists.txt. Пресеты (CMakePresets.json) закрепляют стандартные конфигурации для команды и CI, а CTest встраивает запуск тестов в тот же пайплайн. Альтернативы вроде Bazel или Meson имеет смысл рассматривать только при монорепозиториях гигантского размера или особых требованиях к воспроизводимости.

Типичные ошибки

Устаревший стиль с include_directories() и глобальным CMAKE_CXX_FLAGS протекает во все цели проекта и ломает подключаемые библиотеки. Сборка в исходном каталоге засоряет репозиторий и мешает держать несколько конфигураций — всегда используйте отдельный каталог build. Жёстко прописанные абсолютные пути и флаги конкретного компилятора делают проект непереносимым; вместо них применяйте генераторные выражения и target_compile_features(app PRIVATE cxx_std_20). Использование file(GLOB) для списка исходников без CONFIGURE_DEPENDS приводит к тому, что новые файлы не попадают в сборку до повторной конфигурации. Наконец, слишком низкая cmake_minimum_required отключает современные политики и меняет семантику команд.

Связанные понятия

Полезные ресурсы

🔤 Английские термины в этой теме

Слова из этой темы, которые русскоязычные часто произносят неверно. Кнопка 🔊 произносит голосом браузера.

Весь словарь терминов →