CMakeMiddleTechnical

Что такое cache variables в CMake и как их определять и использовать?

Cache-переменные CMake хранятся в CMakeCache.txt, переживают перезапуск конфигурации и задаются через set(VAR value CACHE TYPE docstring) или option(); пользователь может переопределить их флагом -D при вызове cmake.

Что такое cache-переменные в CMake

Cache-переменные — это переменные, которые CMake сохраняет в файле CMakeCache.txt в директории сборки. В отличие от обычных переменных, которые существуют только во время выполнения скрипта, cache-переменные переживают перезапуск cmake и доступны пользователю для изменения через cmake-gui, ccmake или флаг -D.

Объявление cache-переменных

Синтаксис команды set с ключевым словом CACHE:

set(<variable> <value> CACHE <type> <docstring> [FORCE])

Типы переменных:

  • BOOL — логическое значение (ON/OFF)
  • STRING — произвольная строка
  • FILEPATH — путь к файлу
  • PATH — путь к директории
  • INTERNAL — скрыто в GUI, используется самим CMake

Практические примеры

# Флаг включения тестов — пользователь может переопределить через -D
set(BUILD_TESTS ON CACHE BOOL "Build unit tests")

# Путь к внешней библиотеке
set(OPENSSL_ROOT_DIR "" CACHE PATH "Path to OpenSSL root directory")

# Выбор бэкенда рендеринга
set(RENDERER "vulkan" CACHE STRING "Renderer backend (vulkan/opengl/metal)")
set_property(CACHE RENDERER PROPERTY STRINGS vulkan opengl metal)

# Принудительная перезапись даже если пользователь уже изменил значение
set(INTERNAL_VERSION "1.2.3" CACHE STRING "" FORCE)

Использование cache-переменных из командной строки

# Установка при первом configure
cmake -S . -B build -DBUILD_TESTS=OFF -DOPENSSL_ROOT_DIR=/usr/local/ssl

# Изменение уже закешированного значения
cmake -S . -B build -DRENDERER=opengl

# Просмотр всех cache-переменных
cmake -L build/        # только пользовательские
cmake -LA build/       # включая ADVANCED
cmake -LAH build/      # с docstring

Разница между обычной переменной и cache-переменной

# Обычная переменная — локальная, не сохраняется между запусками cmake
set(MY_LOCAL "hello")

# Cache-переменная — сохраняется в CMakeCache.txt
set(MY_CACHED "hello" CACHE STRING "Cached value")

# ВАЖНО: обычная переменная перекрывает cache-переменную того же имени
set(MY_CACHED "override")  # теперь ${MY_CACHED} == "override", cache не тронут
unset(MY_CACHED)             # после этого ${MY_CACHED} снова берётся из cache

Опция option() как синтаксический сахар для BOOL cache-переменных

# Эквивалентно set(ENABLE_ASAN OFF CACHE BOOL "Enable AddressSanitizer")
option(ENABLE_ASAN "Enable AddressSanitizer" OFF)

if(ENABLE_ASAN)
  target_compile_options(myapp PRIVATE -fsanitize=address)
  target_link_options(myapp PRIVATE -fsanitize=address)
endif()

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

  • Stale cache после изменения CMakeLists.txt: если переименовали переменную, старое значение остаётся в CMakeCache.txt и сбивает с толку. Решение: удалить build/CMakeCache.txt или всю директорию сборки.
  • FORCE не обновляет значение в GUI немедленно: FORCE перезаписывает cache на диске, но cmake-gui может показывать старое значение до перезагрузки.
  • Порядок приоритетов: обычная переменная в текущем scope перекрывает cache-переменную того же имени — это неочевидный источник багов.
  • INTERNAL-переменные не видны в GUI: использование типа INTERNAL для скрытия «служебных» значений — осознанное решение, но может запутать при отладке.
  • Документирующая строка обязательна: пустой docstring ("") — плохая практика, особенно для публичного проекта; cmake-gui показывает его как подсказку.
  • Multi-config генераторы игнорируют CMAKE_BUILD_TYPE: при использовании Ninja Multi-Config или Visual Studio cache-переменная CMAKE_BUILD_TYPE не работает — нужен --config Release при сборке.
  • set_property STRINGS: без него cmake-gui показывает STRING-переменную как свободный ввод, а не как выпадающий список — пользователь может ввести некорректное значение.

Common mistakes

  • Объяснять cache variables только по синтаксису, без жизненного цикла и стоимости.
  • Игнорировать ошибки, null/empty состояния, порядок инициализации или режим сборки.
  • Давать пример, который работает в демо, но ломается при изменении владельца ресурса.
  • Трактовать CMake как shell-скрипт вместо описания графа таргетов.

What the interviewer is testing

  • Кандидат формулирует точную модель для cache variables, а не только определение.
  • Пример компилируем, безопасен по lifetime и соответствует версии технологии.
  • Названы trade-off, ограничения и диагностируемые симптомы ошибки.
  • Разделяет configure/generate/build и использует target-based подход.

Sources

Related topics