Відповіді:
Під час написання сценаріїв 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 . Будь-які ідеї?