Yo era de los que en algun día de la newbie-esca vida me atemorizaban los Makefiles. Temía que en la oscuridad de la noche saliera un Makefile del ropero, o que por debajo de la cama un Makefile me jalara los pies. Pues no mas.
CMake es una excelente herramienta para generar Makefiles, y no solo eso tambien genera soluciones de Visual Studio, Code::Blocks, Kdevelop entre muchas otras. Así que me puse a investigar y resulta que CMake es trivial de usar, hasta un newbie como yo lo puede usar (por lo tanto otros newbies también podrían usarlo).
1. Hello World: El código fuente
Usaremos este código que muestra CMake para compilar y enlazar un programa principal con una librería extra generada por nosotros mismos. La siguiente estructura de directorios es la que hay que crear:
holaMundoCMake
|-- CMakeLists.txt
|-- build
`-- src
|-- hola.cpp
`-- milib
|-- CMakeLists.txt
|-- milib.cpp
`-- milib.h
La idea aqui es que vamos a generar un pequeño programita a partir del codigo en hola.cpp y de la libreria milib.cpp, el código de hola.cpp es muy sencillo:
hola.cpp:
#include "milib.h"
int main(int argc, char* argv){
printf("\n Hola mundo desde main");
hola(2);
printf("\n");
}
Y lo que hace es cargar el header milib.h que es donde está definida la función hola().
milib.h:
#include <stdio.h>
//Prototipo de funcion
void hola(int);
milib.c:
#include "milib.h"
// Implementacion de la funcion
void hola(int veces){
int i=0;
while (i<veces){
printf("\n [%u] Hola Mundo, desde 'milib'" , i);
i++;
}
}
El código es realmente trivial (si no lo comprendes mejor ni sigas leyendo). Hasta este punto no hemos usado nada de CMake ni hemos creado Makefiles ni nada. El código bien podríamos compilarlo a mano.
2. Hello World: Las CMakeLists.txt para CMake
Hay un archivo de CMake en holaMundoCMake/CMakeLists.txt y hay otro en holaMundoCMake/src/milib/CMakeLists.txt, éstos son los archivos clave para CMake. Con los comentarios se explican solos.
holaMundoCMake/CMakeLists.txt:
# El nombre del proyecto "HELLO".
# CMake genera automaticamente una variable llamada
# HELLO_SOURCE_DIR que puede llamarse usando
# ${HELLO_SOURCE_DIR} con la ruta del codigo
# lo mismo con ${HELLO_BINARY_DIR} para binarios
project (HELLO)
# Le decimos donde poner los binarios de librerias y ejecutables
# CMake admite instrucciones partidas en varias lineas
SET (LIBRARY_OUTPUT_PATH ${HELLO_BINARY_DIR}/bin
CACHE PATH "Directory for Libraries")
SET (EXECUTABLE_OUTPUT_PATH ${HELLO_BINARY_DIR}/bin
CACHE PATH "Directory for Executables")
# Decimos a CMake que haga recursion a los siguientes directorios
# en orden de aparicion
add_subdirectory (src/milib)
# Directorios que debe incluir, ademas de los estandar.
include_directories (${HELLO_SOURCE_DIR}/src/milib/)
# Directorios para el enlazador, ademas de los estandar
# Para este ejemplo no los necesitamos ya que la unica libreria
# adicional es 'milib' y ya sabe donde encontrarla pues el mismo
# la genera
#link_directories (aqui pones mas rutas separadas por espacios)
# Decirle que queremos un ejecutable llamado holaMundo
# y le decimos el source para que lo compile
add_executable (holaMundo src/hola.cpp)
# Tenemos una libreria adicional llamada milib, enlazarla
target_link_libraries (holaMundo milib)
El segundo CMakeLists sirve para compilar la libreria “milib” y es mucho mas corto:
holaMundoCMake/src/milib/CMakeLists.txt
# Agregar una libreria llamada milib generada poru un cpp
# se pueden agregar muchas librerias con varios add_library
# Se deben listar todos los archivos fuente
add_library (milib milib.cpp milib.h)
3. Hello World: Generar Makefiles con CMake y compilar
En linux el modo por default es generar Makefiles, así que entramos al directorio build que actualmente está vacío y generamos los Makefiles:
~/Documentos$ cd holaMundoCMake
~/Documentos/holaMundoCMake/$ cd build
~/Documentos/holaMundoCMake/build$ cmake ../
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Check size of void*
-- Check size of void* - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ariel/Documentos/holaMundoCMake/build
Listo, ya estan los Makefiles generados, ahora a compilar con make:
~/Documentos/holaMundoCMake/build$ make
Scanning dependencies of target milib
[ 50%] Building CXX object src/milib/CMakeFiles/milib.dir/milib.o
Linking CXX static library ../../bin/libmilib.a
[ 50%] Built target milib
Scanning dependencies of target holaMundo
[100%] Building CXX object CMakeFiles/holaMundo.dir/src/hola.o
Linking CXX executable bin/holaMundo
[100%] Built target holaMundo
ariel@surfer:~/Documentos/eclipse/holaMundoCMake/build$ make clean
ariel@surfer:~/Documentos/eclipse/holaMundoCMake/build$ make
[ 50%] Building CXX object src/milib/CMakeFiles/milib.dir/milib.o
Linking CXX static library ../../bin/libmilib.a
[ 50%] Built target milib
[100%] Building CXX object CMakeFiles/holaMundo.dir/src/hola.o
Linking CXX executable bin/holaMundo
[100%] Built target holaMundo
En el directorio build/bin se encuentra el binario holaMundo,
~/Documentos/holaMundoCMake/build$ cd bin/
~/Documentos/holaMundoCMake/build$ ./holaMundo
Hola mundo desde main
[0] Hola Mundo, desde 'milib'
[1] Hola Mundo, desde 'milib'
¡Listo! ¿Quién dijo que habría que generar Makefiles a mano? Generar CMakeLists.txt es mucho mas fácil y mas intuitivo.