Esta receta es una guía rápida de CMake. Se trata de una herramienta para la construcción automática de proyectos software, facilitando su portabilidad.
Unas herramientas parecidas son las conocidas como "Autotools". CMake es, a juicio de muchos, más sencillo de utilizar que las Autotools siendo, además, muy versátil, potente y escalable. Y como muestra de ello, proyectos como KDE se han pasado a CMake de forma satisfactoria.

Introducción

Antes de comenzar a utilizar CMake es recomendable tener en cuenta algunas cuestiones. En primer lugar, CMake necesita como entrada un fichero llamado CMakeLists.txt. Este fichero contiene un programa que describe qué dependencias deben cumplirse (el configure) y cómo se construye el proyecto (una especie de Makefile de alto nivel). El lenguaje que se utiliza para crear este programa es propio de CMake. Se trata de un lenguaje imperativo, que se ejecuta de forma secuencial y cuya sintaxis es bastante regular y simple:
comando1 (arg1 arg2)
comando2 (arg1 arg2 arg3 ...)
Todo el fichero CMakeLists.txt está constituido por comandos que describen tanto las dependencias como la forma de construir el proyecto. También existen estructuras de control (if) y bucles (foreach, while). Gracias a estas estructuras, construir un programa que describa los pormenores de la construcción de un proyecto es fácil para aquellos que estamos acostumbrados a programar. Para obtener CMake:
# apt-get install cmake

Hola mundo!

Si en el CMakeLists.txt se describe un programa, entonces debe ser posible hace un "Hola Mundo", ¿verdad?. Efectivamente, se puede. Crea el archivo CMakeLists.txt con el siguiente contenido:
SET(saludo "Hola Mundo")
MESSAGE(${saludo})
El programa anterior presenta dos aspectos muy útiles: crear variables (utilizando SET) y acceder a su contenido (${variable}). Para probarlo, ejecuta lo siguiente en el mismo directorio donde se encuentra el archivo:
$ cmake .
Y obtendrás la siguiente salida:
cleto@michi:/tmp/cmake$ cmake .
-- The C compiler identification is GNU
-- The CXX compiler identification is GNU
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
Hola Mundo
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/cmake
Las comprobaciones que CMake hace antes del mensaje "Hola Mundo" son las correspondientes para un proyecto programado en C/C++. Por defecto, si no se especifica otro lenguaje, se harán estas comprobaciones. Prueba ahora a ejecutar de nuevo el comando anterior:
cleto@michi:/tmp/cmake$ cmake .
Hola Mundo
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/cmake
¿¡Ahora no se han hecho las comprobaciones!?. Esto se debe a que CMake cachea todo el proceso de creación de las comprobaciones, de forma que la siguiente ejecución será mucho más rápida. Toda la caché está almacenada en el archivo CMakeCache.txt generado. Las comprobaciones se siguen haciendo aunque no aparezcan en el log. Ahora supón el siguiente ejemplo:
SET(saludo1 "Hola Mundo")
SET(saludo2 Hola Mundo)

MESSAGE(${saludo1})
MESSAGE(${saludo2})
MESSAGE("${saludo2}")
Este ejemplo pone de manifiesto la importante diferencia entre un string y una lista de strings (los únicos tipos básicos que maneja CMake). La salida sería:
cleto@michi:/tmp/cmake$ cmake .
Hola Mundo
HolaMundo
Hola;Mundo
[...]
La primera salida corresponde con una cadena de caracteres y, por tanto, MESSAGE toma un sólo argumento. La segunda es la salida de una lista y MESSAGE toma como entrada 2 argumentos (Hola y Mundo). En la tercera se produce una conversión de lista a cadena, por lo que el tercer comando sólo tiene un parámetro de entrada. En CMake, cada elemento de la lista se separa con un ';'. Por tanto, el siguiente código sería equivalente:
SET(saludo2 Hola;Mundo) # Lo mismo que SET(saludo2 Hola Mundo)
En la documentación, puedes obtener más información sobre la sintaxis de CMake.

Makefile generado

Por defecto, en sistema UNIX como GNU/Linux, CMake genera un Makefile con diferentes objetivos. Si ejecutas make para el ejemplo del "Hola Mundo", obviamente, no pasará nada ya que hasta el momento no se ha creado un programa para compilar proyectos.

Limpiando todo lo generado

Si has mirado todo lo que genera CMake te habrás podido asustar. Si pones el archivo CMakeLists.txt en el mismo sitio donde tienes el código fuente de tu aplicación, cuando quieras eliminar todo lo generado podrá ser realmente tedioso e incómodo. Para ello, se recomienda hacer lo siguiente:
$ ls
CMakeLists.txt
$ mkdir build
$ cd build
$ cmake .. 
Así, si quieres borrar todo lo generado, bastará con borrar el contenido del directorio build. En los ejemplos siguientes, se seguirá esta estrategia.

Ejemplos

Vamos a utilizar CMake para lo que realmente sirve: construir automáticamente proyectos. Cada uno de los siguientes ejemplos muestran cómo satisfacer las necesidades más habituales a la hora de construir ejecutables, librerías, etc. así como su instalación y configuración. Se recomienda una lectura secuencial de las mismas:

Referencias



blog comments powered by Disqus