Каков синтаксис CMake для установки и использования переменных?


Я спрашиваю это как напоминание себе в следующий раз, когда я использую CMake. Он никогда не прилипает, и результаты Google не велики.

каков синтаксис для установки и использования переменных в CMake?

3 84

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})

Документация

область или "какое значение имеет моя переменная есть?"

во-первых, есть "нормальные переменные" и вещи, которые вам нужно знать об их объеме:

  • нормальные переменные видны 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()

вот несколько основных примеров, чтобы начать быстро и грязно.

один элемент переменной

установить переменную:

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}")

CMake, например, документы на переменные

$ENV{FOO} для использования, где FOO выбирается из переменной окружения. в противном случае используйте как ${FOO}, где FOO-некоторая другая переменная. Для установки,SET(FOO "foo") будет использоваться в cmake.