Каков синтаксис 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()
).- The
add_subdirectory()
иfunction()
команды особенные, потому что они открывают свою собственную область.
- значения переменных
set(...)
есть только видимые там, и они делают копию из всех нормальных переменных уровня области они вызываются из (называемой родительской областью).- поэтому, если вы находитесь в подкаталоге или функции, вы можете изменить уже существующую переменную в родительской области с помощью
set(... PARENT_SCOPE)
- вы можете использовать это, например, в функциях, передавая имя переменной в качестве параметра функции. Примером может быть
function(xyz _resultVar)
установкаset(${_resultVar} 1 PARENT_SCOPE)
- с другой стороны все, что вы установить в
include()
илиmacro()
скрипты будут изменять переменные непосредственно в области, где они вызываются.во-вторых, есть "кэш глобальных переменных". То, что вам нужно знать о кэше:
- если в текущей области не определена нормальная переменная с заданным именем, CMake будет искать соответствующую запись кэша.
- значения кэша хранятся в
CMakeCache.txt
файл в вашем двоичном выходном каталоге.в значения в кэше могут быть изменены в графический интерфейс CMake приложение, прежде чем они будут созданы. Поэтому они - по сравнению с обычными переменными-имеют
type
иdocstring
. Я обычно не использую графический интерфейс, поэтому я используюset(... CACHE INTERNAL "")
чтобы установить мои глобальные и постоянные значения.обратите внимание:
INTERNAL
тип переменной кэша подразумеваетFORCE
в скрипте CMake вы можете изменить только существующие записи кэша если вы используете
set(... CACHE ... FORCE)
синтаксис. Это поведение используется, например, самим CMake, потому что обычно оно не вызывает записи кэша, и поэтому вы можете предварительно определить его с другим значением.- вы можете использовать командную строку для установки записей в кэше с синтаксисом
cmake -D var:type=value
, простоcmake -D var=value
илиcmake -C CMakeInitialCache.cmake
.- вы можете unset записи в кэше с
unset(... CACHE)
.кэш является глобальным, и вы можете установите их практически в любом месте в ваших сценариях CMake. Но я бы рекомендовал вам дважды подумать о том, где использовать переменные кэша (они являются глобальными и они устойчивы). Я обычно предпочитаю
set_property(GLOBAL PROPERTY ...)
иset_property(GLOBAL APPEND PROPERTY ...)
синтаксис для определения моих собственных непостоянных глобальных переменных.переменные подводные камни и "как отлаживать изменения переменных?"
чтобы избежать подводных камней, вы должны знать следующее о переменных:
- локальные переменные скрывают кэширование переменные, если оба имеют одинаковое имя
- The
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
стиль отладки с помощью )
- с
if(MyVariable)
вы можете напрямую проверить переменную на true / false (здесь нет необходимости заключая${...}
)- True, если константа
1
,ON
,YES
,TRUE
,Y
, или ненулевое число.- False, если константа
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()
аргументы в виде переменных или ключевых слов при отсутствии кавычек."- The
option()
- в основном просто кэшированные строки, которые могут быть только
ON
илиOFF
и они позволяют некоторые специальные обработки, такие как например зависимости- но будьте в курсе, не ошибка
option
с
вот несколько основных примеров, чтобы начать быстро и грязно.
один элемент переменной
установить переменную:
SET(INSTALL_ETC_DIR "etc")
использование переменной:
SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d")
переменная Mult-item (т. е. список)
установить переменную:
SET(PROGRAM_SRCS program.c program_utils.c a_lib.c b_lib.c config.c )
использование переменной:
add_executable(program "${PROGRAM_SRCS}")