Qual è la sintassi di CMake per impostare e utilizzare le variabili?


168

Lo chiederò come promemoria per me la prossima volta che userò CMake. Non si attacca mai e i risultati di Google non sono eccezionali.

Qual è la sintassi per impostare e utilizzare le variabili in CMake?

Risposte:


281

Quando si scrivono script CMake, è necessario conoscere molto la sintassi e come utilizzare le variabili in CMake.

La sintassi

Stringhe usando set():

  • set(MyString "Some Text")
  • set(MyStringWithVar "Some other Text: ${MyString}")
  • set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")

O con string():

  • string(APPEND MyStringWithContent " ${MyString}")

Elenchi che utilizzano set():

  • set(MyList "a" "b" "c")
  • set(MyList ${MyList} "d")

O meglio con list():

  • list(APPEND MyList "a" "b" "c")
  • list(APPEND MyList "d")

Elenchi di nomi di file:

  • set(MySourcesList "File.name" "File with Space.name")
  • list(APPEND MySourcesList "File.name" "File with Space.name")
  • add_excutable(MyExeTarget ${MySourcesList})

La documentazione

L'ambito o "Quale valore ha la mia variabile?"

Innanzitutto ci sono le "variabili normali" e le cose che devi sapere sul loro ambito:

  • Variabili normali sono visibili ad CMakeLists.txtessi sono fissati in e tutto chiamato da lì ( add_subdirectory(), include(), macro()e function()).
  • I comandi add_subdirectory()e function()sono speciali, perché aprono il loro ambito.
    • Le variabili di significato set(...)sono visibili solo lì e creano una copia di tutte le normali variabili del livello di ambito da cui vengono chiamate (chiamato ambito padre).
    • Quindi, se ci si trova in una sottodirectory o in una funzione, è possibile modificare una variabile già esistente nell'ambito genitore con set(... PARENT_SCOPE)
    • È possibile utilizzare questo ad es. Nelle funzioni passando il nome della variabile come parametro di funzione. Un esempio potrebbe essere l' function(xyz _resultVar)impostazioneset(${_resultVar} 1 PARENT_SCOPE)
  • D'altra parte, tutto ciò che viene impostato include()o gli macro()script modificheranno le variabili direttamente nell'ambito da cui vengono chiamate.

In secondo luogo c'è la "Global Variables Cache". Cose che devi sapere sulla cache:

  • Se nessuna variabile normale con il nome specificato è definita nell'ambito corrente, CMake cercherà una voce Cache corrispondente.
  • I valori della cache sono memorizzati nel CMakeCache.txtfile nella directory di output binaria.
  • I valori nella cache possono essere modificati nell'applicazione GUI di CMake prima che vengano generati. Pertanto, rispetto alle variabili normali, hanno a typee a docstring. Normalmente non utilizzo la GUI, quindi utilizzo i set(... CACHE INTERNAL "")miei valori globali e persistenti.

    Si noti che il INTERNALtipo di variabile della cache implicaFORCE

  • In uno script CMake è possibile modificare le voci della cache esistenti solo se si utilizza la set(... CACHE ... FORCE)sintassi. Questo comportamento viene utilizzato ad esempio da CMake stesso, perché normalmente non forza le voci della cache in sé e quindi è possibile pre-definirlo con un altro valore.

  • È possibile utilizzare la riga di comando per impostare le voci nella cache con la sintassi cmake -D var:type=value, solo cmake -D var=valueo con cmake -C CMakeInitialCache.cmake.
  • È possibile annullare l' inserimento delle voci nella cache con unset(... CACHE).

La cache è globale e puoi impostarla praticamente ovunque nei tuoi script CMake. Ma ti consiglio di pensarci due volte su dove usare le variabili Cache (sono globali e persistenti). Normalmente preferisco la sintassi set_property(GLOBAL PROPERTY ...)e set_property(GLOBAL APPEND PROPERTY ...)per definire le mie variabili globali non persistenti.

Insidie ​​variabili e "Come eseguire il debug delle modifiche alle variabili?"

Per evitare insidie ​​dovresti sapere quanto segue sulle variabili:

  • Le variabili locali nascondono le variabili memorizzate nella cache se entrambe hanno lo stesso nome
  • I find_...comandi, se hanno esito positivo, scrivono i loro risultati come variabili memorizzate nella cache "in modo che nessuna chiamata effettui nuovamente la ricerca"
  • Le liste in CMake sono solo stringhe con delimitatori di punto e virgola e quindi le virgolette sono importanti
    • set(MyVar a b c)è "a;b;c"ed set(MyVar "a b c")è"a b c"
    • Si consiglia di utilizzare sempre le virgolette con l'unica eccezione quando si desidera dare un elenco come elenco
    • Preferisce generalmente il list()comando per la gestione degli elenchi
  • L'intero problema dell'ambito sopra descritto. Soprattutto si consiglia di utilizzare functions()anziché macros()perché non si desidera che le variabili locali vengano visualizzate nell'ambito genitore.
  • Molte variabili utilizzate da CMake sono impostate con le chiamate project()e enable_language(). Quindi potrebbe essere importante impostare alcune variabili prima di usare quei comandi.
  • Le variabili di ambiente possono differire da dove CMake ha generato l'ambiente di creazione e da quando vengono utilizzati i file di creazione.
    • Una modifica in una variabile di ambiente non riavvia il processo di generazione.
    • Soprattutto un ambiente IDE generato può differire dalla riga di comando, quindi si consiglia di trasferire le variabili di ambiente in qualcosa che viene memorizzato nella cache.

