Cmake

Este documento proporciona una visión rápida de CMake – una alternativa multiplataforma a Makefiles y make de linux. Para obtener ayuda sobre el uso de make y Makefiles sin CMake, consulte la documentación del profesor Newhall. Este documento fue escrito para la versión 2.6 de cmake, que se instala en las máquinas del laboratorio a través de stow (a partir de enero de 2009).

Por qué CMake

Personalmente me gusta CMake porque parece más intuitivo que escribir un Makefile estándar. Las cosas básicas y comunes son bastante fáciles y las más difíciles son posibles, aunque la mayoría de las cosas que construyo son bastante básicas. Para demostrar CMake, he incluido algo de código de ejemplo en el archivo cmake.tgz (4 KB). Guarda el archivo y descomprime el contenido en cualquier lugar de tu directorio. Por ejemplo:

$ tar xzvf cmake.tgz$ cd cmake$ lsCMakeLists.txt w01-cpp/
CMakeLists.txt

CMake se controla escribiendo instrucciones en archivos CMakeLists.txt. Cada directorio de tu proyecto debe tener un archivo CMakeLists.txt. Lo bueno de CMake es que los archivos CMakeLists.txt en un subdirectorio heredan las propiedades establecidas en el directorio principal, reduciendo la cantidad de código duplicado. Para nuestro proyecto de ejemplo, sólo tenemos un subdirectorio: w01-cpp. El archivo CMakeLists.txt para el directorio cmake de nivel superior es bastante simple, pero demuestra algunas características clave.

cmake_minimum_required(VERSION 2.6)project(CMAKEDEMO)#There are lots of scripts with cmake#for finding external libraries. #see /usr/local/share/cmake-2.6/Modules/Find*.cmake for more examplesfind_package(GLUT)find_package(OpenGL)set(CMAKE_CXX_FLAGS "-g -Wall")add_subdirectory(w01-cpp)

Este código de demostración incluye código que requiere librerías OpenGL externas para los gráficos. En una configuración típica de Makefile probablemente necesitaríamos especificar dónde están los archivos de cabecera de OpenGL, por ejemplo, -I/usr/local/include, qué bibliotecas utilizar, por ejemplo, -lGL -lGLU -lglut, y la ubicación de las bibliotecas. La ubicación de los archivos de cabecera y las bibliotecas probablemente varíe de una instalación a otra y de una plataforma a otra. Sin embargo, suele haber algunos lugares estándar en los que buscar, y CMake automatiza esta búsqueda mediante las macros find_package. Así, find_package(GLUT) y find_package(OpenGL) encuentra la ubicación de los archivos de cabecera y las bibliotecas y establece las bibliotecas más comunes que se enlazan en un proyecto típico de OpenGL. CMake tiene soporte para encontrar muchos paquetes. Ver /usr/local/share/cmake-2.6/Modules/Find*.cmake para más ejemplos. Para utilizar uno de estos scripts, utilice find_package(PKGname) si el script de CMake se llama FindPKGname.cmake.

Para más información sobre la búsqueda de bibliotecas externas o la creación de sus propias macros de búsqueda de paquetes, consulte el wiki de KitWare sobre el tema.

Puede establecer banderas comunes que establecería en un Makefile típico utilizandoingset(VARNAME VALUE). En este ejemplo he habilitado los símbolos de depuración (-g) y todas las advertencias (-Wall). También le di un nombre a este proyecto CMake usando project(CMAKEDEMO). Puedes nombrar tu proyecto como quieras. Usaremos esta información en el archivo CMakeLists.txt en el directorio w01-cpp. Finalmente indicamos que la mayor parte del código está realmente en el w01-cpp diciéndole a nuestro archivo CMakeLists.txt de nivel superior que añada_subdirectorio(w01-cpp)

Echemos un vistazo al archivo CMakeLists.txt en el subdirectorio w01-cpp:

include_directories(${CMAKEDEMO_SOURCE_DIR}/w01-cpp)link_directories(${CMAKEDEMO_BINARY_DIR}/w01-cpp)#the one C fileadd_executable(cdemo cdemo.c)target_link_libraries(cdemo m) #link the math library#these are all compiled the same wayset(PROGRAMS oglfirst pointers)set(CORELIBS ${GLUT_LIBRARY} ${OPENGL_LIBRARY} m)foreach(program ${PROGRAMS}) add_executable(${program} ${program}.cpp) target_link_libraries(${program} ${CORELIBS})endforeach(program)#building just a library. add_library(geometry geometry.cpp)add_executable(test_geometry test_geometry.cpp)#linking against a custom librarytarget_link_libraries(test_geometry ${CORELIBS} geometry)

La macro include_directories le dice a CMake dónde buscar los archivos fuente. Al declarar el nombre del proyecto CMAKEDEMO en el archivo CMakeLists.txt de nivel superior, las variables CMAKEDEMO_SOURCE_DIR y CMAKEDEMO_BINARY_DIR se establecen en función de la ubicación actual de su código y la ubicación actual de su directorio de construcción (más sobre esta última ubicación más adelante). Añadir un objetivo para un nuevo ejecutable binario es fácil. Sólo tienes que añadir una línea add_executable(cdemo cdemo.c). CMake averiguará automáticamente el compilador basándose en la extensión del tipo de archivo. Si se necesitan bibliotecas adicionales, puedes decirle a CMake que enlace con ellas usando target_link_libraries(cdemo m). Esto le dice a CMake que el programa cdemo necesita enlazar con la biblioteca de matemáticas. Puede enlazar con más de una biblioteca especificando las bibliotecas en una lista. Ver por ejemplo set(CORELIBS ${GLUT_LIBRARY} ${OPENGL_LIBRARY} m). Las variables GLUT_LIBRARY y OPENGL_LIBRARY son establecidas por CMake cuando usamos find_package(GLUT) y find_package(OpenGL). Para averiguar qué variables se establecen cuando se utiliza find_package, probablemente tendrá que abrir el archivo Find*.cmake correspondiente y leer la documentación, normalmente útil pero escueta.

