Monorepositório com C++: organização de código para iniciantes

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

O que é um monorepositório e por que ele é necessário em C++?



Um monorepositório (monorepo) é uma abordagem de gerenciamento de código onde todos os componentes do projeto, bibliotecas, utilitários e até mesmo a documentação são armazenados em um único repositório. Para projetos em C++, isso é especialmente relevante, pois a linguagem tradicionalmente exige uma estrutura clara de arquivos e dependências.



Vantagens do monorepositório para C++:

  • Versão única de dependências — todos os módulos usam a mesma versão das bibliotecas, eliminando conflitos de ABI.
  • Compilação simplificada — um único CMakeLists.txt ou sistema de build gerencia todo o projeto.
  • Commits atômicos — alterações em vários módulos podem ser combinadas em um único commit, facilitando o code review.
  • Refatoração fácil — a alteração de uma API em um local é imediatamente visível em todos os módulos dependentes.


No entanto, o monorepositório não é adequado para todos: se as equipes são totalmente independentes e usam versões diferentes de compiladores, é melhor considerar um multirepositório. Para iniciantes, o monorepositório é uma excelente maneira de evitar dores de cabeça com a configuração de caminhos e dependências.



Parte principal: criando um monorepositório para um projeto C++



1. Estrutura de diretórios



Uma estrutura correta é a base de qualquer monorepositório. Modelo recomendado para C++:



my_monorepo/├── CMakeLists.txt          # Arquivo CMake raiz├── cmake/                  # Módulos CMake auxiliares│   └── helpers.cmake├── libs/                   # Bibliotecas│   ├── core/               # Núcleo do projeto│   │   ├── CMakeLists.txt│   │   ├── include/core/│   │   └── src/│   └── utils/              # Utilitários│       ├── CMakeLists.txt│       ├── include/utils/│       └── src/├── apps/                   # Aplicativos executáveis│   ├── main_app/│   │   ├── CMakeLists.txt│   │   └── main.cpp│   └── test_app/│       ├── CMakeLists.txt│       └── main.cpp├── tests/                  # Testes (se não incorporados aos módulos)│   └── test_core.cpp├── scripts/                # Scripts de compilação e CI│   └── build.sh├── .gitignore└── README.md


Regra fundamental: cada módulo (biblioteca ou aplicativo) deve ser autossuficiente. Ele contém seu próprio CMakeLists.txt, arquivos de cabeçalho em include/ e código-fonte em src/.



2. Configuração do CMakeLists.txt raiz



O CMakeLists.txt raiz gerencia toda a compilação. Ele deve definir as configurações comuns do compilador, o padrão C++ e incluir os módulos filhos:



cmake_minimum_required(VERSION 3.20)project(MyMonorepo VERSION 1.0.0 LANGUAGES CXX)

# Define o padrão C++17 único para todo o projetoset(CMAKE_CXX_STANDARD 17)set(CMAKE_CXX_STANDARD_REQUIRED ON)set(CMAKE_CXX_EXTENSIONS OFF)

# Opção para compilar testesoption(BUILD_TESTS "Build tests" OFF)

# Inclui módulos auxiliaresinclude(cmake/helpers.cmake)

# Adiciona subdiretórios com bibliotecasadd_subdirectory(libs/core)add_subdirectory(libs/utils)

# Adiciona aplicativosadd_subdirectory(apps/main_app)add_subdirectory(apps/test_app)

# Se os testes estiverem ativados, inclui-osif(BUILD_TESTS) enable_testing() add_subdirectory(tests)endif()


3. Exemplo de biblioteca: libs/core



Vamos considerar a biblioteca core, que contém uma classe para trabalhar com números. Estrutura de arquivos:



libs/core/├── CMakeLists.txt├── include/core/│   └── calculator.h└── src/    └── calculator.cpp


Conteúdo de include/core/calculator.h:



#ifndef CORE_CALCULATOR_H#define CORE_CALCULATOR_H

namespace core {

class Calculator {public: Calculator() = default; int add(int a, int b); int multiply(int a, int b);};

} // namespace core

#endif // CORE_CALCULATOR_H


Blogs

Book Recommendations