Sistemas de Compilacion: CMake y Gestion de Paquetes
Domina los fundamentos de CMake, CMake moderno basado en targets, FetchContent para dependencias, gestores de paquetes vcpkg y Conan, y flags del compilador para compilaciones seguras y optimizadas.
Por Que Importan los Sistemas de Compilacion
A medida que los proyectos de C++ crecen mas alla de un solo archivo, necesitas un sistema de compilacion para gestionar la compilacion, el enlace, las dependencias y las diferencias de plataforma. Ejecutar manualmente g++ *.cpp no escala: necesitas compilaciones incrementales (recompilar solo archivos cambiados), deteccion de bibliotecas, soporte multiplataforma y compilaciones reproducibles. CMake se ha convertido en el generador de sistema de compilacion estandar de facto para C++. No compila codigo por si mismo — genera archivos de compilacion nativos (Makefiles, archivos Ninja, proyectos de Visual Studio) para tu plataforma.
Fundamentos de CMake
Un archivo CMakeLists.txt describe la estructura de tu proyecto. CMake moderno (3.12+) usa un enfoque basado en targets donde todo se adjunta a targets (ejecutables o bibliotecas):
# CMakeLists.txt — minimum viable project
cmake_minimum_required(VERSION 3.20)
project(MyApp VERSION 1.0.0 LANGUAGES CXX)
# Set C++ standard for the entire project
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) # use -std=c++20, not -std=gnu++20
# Create an executable target
add_executable(myapp
src/main.cpp
src/engine.cpp
src/utils.cpp
)
# Add include directories for this target
target_include_directories(myapp PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
# Create a library target
add_library(mathlib STATIC
src/math/vector.cpp
src/math/matrix.cpp
)
target_include_directories(mathlib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include/math
)
# Link the library to the executable
target_link_libraries(myapp PRIVATE mathlib)
# Compiler warnings — essential for quality code
target_compile_options(myapp PRIVATE
$<$<CXX_COMPILER_ID:GNU,Clang>:-Wall -Wextra -Wpedantic -Werror>
$<$<CXX_COMPILER_ID:MSVC>:/W4 /WX>
)Compilando con CMake
CMake usa un proceso de dos pasos: configurar (generar archivos de compilacion) y compilar (compilar). Usa siempre compilaciones fuera del arbol fuente para mantener el arbol fuente limpio:
# Configure — generate build files in a 'build' directory
cmake -B build -DCMAKE_BUILD_TYPE=Release
# Build — compile the project
cmake --build build --parallel $(nproc)
# Install (optional)
cmake --install build --prefix /usr/local
# Common build types:
# Debug — -O0 -g (full debug symbols, no optimization)
# Release — -O3 -DNDEBUG (max optimization, no asserts)
# RelWithDebInfo — -O2 -g -DNDEBUG (optimized with debug info)
# MinSizeRel — -Os -DNDEBUG (optimize for size)
# Run with sanitizers (add to CMakeLists.txt or command line)
cmake -B build-asan -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer"FetchContent: Gestion de Dependencias
El modulo FetchContent de CMake descarga y compila dependencias en tiempo de configuracion, facilitando la incorporacion de bibliotecas sin configuracion manual:
cmake_minimum_required(VERSION 3.20)
project(MyApp LANGUAGES CXX)
include(FetchContent)
# Fetch GoogleTest
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.14.0
)
# Fetch fmt (formatting library)
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 10.2.1
)
# Download and make available
FetchContent_MakeAvailable(googletest fmt)
add_executable(myapp src/main.cpp)
target_link_libraries(myapp PRIVATE fmt::fmt)
# Test executable
enable_testing()
add_executable(tests tests/test_main.cpp)
target_link_libraries(tests PRIVATE GTest::gtest_main)
add_test(NAME unit_tests COMMAND tests)vcpkg y Conan
Para proyectos mas grandes con muchas dependencias, los gestores de paquetes dedicados de C++ proporcionan mejor resolucion de dependencias y almacenamiento en cache:
vcpkg (Microsoft) — se integra directamente con CMake a traves de un archivo de toolchain. Instala paquetes globalmente o en "modo manifiesto" con un archivo vcpkg.json:
{
"dependencies": ["fmt", "spdlog", "nlohmann-json", "catch2"]
}Usar con: cmake -B build -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
Conan — usa un conanfile.txt o conanfile.py para declarar dependencias. Soporta multiples configuraciones de compilacion y almacenamiento en cache de binarios:
[requires]
fmt/10.2.1
spdlog/1.13.0
[generators]
CMakeDeps
CMakeToolchainAmbos gestores de paquetes mantienen repositorios de miles de bibliotecas de C++ con binarios probados y pre-compilados.
Sigue estas reglas para un CMake mantenible:
1. Usa siempre comandos basados en targets: target_include_directories, target_compile_options, target_link_libraries — nunca include_directories ni add_definitions (que contaminan el ambito global).
2. Comprende PRIVATE/PUBLIC/INTERFACE: PRIVATE = solo para este target, PUBLIC = para este target y sus consumidores, INTERFACE = solo para consumidores.
3. Establece el estandar de C++ por target o a nivel de proyecto, nunca con flags crudos como -std=c++20.
4. Habilita las advertencias maximas: -Wall -Wextra -Wpedantic (GCC/Clang) o /W4 (MSVC). Considera -Werror / /WX en CI.
5. Usa cmake --preset para compilaciones reproducibles (CMakePresets.json).
6. Nunca codifiques rutas de forma fija — usa find_package, FetchContent o gestores de paquetes.
Usar file(GLOB ...) para recolectar fuentes: file(GLOB SOURCES src/*.cpp) NO se re-ejecuta cuando se agregan o eliminan archivos. Los archivos nuevos no seran compilados hasta que reconfigures manualmente. Siempre lista los archivos fuente explicitamente.
Olvidar CMAKE_CXX_EXTENSIONS OFF: Sin esto, GCC usa -std=gnu++20 en lugar de -std=c++20, habilitando extensiones no estandar que rompen la portabilidad.
Mezclar add_subdirectory y FetchContent: Ambos incorporan proyectos externos, pero interactuan de forma diferente con la cache de compilacion. Elige un enfoque por dependencia.
No establecer CMAKE_EXPORT_COMPILE_COMMANDS ON: Esto genera compile_commands.json, que es necesario para clang-tidy, clangd (LSP) y muchas integraciones de IDE. Habilitalo siempre.
- CMake es el generador de sistema de compilacion estandar de C++ — aprende su API basada en targets
- Usa comandos
target_*(no de ambito global) con visibilidad PRIVATE/PUBLIC/INTERFACE - FetchContent descarga y compila dependencias en tiempo de configuracion — ideal para conjuntos pequenos de dependencias
- vcpkg (modo manifiesto) y Conan manejan grafos de dependencias mas grandes con almacenamiento en cache de binarios
- Siempre habilita las advertencias (
-Wall -Wextra -Wpedantic) y usa compilaciones fuera del arbol fuente - Genera
compile_commands.jsonpara herramientas de IDE y analisis estatico
Quiz — Pon a prueba tus conocimientos
(15 XP)1. Que hace `target_link_libraries(myapp PRIVATE mathlib)`?
2. Por que se considera una mala practica `file(GLOB SOURCES src/*.cpp)` en CMake?
3. Cual es el proposito de `CMAKE_CXX_EXTENSIONS OFF`?