CMake se refiere a cross-platform make, su uso principal es el de controlar el 
proceso de compilación de software sin depender de la plataforma. 
Actualmente abarca múltiples 
herramientas para administrar la compilación, pruebas, y empaquetado de software.
Con CMake es posible generar archivos de compilación Make (Unix), Xcode (Apple), 
Visual Studio (Microsoft), Ninja, y Qt, entre otros, para proyectos C y C++,
 también se puede compilar, lanzar la ejecución de pruebas unitarias (ctest), y 
generar paquetes (cpack).
Conforme han ido evolucionando los estándares para C y C++ también lo ha hecho
CMake, facilitando la forma de crear un proyecto. Desde 2014 con la liberación de
la versión 3.0 se considera como CMake moderno, en el cual se prioriza el uso de 
targets y properties sobre las tradicionales variables.
Hola CMake
El primer paso para crear un proyecto CMake C++ es crear el archivo CMakeLists.txt
con las instrucciones mínimas requeridas:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.0...3.15)
project(hola_cmake VERSION 0.0.1 LANGUAGES CXX)
add_executable(${PROJECT_NAME} main.cpp)
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17)
La primera línea es un comentario.
La segunda línea valida que el proyecto sea compatible con la versión de CMake 
instalada, donde la versión mínima es la 3.0 y la máxima es la 3.15.
La tercera línea define el nombre del proyecto, su versión, y lenguaje.
La siguiente define el Binario Objetivo (target) y los archivos a incluir en éste.
La última línea define el estándar de C++ que el proyecto va a usar.
Con esas instrucciones ya se tienen los mínimos requerimientos para el proyecto
hola_cmake con el siguiente código fuente:
// main.cpp
#include <iostream>
int main()
{
  std::cout << "Hola CMake\n";
  return 0;
}
Binarios objetivo: Targets
Un proyecto CMake puede tener el objetivo de crear uno o varios Ejecutables, y Bibliotecas.
Los archivos binarios generados tienen diferentes sufijos o prefijos dependiendo
de la plataforma destino. 
Por ejemplo, para los ejecutables en Windows CMake agrega el sufijo .exe.
Para las bibliotecas se puede configurar que sea estática (.lib ), o dinámica 
(compartida .dll, .so, .dylib).
El nombre del target debe ser único en el proyecto, pero pueden existir varios 
targets con diferente nombre en un mismo proyecto. Desde la versión 3.1 de CMake
está disponible el comando target_sources().
En las versiones más recientes (>3.15) los archivos de código fuente se pueden 
definir por separado de los targets por medio del comando target_sources():
# CMakeLists.txt
#...
add_executable("hola_cmake")
add_library("hola_cmake_bib_estatica"   STATIC)
add_library("hola_cmake_bib_compartida" SHARED)
target_sources("hola_cmake"                PUBLIC main.cpp)
target_sources("hola_cmake_bib_estatica"   PUBLIC foo.cpp)
target_sources("hola_cmake_bib_compartida" PUBLIC bar.cpp)
#...
Opciones
Las opciones son variables personalizadas para el proyecto que el usuario puede
modificar sin necesidad de cambiar el archivo CMakeLists.txt:
# CMakeLists.txt
#...
# Options
option(ENABLE_TESTS "Habilitar compilación de pruebas" False)
option(ENABLE_CONAN "Habilitar uso de Conan" False)
#...
Así el usuario puede ejecutar los comandos de generación con valores diferentes dependiendo de la configuración requerida. Por ejemplo para una configuración en modo release se puede dejar sin habilitar la compilación de pruebas, pero para una configuración en modo debug habilitarlas:
cmake .. -DENABLE_TESTS=True
Subdirectorios
Por medio del comando add_subdirectory() es posible indicarle al proyecto que 
en un subdirectorio hay otro archivo CMakeLists.txt que también hace parte del 
proyecto.
Teniendo un directorio exclusivo para pruebas (test) con su 
propio archivo de CMakeLists, el archivo principal lo agrega al proyecto así:
# CMakeLists.txt
#...
if(ENABLE_TESTS)
  add_subdirectory(test)
else()
  message("Compilación de pruebas deshabilitada")
endif()
Ejecución de CMake
La ejecución de los comandos CMake se divide en dos pasos: generación y compilación.
CMake incluye integración con múltiples IDEs en las cuales se pueden personalizar 
estos dos pasos.
La generación corresponde a crear los archivos con las instrucciones de compilación
de acuerdo al generador seleccionado. Si no se selecciona uno, CMake elige
el predeterminado para la plataforma en la cual se está ejecutando. 
Es recomendable que la generación y compilación se hagan en un directorio diferente
al directorio raíz del proyecto, y dentro de éste, pero que sea excluido del
sistema de control de versiones.
Para un sistema GNU/Linux con Ubuntu, para el proyecto hola_cmake se puede crear el
directorio cmake-build/  desde el cual se ejecuta el comando de generación:
cmake .. -G "Unix Makefiles" -DENABLE_TESTS=True
Donde "Unix Makefiles" es el generador elegido.
La compilación desde CMake crea los archivos binarios para los targets
definidos en el proyecto. Desde un terminal Unix el comando de compilación
desde el directorio cmake-build/ es:
cmake --build ./
Si los archivos de compilación fueron generados de manera satisfactoria, y la compilación fue exitosa, se habrán creado los objetivos:
hola_cmake 
libhola_cmake_bib_estatica.a
libhola_cmake_bib_compartida.so
Al correr el ejecutable se obtiene el resultado esperado:
$ ./hola_cmake 
Hola CMake
Consideraciones
- Para versiones de cmake menores a 3.15 pueden aparecer mensajes de 
advertencia relacionados con el comando target_sources().
Fuentes
- Documentación oficial de CMake
- Henry Schreiner: Introducción a CMake moderno - Gitbook.
- Pablo Arias: It’s time to do cmake right - Blog.
- Bill Hoffman: Open Source Tools to Build Test and Deploy C++ Software - Google Tech Talk 2007.
- Mateusz Pusz: Git, CMake, Conan - How to ship and reuse our C++ projects - CppCon 2018.
 
       
       
      
Deja un comentario