Respuestas:
Al escribir scripts de CMake, hay mucho que necesita saber sobre la sintaxis y cómo usar variables en CMake.
Cadenas usando set()
:
set(MyString "Some Text")
set(MyStringWithVar "Some other Text: ${MyString}")
set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")
O con string()
:
string(APPEND MyStringWithContent " ${MyString}")
Listas que usan set()
:
set(MyList "a" "b" "c")
set(MyList ${MyList} "d")
O mejor con list()
:
list(APPEND MyList "a" "b" "c")
list(APPEND MyList "d")
Listas de nombres de archivo:
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 CMakePrimero están las "Variables normales" y las cosas que necesita saber sobre su alcance:
CMakeLists.txt
que se fijan en todo y se llama desde allí ( add_subdirectory()
, include()
, macro()
y function()
).add_subdirectory()
y function()
son especiales, porque abren su propio alcance.
set(...)
solo son visibles allí y hacen una copia de todas las variables normales del nivel de alcance desde el que se llaman (llamado alcance primario).set(... PARENT_SCOPE)
function(xyz _resultVar)
establecerset(${_resultVar} 1 PARENT_SCOPE)
include()
o los macro()
scripts modificarán las variables directamente en el ámbito de donde se llaman.En segundo lugar está el "Caché de variables globales". Cosas que debes saber sobre el caché:
CMakeCache.txt
archivo en su directorio de salida binario.Los valores en la caché se pueden modificar en la aplicación GUI de CMake antes de que se generen. Por lo tanto, en comparación con las variables normales, tienen a type
y a docstring
. Normalmente no uso la GUI, así que la uso set(... CACHE INTERNAL "")
para establecer mis valores globales y persistentes.
Tenga en cuenta que el INTERNAL
tipo de variable de caché implicaFORCE
En un script CMake, solo puede cambiar las entradas de caché existentes si usa la set(... CACHE ... FORCE)
sintaxis. Este comportamiento es utilizado, por ejemplo, por el propio CMake, porque normalmente no fuerza las entradas de caché y, por lo tanto, puede predefinirlo con otro valor.
cmake -D var:type=value
, solo cmake -D var=value
o con cmake -C CMakeInitialCache.cmake
.unset(... CACHE)
.La memoria caché es global y puede configurarlos prácticamente en cualquier lugar en sus scripts CMake. Pero le recomendaría que lo piense dos veces antes de utilizar las variables de caché (son globales y persistentes). Normalmente prefiero la sintaxis set_property(GLOBAL PROPERTY ...)
y set_property(GLOBAL APPEND PROPERTY ...)
para definir mis propias variables globales no persistentes.
Para evitar dificultades, debe saber lo siguiente acerca de las variables:
find_...
comandos, si tienen éxito, escriben sus resultados como variables en caché "para que ninguna llamada vuelva a buscar"set(MyVar a b c)
es "a;b;c"
y set(MyVar "a b c")
es"a b c"
list()
comando para manejar listasfunctions()
lugar de macros()
porque no desea que sus variables locales se muestren en el ámbito primario.project()
y enable_language()
. Por lo tanto, podría ser importante establecer algunas variables antes de usar esos comandos.A veces solo ayuda la depuración de variables. Lo siguiente puede ayudarlo:
printf
estilo de depuración usando el message()
comando. También hay algunos módulos listos para usar que se envían con CMake: CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmakeCMakeCache.txt
archivo en su directorio de salida binario. Este archivo incluso se genera si falla la generación real de su entorno de creación.cmake --trace ...
para ver el proceso de análisis completo de CMake. Esa es una especie de última reserva, ya que genera mucha salida.$ENV{...}
y escribir set(ENV{...} ...)
variables de entorno$<...>
solo se evalúan cuando el generador de CMake escribe el entorno de creación (en comparación con las variables normales que se reemplazan "en el lugar" por el analizador)${${...}}
usted puede dar nombres de variables en una variable y hacer referencia a su contenido.if()
comando)
if(MyVariable)
usted puede verificar directamente una variable para verdadero / falso (no es necesario aquí para el cerramiento ${...}
)1
, ON
, YES
, TRUE
, Y
, o un número distinto de cero.0
, OFF
, NO
, FALSE
, N
, IGNORE
, NOTFOUND
, la cadena vacía, o termina en el sufijo -NOTFOUND
.if(MSVC)
, pero puede ser confusa para alguien que no conoce este atajo de sintaxis.set(CMAKE_${lang}_COMPILER ...)
if()
comandos. Aquí hay un ejemplo donde CMAKE_CXX_COMPILER_ID
es "MSVC"
y MSVC
es "1"
:
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
es cierto, porque se evalúa a if("1" STREQUAL "1")
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
es falso porque se evalúa como if("MSVC" STREQUAL "1")
if(MSVC)
cmake_policy(SET CMP0054 NEW)
"solo interpretar if()
argumentos como variables o palabras clave cuando no se citan".option()
comando
ON
o OFF
y permiten un manejo especial como, por ejemplo, dependenciasoption
con el set
comando. El valor dado a option
es realmente solo el "valor inicial" (transferido una vez al caché durante el primer paso de configuración) y luego debe ser modificado por el usuario a través de la GUI de CMake .${MyString}
conduce a un montón de errores para "si se dan argumentos ..." como el error CMake cerca de if: "si se dan argumentos" seguido de paréntesis, "NOT", "IGUAL" y similares .
MyString
contiene un nombre de variable que luego será nuevamente desreferenciado . Creo que nadie realmente quiere ese OLD
comportamiento. Así que desde mi punto de vista es totalmente seguro y compatible con la política acaba de establecer CMP0054
a NEW
(véase la discusión aquí ).
if (MyString ...)
(si su código le da la advertencia).
Aquí hay un par de ejemplos básicos para comenzar rápido y sucio.
Establecer variable:
SET(INSTALL_ETC_DIR "etc")
Usar variable:
SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d")
Establecer variable:
SET(PROGRAM_SRCS
program.c
program_utils.c
a_lib.c
b_lib.c
config.c
)
Usar variable:
add_executable(program "${PROGRAM_SRCS}")
if ("${MyString}" ...)
estoy viendo advertencias:Policy CMP0054 is not set: Only interpret if() arguments as variables or keywords when unquoted
. Ver, por ejemplo, Build 367 . ¿Algunas ideas?