Risposte:
Quando si scrivono script CMake, è necessario conoscere molto la sintassi e come utilizzare le variabili in CMake.
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})
set()
Comando CMakestring()
Comando CMakelist()
Comando CMakeInnanzitutto ci sono le "variabili normali" e le cose che devi sapere sul loro ambito:
CMakeLists.txt
essi sono fissati in e tutto chiamato da lì ( add_subdirectory()
, include()
, macro()
e function()
).add_subdirectory()
e function()
sono speciali, perché aprono il loro ambito.
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).set(... PARENT_SCOPE)
function(xyz _resultVar)
impostazioneset(${_resultVar} 1 PARENT_SCOPE)
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:
CMakeCache.txt
file 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 type
e a docstring
. Normalmente non utilizzo la GUI, quindi utilizzo i set(... CACHE INTERNAL "")
miei valori globali e persistenti.
Si noti che il INTERNAL
tipo 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.
cmake -D var:type=value
, solo cmake -D var=value
o con cmake -C CMakeInitialCache.cmake
.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.
Per evitare insidie dovresti sapere quanto segue sulle variabili:
find_...
comandi, se hanno esito positivo, scrivono i loro risultati come variabili memorizzate nella cache "in modo che nessuna chiamata effettui nuovamente la ricerca"set(MyVar a b c)
è "a;b;c"
ed set(MyVar "a b c")
è"a b c"
list()
comando per la gestione degli elenchifunctions()
anziché macros()
perché non si desidera che le variabili locali vengano visualizzate nell'ambito genitore.project()
e enable_language()
. Quindi potrebbe essere importante impostare alcune variabili prima di usare quei comandi.A volte aiuta solo il debug delle variabili. Quanto segue può aiutarti:
printf
stile di debug usando il message()
comando. Esistono anche alcuni moduli pronti all'uso forniti con CMake stesso: CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmakeCMakeCache.txt
file nella directory di output binaria. Questo file viene generato anche se la generazione effettiva del tuo ambiente make non riesce.cmake --trace ...
per vedere il processo di analisi completo di CMake. È una specie dell'ultima riserva, perché genera molto output.$ENV{...}
e scrivere set(ENV{...} ...)
variabili di ambiente$<...>
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)${${...}}
te puoi dare nomi di variabili in una variabile e fare riferimento al suo contenuto.if()
comando)
if(MyVariable)
puoi controllare direttamente una variabile per true / false (non è necessario qui per racchiudere ${...}
)1
, ON
, YES
, TRUE
, Y
, o un numero diverso da zero.0
, OFF
, NO
, FALSE
, N
, IGNORE
, NOTFOUND
, la stringa vuota, o termina nel suffisso -NOTFOUND
.if(MSVC)
, ma può essere fonte di confusione per qualcuno che non conosce questo collegamento alla sintassi.set(CMAKE_${lang}_COMPILER ...)
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")
if(MSVC)
cmake_policy(SET CMP0054 NEW)
"interpretare gli if()
argomenti solo come variabili o parole chiave quando non quotati".option()
comando
ON
o OFF
e consentono una gestione speciale come ad esempio le dipendenzeoption
con il set
comando. 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 .${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 .
MyString
contiene un nome variabile che verrà nuovamente de-referenziato. Credo che nessuno voglia davvero quel OLD
comportamento. Quindi, dal mio punto di vista la sua totalmente sicuro e compatibile alla politica solo set CMP0054
per NEW
(vedi la discussione qui ).
if (MyString ...)
(se è il tuo codice a dare l'avvertimento).
${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")
.
Ecco un paio di esempi di base per iniziare in modo rapido e sporco.
Imposta variabile:
SET(INSTALL_ETC_DIR "etc")
Usa variabile:
SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d")
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}")
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?