Введение
Мы живем в удивительное время. C++26 уже здесь, привнося в язык рефлексию и долгожданные сетевые возможности, а инструменты сборки наконец-то догнали и перегнали потребности разработчиков. Долгие годы CMake был тем самым «необходимым злом» — могучим, но неповоротливым монстром, скрипты на котором было сложно читать, а ошибки конфигурации пугали новичков.
Новая парадигма: File-Based API 2.0 и тотальная прозрачность
Проблема прошлого: Отладка сложных сборок была похожа на шаманство. Нужно было запускать make, смотреть вывод, гадать, почему линковщик ругается.
Решение в CMake 4.0: API, работающий с файлами, был кардинально расширен. Теперь это не просто «экспорт данных», а полноценная система интроспекции .
Глубокое Debug-информирование
Теперь в процессе конфигурации CMake генерирует не просто команды, а граф зависимостей с метаданными. Вы можете получить JSON-файл, в котором расписано:
- Почему линкуется конкретная библиотека (трассировка до корневого target_link_libraries).
- Какие флаги откуда пришли (из INTERFACE, из свойства таргета, из переменной окружения).
- Граф вызовов функций самого CMake (профилирование производительности скриптов).
Пример использования для отладки:
Вместо того чтобы гадать, почему линковщик подхватил старую версию библиотеки, вы запрашиваете:
cmake --build . --target help-file-api cat build/.cmake/api/v1/query/client-/target-[your_target]-debug.json
На выходе вы видите полную родословную каждого объекта.
Революция в работе с линкером: Префикс LINKER:
Это, пожалуй, самое важное изменение для тех, кто мучился с флагами линковки на разных платформах. Раньше, чтобы передать флаг линковщику, приходилось использовать обертки компилятора (-Wl, в GCC/Clang) или специфические для MSVC флаги. Это делало код CMake уродливым и полным платформенно-зависимых условий.
CMake 4.0 вводит гениально простой префикс LINKER: .
Было (старый стиль, полный костылей):
# Для GCC/Clang target_link_options(my_app PRIVATE "-Wl,--wrap,malloc") # Для MSVC if(MSVC) target_link_options(my_app PRIVATE "/INCLUDE:malloc_wrap") endif()
Стало (CMake 4.0+):
# CMake сам преобразует этот флаг в синтаксис, понятный текущему тулчейну target_link_options(my_app PRIVATE "LINKER:--wrap,malloc")
Как это работает под капотом:
- GCC/Clang: Преобразуется в -Wl,--wrap,malloc.
- MSVC: Преобразуется в /INCLUDE:malloc_wrap.
- Apple LD: Преобразуется в -Wl,-wrap,malloc.
Это кардинально упрощает написание кроссплатформенных проектов. Теперь не нужно писать горы условий. Это работает и для передачи целых скриптов линковщику.
Интеграция с экосистемами: Python и Ruby больше не «чужие»
Раньше, если вы писали модуль на C++ для Python (Pybind11) или Ruby, вам приходилось вручную вызывать find_package для PythonLibs, возиться с виртуальными окружениями, правильно линковать интерпретатор.
CMake 4.0 представил Native Ecosystem Modules . Теперь CMake понимает структуру этих языков «из коробки».
Пример сборки модуля для Python 3.12+
cmake_minimum_required(VERSION 4.0) project(SuperFastCalculator LANGUAGES CXX) # Встроенный модуль. Не нужно искать пути вручную! find_package(Python REQUIRED COMPONENTS Interpreter Development.Module) # Создаем разделяемую библиотеку, которая является Python-модулем python_add_library(super_calc MODULE src/calc.cpp) # Линкуем с правильными флагами для Python (автоматически) target_link_libraries(super_calc PRIVATE Python::Module) # Устанавливаем прямо в site-packages install(TARGETS super_calc DESTINATION ${Python_SITEARCH})
Ключевой момент: CMake 4.2.1 расширил поддержку компиляторов для фортрана (LLVMFlang) , что важно для научных гибридных проектов (C++ + Fortran).
Эволюция поддержки компиляторов и платформ (Версии 4.1 и 4.2)
Выход обновлений 4.1 и 4.2 в конце 2025 — начале 2026 года привнес важные коррективы, которые обязан знать каждый .
Visual Studio 2026 (v18) и ARM64
CMake 4.2 полностью адаптирован под VS 2026. Критическое изменение касается Android-разработки в Visual Studio: обновлен параметр ApplicationTypeRevision до версии 3.0. Если вы собираете мобильные приложения под Android через VS, теперь это требует явного указания в тулчейне.
Emscripten (WebAssembly) стал «взрослым»
Раньше CMake принудительно добавлял флаг -fPIC для Emscripten, что было избыточно. В версии 4.2.0 этот хардкод убрали .
- Фикс: try_run теперь корректно запускает .js файл, а не пытается выполнить .wasm бинарник напрямую. Это исправляет кучу ошибок при конфигурации проектов, собираемых в WebAssembly.
Современный шаблон проекта на C++26 и CMake 4.0
Прошли времена, когда в CMakeLists.txt писали «глобальные» переменные и команды include_directories. Современный подход — это строгая изоляция таргетов.
Давайте разберем идеальный шаблон проекта, использующего C++26, модули (std modules) и пакетный менеджер Conan 2.x, интегрированный с CMake 4.0 .
Структура проекта:
my_modern_lib/ ├── CMakeLists.txt (корневой) ├── conanfile.txt ├── src/ │ ├── CMakeLists.txt │ ├── my_lib_module.cppm (C++20/26 модуль!) │ └── my_lib.cpp ├── include/ │ └── my_lib/ │ └── public_api.h └── tests/ ├── CMakeLists.txt └── test_basic.cpp
Шаг 1: Корневой CMakeLists.txt (Тулчейн и Глобальные настройки)
cmake_minimum_required(VERSION 4.0) # Политики CMake: используем поведение версии 4.0 cmake_policy(VERSION 4.0) project(ModernProject VERSION 1.0.0 LANGUAGES CXX) # Устанавливаем стандарт C++26 как ИНТЕРФЕЙСНЫЙ для всех, кто нас подключает set(CMAKE_CXX_STANDARD 26) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # Не используем GNU расширения # Оптимизация: кэш для компилятора (поддержка встроена в CMake 4) find_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") endif() # Добавляем директории с кодом add_subdirectory(src) add_subdirectory(tests)
Шаг 2: Библиотека с поддержкой C++20 Modules (src/CMakeLists.txt)
Это магия CMake 4.0. Работа с .cppm файлами теперь «first-class citizen», а не через экспериментальные флаги.
# Объявляем библиотеку. PUBLIC_HEADER - явно указываем заголовочные файлы add_library(my_core_library) target_sources(my_core_library PUBLIC FILE_SET CXX_MODULES FILES my_lib_module.cppm # Это C++ модуль! PRIVATE my_lib.cpp PUBLIC FILE_SET HEADERS BASE_DIRS ../include FILES ../include/my_lib/public_api.h ) # Линковка библиотек target_link_libraries(my_core_library PUBLIC Boost::boost # Виртуальный импорт из Conan PRIVATE Threads::Threads ) # Флаги компиляции: только для этого таргета! target_compile_options(my_core_library PRIVATE $:/permissive- /EHsc> $>:-Wall -Wextra -Wpedantic> ) # Указываем, что установить install(TARGETS my_core_library EXPORT MyProjectTargets FILE_SET HEADERS DESTINATION include FILE_SET CXX_MODULES DESTINATION lib/cmake)
Шаг 3: Использование Conan 2.x (Пакетный менеджер)
CMake 4.0 отлично понимает профили Conan. Файл conanfile.txt:
[requires] boost/1.86.0 fmt/10.2.1 [generators] CMakeDeps CMakeToolchain [options] boost/*:shared=True
Сборка проекта одной командой:
conan install . --build=missing -s build_type=Release cmake --preset conan-release # Используем пресет, сгенерированный Conan cmake --build --preset conan-release
Интеграция тестирования: Google Test и CTest 4.0
CMake 4.0 расширил возможности CTest. Теперь он умеет напрямую парсить результаты тестов Google Test без лишних оберток. Функция gtest_discover_tests стала еще умнее .
Пример (tests/CMakeLists.txt):
add_executable(tests test_basic.cpp) target_link_libraries(tests PRIVATE my_core_library GTest::gtest_main) # Включаем тесты в CTest include(GoogleTest) gtest_discover_tests(tests PROPERTIES ENVIRONMENT "TEST_VAR=42" # Переменные окружения для тестов TIMEOUT 10 ) # Новая фишка CMake 4.0: Пропуск тестов по условию set_tests_properties(SomeFlakyTest PROPERTIES SKIP_RETURN_CODE 77 # Если тест вернул 77, CTest пометит его как пропущенный, а не упавший )
Деплой и упаковка: CPack стал умнее
CPack получил улучшенный генератор для AppImage и обновленную поддержку для пакетов . Теперь можно создавать установщики, которые учитывают модули C++20/26.
Важное изменение в экспорте (CPS): Исправлены ошибки экспорта определений (definitions) при использовании современных форматов пакетов, таких как CPS (Common Package Specification) . Это значит, что если вы подключаете библиотеку через find_package, макросы и определения (defs) передаются правильно и не теряются.
Заключение
Подводя итог нашему глубокому погружению в экосистему сборки 2026 года, можно сделать однозначный вывод: CMake 4.0 стал не просто инструментом, а полноценным оркестратором разработки.