Ответы:
При написании сценариев 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})set()Commandstring()Commandlist()CommandСначала есть «Нормальные переменные» и вещи, которые вы должны знать об их области действия:
CMakeLists.txtони установлены в и все , называется оттуда ( add_subdirectory(), include(), macro()и function()).add_subdirectory()И function()команды являются особенными, потому что они открывают, свои собственные рамки.
set(...)там видны только там, и они копируют все нормальные переменные уровня области действия, из которого они вызываются (называемые родительской областью действия).set(... PARENT_SCOPE)function(xyz _resultVar)установкаset(${_resultVar} 1 PARENT_SCOPE)include()или macro()скрипты, изменяет переменные непосредственно в области, откуда они вызываются.Во-вторых, это «Кэш глобальных переменных». Что нужно знать о кеше:
CMakeCache.txtфайле в вашем каталоге двоичного вывода.Значения в Cache могут быть изменены в приложении с графическим интерфейсом CMake перед их генерацией. Поэтому они - по сравнению с обычными переменными - имеют a typeи a docstring. Я обычно не использую графический интерфейс, поэтому я использую set(... CACHE INTERNAL "")для установки своих глобальных и постоянных значений.
Обратите внимание, что INTERNALтип переменной кеша подразумеваетFORCE
В сценарии CMake вы можете изменять существующие записи в кэше, только если используете set(... CACHE ... FORCE)синтаксис. Это поведение используется, например, самим CMake, потому что обычно оно не заставляет сами записи 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_...команды - в случае успеха - напишете свои результаты в виде кэшированных переменных « так что ни один звонок не будет снова искать»set(MyVar a b c)есть "a;b;c"и set(MyVar "a b c")есть"a b c"list()команду для обработки списковfunctions()вместо, macros()потому что вы не хотите, чтобы ваши локальные переменные отображались в родительской области видимости.project()и enable_language()вызовами. Поэтому может быть важно установить некоторые переменные перед использованием этих команд.Иногда помогают только отладочные переменные. Следующее может помочь вам:
printfстиль отладки с помощью message()команды. Есть также некоторые готовые к использованию модули, поставляемые с самим CMake: CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmakeCMakeCache.txtфайл в вашей директории двоичного вывода. Этот файл создается даже в случае сбоя фактической генерации вашей среды создания.cmake --trace ...чтобы увидеть полный процесс разбора CMake. Это своего рода последний резерв, потому что он генерирует много продукции.$ENV{...}и записывать set(ENV{...} ...)переменные окружения$<...>оцениваются только тогда, когда генератор CMake записывает среду make (это сравнение с обычными переменными, которые заменяются парсером "на месте")${${...}}вы можете дать имена переменных в переменной и ссылаться на ее содержимое.if()Команду)
if(MyVariable)вы можете напрямую проверить переменную на true / false (здесь нет необходимости для включения ${...})1, ON, YES, TRUE, Y, или ненулевое число.0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, пустая строка, или заканчивается в суффиксе -NOTFOUND.if(MSVC), но он может сбивать с толку тех, кто не знает этого ярлыка синтаксиса.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_policy(SET CMP0054 NEW)«интерпретировать if()аргументы как переменные или ключевые слова без кавычек».option()команда
ONили, OFFи они допускают некоторую специальную обработку, например, зависимостиoptionвиду , не путайте с setкомандой. Присвоенное значение на optionсамом деле является только «начальным значением» (переданным один раз в кэш на первом этапе настройки) и впоследствии должно быть изменено пользователем через графический интерфейс CMake .${MyString}приводит к куче ошибок для «если даны аргументы ...», таких как ошибка CMake рядом с if: «если даны аргументы», за которыми следуют паратезы, «НЕ», «РАВНЫЕ» и тому подобное .
MyStringоно содержит имя переменной, которая затем будет разыменована . Я считаю, что никто не хочет такого OLDповедения. Таким образом , с моей точки зрения его абсолютно безопасным и обратную совместимость просто установить политику , CMP0054чтобы NEW(см обсуждение здесь ).
if (MyString ...)(если ваш код дает предупреждение).
${MyString}и заменили его MyString(или я думаю, что мы удалили их все). До сих пор нет радости: Сборка 372 . Дерьмо даже не исходит из нашего кода. Похоже, что идет от CMake. Строка 283 есть if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC").
Вот пара основных примеров, чтобы начать быстро и грязно.
Установить переменную:
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}")
if ("${MyString}" ...)я вижу предупреждение:Policy CMP0054 is not set: Only interpret if() arguments as variables or keywords when unquoted. См. Например, Build 367 . Любые идеи?