C++ 单体仓库:代码组织实践指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么要为 C++ 使用 Monorepo?



在现代 C++ 开发中,尤其是在中大型项目中,代码组织成为一项至关重要的任务。Monorepo 是一种将所有组件、库和服务的代码存储在单一仓库中的方法。与多仓库不同,monorepo 提供了单一入口点,简化了重构,并简化了依赖管理。在实践中,这意味着你可以更改库的 API,并立即查看它如何影响所有依赖模块。



在本文中,我们将详细讲解在 monorepo 中组织 C++ 代码的实践方面:从文件夹结构到设置 CI/CD。你将学习如何避免常见错误,并使构建过程快速且可预测。



1. C++ 的 Monorepo 结构



正确的文件夹结构是成功 monorepo 的基础。让我们看看为 C++ 项目推荐的分层结构。



基本目录层次结构



my_project/├── CMakeLists.txt          # 根构建文件├── cmake/                  # 自定义 CMake 模块│   └── FindMyLib.cmake├── libs/                   # 内部库│   ├── 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/                   # 可执行应用程序│   ├── server/│   │   ├── CMakeLists.txt│   │   └── src/│   │       └── main.cpp│   └── cli/│       ├── CMakeLists.txt│       └── src/│           └── main.cpp├── tests/                  # 集成测试│   ├── CMakeLists.txt│   └── test_integration.cpp├── third_party/            # 外部依赖(供应商代码)│   ├── fmt/│   └── spdlog/├── .github/                # CI/CD 配置│   └── workflows/│       └── build.yml└── README.md


关键原则:

  • libs/ — 所有内部库。每个库都有自己的文件夹,包含一个 CMakeLists.txt。
  • apps/ — 可执行文件。它们依赖于 libs/ 中的库。
  • third_party/ — 供应商依赖(git 子模块或复制的源代码)。
  • tests/ — 验证多个库交互的集成测试。


库的 CMakeLists.txt 示例



# 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)


重要提示: 使用 PUBLIC 和 PRIVATE 来正确传播依赖关系。这是一个关键点——如果库 A 仅在其源文件中使用库 B,则将 B 设为 PRIVATE。



2. Monorepo 中的依赖管理



Monorepo 的主要挑战之一是“依赖地狱”。在 C++ 中,这通过 CMake 面向目标的设计 来解决。



规则:一个目标——一个库



每个库应只导出一个 CMake 目标。这简化了链接并防止了循环依赖。



# 根 CMakeLists.txtcmake_minimum_required(VERSION 3.20)project(MyProject VERSION 1.0.0 LANGUAGES CXX)

# 包含所有库add_subdirectory(libs/core)add_subdirectory(libs/network)

博客

书籍推荐