Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

При написании сценариев 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()).
  • add_subdirectory() и function() являются специальными, потому что они открывают свою собственную область видимости.
    • Значения переменных set(...) там видны только там, и они копируют все нормальные переменные уровня области действия, из которого они вызываются (называемые родительской областью действия).
    • Поэтому, если вы находитесь в подкатегории -D или в функции, вы можете изменить уже существующую переменную в родительской области с помощью set(... PARENT_SCOPE)
    • Вы можете использовать это, например, в функциях, передавая имя переменной в качестве параметра функции. В качестве примера можно привести function(xyz _resultVar) которой установлено значение set(${_resultVar} 1 PARENT_SCOPE)
  • С другой стороны, все, что вы устанавливаете в скриптах include() или macro() будет изменять переменные непосредственно в области их вызова.

Во-вторых, это "Кэш глобальных переменных". Что нужно знать о кеше:

  • Если в текущей области не определена нормальная переменная с заданным именем, CMake будет искать соответствующую запись в Cache.
  • Значения кэша хранятся в файле CMakeCache.txt в вашей директории двоичного вывода.
  • Значения в Cache могут быть изменены в приложении CMake GUI перед их генерацией. Поэтому они - по сравнению с обычными переменными - имеют type и docstring. Обычно я не использую графический интерфейс, поэтому я использую set(... CACHE INTERNAL "") для установки моих глобальных и постоянных значений.

    Обратите внимание, что тип переменной INTERNAL кеша подразумевает FORCE

  • В сценарии CMake вы можете изменять существующие записи в кэше, только если используете синтаксис set(... CACHE... FORCE). Это поведение используется, например, самим CMake, потому что обычно оно не заставляет сами записи Cache, и поэтому вы можете предварительно -D определить его с другим значением.

  • Вы можете использовать командную строку для установки записей в Cache с помощью синтаксиса cmake -D var:type=value, просто cmake -D var=value или cmake -C CMakeInitialCache.cmake.
  • Вы можете сбросить записи в Cache с помощью unset(... CACHE).

Кэш является глобальным, и вы можете установить его практически в любом месте ваших сценариев CMake. Но я бы порекомендовал вам дважды подумать о том, где использовать переменные Cache (они глобальные и постоянные). Обычно я предпочитаю set_property(GLOBAL PROPERTY...) и set_property(GLOBAL APPEND PROPERTY...) определять свои собственные непостоянные глобальные переменные.

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

Чтобы избежать ошибок, вы должны знать следующее о переменных:

  • Локальные переменные скрывают кэшированные переменные, если оба имеют одинаковое имя
  • Команды find_... - в случае успеха - записывают свои результаты в виде кэшированных переменных, "чтобы ни один вызов не выполнялся снова"
  • Списки в CMake - это просто строки с разделителями точек с запятой, поэтому кавычки важны
    • set(MyVar abc) - "a;b;c" а set(MyVar "abc") - "abc"
    • Рекомендуется всегда использовать кавычки с одним исключением, если вы хотите предоставить список в виде списка
    • Обычно предпочитают команду list() для обработки списков
  • Весь объем вопроса описан выше. Особенно рекомендуется использовать functions() вместо macros() потому что вы не хотите, чтобы ваши локальные переменные отображались в родительской области.
  • Многие переменные, используемые CMake, устанавливаются с помощью вызовов project() и enable_language(). Поэтому может быть важно установить некоторые переменные перед использованием этих команд.
  • Переменные среды могут отличаться от того, где CMake сгенерировал среду make, и когда файлы make используются.
    • Изменение переменной среды не запускает процесс генерации заново.
    • Особенно сгенерированная среда IDE может отличаться от вашей командной строки, поэтому рекомендуется переносить переменные среды во что-то, что кэшируется.

Иногда помогают только отладочные переменные. Следующее может помочь вам:

  • Просто используйте старый стиль отладки printf с помощью команды message(). Есть также некоторые готовые к использованию модули, поставляемые с самим CMake: CMakePrintHelpers.cmake, CMakePrintSystemInformation.cmake
  • Посмотрите в файл CMakeCache.txt в вашей директории двоичного вывода. Этот файл генерируется даже в случае сбоя фактической генерации среды make.
  • Используйте variable_watch(), чтобы увидеть, где ваши переменные читаются/записываются/удаляются.
  • Посмотрите в свойствах каталога CACHE_VARIABLES и VARIABLES
  • Вызовите cmake --trace... чтобы увидеть полный процесс разбора CMake. Такого рода последний резерв, потому что он генерирует много продукции.

Специальный синтаксис

  • Переменные среды
    • Вы можете читать $ENV{...} и записывать переменные окружения set(ENV{...}...)
  • Выражения генератора
    • Выражения генератора $<...> оцениваются только тогда, когда генератор CMake записывает среду make (это сравнение с обычными переменными, которые заменяются парсером "на месте")
    • Очень удобно, например, в командных строках компилятора/компоновщика и в средах с множественной конфигурацией -C
  • Рекомендации
    • С ${${...}} вы можете давать имена переменных в переменной и ссылаться на ее содержимое.
    • Часто используется при указании имени переменной в качестве параметра функции/макроса.
  • Постоянные значения (см. Команду if())
    • С помощью if(MyVariable) вы можете напрямую проверить переменную на true/false (здесь нет необходимости для вложенных ${...})
    • Истинно, если константа равна 1, ON, YES, TRUE, Y или ненулевое число.
    • False, если константа 0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, пустая строка или заканчивается суффиксом -NOTFOUND.
    • Этот синтаксис часто используется для чего-то вроде if(MSVC), но он может сбивать с толку тех, кто не знает этого ярлыка синтаксиса.
  • Рекурсивные замены
    • Вы можете создавать имена переменных, используя переменные. После того, как CMake подставил переменные, он снова проверит, является ли результат самой переменной. Это очень мощная функция, используемая в самом CMake, например, как set(CMAKE_${lang}_COMPILER...) шаблонов set(CMAKE_${lang}_COMPILER...)
    • Но учтите, что это может вызвать головную боль в командах if(). Вот пример, где CMAKE_CXX_COMPILER_ID равен "MSVC" а MSVC равен "1":
      • if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") имеет значение true, поскольку оно оценивается как if("1" STREQUAL "1")
      • if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") имеет значение false, поскольку оно оценивается как if("MSVC" STREQUAL "1")
      • Таким образом, лучшим решением здесь будет - см. Выше - напрямую проверить, if(MSVC)
    • Хорошей новостью является то, что это было исправлено в CMake 3.1 с введением политики CMP0054. Я бы рекомендовал всегда устанавливать в cmake_policy(SET CMP0054 NEW) значение "интерпретировать аргументы if() как переменные или ключевые слова в кавычках".
  • Команда option()
    • В основном это просто кэшированные строки, которые могут быть только ON или OFF и они допускают некоторую специальную обработку, например, зависимости
    • Но имейте в виду, не путайте option с командой set. Значение, данное option на самом деле является только "начальным значением" (переданным один раз в кэш на первом этапе настройки) и впоследствии должно быть изменено пользователем через графический интерфейс CMake.

Рекомендации

Ответ 2

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

Одна переменная элемента

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

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

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

Ответ 3

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