Odpowiedzi:
Pisząc skrypty CMake, musisz dużo wiedzieć o składni i jak używać zmiennych w CMake.
Ciągi używające set()
:
set(MyString "Some Text")
set(MyStringWithVar "Some other Text: ${MyString}")
set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")
Lub z string()
:
string(APPEND MyStringWithContent " ${MyString}")
Listy używające set()
:
set(MyList "a" "b" "c")
set(MyList ${MyList} "d")
Lub lepiej z list()
:
list(APPEND MyList "a" "b" "c")
list(APPEND MyList "d")
Listy nazw plików:
set(MySourcesList "File.name" "File with Space.name")
list(APPEND MySourcesList "File.name" "File with Space.name")
add_excutable(MyExeTarget ${MySourcesList})
set()
Poleceniestring()
Polecenielist()
PolecenieNajpierw są „Zmienne normalne” i rzeczy, które musisz wiedzieć o ich zakresie:
CMakeLists.txt
są ustawione i wszystkiego zwana stamtąd ( add_subdirectory()
, include()
, macro()
ifunction()
).add_subdirectory()
ifunction()
polecenia są wyjątkowe, ponieważ otwierają się własnym zakresie.
set(...)
są tam tylko widoczne i tworzą kopię wszystkich normalnych zmiennych z poziomu zakresu, z którego są wywoływane (tzw. Zasięg nadrzędny).set(... PARENT_SCOPE)
function(xyz _resultVar)
ustawienieset(${_resultVar} 1 PARENT_SCOPE)
include()
lub macro()
skrypty, zmodyfikuje zmienne bezpośrednio w zakresie, z którego są wywoływane.Drugi to „Global Variables Cache”. Rzeczy, które musisz wiedzieć o pamięci podręcznej:
CMakeCache.txt
pliku w katalogu danych binarnych.Wartości w pamięci podręcznej można modyfikować w aplikacji GUI CMake przed ich wygenerowaniem. Dlatego - w porównaniu do normalnych zmiennych - mają a type
i a docstring
. Zwykle nie używam GUI, więc używamset(... CACHE INTERNAL "")
do ustawiania moich globalnych i trwałych wartości.
Należy pamiętać, że INTERNAL
typ zmiennej pamięci podręcznej ma znaczenieFORCE
W skrypcie CMake możesz zmienić istniejące wpisy pamięci podręcznej tylko wtedy, gdy używasz set(... CACHE ... FORCE)
składni. Zachowanie to jest wykorzystywane np. Przez sam CMake, ponieważ normalnie nie wymusza ono samodzielnie wpisów do pamięci podręcznej i dlatego można je wstępnie zdefiniować inną wartością.
cmake -D var:type=value
, tylko cmake -D var=value
lub z cmake -C CMakeInitialCache.cmake
.unset(... CACHE)
.Pamięć podręczna jest globalna i możesz ją ustawić praktycznie w dowolnym miejscu w skryptach CMake. Ale radziłbym dwa razy zastanowić się, gdzie używać zmiennych pamięci podręcznej (są globalne i trwałe). Zwykle wolę składnię set_property(GLOBAL PROPERTY ...)
i set_property(GLOBAL APPEND PROPERTY ...)
do definiowania własnych nietrwałych zmiennych globalnych.
Aby uniknąć pułapek, powinieneś wiedzieć, co następuje o zmiennych:
find_...
komendy - w razie powodzenia - robić napisać swoje wyniki jako pamięci podręcznej zmiennych „tak, że żadne połączenie nie będzie szukał ponownie”set(MyVar a b c)
jest "a;b;c"
i set(MyVar "a b c")
jest"a b c"
list()
polecenie do obsługi listfunctions()
zamiast, macros()
ponieważ nie chcesz, aby zmienne lokalne pojawiały się w zakresie nadrzędnym.project()
i enable_language()
. Dlatego może być ważne, aby ustawić pewne zmienne przed użyciem tych poleceń.Czasami pomaga tylko debugowanie zmiennych. Poniższe mogą Ci pomóc:
printf
stylu debugowania, używając message()
polecenia. Istnieje również kilka gotowych do użycia modułów dostarczanych z samym CMake: CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmakeCMakeCache.txt
pliku w katalogu wyjściowym binarnym. Ten plik jest nawet generowany, jeśli rzeczywiste generowanie środowiska make zawiedzie.cmake --trace ...
aby zobaczyć cały proces analizowania CMake. To w pewnym sensie ostatnia rezerwa, ponieważ generuje dużo mocy.$ENV{...}
i zapisywać set(ENV{...} ...)
zmienne środowiskowe$<...>
są oceniane tylko wtedy, gdy generator CMake zapisuje środowisko make (porównanie do zwykłych zmiennych, które są zastępowane „w miejscu” przez parser)${${...}}
możesz nadać zmiennym nazwy w zmiennej i odwołać się do jej zawartości.if()
polecenie)
if(MyVariable)
możesz bezpośrednio sprawdzić zmienną pod kątem prawdy / fałszu (nie ma potrzeby dołączania ${...}
)1
, ON
, YES
, TRUE
, Y
, lub numer niezerowe.0
, OFF
, NO
, FALSE
, N
, IGNORE
, NOTFOUND
, pusty ciąg znaków lub kończy się przyrostkiem -NOTFOUND
.if(MSVC)
, ale może być myląca dla kogoś, kto nie zna tego skrótu składniowego.set(CMAKE_${lang}_COMPILER ...)
if()
poleceniach. Oto przykład, gdzie CMAKE_CXX_COMPILER_ID
jest "MSVC"
i MSVC
jest "1"
:
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
jest prawdą, ponieważ wartościuje do if("1" STREQUAL "1")
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
jest fałszem, ponieważ wartościuje do if("MSVC" STREQUAL "1")
if(MSVC)
cmake_policy(SET CMP0054 NEW)
„interpretuj if()
argumenty jako zmienne lub słowa kluczowe tylko wtedy, gdy nie są cytowane”.option()
komenda
ON
lub OFF
i pozwalają na pewną specjalną obsługę, jak np. Zależnościoption
z set
poleceniem. Wartość podana option
jest w rzeczywistości tylko "wartością początkową" (przesyłana raz do pamięci podręcznej podczas pierwszego kroku konfiguracji) i jest później przeznaczona do zmiany przez użytkownika za pomocą GUI CMake .${MyString}
prowadzi do wielu błędów dla „jeśli podane argumenty ...”, takich jak CMake błąd blisko if: „jeśli podane argumenty”, po których następują parantze, „NIE”, „RÓWNE” i podobne .
MyString
nie zawiera nazwy zmiennej, która następnie zostanie ponownie usunięta . Uważam, że nikt tak naprawdę nie chce takiego OLD
zachowania. Z mojego punktu widzenia jest to całkowicie bezpieczne i wstecznie kompatybilne, aby po prostu ustawić politykę CMP0054
na NEW
(zobacz dyskusję tutaj ).
if (MyString ...)
(jeśli to twój kod daje ostrzeżenie).
${MyString}
i zastąpiliśmy je MyString
(lub wydaje mi się, że usunęliśmy je wszystkie). Wciąż brak radości: zbuduj 372 . Bzdury nawet nie pochodzą z naszego kodu. Wygląda na to, że pochodzi z CMake. Linia 283 jest if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
.
Oto kilka podstawowych przykładów, które pomogą Ci szybko i łatwo zacząć.
Ustaw zmienną:
SET(INSTALL_ETC_DIR "etc")
Użyj zmiennej:
SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d")
Ustaw zmienną:
SET(PROGRAM_SRCS
program.c
program_utils.c
a_lib.c
b_lib.c
config.c
)
Użyj zmiennej:
add_executable(program "${PROGRAM_SRCS}")
if ("${MyString}" ...)
Jestem ostrzeżenia zobaczyć:Policy CMP0054 is not set: Only interpret if() arguments as variables or keywords when unquoted
. Zobacz na przykład Build 367 . Jakieś pomysły?