¿Cuál es la sintaxis de CMake para configurar y usar variables?
Me pregunto esto como recordatorio la próxima vez que use CMake. Nunca funciona y los resultados de Google no son muy buenos.
¿Cuál es la sintaxis para configurar y usar variables en CMake?
Al escribir scripts de CMake, es necesario saber mucho sobre la sintaxis y cómo usar variables en CMake.
La sintaxis
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 utilizan 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 archivos:
set(MySourcesList "File.name" "File with Space.name")
list(APPEND MySourcesList "File.name" "File with Space.name")
add_excutable(MyExeTarget ${MySourcesList})
La documentación
- CMake/Sintaxis del idioma
- CMake: Listas de variables Cadenas
- CMake: variables útiles
set()
Comando CMakestring()
Comando CMakelist()
Comando CMake- Cmake: generador de expresiones
El Alcance o "¿Qué valor tiene mi variable?"
Primero están las "Variables normales" y lo que necesitas saber sobre su alcance:
- Las variables normales son visibles para quienes
CMakeLists.txt
están configuradas y todo lo que se llama desde allí ( ,add_subdirectory()
y ) .include()
macro()
function()
- Los comandos
add_subdirectory()
yfunction()
son especiales porque abren su propio alcance. - Es decir, las variables
set(...)
que allí solo son visibles allí y hacen una copia de todas las variables normales del nivel de alcance desde el que se llaman (llamado alcance principal). - Entonces, si está en un subdirectorio o en una función, puede modificar una variable ya existente en el ámbito principal con
set(... PARENT_SCOPE)
- Puede utilizar esto, por ejemplo, en funciones pasando el nombre de la variable como parámetro de función. Un ejemplo sería
function(xyz _resultVar)
establecerset(${_resultVar} 1 PARENT_SCOPE)
- Por otro lado, todo lo que configure en
include()
losmacro()
scripts modificará las variables directamente en el ámbito desde donde se llaman.
En segundo lugar está la "Caché de variables globales". Cosas que necesitas saber sobre la caché:
Si no se define ninguna variable normal con el nombre dado en el alcance actual, CMake buscará una entrada de caché coincidente.
Los valores de caché se almacenan en el
CMakeCache.txt
archivo de su directorio de salida binaria.Los valores en la caché se pueden modificar en la aplicación GUI de CMake antes de generarlos. Por lo tanto, en comparación con las variables normales, tienen a
type
y adocstring
. Normalmente no uso la GUI, así que la usoset(... CACHE INTERNAL "")
para establecer mis valores globales y persistentes.Tenga en cuenta que el
INTERNAL
tipo de variable de caché implicaFORCE
En un script de CMake, solo puede cambiar las entradas de caché existentes si usa la
set(... CACHE ... FORCE)
sintaxis. Este comportamiento lo utiliza, por ejemplo, el propio CMake, porque normalmente no fuerza las entradas de la caché y, por lo tanto, puede predefinirlo con otro valor.Puede utilizar la línea de comando para configurar entradas en la caché con la sintaxis
cmake -D var:type=value
, justcmake -D var=value
o withcmake -C CMakeInitialCache.cmake
.Puede desarmar entradas en la caché con
unset(... CACHE)
.
El caché es global y puede configurarlo prácticamente en cualquier lugar de sus scripts de CMake. Pero te recomendaría que lo pienses dos veces acerca de dónde usar las variables de caché (son globales y persistentes). Normalmente prefiero la sintaxis set_property(GLOBAL PROPERTY ...)
and set_property(GLOBAL APPEND PROPERTY ...)
para definir mis propias variables globales no persistentes.
Errores de variables y "¿Cómo depurar cambios de variables?"
Para evitar problemas, debe saber lo siguiente sobre las variables:
- Las variables locales ocultan las variables almacenadas en caché si ambas tienen el mismo nombre
- Los
find_...
comandos, si tienen éxito, escriben sus resultados como variables almacenadas en caché "para que ninguna llamada vuelva a buscar". - Las listas en CMake son solo cadenas con delimitadores de punto y coma y, por lo tanto, las comillas son importantes
set(MyVar a b c)
es"a;b;c"
yset(MyVar "a b c")
es"a b c"
- La recomendación es que siempre uses comillas con la única excepción cuando quieras dar una lista como lista.
- Generalmente prefiero el
list()
comando para manejar listas. - Todo el problema del alcance descrito anteriormente. Especialmente se recomienda usarlo
functions()
en lugar demacros()
porque no desea que sus variables locales aparezcan en el ámbito principal. - Muchas variables utilizadas por CMake se configuran con las llamadas
project()
yenable_language()
. Por lo tanto, podría resultar importante establecer algunas variables antes de utilizar esos comandos. - Las variables de entorno pueden diferir de dónde CMake generó el entorno de creación y cuándo se utilizan los archivos de creación.
- Un cambio en una variable de entorno no reactiva el proceso de generación.
- Especialmente un entorno IDE generado puede diferir de su línea de comando, por lo que se recomienda transferir las variables de su entorno a algo que esté almacenado en caché.
A veces sólo ayuda la depuración de variables. Lo siguiente puede ayudarle:
- Simplemente use
printf
el estilo de depuración antiguo usando elmessage()
comando. También hay algunos módulos listos para usar que se envían con CMake: CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmake - Busque
CMakeCache.txt
el archivo en su directorio de salida binaria. Este archivo se genera incluso si falla la generación real de su entorno de creación. - Utilice variable_watch() para ver dónde se leen/escriben/eliminan sus variables.
- Busque en las propiedades del directorio CACHE_VARIABLES y VARIABLES
- Llame
cmake --trace ...
para ver el proceso de análisis completo de CMake. Esa es una especie de última reserva, porque genera mucha producción.
Sintaxis especial
- Variables de entorno
- Puedes leer
$ENV{...}
y escribirset(ENV{...} ...)
variables de entorno. - Expresiones generadoras
- Las expresiones del generador
$<...>
solo se evalúan cuando el generador de CMake escribe el entorno de creación (en comparación con las variables normales que el analizador reemplaza "in situ") - Muy útil, por ejemplo, en líneas de comando del compilador/enlazador y en entornos de configuración múltiple
- Referencias
- Con
${${...}}
puede dar nombres de variables en una variable y hacer referencia a su contenido. - A menudo se utiliza cuando se da un nombre de variable como parámetro de función/macro.
- Valores constantes (ver
if()
comando) - Con
if(MyVariable)
usted puede verificar directamente una variable para ver si es verdadero/falso (aquí no es necesario adjuntarlo${...}
) - Verdadero si la constante es
1
,ON
,YES
,TRUE
,Y
o un número distinto de cero. - Falso si la constante es
0
,OFF
,NO
,FALSE
,N
,IGNORE
,NOTFOUND
la cadena vacía o termina en el sufijo-NOTFOUND
. - Esta sintaxis se utiliza a menudo para algo como
if(MSVC)
, pero puede resultar confuso para alguien que no conoce este atajo de sintaxis. - Sustituciones recursivas
- Puede construir nombres de variables utilizando variables. Después de que CMake haya sustituido las variables, comprobará nuevamente si el resultado es una variable en sí. Esta es una característica muy poderosa que se utiliza en CMake, por ejemplo, como una especie de plantilla.
set(CMAKE_${lang}_COMPILER ...)
- Pero tenga en cuenta que esto puede causarle dolores de cabeza con
if()
los comandos. A continuación se muestra un ejemplo de dóndeCMAKE_CXX_COMPILER_ID
está"MSVC"
yMSVC
está"1"
:if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
es cierto, porque se evalúa comoif("1" STREQUAL "1")
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
es falso, porque se evalúa comoif("MSVC" STREQUAL "1")
- Entonces, la mejor solución aquí sería (ver arriba) verificar directamente
if(MSVC)
- La buena noticia es que esto se solucionó en CMake 3.1 con la introducción de la política CMP0054 . Recomendaría configurar siempre
cmake_policy(SET CMP0054 NEW)
"interpretar sóloif()
los argumentos como variables o palabras clave cuando no están entre comillas". - El
option()
comando - Principalmente solo cadenas almacenadas en caché que solo pueden ser
ON
oOFF
y permiten algún manejo especial como, por ejemplo, dependencias . - Pero tenga cuidado , no confunda
option
con elset
comando. El valor dadooption
es en realidad solo el "valor inicial" (transferido una vez al caché durante el primer paso de configuración) y luego el usuario debe cambiarlo a través de la GUI de CMake .
Referencias
- ¿Cómo se utiliza CMake?
- cmake, perdido en el concepto de variables globales (y alternativas PARENT_SCOPE o add_subdirectory)
- Recorriendo una lista de cadenas
- Cómo almacenar la configuración de compilación de CMake
- La comparación de CMake con una cadena vacía con STREQUAL falló
- ¿Cuándo debo citar las variables de CMake?
Aquí hay un par de ejemplos básicos para comenzar de manera rápida y sucia.
Variable de un elemento
Establecer variable:
SET(INSTALL_ETC_DIR "etc")
Utilice variables:
SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d")
Variable de varios elementos (es decir, lista)
Establecer variable:
SET(PROGRAM_SRCS
program.c
program_utils.c
a_lib.c
b_lib.c
config.c
)
Utilice variables:
add_executable(program "${PROGRAM_SRCS}")
CMake documentos sobre variables