Monorepo with C++: Code Organization and Best Practices

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why Do You Need a Monorepo in C++?



Developing large C++ projects often faces the problem of code organization. Teams choose between a monorepo (one repository for all code) and a multirepo (separate repositories for each library). In the context of C++, a monorepo offers several advantages: simplified refactoring, a single version of dependencies, and a centralized build system.



This article will guide you through the key aspects of organizing a monorepo for C++: from folder structure to setting up CMake and managing dependencies. You will learn how to make a project scalable and convenient for the team.



1. Monorepo Structure for C++



A proper structure is the foundation of a successful monorepo. It is recommended to use a hierarchy that separates libraries, applications, and external dependencies.



Example of a Basic Structure



my_monorepo/├── CMakeLists.txt          # Root CMake file├── cmake/                  # Auxiliary CMake modules├── libs/                   # Project libraries│   ├── core/               # Core (logic, utilities)│   │   ├── include/│   │   │   └── core/│   │   ├── src/│   │   └── CMakeLists.txt│   ├── network/            # Network modules│   │   ├── include/│   │   ├── src/│   │   └── CMakeLists.txt│   └── utils/              # Auxiliary utilities│       ├── include/│       ├── src/│       └── CMakeLists.txt├── apps/                   # Executable applications│   ├── server/│   │   ├── src/│   │   └── CMakeLists.txt│   └── client/│       ├── src/│       └── CMakeLists.txt├── tests/                  # Integration tests├── third_party/            # External dependencies (git submodules)│   ├── fmt/│   └── spdlog/└── scripts/                # Scripts for CI/CD and development


Key Principles



  • libs/: Each library is a self-contained module with its own CMakeLists.txt.
  • apps/: Applications use libraries via target_link_libraries.
  • third_party/: External dependencies are added via git submodules or FetchContent.
  • tests/: A separate directory for tests that check component integration.


2. Build System: CMake for a Monorepo



CMake is the standard tool for C++ projects. In a monorepo, it allows managing dependencies between libraries and applications.



Root CMakeLists.txt



Create a root file that includes all subprojects:



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

set(CMAKE_CXX_STANDARD 20)set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Include external dependenciesadd_subdirectory(third_party/fmt)add_subdirectory(third_party/spdlog)

# Include librariesadd_subdirectory(libs/core)add_subdirectory(libs/network)add_subdirectory(libs/utils)

# Include applicationsadd_subdirectory(apps/server)add_subdirectory(apps/client)

# Include testsenable_testing()add_subdirectory(tests)


Example CMakeLists.txt for a Library



# libs/core/CMakeLists.txtadd_library(core    src/core_module.cpp    src/utilities.cpp)

target_include_directories(core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

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


Building and Testing



To build the entire project, use:



mkdir build && cd buildcmake .. -DCMAKE_BUILD_TYPE=Releasecmake --build . --parallelctest --output-on-failure


3. Dependency Management in a Monorepo



One of the main problems of a monorepo is controlling dependency versions. In C++, there are several

Blogs

Book Recommendations