Dado que varios programas en esta carpeta w01-cpp se compilan de la misma manera y se enlazan contra las mismas bibliotecas, podemos procesarlos todos con un simple bucle mostrado arriba usando la macro foreach en CMake. Finalmente mostramos cómo crear nuestra propia biblioteca usando add_library(geometry geometry.cpp) y enlazando contra esta biblioteca en target_link_libraries(test_geometry ${CORELIBS} geometry).

Construir con CMake

Configurar un montón de archivos CMakeLists.txt no te permitirá inmediatamente construir tu proyecto. CMake es sólo una envoltura de plataforma cruzada alrededor de los sistemas de construcción más tradicionales. En el caso de linux, esto significa make. Un rápido paso de preprocesamiento convertirá tu descripción CMakeLists.txt en un sistema de construcción make tradicional automáticamente. Una característica agradable y muy recomendable de CMake es la capacidad de hacer construcciones fuera de la fuente. De esta manera usted puede hacer todos sus archivos .o, varios archivos dependientes temporales, e incluso los ejecutables binarios sin abarrotar su árbol de código fuente. Para utilizar las construcciones fuera del código fuente, cree un directorio de construcción en su carpeta de nivel superior (técnicamente, esto puede ser en cualquier lugar, pero la carpeta del proyecto de nivel superior parece ser una opción lógica). A continuación, cambiar en su directorio de construcción y ejecutar cmake apuntando al directorio del nivel superior CMakeLists.txt. Por ejemplo:

cumin$ cd cmake/cumin$ lsCMakeLists.txt w01-cpp/cumin$ mkdir buildcumin$ lsCMakeLists.txt build/ w01-cpp/cumin$ cd build/cumin$ cmake ..

Recuerda estar en tu directorio de construcción y apuntar cmake sólo al directorio que contiene el archivo CMakeLists.txt de nivel superior, no al propio archivo. Si todo va bien, cmake procesará sus archivos CMakeLists.txt, encontrará la ubicación de todas las bibliotecas y rutas de inclusión y arrojará un montón de información de configuración, incluyendo un Makefile tradicional en su directorio de construcción. (Si usted tiene alguna familiaridad con autotools/autohell, este proceso de cmake es similar a ./configure). Ahora está listo para construir usando el sistema make tradicional. Ejecute make en su directorio de construcción para compilar y enlazar todo. CMake incluso incluye algunos colores agradables, barras de progreso, y suprime un montón de salida de gcc. Si desea una salida verbosa, puede escribir VERBOSE=1 make (útil si algo va mal).

Debido a la forma en que configuramos la construcción fuera del código fuente y el link_directories(${CMAKEDEMO_BINARY_DIR}/w01-cpp), nuestros binarios recién compilados están en la carpeta w01-cpp en el directorio de construcción donde acabamos de ejecutar make.

cumin$ cd w01-cpp/cumin$ lsCMakeFiles/ cdemo* libgeometry.a pointers*Makefile cmake_install.cmake oglfirst* test_geometry*cumin$ ./cdemo Sqrt(2) = 1.4142 This concludes a short C democumin$ ./oglfirst cumin$ ./test_geometry 

Pulsa ESC para salir de las demos de OpenGL.

Resumiendo

Si modificas el código en tu directorio fuente, incluyendo incluso un archivo CMakeLists.txt y vuelves a ejecutar make en el directorio de construcción, make y cmake recompilarán y reconstruirán los cambios necesarios. Si sólo está haciendo cambios en un subdirectorio, puede simplemente ejecutar make en el subdirectorio correspondiente en el árbol de construcción para procesar las actualizaciones.

Una fuente inicial de confusión con las construcciones fuera del código fuente es que básicamente tienes dos copias de tu árbol de código fuente, una con el código fuente real, y otra con los Makefiles y los ejecutables binarios (en el árbol de construcción). Probablemente es mejor mantener dos ventanas abiertas con una en el árbol de construcción para hacer y ejecutar sus programas, y una ventana en el árbol de código fuente para modificar los archivos de origen.

Una cosa buena acerca de las construcciones fuera de la fuente es que la limpieza de los archivos de objetos, archivos makedepend, binarios, y otros desechos de construcción misceláneos se puede hacer simplemente borrando todo el directorio de construcción porque no hay fuente. También puede utilizar make clean para limpiar los archivos de objetos y binarios reales, pero cuando usted está planeando alquitranar su fuente o distribuir su código a las masas, puede simplemente hacer

cumin$ cd cmakecumin$ lsCMakeLists.txt build/ w01-cpp/cumin$ rm -rf build/cumin$ lsCMakeLists.txt w01-cpp/

para limpiar y empaquetar su código.

Más para explorar

Esto sólo toca la superficie de lo que CMake puede hacer. Echa un vistazo a la Wiki de CMake para obtener más información. Espero actualizar esta página si nos encontramos con ejemplos más complejos, y estoy feliz de tomar los comentarios o consejos de otros cursos que podrían estar utilizando CMake. Para usuarios muy avanzados, CMake tiene un programa compañero CPack para empaquetar automáticamente los binarios y el código fuente para Ubuntu/Debian (.deb), Red Hat (.rpm), OSXX11, tgz, CygWin, y sistemas Nullsoft.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.