Introdução: Por que um monorepositório em C++?
\n\nNo mundo do desenvolvimento C++, mais cedo ou mais tarde surge a pergunta: como organizar o código quando há muitos projetos? Bibliotecas, utilitários, executáveis — tudo isso precisa ser vinculado, versionado e compilado. A abordagem tradicional com vários repositórios separados (multirrepositório) frequentemente leva a problemas: é difícil sincronizar alterações, testar a integração é complicado e as dependências entre projetos se tornam um pesadelo.
\n\nA alternativa é o monorepositório. É um único repositório que armazena todos os componentes do seu projeto: bibliotecas, aplicações, testes, documentação. Essa abordagem é amplamente utilizada no Google, Facebook, Microsoft e muitas outras empresas. Para C++, o monorepositório oferece várias vantagens:
\n\n- \n
- Versão única de dependências — você sempre sabe qual versão da biblioteca está sendo usada em todos os projetos. \n
- Commits atômicos — a alteração da API de uma biblioteca e a atualização de todos os seus consumidores ocorrem em um único commit. \n
- CI/CD simplificado — um único pipeline para todos os componentes. \n
- Transparência — é fácil ver como todo o projeto está estruturado. \n
Neste artigo, abordaremos a organização prática de um monorepositório para C++ usando CMake, mostraremos a estrutura de pastas e exemplos de código.
\n\n1. Estrutura de pastas: a base da organização
\n\nO primeiro passo para um monorepositório bem-sucedido é uma estrutura de diretórios bem planejada. Aqui está um modelo recomendado para um projeto C++:
\n\nmy_project/\n├── CMakeLists.txt # Arquivo CMake raiz\n├── README.md\n├── .gitignore\n├── .clang-format\n├── cmake/ # Módulos CMake auxiliares\n│ └── FindMyLib.cmake\n├── libs/ # Bibliotecas\n│ ├── core/ # Biblioteca core\n│ │ ├── CMakeLists.txt\n│ │ ├── include/\n│ │ │ └── core/\n│ │ │ ├── math.h\n│ │ │ └── string_utils.h\n│ │ └── src/\n│ │ ├── math.cpp\n│ │ └── string_utils.cpp\n│ └── network/ # Biblioteca network\n│ ├── CMakeLists.txt\n│ ├── include/\n│ │ └── network/\n│ │ └── http_client.h\n│ └── src/\n│ └── http_client.cpp\n├── apps/ # Aplicações executáveis\n│ ├── server/\n│ │ ├── CMakeLists.txt\n│ │ └── src/\n│ │ └── main.cpp\n│ └── cli_tool/\n│ ├── CMakeLists.txt\n│ └── src/\n│ └── main.cpp\n├── tests/ # Testes\n│ ├── CMakeLists.txt\n│ ├── test_core/\n│ │ ├── CMakeLists.txt\n│ │ └── test_math.cpp\n│ └── test_network/\n│ ├── CMakeLists.txt\n│ └── test_http_client.cpp\n└── third_party/ # Dependências externas (git submodules ou FetchContent)\n └── googletest/\n\n\nPrincípios-chave:
\n- \n
- libs/ — todas as bibliotecas. Cada biblioteca é uma pasta separada com seu próprio CMakeLists.txt. \n
- apps/ — todos os arquivos executáveis. Eles dependem das bibliotecas em libs/. \n
- tests/ — testes, organizados por biblioteca. \n
- third_party/ — dependências externas. Use
git submodulesouFetchContentpara incluí-las. \n
2. CMake: configurando a compilação do monorepositório
\n\nCMake é a ferramenta ideal para um monorepositório. Vamos ver como configurar o CMakeLists.txt raiz e os arquivos para as bibliotecas.
CMakeLists.txt raiz
\n\ncmake_minimum_required(VERSION 3.20)\nproject(MyProject VERSION 1.0.0 LANGUAGES CXX)\n\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\n# Opções para ativar/desativar componentes\noption(BUILD_TESTS "Build tests" ON)\noption(BUILD_APPS "Build applications" ON)\n\n# Inclui dependências externas\ninclude(FetchConte