引言:为什么 C++ 需要单体仓库?
\n\n在 C++ 开发的世界中,迟早会遇到一个问题:当项目数量增多时,如何组织代码?库、工具、可执行文件——所有这些都需要以某种方式进行关联、版本控制和构建。传统的多仓库方法(多仓库)常常导致问题:变更同步困难、集成测试复杂、项目间的依赖关系变成噩梦。
\n\n另一种选择是 单体仓库。这是一个统一的仓库,存储着项目的所有组件:库、应用程序、测试、文档。这种方法被 Google、Facebook、Microsoft 以及许多其他公司广泛使用。对于 C++,单体仓库具有以下优势:
\n\n- \n
- 统一的依赖版本——您始终知道所有项目中使用的是哪个版本的库。 \n
- 原子提交——库 API 的更改及其所有使用者的更新在同一个提交中完成。 \n
- 简化的 CI/CD——所有组件共享一个流水线。 \n
- 透明性——轻松了解整个项目的结构。 \n
在本文中,我们将探讨使用 CMake 组织 C++ 单体仓库的实践方法,展示文件夹结构和代码示例。
\n\n1. 文件夹结构:秩序的基础
\n\n成功单体仓库的第一步是精心设计的目录结构。以下是 C++ 项目的推荐模板:
\n\nmy_project/\n├── CMakeLists.txt # 根 CMake 文件\n├── README.md\n├── .gitignore\n├── .clang-format\n├── cmake/ # 辅助 CMake 模块\n│ └── FindMyLib.cmake\n├── libs/ # 库\n│ ├── core/ # 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/ # network 库\n│ ├── CMakeLists.txt\n│ ├── include/\n│ │ └── network/\n│ │ └── http_client.h\n│ └── src/\n│ └── http_client.cpp\n├── apps/ # 可执行应用程序\n│ ├── server/\n│ │ ├── CMakeLists.txt\n│ │ └── src/\n│ │ └── main.cpp\n│ └── cli_tool/\n│ ├── CMakeLists.txt\n│ └── src/\n│ └── main.cpp\n├── 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/ # 外部依赖(git submodules 或 FetchContent)\n └── googletest/\n\n\n关键原则:
\n- \n
- libs/——所有库。每个库是一个独立的文件夹,包含自己的 CMakeLists.txt。 \n
- apps/——所有可执行文件。它们依赖于 libs/ 中的库。 \n
- tests/——按库组织的测试。 \n
- third_party/——外部依赖。使用
git submodules或FetchContent来引入它们。 \n
2. CMake:配置单体仓库的构建
\n\nCMake 是单体仓库的理想工具。让我们看看如何配置根 CMakeLists.txt 和库的文件。
根 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# 用于启用/禁用组件的选项\noption(BUILD_TESTS "Build tests" ON)\noption(BUILD_APPS "Build applications" ON)\n\n# 引入外部依赖\ninclude(FetchConte