Що таке синтаксис CMake для встановлення та використання змінних?


168

Я прошу це як нагадування про себе наступного разу, коли я буду використовувати CMake. Він ніколи не прилипає, а результати Google не великі.

Який синтаксис для встановлення та використання змінних у CMake?

Відповіді:


281

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

Друге - "Кеш глобальних змінних". Що потрібно знати про кеш:

  • Якщо в поточному діапазоні не визначена нормальна змінна із вказаним іменем, CMake шукатиме відповідний запис кешу.
  • Значення кешу зберігаються у 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_...команди - в разі успіху - напишете свої результати в вигляді кешованих змінних «так що ні один дзвінок не буде знову шукати»
  • Списки в 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стиль налагодження за допомогою message()команди. Також є кілька готових до використання модулів, що постачаються разом із самим CMake: CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmake
  • Загляньте у CMakeCache.txtфайл у своєму каталозі бінарних вихідних даних. Цей файл навіть генерується, якщо фактичне покоління вашого середовища середовища виходить з ладу.
  • Використовуйте varia_watch (), щоб побачити, де ваші змінні читаються / записуються / видаляються.
  • Перегляньте властивості каталогу CACHE_VARIABLES та VARIABLES
  • Зателефонуйте, 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), але це може бути заплутаним для того, хто не знає цього ярлика синтаксису.
  • Рекурсивні заміни
    • Ви можете побудувати імена змінних за допомогою змінних. Після того, як 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()аргументи як змінні чи ключові слова, коли їх немає".
  • option()команда
    • В основному тільки кешувати рядки , які тільки можуть бути ONабо OFFі вони дозволяють деякі спеціальну обробку , як , наприклад , залежно
    • Але будьте в курсі , не помиліться optionз setкомандою. Значення, яке надається option, насправді є лише "початковим значенням" (переноситься один раз до кеша під час першого кроку налаштування) і після цього призначене для зміни користувачем через графічний інтерфейс CMake .

Список літератури


Коли я використовую if ("${MyString}" ...)я бачу попередження: Policy CMP0054 is not set: Only interpret if() arguments as variables or keywords when unquoted. Дивіться, наприклад, Build 367 . Будь-які ідеї?
jww

І відміняння котиків ${MyString}призводить до купі помилок "якщо дано аргументи ...", наприклад, помилка CMake поблизу if: "якщо дані аргументи", а потім парафези, "NOT", "EQUALS" тощо .
jww

@jww Попередження означає, що MyStringвін містить ім'я змінної, яке потім знову буде де-посиланням. Я вважаю, що такої OLDповедінки ніхто не хоче . Таким чином , з моєї точки зору його абсолютно безпечним і зворотну сумісність просто встановити політику , CMP0054щоб NEW(див обговорення тут ).
Флоріан

@jww І найбезпечніший спосіб уникнути цих проблем / попереджень - це просто зробити if (MyString ...)(якщо це ваш код із попередженням).
Флоріан

Дякую. Ми видалили всі події ${MyString}та замінили їх MyString(або, я вважаю, ми видалили їх усі). Ще немає радості: Build 372 . Лайно навіть не походить від нашого коду. Схоже, він походить від CMake. Рядок 283 є if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC").
jww

18

Ось кілька основних прикладів, щоб почати швидко і брудно.

Одна змінна деталь

Встановити змінну:

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 документи на змінні


1

$ENV{FOO}для використання, де FOOвибирається зі змінної середовища. в іншому випадку використовувати як ${FOO}, де FOOє інша змінна. Для налаштування SET(FOO "foo")буде використано в CMake.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.