Versión mínima
Aquí está la primera línea de cada CMakeLists.txt
, que es el nombre requerido del archivo que busca CMake:
cmake_minimum_required(VERSION 3.1)
Mencionemos un poco la sintaxis de CMake. El nombre del comandocmake_minimum_required
no distingue entre mayúsculas y minúsculas, por lo que la práctica común es utilizarlas. 1 El VERSION
es una palabra clave especial para esta función. Y el valor de la versión sigue a la palabra clave. Como en todo este libro, basta con hacer clic en el nombre del comando para ver la documentación oficial, y utilizar el menú desplegable para cambiar la documentación entre las versiones de CMake.
¡Esta línea es especial! 2 La versión de CMake también dictará las políticas, que definen los cambios de comportamiento. Por lo tanto, si establece minimum_required
a VERSION2.8
, obtendrá el comportamiento de enlace incorrecto en macOS, por ejemplo, incluso en las últimas versiones de CMake. Si lo estableces a 3.3 o menos, obtendrás el comportamiento incorrecto de los símbolos ocultos, etc. Una lista de políticas y versiones está disponible atpolicies.
A partir de CMake 3.12, esto admite un rango, como VERSION 3.1...3.15
;esto significa que soporta tan bajo como 3.1, pero también han probado con la configuración newpolicy hasta 3.15. Esto es mucho más agradable para los usuarios que necesitan los mejores ajustes, y debido a un truco en la sintaxis, es compatible con versiones antiguas de CMake (aunque en realidad ejecutando CMake 3.1-3.11 sólo establecerá la versión 3.1 de las políticas en este ejemplo, ya que esas versiones no trataron esto especialmente). Las nuevas versiones de las políticas tienden a ser más importantes para los usuarios de macOS yWindows, que también suelen tener una versión muy reciente de CMake.
Esto es lo que deben hacer los nuevos proyectos:
cmake_minimum_required(VERSION 3.7...3.20)if(${CMAKE_VERSION} VERSION_LESS 3.12) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})endif()
Si la versión de CMake es inferior a la 3.12, el bloque if será verdadero, y la política se establecerá a la versión actual de CMake. Si la versión de CMake es 3.12 o superior, el bloque if será falso, pero se respetará la nueva sintaxis de cmake_minimum_required
y seguirá funcionando correctamente.
ADVERTENCIA: El modo de servidor CMake de MSVC originalmente tenía un abug en la lectura de este formato, por lo que si necesita soportar construcciones de Windows sin línea de comandos para versiones antiguas de MSVC, querrá hacer esto en su lugar:
cmake_minimum_required(VERSION 3.7)if(${CMAKE_VERSION} VERSION_LESS 3.20) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})else() cmake_policy(VERSION 3.20)endif()
Si realmente necesita establecer un valor bajo aquí, puede usarcmake_policy
para aumentar condicionalmente el nivel de política o establecer una política específica. Por favor, al menos haga esto para sus usuarios de macOS!
Configurar un proyecto
Ahora, cada archivo CMake de nivel superior tendrá la siguiente línea:
project(MyProject VERSION 1.0 DESCRIPTION "Very nice project" LANGUAGES CXX)
Ahora vemos aún más sintaxis. Las cadenas se citan, los espacios en blanco no importan, y el nombre del proyecto es el primer argumento (posicional). Todos los argumentos de las palabras clave son opcionales. La versión establece un montón de variables, como MyProject_VERSION
y PROJECT_VERSION
. Los idiomas son C
, CXX
,Fortran
, ASM
, CUDA
(CMake 3.8+), CSharp
(3.8+), y SWIFT
(CMake3.15+ experimental). C CXX
es el valor por defecto. En CMake 3.9, DESCRIPTION
fue añadido para establecer una descripción del proyecto, también. La documentación de project
puede ser útil.
Puede añadir comentarios con el carácter #
. CMake también tiene una sintaxis en línea para los comentarios, pero rara vez se utiliza.
No hay nada especial en el nombre del proyecto. No hay objetivos se añaden en este punto.
Hacer un ejecutable
Aunque las bibliotecas son mucho más interesantes, y vamos a pasar la mayor parte de nuestro tiempo con ellos, vamos a empezar con un simple ejecutable.
add_executable(one two.cpp three.h)
Hay varias cosas para desempacar aquí. one
es tanto el nombre del archivo ejecutable generado, como el nombre del objetivo CMake creado (pronto oirás mucho más sobre objetivos, lo prometo). La lista de archivos fuente viene a continuación, y puedes listar tantos como quieras. CMake es inteligente, y sólo compilará las extensiones de los archivos fuente. Las cabeceras serán, para la mayoría de los propósitos, ignoradas; la única razón para listarlas es para que aparezcan en los IDEs. Los objetivos aparecen como carpetas en muchos IDEs. Más información sobre el sistema de construcción general y los objetivos está disponible en buildsystem.
Hacer una biblioteca
Hacer una biblioteca se hace con add_library
, y es casi tan simple:
add_library(one STATIC two.cpp three.h)
Usted puede elegir un tipo de biblioteca, STATIC, SHARED, o MODULE. Si deja esta opción desactivada, el valor de BUILD_SHARED_LIBS
se utilizará para elegir entre STATIC y SHARED.
Como verá en las siguientes secciones, a menudo necesitará hacer un objetivo ficticio, es decir, uno en el que no se necesita compilar nada, por ejemplo, para una biblioteca de sólo cabecera. Eso se llama una biblioteca INTERFACE, y es otra opción; la única diferencia es que no puede ser seguida por nombres de archivos.
También puede hacer una biblioteca ALIAS
con una biblioteca existente, que simplemente le da un nuevo nombre para un objetivo. El único beneficio de esto es que puede hacer bibliotecas con ::
en el nombre (que verá más adelante). 3
Los objetivos son tus amigos
Ahora que hemos especificado un objetivo, ¿cómo añadimos información sobre él? Por ejemplo, tal vez necesita un directorio de inclusión:
target_include_directories(one PUBLIC include)
target_include_directories
añade un directorio de inclusión a un objetivo. PUBLIC
no significa mucho para un ejecutable; para una biblioteca permite a CMake saber que cualquier objetivo que se vincule a este objetivo también debe necesitar ese directorio de inclusión. Otras opciones son PRIVATE
(sólo afecta al objetivo actual, no a las dependencias), y INTERFACE
(sólo se necesita para las dependencias).
Podemos entonces encadenar objetivos:
add_library(another STATIC another.cpp another.h)target_link_libraries(another PUBLIC one)
target_link_libraries
es probablemente el comando más útil y confuso de CMake. Toma un objetivo (another
) y añade una dependencia si se da un objetivo. Si no existe un objetivo con ese nombre (one
), entonces añade un enlace a una biblioteca llamada one
en su ruta (de ahí el nombre del comando). O puede darle una ruta completa a una biblioteca. O una bandera del enlazador. Solo para añadir un poco de confusión final, el CMake clásico te permitía omitir la selección de la palabra clave PUBLIC
, etc. Si esto se hizo en un objetivo, obtendrá un error si trata de mezclar estilos más adelante en la cadena.
Enfóquese en usar objetivos en todas partes, y palabras clave en todas partes, y estará bien.
Los objetivos pueden tener directorios de inclusión, bibliotecas enlazadas (o objetivos enlazados), opciones de compilación, definiciones de compilación, características de compilación (ver el capítulo C++11), y más. Como verás en los dos capítulos de proyectos incluidos, a menudo puedes conseguir objetivos (y siempre hacer objetivos) para representar todas las bibliotecas que utilizas. Incluso cosas que no son verdaderas bibliotecas, como OpenMP, pueden ser representadas con objetivos. Esta es la razón por la que Modern CMake es genial!
Sumérgete
Mira si puedes seguir el siguiente archivo. Hace una simple biblioteca C++11 y un programa que la utiliza. No hay dependencias. Discutiré más opciones estándar de C++ más adelante, usando el sistema CMake 3.8 por ahora.
cmake_minimum_required(VERSION 3.8)project(Calculator LANGUAGES CXX)add_library(calclib STATIC src/calclib.cpp include/calc/lib.hpp)target_include_directories(calclib PUBLIC include)target_compile_features(calclib PUBLIC cxx_std_11)add_executable(calc apps/calc.cpp)target_link_libraries(calc PUBLIC calclib)
1. En este libro, evitaré mayormente mostrarte la manera incorrecta de hacer las cosas; puedes encontrar muchos ejemplos de eso en línea. Mencionaré alternativas ocasionalmente, pero no se recomiendan a menos que sean absolutamente necesarias; a menudo sólo están ahí para ayudarte a leer código CMake más antiguo.
2. A veces verás
FATAL_ERROR
aquí, que era necesario para soportar fallos agradables cuando se ejecutaba esto en CMake <2.6, que ya no debería ser un problema.
3. La sintaxis
::
fue originalmente pensada para las bibliotecasINTERFACE IMPORTED
, que se suponía explícitamente que eran bibliotecas definidas fuera del proyecto actual. Pero, debido a esto, la mayoría de los comandostarget_*
no funcionan en las bibliotecasIMPORTED
, lo que dificulta su configuración. Así que no use la palabra claveIMPORTED
por ahora, y use un objetivoALIAS
en su lugar; estará bien hasta que empiece a exportar objetivos. Esta limitación fue corregida en CMake 3.11.