Monorepositorio con C++: organización del código en la práctica

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: ¿por qué un monorepositorio para C++?



En el desarrollo moderno de C++, especialmente en proyectos de tamaño mediano y grande, la organización del código se convierte en una tarea crítica. El monorepositorio (monorepo) es un enfoque en el que el código de todos los componentes, bibliotecas y servicios se almacena en un solo repositorio. A diferencia de los multirepositorios, un monorepositorio ofrece un único punto de entrada, simplifica la refactorización y la gestión de dependencias. En la práctica, esto significa que puedes modificar la API de una biblioteca y ver inmediatamente cómo afecta a todos los módulos dependientes.



En este artículo, analizaremos los aspectos prácticos de organizar código C++ en un monorepositorio: desde la estructura de carpetas hasta la configuración de CI/CD. Aprenderás cómo evitar errores típicos y hacer que la compilación sea rápida y predecible.



1. Estructura del monorepositorio para C++



Una estructura de carpetas correcta es la base de un monorepositorio exitoso. Consideremos la jerarquía recomendada para proyectos C++.



Jerarquía básica de directorios



my_project/├── CMakeLists.txt          # Archivo raíz de compilación├── cmake/                  # Módulos CMake personalizados│   └── FindMyLib.cmake├── libs/                   # Bibliotecas internas│   ├── core/│   │   ├── CMakeLists.txt│   │   ├── include/│   │   │   └── core/│   │   │       ├── utils.h│   │   │       └── types.h│   │   └── src/│   │       ├── utils.cpp│   │       └── types.cpp│   └── network/│       ├── CMakeLists.txt│       ├── include/│       │   └── network/│       │       └── http_client.h│       └── src/│           └── http_client.cpp├── apps/                   # Aplicaciones ejecutables│   ├── server/│   │   ├── CMakeLists.txt│   │   └── src/│   │       └── main.cpp│   └── cli/│       ├── CMakeLists.txt│       └── src/│           └── main.cpp├── tests/                  # Pruebas de integración│   ├── CMakeLists.txt│   └── test_integration.cpp├── third_party/            # Dependencias externas (vendoring)│   ├── fmt/│   └── spdlog/├── .github/                # Configuración de CI/CD│   └── workflows/│       └── build.yml└── README.md


Principios clave:

  • libs/ — todas las bibliotecas internas. Cada biblioteca tiene su propia carpeta con CMakeLists.txt.
  • apps/ — archivos ejecutables. Dependen de las bibliotecas en libs/.
  • third_party/ — dependencias de proveedores (git submodules o código fuente copiado).
  • tests/ — pruebas de integración que verifican la interacción de múltiples bibliotecas.


Ejemplo de CMakeLists.txt para una biblioteca



# libs/core/CMakeLists.txtadd_library(core    src/utils.cpp    src/types.cpp)

target_include_directories(core PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>)

target_link_libraries(core PUBLIC fmt::fmt spdlog::spdlog)


Importante: Usa PUBLIC y PRIVATE para la propagación correcta de dependencias. Este es un punto clave: si la biblioteca A usa la biblioteca B solo en sus propios archivos fuente, haz que B sea PRIVATE.



2. Gestión de dependencias en el monorepositorio



Uno de los principales problemas de los monorepositorios es el "infierno de las dependencias". En C++, esto se resuelve mediante el diseño orientado a objetivos de CMake (CMake target-oriented design).



Regla: un objetivo — una biblioteca



Cada biblioteca debe exportar exactamente un objetivo de CMake. Esto simplifica el enlace y previene dependencias cíclicas.



# CMakeLists.txt raízcmake_minimum_required(VERSION 3.20)project(MyProject VERSION 1.0.0 LANGUAGES CXX)

# Incluir todas las bibliotecasadd_subdirectory(libs/core)add_subdirectory(libs/network)

Blogs

Book Recommendations