A volte aiuta solo il debug delle variabili. Quanto segue può aiutarti:

  • Usa semplicemente il vecchio printfstile di debug usando il message()comando. Esistono anche alcuni moduli pronti all'uso forniti con CMake stesso: CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmake
  • Cerca nel CMakeCache.txtfile nella directory di output binaria. Questo file viene generato anche se la generazione effettiva del tuo ambiente make non riesce.
  • Usa variabile_orologio () per vedere dove vengono lette / scritte / rimosse le variabili.
  • Cerca nelle proprietà della directory CACHE_VARIABLES e VARIABLES
  • Chiama cmake --trace ...per vedere il processo di analisi completo di CMake. È una specie dell'ultima riserva, perché genera molto output.

Sintassi speciale

  • variabili ambientali
    • È possibile leggere $ENV{...}e scrivere set(ENV{...} ...)variabili di ambiente
  • Espressioni del generatore
    • Le espressioni del generatore $<...>vengono valutate solo quando il generatore di CMake scrive l'ambiente di creazione (confrontandolo con le variabili normali che vengono sostituite "sul posto" dal parser)
    • Molto utile, ad esempio nelle righe di comando del compilatore / linker e in ambienti multi-configurazione
  • Riferimenti
    • Con ${${...}}te puoi dare nomi di variabili in una variabile e fare riferimento al suo contenuto.
    • Utilizzato spesso quando si assegna un nome di variabile come parametro funzione / macro.
  • Valori costanti (vedi if()comando)
    • Con if(MyVariable)puoi controllare direttamente una variabile per true / false (non è necessario qui per racchiudere ${...})
    • Vero se la costante è 1, ON, YES, TRUE, Y, o un numero diverso da zero.
    • False se la costante è 0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, la stringa vuota, o termina nel suffisso -NOTFOUND.
    • Questa sintassi viene spesso utilizzata per qualcosa di simile if(MSVC), ma può essere fonte di confusione per qualcuno che non conosce questo collegamento alla sintassi.
  • Sostituzioni ricorsive
    • Puoi costruire nomi di variabili usando le variabili. Dopo che CMake ha sostituito le variabili, verificherà di nuovo se il risultato è una variabile stessa. Questa è una funzione molto potente utilizzata in CMake stesso, ad esempio come una sorta di modelloset(CMAKE_${lang}_COMPILER ...)
    • Ma attenzione, questo può darti mal di testa nei if()comandi. Ecco un esempio in cui CMAKE_CXX_COMPILER_IDè "MSVC"ed MSVCè "1":
      • if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") è vero, perché valuta if("1" STREQUAL "1")
      • if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") è falso, perché valuta if("MSVC" STREQUAL "1")
      • Quindi la migliore soluzione qui sarebbe - vedi sopra - per verificare direttamente if(MSVC)
    • La buona notizia è che ciò è stato risolto in CMake 3.1 con l'introduzione della politica CMP0054 . Consiglierei di impostare sempre cmake_policy(SET CMP0054 NEW)"interpretare gli if()argomenti solo come variabili o parole chiave quando non quotati".
  • Il option()comando
    • Principalmente solo stringhe memorizzate nella cache che solo possono essere ONo OFFe consentono una gestione speciale come ad esempio le dipendenze
    • Ma attenzione , non confondere il optioncon il setcomando. Il valore assegnato optionè in realtà solo il "valore iniziale" (trasferito una volta nella cache durante il primo passaggio di configurazione) e successivamente viene modificato dall'utente tramite la GUI di CMake .

Riferimenti


Quando uso if ("${MyString}" ...)sono avvertimenti vedendo: Policy CMP0054 is not set: Only interpret if() arguments as variables or keywords when unquoted. Vedi, ad esempio, Build 367 . Qualche idea?
17-17

E l'annullamento della quotazione ${MyString}porta a una serie di errori per "se dati argomenti ..." come l' errore CMake vicino a se: "se dati argomenti" seguito da parentesi, "NON", "EQUALS" e simili .
17-17

@jww L'avvertimento indica che MyStringcontiene un nome variabile che verrà nuovamente de-referenziato. Credo che nessuno voglia davvero quel OLDcomportamento. Quindi, dal mio punto di vista la sua totalmente sicuro e compatibile alla politica solo set CMP0054per NEW(vedi la discussione qui ).
Florian,

@jww E il modo più sicuro per evitare quei problemi / avvertenze è semplicemente farlo if (MyString ...)(se è il tuo codice a dare l'avvertimento).
Florian,

Grazie. Abbiamo rimosso tutte le occorrenze ${MyString}e le abbiamo sostituite con MyString(o credo che le abbiamo rimosse tutte). Ancora nessuna gioia: costruisci 372 . La merda non proviene nemmeno dal nostro codice. Sembra provenire da CMake. La linea 283 è if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC").
17-17

18

Ecco un paio di esempi di base per iniziare in modo rapido e sporco.

Una variabile articolo

Imposta variabile:

SET(INSTALL_ETC_DIR "etc")

Usa variabile:

SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d")

Variabile multi-articolo (es. Elenco)

Imposta variabile:

SET(PROGRAM_SRCS
        program.c
        program_utils.c
        a_lib.c
        b_lib.c
        config.c
        )

Usa variabile:

add_executable(program "${PROGRAM_SRCS}")

CMake documenti su variabili


1

$ENV{FOO}per l'utilizzo, dove FOOviene prelevato dalla variabile d'ambiente. altrimenti usa come ${FOO}, dove FOOc'è qualche altra variabile. Per l'impostazione, SET(FOO "foo")sarebbe utilizzato in CMake.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.