Antworten:
Beim Schreiben von CMake-Skripten müssen Sie viel über die Syntax und die Verwendung von Variablen in CMake wissen.
Zeichenfolgen mit set()
:
set(MyString "Some Text")
set(MyStringWithVar "Some other Text: ${MyString}")
set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")
Oder mit string()
:
string(APPEND MyStringWithContent " ${MyString}")
Listen mit set()
:
set(MyList "a" "b" "c")
set(MyList ${MyList} "d")
Oder besser mit list()
:
list(APPEND MyList "a" "b" "c")
list(APPEND MyList "d")
Listen der Dateinamen:
set(MySourcesList "File.name" "File with Space.name")
list(APPEND MySourcesList "File.name" "File with Space.name")
add_excutable(MyExeTarget ${MySourcesList})
set()
Befehlstring()
Befehllist()
BefehlZuerst gibt es die "normalen Variablen" und Dinge, die Sie über ihren Umfang wissen müssen:
CMakeLists.txt
sie gesetzt in und alles rief von dort aus ( add_subdirectory()
, include()
, macro()
und function()
).add_subdirectory()
und function()
sind etwas Besonderes, da sie ihren eigenen Bereich eröffnen.
set(...)
dort nur dort sichtbar sind und eine Kopie aller normalen Variablen der Bereichsebene erstellen, von der aus sie aufgerufen werden (als übergeordneter Bereich bezeichnet).set(... PARENT_SCOPE)
function(xyz _resultVar)
Einstellenset(${_resultVar} 1 PARENT_SCOPE)
include()
oder macro()
Skripte Variablen direkt in dem Bereich, von dem aus sie aufgerufen werden.Zweitens gibt es den "Global Variables Cache". Dinge, die Sie über den Cache wissen müssen:
CMakeCache.txt
Datei in Ihrem Binärausgabeverzeichnis gespeichert .Die Werte im Cache können in der GUI- Anwendung von CMake geändert werden, bevor sie generiert werden. Daher haben sie - im Vergleich zu normalen Variablen - a type
und a docstring
. Normalerweise verwende ich die GUI nicht, daher set(... CACHE INTERNAL "")
setze ich meine globalen und dauerhaften Werte.
Bitte beachten Sie, dass der INTERNAL
Typ der Cache-Variablen dies impliziertFORCE
In einem CMake-Skript können Sie vorhandene Cache-Einträge nur ändern, wenn Sie die set(... CACHE ... FORCE)
Syntax verwenden. Dieses Verhalten wird zB von CMake selbst verwendet, da es normalerweise keine Cache-Einträge selbst erzwingt und Sie es daher mit einem anderen Wert vordefinieren können.
cmake -D var:type=value
festzulegen .cmake -D var=value
cmake -C CMakeInitialCache.cmake
unset(... CACHE)
.Der Cache ist global und Sie können sie praktisch überall in Ihren CMake-Skripten festlegen. Ich würde Ihnen jedoch empfehlen, zweimal darüber nachzudenken, wo Cache-Variablen verwendet werden sollen (sie sind global und dauerhaft). Normalerweise bevorzuge ich die Syntax set_property(GLOBAL PROPERTY ...)
und set_property(GLOBAL APPEND PROPERTY ...)
, um meine eigenen nicht persistenten globalen Variablen zu definieren.
Um Fallstricke zu vermeiden, sollten Sie Folgendes über Variablen wissen:
find_...
Befehle schreiben - falls erfolgreich - ihre Ergebnisse als zwischengespeicherte Variablen, "damit kein Aufruf erneut sucht".set(MyVar a b c)
ist "a;b;c"
und set(MyVar "a b c")
ist"a b c"
list()
Befehl zum Behandeln von Listenfunctions()
anstelle von empfohlen, macros()
da Ihre lokalen Variablen nicht im übergeordneten Bereich angezeigt werden sollen.project()
und festgelegt enable_language()
. Daher kann es wichtig werden, einige Variablen festzulegen, bevor diese Befehle verwendet werden.Manchmal hilft nur das Debuggen von Variablen. Folgendes kann Ihnen helfen:
printf
Debugging-Stil mit dem message()
Befehl. Es gibt auch einige gebrauchsfertige Module, die mit CMake selbst geliefert werden : CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmakeCMakeCache.txt
Datei in Ihrem Binärausgabeverzeichnis. Diese Datei wird sogar generiert, wenn die eigentliche Generierung Ihrer make-Umgebung fehlschlägt.cmake --trace ...
an, um den vollständigen Analyseprozess des CMake zu sehen. Das ist eine Art letzte Reserve, weil sie viel Output generiert.$ENV{...}
und schreibenset(ENV{...} ...)
$<...>
werden nur ausgewertet, wenn der Generator von CMake die make-Umgebung schreibt (Vergleich mit normalen Variablen, die vom Parser "an Ort und Stelle" ersetzt werden).${${...}}
Sie einer Variablen Variablennamen geben und auf deren Inhalt verweisen.if()
Befehl)
if(MyVariable)
können Sie eine Variable direkt auf wahr / falsch prüfen (hier ist keine Beilage erforderlich ${...}
)1
, ON
, YES
, TRUE
, Y
, oder eine Zahl ungleich Null.0
, OFF
, NO
, FALSE
, N
, IGNORE
, NOTFOUND
, die leere Zeichenkette, oder endet in dem Suffix -NOTFOUND
.if(MSVC)
, kann jedoch für jemanden verwirrend sein, der diese Syntaxverknüpfung nicht kennt.set(CMAKE_${lang}_COMPILER ...)
if()
Befehlen zu Kopfschmerzen führen kann . Hier ist ein Beispiel, wo CMAKE_CXX_COMPILER_ID
ist "MSVC"
und MSVC
ist "1"
:
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
ist wahr, weil es auswertet if("1" STREQUAL "1")
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
ist falsch, weil es zu auswertet if("MSVC" STREQUAL "1")
if(MSVC)
cmake_policy(SET CMP0054 NEW)
"nur if()
Argumente als Variablen oder Schlüsselwörter zu interpretieren, wenn sie nicht in Anführungszeichen stehen" zu setzen.option()
Befehl
ON
oder sein können OFF
und eine spezielle Behandlung ermöglichen, z. B. Abhängigkeitenoption
mit dem set
Befehl. Der angegebene Wert option
ist eigentlich nur der "Anfangswert" (der im ersten Konfigurationsschritt einmal in den Cache übertragen wurde) und soll anschließend vom Benutzer über die Benutzeroberfläche von CMake geändert werden .${MyString}
der Anführungszeichen führt zu einer Reihe von Fehlern für "wenn gegebene Argumente ..." wie CMake error in der Nähe von if: "wenn gegebene Argumente", gefolgt von Klammern, "NOT", "EQUALS" und ähnlichem .
MyString
sie einen Variablennamen enthält, auf den dann erneut verwiesen wird. Ich glaube, dass niemand dieses OLD
Verhalten wirklich will . Aus meiner Sicht ist es also absolut sicher und abwärtskompatibel, nur die Richtlinien CMP0054
festzulegen NEW
(siehe die Diskussion hier ).
if (MyString ...)
(wenn es Ihr Code ist, der die Warnung gibt).
${MyString}
und durch ersetzt MyString
(oder ich glaube, wir haben sie alle entfernt). Immer noch keine Freude: Build 372 . Der Mist kommt nicht einmal von unserem Code. Es scheint von CMake zu kommen. Zeile 283 ist if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
.
Hier sind einige grundlegende Beispiele, um schnell und schmutzig loszulegen.
Variable setzen:
SET(INSTALL_ETC_DIR "etc")
Variable verwenden:
SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d")
Variable setzen:
SET(PROGRAM_SRCS
program.c
program_utils.c
a_lib.c
b_lib.c
config.c
)
Variable verwenden:
add_executable(program "${PROGRAM_SRCS}")
if ("${MyString}" ...)
sehe ich Warnungen :Policy CMP0054 is not set: Only interpret if() arguments as variables or keywords when unquoted
. Siehe zum Beispiel Build 367 . Irgendwelche Ideen?