Каков синтаксис CMake для установки и использования переменных?
Я спрашиваю это как напоминание себе в следующий раз, когда я использую CMake. Он никогда не прилипает, и результаты Google не очень хороши.
Какой синтаксис для установки и использования переменных в CMake?
3 ответа
При написании сценариев CMake нужно много знать о синтаксисе и о том, как использовать переменные в CMake.
Синтаксис
Использование строк set()
:
set(MyString "Some Text")
set(MyStringWithVar "Some other Text: ${MyString}")
set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")
Или с string()
:
string(APPEND MyStringWithContent " ${MyString}")
Использование списков set()
:
set(MyList "a" "b" "c")
set(MyList ${MyList} "d")
Или лучше с list()
:
list(APPEND MyList "a" "b" "c")
list(APPEND MyList "d")
Списки имен файлов:
set(MySourcesList "File.name" "File with Space.name")
list(APPEND MySourcesList "File.name" "File with Space.name")
add_excutable(MyExeTarget ${MySourcesList})
Документация
- CMake / Синтаксис языка
- CMake: переменные списки строк
- CMake: полезные переменные
- CMake
set()
команда - CMake
string()
команда - CMake
list()
команда - Cmake: выражения генератора
Область действия или "Какое значение имеет моя переменная?"
Сначала есть "Нормальные переменные" и вещи, которые вам нужно знать об их области действия:
- Нормальные переменные видны
CMakeLists.txt
они установлены и все оттуда вызывается (add_subdirectory()
,include()
,macro()
а такжеfunction()
). -
add_subdirectory()
а такжеfunction()
Команды являются особенными, потому что они открывают свою собственную область.- Значение переменных
set(...)
они видны только там, и они копируют все нормальные переменные уровня области, из которой они вызваны (так называемая родительская область). - Поэтому, если вы находитесь в подкаталоге или функции, вы можете изменить уже существующую переменную в родительской области с помощью
set(... PARENT_SCOPE)
- Вы можете использовать это, например, в функциях, передавая имя переменной в качестве параметра функции. Примером будет
function(xyz _resultVar)
устанавливаетset(${_resultVar} 1 PARENT_SCOPE)
- Значение переменных
- С другой стороны, все, что вы установили в
include()
или жеmacro()
Сценарии изменят переменные непосредственно в области их вызова.
Во-вторых, это "Кэш глобальных переменных". Что нужно знать о кеше:
- Если в текущей области не определена нормальная переменная с данным именем, CMake будет искать соответствующую запись в Cache.
- Значения кэша хранятся в
CMakeCache.txt
файл в вашем каталоге двоичного вывода. Значения в Cache могут быть изменены в приложении CMake с графическим интерфейсом перед их генерацией. Поэтому они - по сравнению с обычными переменными - имеют
type
иdocstring
, Я обычно не использую графический интерфейс, поэтому я используюset(... CACHE INTERNAL "")
установить мои глобальные и постоянные значения.Обратите внимание, что
INTERNAL
тип переменной кеша подразумеваетFORCE
В сценарии CMake вы можете изменять существующие записи в кэше, только если вы используете
set(... CACHE ... FORCE)
синтаксис. Это поведение используется, например, самим CMake, потому что обычно оно не заставляет сами записи Cache, и поэтому вы можете предварительно определить его с другим значением.- Вы можете использовать командную строку для установки записей в Cache с синтаксисом
cmake -D var:type=value
, простоcmake -D var=value
или сcmake -C CMakeInitialCache.cmake
, - Вы можете удалить записи в кеше с помощью
unset(... CACHE)
,
Кэш является глобальным, и вы можете установить его практически в любом месте ваших сценариев CMake. Но я бы порекомендовал вам дважды подумать о том, где использовать переменные Cache (они глобальные и постоянные). Я обычно предпочитаю set_property(GLOBAL PROPERTY ...)
а также set_property(GLOBAL APPEND PROPERTY ...)
синтаксис для определения моих собственных непостоянных глобальных переменных.
Ловушки переменных и "Как отладить изменения переменных?"
Чтобы избежать ошибок, вы должны знать следующее о переменных:
- Локальные переменные скрывают кэшированные переменные, если оба имеют одинаковое имя
-
find_...
Команды - в случае успеха - пишите свои результаты в виде кэшированных переменных "чтобы ни один вызов не выполнялся снова" - Списки в CMake - это просто строки с разделителями точек с запятой, поэтому кавычки важны
set(MyVar a b c)
является"a;b;c"
а такжеset(MyVar "a b c")
является"a b c"
- Рекомендуется всегда использовать кавычки с одним исключением, если вы хотите сделать список списком.
- Вообще предпочитаю
list()
команда для обработки списков
- Весь объем вопроса описан выше. Особенно рекомендуется использовать
functions()
вместоmacros()
потому что вы не хотите, чтобы ваши локальные переменные отображались в родительской области видимости. - Многие переменные, используемые CMake, устанавливаются с помощью
project()
а такжеenable_language()
звонки. Поэтому может быть важно установить некоторые переменные перед использованием этих команд. - Переменные среды могут отличаться от того, где CMake сгенерировал среду make, и когда файлы make используются.
- Изменение переменной среды не запускает процесс генерации заново.
- Особенно сгенерированная среда IDE может отличаться от вашей командной строки, поэтому рекомендуется переносить переменные среды в нечто, что кэшируется.
Иногда помогают только отладочные переменные. Следующее может помочь вам:
- Просто используй старую
printf
стиль отладки с помощьюmessage()
команда. Есть также некоторые готовые к использованию модули, поставляемые с самим CMake: CMakePrintHelpers.cmake, CMakePrintSystemInformation.cmake - Заглянуть в
CMakeCache.txt
файл в вашем каталоге двоичного вывода. Этот файл создается даже в случае сбоя фактической генерации вашей среды создания. - Используйте variable_watch(), чтобы увидеть, где ваши переменные читаются / записываются / удаляются.
- Посмотрите в свойствах каталога CACHE_VARIABLES и VARIABLES
- Вызов
cmake --trace ...
чтобы увидеть полный процесс разбора CMake. Это своего рода последний резерв, потому что он генерирует много продукции.
Специальный синтаксис
- Переменные среды
- Вы можете прочитать
$ENV{...}
и писатьset(ENV{...} ...)
переменные среды
- Вы можете прочитать
- Выражения генератора
- Генератор выражений
$<...>
оцениваются, только когда генератор CMake записывает среду make (это сравнение с обычными переменными, которые заменяются парсером "на месте") - Очень удобно, например, в командных строках компилятора / компоновщика и в средах с несколькими конфигурациями
- Генератор выражений
- Рекомендации
- С
${${...}}
Вы можете дать имена переменных в переменной и ссылаться на ее содержимое. - Часто используется при указании имени переменной в качестве параметра функции / макроса.
- С
- Постоянные значения (см.
if()
команда)- С
if(MyVariable)
Вы можете напрямую проверить переменную на true/false (здесь нет необходимости для включения${...}
) - True, если константа
1
,ON
,YES
,TRUE
,Y
или ненулевое число. - Ложь, если константа
0
,OFF
,NO
,FALSE
,N
,IGNORE
,NOTFOUND
, пустая строка или заканчивается суффиксом-NOTFOUND
, - Этот синтаксис часто используется для чего-то вроде
if (MSVC)
, но это может сбить с толку тех, кто не знает этот синтаксис ярлык.
- С
- Рекурсивные замены
- Вы можете создавать имена переменных, используя переменные. После того, как CMake подставил переменные, он снова проверит, является ли результат самой переменной. Это очень мощная функция, используемая в самом CMake, например, в качестве шаблона.
set(CMAKE_${lang}_COMPILER ...)
- Но имейте в виду, что это может вызвать головную боль в
if ()
команды. Вот пример, гдеCMAKE_CXX_COMPILER_ID
является"MSVC"
а такжеMSVC
является"1"
:if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
верно, потому что это оцениваетif ("1" STREQUAL "1")
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
ложно, потому что это оцениваетif ("MSVC" STREQUAL "1")
- Таким образом, лучшим решением здесь будет - см. Выше - напрямую проверить
if (MSVC)
- Хорошей новостью является то, что это было исправлено в CMake 3.1 с введением политики CMP0054. Я бы рекомендовал всегда устанавливать
cmake_policy(SET CMP0054 NEW)
"только интерпретироватьif()
аргументы как переменные или ключевые слова, когда без кавычек. "
- Вы можете создавать имена переменных, используя переменные. После того, как CMake подставил переменные, он снова проверит, является ли результат самой переменной. Это очень мощная функция, используемая в самом CMake, например, в качестве шаблона.
-
option()
команда- В основном только кэшированные строки, которые могут быть только
ON
или жеOFF
и они допускают некоторую специальную обработку, например, зависимости - Но знайте, не перепутайте
option
сset
команда. Значение, данноеoption
на самом деле является только "начальным значением" (передается один раз в кэш на первом этапе настройки) и впоследствии должно быть изменено пользователем через графический интерфейс CMake.
- В основном только кэшированные строки, которые могут быть только
Рекомендации
Вот пара основных примеров, чтобы начать быстро и грязно.
Одна переменная элемента
Установить переменную:
SET(INSTALL_ETC_DIR "etc")
Используйте переменную:
SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d")
Многоэлементная переменная (т.е. список)
Установить переменную:
SET(PROGRAM_SRCS
program.c
program_utils.c
a_lib.c
b_lib.c
config.c
)
Используйте переменную:
add_executable(program "${PROGRAM_SRCS}")
$ENV{FOO}
для использования, где FOO выбирается из переменной окружения. иначе использовать как ${FOO}
где FOO - некоторая другая переменная. Для настройки, SET(FOO "foo")
будет использоваться в cmake.