¿Cuál es la sintaxis de CMake para configurar y usar variables?

Resuelto CivFan asked hace 9 años • 3 respuestas

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?

CivFan avatar Jun 25 '15 05:06 CivFan
Aceptado

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 CMake
  • string()Comando CMake
  • list()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.txtestán configuradas y todo lo que se llama desde allí ( , add_subdirectory()y ) .include()macro()function()
  • Los comandos add_subdirectory()y function()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 conset(... 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()los macro()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.txtarchivo 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 typey 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 INTERNALtipo 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, just cmake -D var=valueo with cmake -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"y set(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 de macros()porque no desea que sus variables locales aparezcan en el ámbito principal.
  • Muchas variables utilizadas por CMake se configuran con las llamadas project()y enable_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 printfel estilo de depuración antiguo usando el message()comando. También hay algunos módulos listos para usar que se envían con CMake: CMakePrintHelpers.cmake , CMakePrintSystemInformation.cmake
  • Busque CMakeCache.txtel 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 escribir set(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, Yo un número distinto de cero.
  • Falso si la constante es 0, OFF, NO, FALSE, N, IGNORE, NOTFOUNDla 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ónde CMAKE_CXX_COMPILER_IDestá "MSVC"y MSVCestá "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 directamenteif(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ólo if()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 ONo OFFy permiten algún manejo especial como, por ejemplo, dependencias .
  • Pero tenga cuidado , no confunda optioncon el setcomando. El valor dado optiones 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?
Florian avatar Jun 25 '2015 07:06 Florian

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

CivFan avatar Jun 24 '2015 22:06 CivFan