应按功能模块建一级目录(如network/、storage/),各模块内统一含include/、src/和CMakeLists.txt,头文件路径即模块名,依赖通过target_link_libraries显式声明,构建产物隔离于build/,子目录CMakeLists.txt禁用project(),第三方依赖统一用FetchContent或find_package管理。

按功能模块建一级目录,每个模块自包含接口和实现
比如 network/、storage/、core/ 这些名字不是随便起的——它们对应真实业务边界或技术职责。每个模块内部结构统一:network/include/network/ 放对外头文件(如 #include <network></network>),network/src/ 放实现,network/CMakeLists.txt 只管自己编译和导出接口。
- 好处是头文件路径即模块名,不用全局
include_directories(),也不用硬编码路径 -
add_subdirectory(network)后,其他模块通过target_link_libraries(other_target PRIVATE network)显式声明依赖 - IDE 自动补全、头文件跳转、Git blame 都更准——因为
tcp_client.h和tcp_client.cpp在同一模块下,路径对齐
构建产物必须隔离在 build/,禁止混入源码树
所有 .o、.a、CMakeCache.txt、生成的可执行文件,一律进 build/。根目录下 gitignore 里写死 build/、out/、dist/。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 不这么做,
git status会不断报一堆二进制变更,CI 构建容易因残留产物失败 - 想同时跑 Debug 和 Release?直接
mkdir build-debug && cd build-debug && cmake -DCMAKE_BUILD_TYPE=Debug .. - 交叉编译时,toolchain 文件只影响当前
build/目录,不会污染源码或其它构建配置
子目录 CMakeLists.txt 别写 project(),除非它是独立项目
绝大多数模块(如 core/、storage/)只是整个项目的组成部分,不是单独可发布的库。它们的 CMakeLists.txt 里不该有 project(core)。
- 有
project()就会重置CMAKE_SOURCE_DIR和CMAKE_BINARY_DIR,导致include_directories()或路径拼接失效 - 正确做法:根目录
CMakeLists.txt调用add_subdirectory(core),子目录只定义add_library(core STATIC ...)和target_include_directories(core PUBLIC core/include) - 如果真需要发布独立库(比如给第三方用),再单独抽成 git submodule,配自己的
project()和install()
第三方依赖统一走 FetchContent 或 find_package,别放 third_party/ 下手动管理
把 abseil 或 gtest 的源码 clone 到 third_party/ 并手动加 add_subdirectory(),短期省事,长期埋雷。
-
FetchContent_Declare()能自动拉取指定 commit/tag,避免本地 diff 污染、版本不一致 -
find_package(OpenSSL REQUIRED)比硬写include_directories(/usr/local/include)更可靠,适配不同系统路径 - 所有依赖声明集中在根目录
CMakeLists.txt或cmake/Dependencies.cmake,一眼看清项目“吃”了哪些外部东西
#include <module></module>,而不是 #include "relative/path.h"。前者靠 target_include_directories(... PUBLIC include) 控制可见性,后者绕过依赖检查,时间一长谁改了什么根本没法追溯。

















