Introduction: Why Do You Need a Monorepository in C++?
\n\nIn the world of C++ development, sooner or later the question arises: how to organize code when there are many projects? Libraries, utilities, executables — all of this needs to be linked, versioned, and built. The traditional approach with many separate repositories (multirepository) often leads to problems: it's difficult to synchronize changes, integration testing is hard, and dependencies between projects become a nightmare.
\n\nThe alternative is a monorepository. This is a single repository that stores all components of your project: libraries, applications, tests, documentation. This approach is actively used at Google, Facebook, Microsoft, and many other companies. For C++, a monorepository offers several advantages:
\n\n- \n
- Single version of dependencies — you always know which version of a library is used across all projects. \n
- Atomic commits — changing a library's API and updating all its consumers happens in one commit. \n
- Simplified CI/CD — one pipeline for all components. \n
- Transparency — it's easy to see how the entire project is structured. \n
In this article, we will break down the practical organization of a monorepository for C++ using CMake, show the folder structure, and provide code examples.
\n\n1. Folder Structure: The Foundation of Order
\n\nThe first step to a successful monorepository is a well-thought-out directory structure. Here is a recommended template for a C++ project:
\n\nmy_project/\n├── CMakeLists.txt # Root CMake file\n├── README.md\n├── .gitignore\n├── .clang-format\n├── cmake/ # Helper CMake modules\n│ └── FindMyLib.cmake\n├── libs/ # Libraries\n│ ├── core/ # Core library\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/ # Network library\n│ ├── CMakeLists.txt\n│ ├── include/\n│ │ └── network/\n│ │ └── http_client.h\n│ └── src/\n│ └── http_client.cpp\n├── apps/ # Executable applications\n│ ├── server/\n│ │ ├── CMakeLists.txt\n│ │ └── src/\n│ │ └── main.cpp\n│ └── cli_tool/\n│ ├── CMakeLists.txt\n│ └── src/\n│ └── main.cpp\n├── tests/ # Tests\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/ # External dependencies (git submodules or FetchContent)\n └── googletest/\n\n\nKey principles:
\n- \n
- libs/ — all libraries. Each library is a separate folder with its own CMakeLists.txt. \n
- apps/ — all executable files. They depend on libraries from libs/. \n
- tests/ — tests organized by library. \n
- third_party/ — external dependencies. Use
git submodulesorFetchContentto include them. \n
2. CMake: Configuring the Monorepository Build
\n\nCMake is the ideal tool for a monorepository. Let's look at how to set up the root CMakeLists.txt and files for libraries.
Root CMakeLists.txt
\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# Options to enable/disable components\noption(BUILD_TESTS "Build tests" ON)\noption(BUILD_APPS "Build applications" ON)\n\n# Include external dependencies\ninclude(FetchConte