Відповіді:
Під час написання сценаріїв 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()
Команда CMakestring()
Команда CMakelist()
Команда 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()
сценарії, буде змінювати змінні безпосередньо в області, звідки вони викликані.Друге - "Кеш глобальних змінних". Що потрібно знати про кеш:
CMakeCache.txt
файлі у вашому каталозі бінарних вихідних даних.Значення в кеші можуть бути змінені в додатку графічного інтерфейсу CMake перед їх генерацією. Тому вони - порівняно зі звичайними змінними - мають a type
і a 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(... CACHE)
.Кеш є глобальним, і ви можете встановити їх практично будь-де у своїх сценаріях CMake. Але я б рекомендував вам подумати два рази про те, де використовувати змінні кеша (вони є глобальними і вони є стійкими). Я, як правило, віддаю перевагу синтаксису 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)
вас можна безпосередньо перевірити змінну на справжню / хибну (тут не потрібно вкладати ${...}
)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: "якщо дані аргументи", а потім парафези, "NOT", "EQUALS" тощо .
MyString
він містить ім'я змінної, яке потім знову буде де-посиланням. Я вважаю, що такої OLD
поведінки ніхто не хоче . Таким чином , з моєї точки зору його абсолютно безпечним і зворотну сумісність просто встановити політику , CMP0054
щоб NEW
(див обговорення тут ).
if (MyString ...)
(якщо це ваш код із попередженням).
Ось кілька основних прикладів, щоб почати швидко і брудно.
Встановити змінну:
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.
if ("${MyString}" ...)
я бачу попередження:Policy CMP0054 is not set: Only interpret if() arguments as variables or keywords when unquoted
. Дивіться, наприклад, Build 367 . Будь-які ідеї?