Знакомство с CMake. Часть 2. Переменные, условия, сообщения, опции.

В прошлой статье я рассмотрел основные задачи, решаемые системой сборки CMake, а также простенький проект. Сейчас я постараюсь внести ясность в механику работы этой системы сборки, чтобы было понятно, как CMake работает с CMakeLists.txt файлами. Это позволит с первого раза безошибочно создавать сложные кроссплатформенные проекты и легко читать чужие проекты.

Порядок чтения

Файл CMakeLists.txt читается только в одном случае – когда выполняется непосредственно сам cmake. Все сообщения, ошибки и предупреждения, возникающие в процессе чтения файла, выводятся только этой командой.

CMakeLists.txt читается построчно, и, как правило, одна строка выполняет одну команду. Допускаются пустые строки и комментарии, начинающиеся с символа #, причем комментарий не обязательно должен начинаться с начала строки.

Также часть файла может не быть прочитана по какому-либо условию.

Переменные

CMake работает в основном с переменными. Они задаются явно, записываются в результате выполнения команд, или используются как аргументы для команд. Переменная – это просто какое-нибудь имя и соответствующее ему значение. Внутри каждая переменная представляет собой просто строковое значение, и интерпретируется в зависимости от команды. Чтобы подставить значение переменной, используется конструкция ${VARNAME}, а для обращения к переменной (изменения) используется просто её имя. Переменные объявлять не надо, они создаются сами в момент первого обращения.

Надо понимать, что подстановка значения переменной через конструкцию ${} работает как простая текстовая замена.

Задать переменную явно:

1
2
3
set(VAR1 “text value”)
set(VAR2 VAR1)
set(VAR3 ${VAR1})

В данном примере значения переменных VAR1 и VAR3 будет «text value», а значение VAR2 – «VAR1». Не стоит об этом забывать! Иногда важен сам факт существования переменной, в таком случае её можно просто объявить:

1
set(VAR1)

Переменные интерпретируются как логические значения, текстовые или списки. Истиной считается любое значение типа «1», «on», «y», «yes», «true» или ненулевое число. Все остальные значения считаются ложью.

Список можно задать обычным set:

1
set(VARS file1 file2 file3)

Для работы со списками есть команда list, например:

1
list(LENGTH VARS VARS_LEN)

В переменную VARS_LEN будет записана длина списка VARS. Или

1
list(APPEND VARS "file4")

В список VARS будет добавлена строка «file4». Полный список действий можно посмотреть в официальной документации.

Поиск библиотек

Одним из ключевых достоинств CMake является его способность искать библиотеки для линковки по системе. Поиском занимается команда:

1
find_library(LIBVAR name path1 ...)

В переменную LIBVAR запишется путь к библиотеке, или LIBVAR-NOTFOUND, если CMake её не нашел. Прелесть в том, что не нужно указывать полное платформозависимое имя библиотеки. CMake сам обернет это имя нужной приставкой и суффиксом, и будет искать её по путям в переменных окружениях системы, в стандартных библиотеках компилятора, или по стандартным путям системы. Т.е, на Windows «find_library(VAR foo)» найдет foo.a, или foo.dll, или libFoo.dll, в Linux это libfoo.so или libfoo.a.

Если в команде указан путь path1 или список путей, то поиск библиотеки начинается с этих путей. Это удобно в том случае, когда нужная библиотека лежит рядом с проектом.

Условия

В CMake возможны условные ветки чтения CMakeLists.txt. для этого используется конструкция if-else-endif:

1
2
3
4
5
6
7
if (EXPRESSION)
  commands…
elseif (EXPRESSION2)
  commands…
else ()
  commands…
endif ()

В аргумент команды if() подается условие выполнения ветки. Это может быть переменная или логическое выражение, содержащее NOT, AND и OR. Для проверки существования переменной используется DEFINED.

Пример:

1
2
3
4
5
6
if (DEFINED DEBUG)
  message(STATUS "Building debug")
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} –g3")
else ()
  message(STATUS "Building release")
endif ()

Сообщения

Для вывода информации в консоль есть очень удобная команда message():

1
message(<mode> "message")

Тип сообщения может быть одним из следующих:

STATUS – просто сообщение

WARNING – предупреждение

AUTHOR_WARNING – предупреждение разработчика

SEND_ERROR – ошибка, при которой продолжается чтение файла, но прекращается генерация Makefile

FATAL_ERROR – критическая ошибка, полная остановка

DEPRECATION – предупреждение о чем-то устаревшем

Напомню, что выводить содержимое переменной следует через ${}

Опции

Хотелось бы дать пользователю или разработчику возможность при сборке проекта выбирать те или иные опции проекта. В CMake для такого случая есть специальная команда:

1
option(OPTNAME "Description" DEFAULT)

Теперь появляется возможность проверять эту опцию в условиях. А чтобы задать значение опции на этапе конфигурации, надо просто выполнить cmake с -D=VALUE. Например:

1
2
3
4
CMakeLists.txt:
option(DEBUG "Enable debug" 0)
shell:
cmake -DDEBUG=1 .

Смотрите также

comments powered by Disqus