CMakeMiddleExperience

Расскажите о случае, когда вы решали проблему с CMake: incident, optimization, migration, debugging или CI/CD.

Типичная проблема — несовместимые версии зависимостей после обновления системных библиотек. Решается через явное указание путей через CMAKE_PREFIX_PATH и переход на FetchContent для воспроизводимых сборок.

Реальный случай: сломанная сборка после обновления CI-образа

На одном проекте (C++ микросервис) CI внезапно начал падать с ошибкой Could not find a package configuration file provided by "Boost" with any of the following names: BoostConfig.cmake. Локально всё собиралось — проблема только в GitLab CI.

Диагностика

# Посмотреть, что нашёл CMake и где искал
cmake -B build --debug-find 2>&1 | grep -A5 "Boost"

# Проверить переменные пути
cmake -B build -DCMAKE_VERBOSE_MAKEFILE=ON

# Напечатать все CMake-переменные (помогает понять окружение)
cmake -B build -LA | grep -i boost

Оказалось, что CI-образ обновили с Ubuntu 20.04 до 22.04, а Boost в системе сменил версию с 1.71 на 1.74 — конфиг-файлы переехали в другой путь.

Решение 1: явный CMAKE_PREFIX_PATH

cmake -B build \
  -DCMAKE_PREFIX_PATH="/usr/lib/x86_64-linux-gnu/cmake" \
  -DBoost_NO_SYSTEM_PATHS=ON

Решение 2: переход на FetchContent (долгосрочное)

include(FetchContent)

FetchContent_Declare(
  Boost
  URL https://github.com/boostorg/boost/releases/download/boost-1.84.0/boost-1.84.0.tar.xz
  URL_HASH SHA256=2e64e5d79a738d0fa6fb546c6e5c2bd28f88d268a2a080546f74e5ff98f29d0e
)
set(BOOST_INCLUDE_LIBRARIES filesystem system)
FetchContent_MakeAvailable(Boost)

target_link_libraries(my_service PRIVATE Boost::filesystem Boost::system)

Решение 3: кэширование зависимостей в CI

# .gitlab-ci.yml
build:
  cache:
    key: cmake-deps-$CI_COMMIT_REF_SLUG
    paths:
      - build/_deps/
  script:
    - cmake -B build -DCMAKE_BUILD_TYPE=Release
    - cmake --build build --parallel $(nproc)

Другой кейс: медленная сборка в CI

Генерация Unix Makefiles вместо Ninja удваивала время сборки. Правка:

cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
ninja -C build -j$(nproc)

Подводные камни

  • Локальное окружение разработчика и CI-образ могут иметь разные версии системных библиотек — всегда фиксируйте версии через FetchContent или vcpkg.
  • find_package(X REQUIRED) без указания версии даёт первую найденную — это может быть несовместимая версия из /usr/local.
  • Кэш CMake (CMakeCache.txt) хранит абсолютные пути — копирование build-директории между машинами или контейнерами ломает сборку.
  • Переменная CMAKE_INSTALL_PREFIX по умолчанию /usr/local — в CI без sudo приводит к ошибке установки; всегда переопределяйте.
  • Переключение между Debug и Release требует пересборки с нуля или отдельной build-директории — cmake -B build-release vs build-debug.
  • FetchContent скачивает зависимости при каждой свежей CI-джобе без кэша — добавьте кэш по хэшу URL или используйте vcpkg с baseline.

What hurts your answer

  • Выдумывать опыт или говорить слишком общими фразами
  • Не объяснять свою личную роль в работе с CMake
  • Не показывать результат, метрики или извлечённые уроки

What they're listening for

  • Может подготовить честный пример использования CMake
  • Показывает свою роль, решения и результат
  • Умеет рефлексировать над trade-offs и уроками

Related topics