@chengzhao-dev/dsh-cpp-workflow 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +14 -11
- package/README.md +14 -11
- package/lib/index.js +4 -4
- package/lib/workspace.js +1 -56
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +2 -2
- package/skills/building-cpp/SKILL.md +25 -12
- package/skills/building-cpp/assets/config/.clang-tidy +1 -0
- package/skills/building-cpp/assets/templates/projects/multi/CMakeLists.txt +2 -2
- package/skills/building-cpp/assets/templates/projects/shared-library/CMakeLists.txt +1 -1
- package/skills/building-cpp/assets/templates/projects/shared-library/greeting/CMakeLists.txt +1 -1
- package/skills/building-cpp/assets/templates/projects/single/CMakeLists.txt +1 -1
- package/skills/building-cpp/assets/templates/projects/static-library/CMakeLists.txt +1 -1
- package/skills/building-cpp/assets/templates/projects/static-library/greeting/CMakeLists.txt +1 -1
- package/skills/building-cpp/examples/tooling.md +3 -3
- package/skills/building-cpp/references/build-script.md +11 -0
- package/skills/building-cpp/references/linking.md +7 -7
- package/skills/building-cpp/references/standards/README.md +1 -1
- package/skills/building-cpp/references/static-analysis.md +3 -3
- package/skills/building-cpp/steps/01-build.md +22 -35
- package/skills/building-cpp/steps/02-tooling.md +2 -2
- package/skills/configuring-cmake/SKILL.md +57 -0
- package/skills/configuring-cmake/assets/cmake/CompileSettings.cmake +126 -0
- package/skills/configuring-cmake/assets/cmake/LinkSettings.cmake +48 -0
- package/skills/configuring-cmake/examples/cmake.md +224 -0
- package/skills/{building-cpp → configuring-cmake}/references/cmake.md +54 -48
- package/skills/configuring-cmake/references/cxx-standard.md +67 -0
- package/skills/configuring-cmake/references/modules.md +105 -0
- package/skills/configuring-cmake/steps/01-targets.md +53 -0
- package/skills/configuring-cmake/steps/02-modules.md +37 -0
- package/skills/configuring-cmake/steps/03-check.md +39 -0
- package/skills/developing-cpp/SKILL.md +17 -3
- package/skills/developing-cpp/examples/comments.md +173 -136
- package/skills/developing-cpp/examples/exceptions.md +38 -19
- package/skills/developing-cpp/examples/structure.md +75 -4
- package/skills/developing-cpp/references/comments.md +82 -99
- package/skills/developing-cpp/references/declaration-order.md +4 -2
- package/skills/developing-cpp/references/exceptions.md +12 -13
- package/skills/developing-cpp/references/file-template.md +131 -0
- package/skills/developing-cpp/references/glossary.md +3 -3
- package/skills/developing-cpp/references/google-cpp-style.md +8 -8
- package/skills/developing-cpp/references/language.md +4 -3
- package/skills/developing-cpp/references/layout.md +21 -12
- package/skills/developing-cpp/references/naming.md +5 -4
- package/skills/developing-cpp/references/project-design.md +1 -1
- package/skills/developing-cpp/references/standard-library.md +2 -1
- package/skills/developing-cpp/references/types.md +1 -2
- package/skills/developing-cpp/scripts/checking-comments.mjs +371 -0
- package/skills/developing-cpp/steps/01-behavior.md +1 -1
- package/skills/developing-cpp/steps/02-boundary.md +4 -4
- package/skills/developing-cpp/steps/03-declaration.md +7 -7
- package/skills/developing-cpp/steps/04-implementation.md +6 -5
- package/skills/building-cpp/assets/cmake/applying-warnings.cmake +0 -10
- package/skills/building-cpp/assets/cmake/fetching-googletest.cmake +0 -15
- package/skills/building-cpp/assets/cmake/setting-rpath.cmake +0 -8
- package/skills/building-cpp/examples/cmake.md +0 -150
- /package/skills/building-cpp/assets/templates/projects/multi/src/{greeting.cc → greeting.cpp} +0 -0
- /package/skills/building-cpp/assets/templates/projects/multi/src/{main.cc → main.cpp} +0 -0
- /package/skills/building-cpp/assets/templates/projects/shared-library/greeting/src/{greeting.cc → greeting.cpp} +0 -0
- /package/skills/building-cpp/assets/templates/projects/shared-library/src/{main.cc → main.cpp} +0 -0
- /package/skills/building-cpp/assets/templates/projects/single/src/{main.cc → main.cpp} +0 -0
- /package/skills/building-cpp/assets/templates/projects/static-library/greeting/src/{greeting.cc → greeting.cpp} +0 -0
- /package/skills/building-cpp/assets/templates/projects/static-library/src/{main.cc → main.cpp} +0 -0
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## 产出
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
一个固定的构建目录、一个可用的编译数据库、一组可复现的配置与构建命令。构建结果只取决于 `environment.json` 声明的组合,不取决于当前 shell 碰巧有什么。
|
|
6
6
|
|
|
7
7
|
```text
|
|
8
|
-
CMakeLists.txt
|
|
9
8
|
build/
|
|
10
9
|
clang/ # compiler=clang
|
|
11
10
|
compile_commands.json
|
|
@@ -14,37 +13,32 @@ build/
|
|
|
14
13
|
compile_commands.json # 指向上面的当前数据库
|
|
15
14
|
```
|
|
16
15
|
|
|
17
|
-
##
|
|
16
|
+
## 前置
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
先读项目技能与 `environment.json`,再确认 `configuring-cmake` 已经把 target 图、公共 include、语言标准和输出目录写进 CMake。target 缺失、标准不对、include 或链接边界没写时,停止本步,转 `configuring-cmake` 的定 target 与标准;不要在这里用全局变量或临时 `-std` 绕过。
|
|
19
|
+
|
|
20
|
+
## 环境
|
|
20
21
|
|
|
21
22
|
| 轴 | 取值 | 含义 |
|
|
22
23
|
| --- | --- | --- |
|
|
23
24
|
| `host` | `windows` / `linux` / `macos` | 编辑器与代理壳所在系统 |
|
|
24
|
-
| `build_host` | `native` / `wsl` | 执行编译和运行产物的环境;`
|
|
25
|
+
| `build_host` | `native` / `wsl` | 执行编译和运行产物的环境;`wsl` 只允许 `host=windows`;`windows` + `native` 本版本不支持 |
|
|
25
26
|
| `compiler` | `clang` / `gcc` | 用哪个编译器;一次只配一个 |
|
|
26
27
|
| `standard` | `c++11`–`c++23` | 一个工程一个语言标准;新工程默认 `c++23`,已有工程按原声明 |
|
|
27
28
|
|
|
28
|
-
环境轴为空、`standard`
|
|
29
|
+
环境轴为空、`standard` 非法或组合非法时,停在定构建,先让用户把 `environment.json` 填对。不要替用户选 WSL、Clang 或构建目录。`windows` + `native` 只给一句「本版本不能在 Windows 原生壳里构建」。
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
## 规则
|
|
31
32
|
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
- 输出目录统一:可执行文件到 `build/<compiler>/bin`,库到 `build/<compiler>/lib`;不要用源码目录当输出目录。
|
|
40
|
-
- 开启 `CMAKE_EXPORT_COMPILE_COMMANDS` 后,把 `build/<compiler>/compile_commands.json` 符号链接到 `build/compile_commands.json`,让 clangd 默认能找到当前数据库。本插件固定产出 `build/<compiler>/` 并在 `build/` 下维护链接,不生成 `out/build/`,也不把两套构建根混用。
|
|
41
|
-
- 目标标准写在 target 上:`target_compile_features(app PRIVATE cxx_std_23)`;库用 `PUBLIC` 传播标准。再加 `set_target_properties(... CXX_STANDARD 23 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF)`:meta-feature 只保证“至少”,`CXX_STANDARD_REQUIRED` 防 decay,`CXX_EXTENSIONS OFF` 把 `-std=gnu++23` 收成 `-std=c++23`。configure 后读 `compile_commands.json` 的最后一个 `-std=`,必须与 `environment.json` 的 `standard` 一致。
|
|
42
|
-
- 工程确有 C 源时才写 `LANGUAGES C CXX`,并且 `CMAKE_C_COMPILER` 与 `CMAKE_CXX_COMPILER` 必须来自同一套编译器(`clang`/`clang++` 或 `gcc`/`g++`);没有 C 源时只启用 CXX。
|
|
43
|
-
- 不写 `file(GLOB ...)`;源文件显式列出,新增文件时改 CMake。
|
|
44
|
-
- 不加 `-march=native`、`-ffast-math` 等改变语义或可移植性的选项;警告选项按团队约定统一加。
|
|
45
|
-
- 配置阶段不隐式下载依赖;需要 GoogleTest 时由项目显式选择固定版本、带哈希的 `FetchContent`,或使用项目自带的 cmake 模块,只把下载用于测试依赖。
|
|
33
|
+
- 生成器固定单配置 Ninja,不用 Ninja Multi-Config:同一源文件会写多条命令,clangd 默认只取第一条,容易读错数据库;构建目录固定 `build/clang` 或 `build/gcc`。
|
|
34
|
+
- 一个 configure 只用一个编译器:`-DCMAKE_CXX_COMPILER=clang++` 或 `g++`;确有 C 源时 C 编译器与 C++ 编译器同属一套。
|
|
35
|
+
- `set(CMAKE_EXPORT_COMPILE_COMMANDS ON)` 由 `configuring-cmake` 写在顶层;Ninja 下产出 `compile_commands.json`。
|
|
36
|
+
- 输出目录由 `configuring-cmake` 统一设到 `build/<compiler>/bin` 与 `build/<compiler>/lib`;本步只核对,不重复设。
|
|
37
|
+
- 配置后把 `build/<compiler>/compile_commands.json` 符号链接到 `build/compile_commands.json`,让 clangd 默认能找到当前数据库;换编译器时重建链接。
|
|
38
|
+
- 不写全局 `CMAKE_CXX_FLAGS`、`include_directories()` 或 `add_definitions()`;这些属于 target 契约,发现就转 `configuring-cmake`。
|
|
39
|
+
- 配置阶段不隐式下载依赖;测试框架由项目显式选择固定版本、带哈希的 `FetchContent`,或使用项目自带模块。
|
|
46
40
|
|
|
47
|
-
|
|
41
|
+
## 命令
|
|
48
42
|
|
|
49
43
|
```bash
|
|
50
44
|
cmake -S . -B build/clang -G Ninja \
|
|
@@ -56,23 +50,16 @@ rm -f build/compile_commands.json
|
|
|
56
50
|
ln -s clang/compile_commands.json build/compile_commands.json
|
|
57
51
|
```
|
|
58
52
|
|
|
59
|
-
GCC 模式把目录和编译器换成 `build/gcc`、`g
|
|
53
|
+
GCC 模式把目录和编译器换成 `build/gcc`、`g++`。每次构建都重新 configure;不要依赖上一次缓存。
|
|
60
54
|
|
|
61
55
|
## 情况
|
|
62
56
|
|
|
63
|
-
**新工程**:从
|
|
64
|
-
|
|
65
|
-
**已有工程**:先读现有 `CMakeLists.txt`,找出全局设置、GLOB、输出目录和 target 命名;只改与当前任务相关的一处。大改前先让通过检查的项目入口跑通,保留可回退点。
|
|
66
|
-
|
|
67
|
-
**库 + 程序**:库 target 的 `PUBLIC` include 根按项目约定设置;本工作流把仓库根作为源码根,程序按 `#include "component/include/name.h"` 包含公共头,不直接包含库的 `src/`。静态库与动态库的接口相同;动态库额外设置运行时库路径。
|
|
57
|
+
**新工程**:从 `../assets/templates/projects/` 选形态;模板缺 target 时先转 `configuring-cmake`,target 齐了再 configure。
|
|
68
58
|
|
|
69
|
-
|
|
59
|
+
**已有工程**:先读现有 `CMakeLists.txt`,只核对 target、标准与输出目录;不改与当前任务无关的 target,大改前先让现有构建跑通。
|
|
70
60
|
|
|
71
|
-
|
|
61
|
+
**测试**:`enable_testing()` 与 `add_subdirectory(tests)` 的顺序由 `configuring-cmake` 定;本步只跑 CTest,不在没有测试时加空测试。
|
|
72
62
|
|
|
73
|
-
|
|
63
|
+
**CMakePresets**:如果项目使用 preset,名称固定 `clang` / `gcc`,与构建目录一致;没有 preset 时直接用上面的命令。
|
|
74
64
|
|
|
75
|
-
|
|
76
|
-
- 正确的最小库 + 程序:`examples/cmake.md`「最小可用形状」。
|
|
77
|
-
- target 与目录的完整说明:`references/cmake.md`。
|
|
78
|
-
- 五档标准的下限、降档替换和工具映射:`references/standards/README.md`。
|
|
65
|
+
下一步:构建可用后,进 `steps/02-tooling.md` 配格式、静态检查与 clangd。
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
- `.clangd` 的 `CompilationDatabase` 指向 `build/<compiler>`;切换编译器时同步改,不能留旧目录。**不要写 `-std`**:它会覆盖 `compile_commands.json`,把 C++23 工程降成旧标准;标准只由构建声明和编译数据库决定。
|
|
14
14
|
- `--query-driver` 是 clangd 的命令行参数,写在 `.vscode/settings.json` 的 `clangd.arguments` 里,不是 `.clangd` 的 YAML 键。它告诉 clangd 允许执行哪个编译器驱动来取系统头路径;路径写绝对路径,并与 `environment.json` 的编译器一致。
|
|
15
15
|
- 首次复制时按轴替换三处:`compiler=clang` 用 `CompilationDatabase: build/clang`、`--query-driver=/usr/bin/clang++` 和 `cmake.debugConfig` 的 `MIMode: lldb` / `miDebuggerPath: /usr/bin/lldb`;`compiler=gcc` 用 `build/gcc`、`/usr/bin/g++` 和 `MIMode: gdb` / `/usr/bin/gdb`。只复制模板而不改这三处,GCC 模式会指向错误的数据库、驱动或调试器。原工程已有的 `.clangd` 不覆盖;要改先征得同意。
|
|
16
|
-
- `.clang-format`
|
|
17
|
-
- `.clang-tidy` 用 `Checks: '-*, google-*, readability-identifier-naming'`,保留 `WarningsAsErrors: '*'` 和 `FormatStyle: file`。`google-*` 覆盖 Google 风格能静态检查的部分;`readability-identifier-naming` 只配项目确实统一的命名项:类型/枚举/别名/模板参数 PascalCase,变量/参数/成员 snake_case,类成员尾随 `_`,结构体成员不尾随,常量 `k` + PascalCase。不要设 `FunctionCase`,Google 允许 `count()` / `set_count()`
|
|
16
|
+
- `.clang-format` 保留 `Language: Cpp`、`BasedOnStyle: Google` 和 `Standard`:模板资产写 `Latest`;工程按 `environment.json` 声明 C++11–C++20 时,把 `Standard` 改成 `c++NN`(映射见 `references/standards/README.md`)。clang-format 21/22 的 `Standard` 不接受 `c++23`,所以 C++23 工程仍写 `Latest`。列宽 80、每级 2 空格、不用 tab、包含顺序都取 Google 预设;不要覆盖 `ColumnLimit`、`TabWidth`、`IncludeCategories` 或指针对齐。需要新规则时先改 `references/google-cpp-style.md` 并说明理由。
|
|
17
|
+
- `.clang-tidy` 用 `Checks: '-*, google-*, portability-avoid-pragma-once, readability-identifier-naming'`,保留 `WarningsAsErrors: '*'` 和 `FormatStyle: file`。`google-*` 覆盖 Google 风格能静态检查的部分;`readability-identifier-naming` 只配项目确实统一的命名项:类型/枚举/别名/模板参数 PascalCase,变量/参数/成员 snake_case,类成员尾随 `_`,结构体成员不尾随,常量 `k` + PascalCase。不要设 `FunctionCase`,Google 允许 `count()` / `set_count()` 这类访问器;`portability-avoid-pragma-once` 要打开,因为工程统一用路径式守卫;不要重新打开 `cppcoreguidelines-*` 整包。
|
|
18
18
|
- `.clang-tidy` 关闭项和例外必须写理由;不要借 `-*` 之后再打开 `cppcoreguidelines-*` 这类非 Google 整族检查。
|
|
19
19
|
- `.vscode/extensions.json` 推荐 clangd、CMake Tools 与 C/C++ 扩展;`.vscode/settings.json` 固定 clangd 参数、CMake 构建目录和 `cmake.debugConfig`。配置、构建、运行和调试只从 CMake Tools 进入,不写 `tasks.json` 或 `launch.json`;C/C++ 扩展只作为 CMake 快速调试的后端,IntelliSense 关闭,避免和 clangd 并行。配置注释用 JSONC 的 `//`,贴在被解释的键上方。
|
|
20
20
|
- 配置注释写「为什么这样设」,不写「这一项是什么」;不写策略头、不指向文档路径。
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: configuring-cmake
|
|
3
|
+
description: 在 C++11–C++23 工程里编写或重构 CMake 时使用:CMakeLists.txt、cmake 模块、target 与属性、依赖与输出目录、语言标准与编译选项、2 空格排版;新工程默认 C++23。改 .h/.cpp 源码先开 developing-cpp;只配置、构建或跑工具链时开 building-cpp。不用于 Quarto、Python 或非 C++ 文档。
|
|
4
|
+
metadata:
|
|
5
|
+
short-description: CMake 配置三步
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# configuring-cmake
|
|
9
|
+
|
|
10
|
+
## 适用场景
|
|
11
|
+
|
|
12
|
+
管 `CMakeLists.txt`、`cmake/` 下的模块、`target_*` 命令、目标属性、include 与链接边界、输出目录、共享库运行时路径、`FetchContent`、preset 与安装导出。函数体、类型、命名、异常和源码注释只开 `developing-cpp`;配置完成后要跑构建、格式化、静态检查或入口脚本时开 `building-cpp`。
|
|
13
|
+
|
|
14
|
+
一次改动同时碰到源码和 CMake 时先开 `developing-cpp` 定行为与边界,再用本技能把源文件、库和程序写进 target,最后到 `building-cpp` 跑检查。只改一个 target 的 include、链接或标准时走增量修正;新工程、新组件、换语言标准或抽公共函数时走整段重构。
|
|
15
|
+
|
|
16
|
+
存在项目技能 `cpp-workflow-project` 时先读它的 `SKILL.md`、`environment.json` 和 `stages/stage-table.md`。`environment.json` 的 `standard` 是 target 标准的唯一来源;缺失、非法或与现有 target 不一致时停在定 target,不猜标准。构建目录、编译器和工具版本由 `building-cpp` 的定构建负责,本技能只写 target 契约。
|
|
17
|
+
|
|
18
|
+
## 两种走法
|
|
19
|
+
|
|
20
|
+
| 走法 | 什么时候用 | 怎么做 |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| 增量修正 | 一个 target 的 include、链接、标准、输出目录或一条属性不对 | 先读现有 `CMakeLists.txt`,只改这一处,不动无关 target 和全局设置 |
|
|
23
|
+
| 整段重构 | 新工程、新组件、抽公共函数、换语言标准或整理目录 | 同样三步;先定 target 图与标准,再定模块与函数,最后跑完整检查 |
|
|
24
|
+
|
|
25
|
+
共同不变量:不发明项目没有声明的 target、标准、编译器或目录;不覆盖已有 `CMakeLists.txt`;不用全局 `include_directories()`、`add_definitions()`、`CMAKE_CXX_FLAGS` 给所有 target 加料;不写 `file(GLOB ...)`;不把 `main()` 编进库;库与程序不下载依赖,只有测试需要时调用 `LinkSettings_FetchGoogleTest`。后一步发现前一步没做完,退回那一步。
|
|
26
|
+
|
|
27
|
+
## 步骤
|
|
28
|
+
|
|
29
|
+
| 步 | 名称 | 文件 | 一句话 |
|
|
30
|
+
| --- | --- | --- | --- |
|
|
31
|
+
| 1 | 定 target 与标准 | `steps/01-targets.md` | target 图、PUBLIC/PRIVATE、标准、输出目录与编译数据库 |
|
|
32
|
+
| 2 | 定模块与函数 | `steps/02-modules.md` | 何时抽函数、文件与命名、导入、注释与 2 空格排版 |
|
|
33
|
+
| 3 | 通过检查 | `steps/03-check.md` | configure、构建、编译数据库与实际 `-std` 核对 |
|
|
34
|
+
|
|
35
|
+
每步只打开同号的一个步骤文件。判不准才打开 `examples/cmake.md`;`references/cmake.md` 保存 target、链接、输出、RPATH、依赖与反模式的完整条文,`references/cxx-standard.md` 保存 C++11–C++23 的标准映射,`references/modules.md` 保存函数与模块契约。可复制的函数在 `assets/cmake/`:`CompileSettings.cmake` 放标准与警告,`LinkSettings.cmake` 放构建期 RPATH 与 GoogleTest 依赖;一个文件按性质收一组函数。
|
|
36
|
+
|
|
37
|
+
五档标准的语言设施、工具映射与降档仍由 `building-cpp/references/standards/` 维护;本技能只负责这些标准在 CMake 里怎么写。
|
|
38
|
+
|
|
39
|
+
### 四类改动
|
|
40
|
+
|
|
41
|
+
先认这次改的是哪一类,再决定从哪一步进;一次改动混了两类时,按「写作 → 布局 → 排版 → 润色」的次序拆开做。
|
|
42
|
+
|
|
43
|
+
| 类型 | 典型请求 | 从哪进 | 先读哪份条文 |
|
|
44
|
+
| --- | --- | --- | --- |
|
|
45
|
+
| 写作 | 新增 target、改公共 include 或链接边界、换语言标准 | 第 1 步 | `steps/01-targets.md`、`references/cxx-standard.md` |
|
|
46
|
+
| 布局 | 抽函数、拆模块、调导入位置 | 第 2 步 | `steps/02-modules.md`、`references/modules.md` |
|
|
47
|
+
| 排版 | 只改 2 空格、行宽或注释形态 | 第 2 步的契约写法 | `references/cmake.md`、`references/modules.md` |
|
|
48
|
+
| 润色 | 只改函数名、注释措辞或错误消息 | 第 2 步 | `references/modules.md` |
|
|
49
|
+
|
|
50
|
+
## 完成判据
|
|
51
|
+
|
|
52
|
+
- target 图显式:程序 target 叫 `app`,库 target 用组件名,程序链接库,库的公共 include 用 `PUBLIC`;没有全局 include、全局编译选项或 GLOB。
|
|
53
|
+
- 每个 target 的标准来自 `environment.json`;`target_compile_features` 与 `CXX_STANDARD`、`CXX_STANDARD_REQUIRED ON`、`CXX_EXTENSIONS OFF` 同时存在,live 的 `compile_commands.json` 最后一条 `-std=` 与声明一致,不是 `gnu++NN`。
|
|
54
|
+
- 复用的 CMake 函数放在 `cmake/` 模块里,文件名用 UpperCamelCase,函数名用 `<ModuleName>_` 加 PascalCase,有目标与参数校验,根 `CMakeLists.txt` 通过 `CMAKE_MODULE_PATH` 导入;没有重复片段和未使用的旧模块。
|
|
55
|
+
- 公开函数上方写中文 `#` 契约:一句功能、空行、边界,再用 `:param` / `:keyword` 标参数;不写 `#[[.rst:` 与 `.. command::`,完整写法见 `references/cmake.md`;函数组之间用 `#---`,不画 `#===...===#` 方框。
|
|
56
|
+
- `CMakeLists.txt` 与 `*.cmake` 用 UTF-8 无 BOM、LF、2 空格缩进、不用 tab;行宽按团队约定,默认 80 列。
|
|
57
|
+
- configure 与构建通过,构建产物不落在源码目录;没有改源码语义,也没有覆盖已有工程文件。
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# CompileSettings
|
|
2
|
+
#
|
|
3
|
+
# 在一个目标上设置 C++ 语言标准与警告等级。
|
|
4
|
+
#
|
|
5
|
+
# 用 include(CompileSettings) 载入。两个函数都只改传入的目标,
|
|
6
|
+
# 不建全局变量,也不下载依赖。
|
|
7
|
+
include_guard(GLOBAL)
|
|
8
|
+
|
|
9
|
+
#-------------------------------------------------------------------------------
|
|
10
|
+
# 让一个目标使用指定的 C++ 标准。
|
|
11
|
+
#
|
|
12
|
+
# :param target: 已经存在的 CMake 目标。
|
|
13
|
+
# :param visibility: 取 PUBLIC、PRIVATE 或 INTERFACE。
|
|
14
|
+
# :param standard: 取 c++11、c++14、c++17、c++20 或 c++23。
|
|
15
|
+
function(CompileSettings_SetCxxStandard target visibility standard)
|
|
16
|
+
if(NOT TARGET "${target}")
|
|
17
|
+
message(FATAL_ERROR
|
|
18
|
+
"CompileSettings_SetCxxStandard: target '${target}' does not exist")
|
|
19
|
+
endif()
|
|
20
|
+
|
|
21
|
+
if(NOT visibility MATCHES "^(PUBLIC|PRIVATE|INTERFACE)$")
|
|
22
|
+
message(FATAL_ERROR
|
|
23
|
+
"CompileSettings_SetCxxStandard: visibility must be "
|
|
24
|
+
"PUBLIC, PRIVATE, or INTERFACE")
|
|
25
|
+
endif()
|
|
26
|
+
|
|
27
|
+
set(supported_standards c++11 c++14 c++17 c++20 c++23)
|
|
28
|
+
if(NOT standard IN_LIST supported_standards)
|
|
29
|
+
message(FATAL_ERROR
|
|
30
|
+
"CompileSettings_SetCxxStandard: standard must be one of "
|
|
31
|
+
"${supported_standards}")
|
|
32
|
+
endif()
|
|
33
|
+
|
|
34
|
+
# c++23 -> 23:两种声明使用同一个编号。
|
|
35
|
+
string(SUBSTRING "${standard}" 3 -1 number)
|
|
36
|
+
target_compile_features("${target}" "${visibility}" "cxx_std_${number}")
|
|
37
|
+
set_target_properties("${target}" PROPERTIES
|
|
38
|
+
CXX_STANDARD "${number}"
|
|
39
|
+
CXX_STANDARD_REQUIRED ON
|
|
40
|
+
CXX_EXTENSIONS OFF
|
|
41
|
+
)
|
|
42
|
+
endfunction()
|
|
43
|
+
|
|
44
|
+
#-------------------------------------------------------------------------------
|
|
45
|
+
# 给一个目标加上编译警告。
|
|
46
|
+
#
|
|
47
|
+
# 只改传入的目标。PRIVATE 不向使用方传播。
|
|
48
|
+
#
|
|
49
|
+
# :param target: 已经存在的 CMake 目标。
|
|
50
|
+
# :param visibility: 取 PRIVATE 或 INTERFACE。
|
|
51
|
+
# :keyword LEVEL: 可省略。取 basic、standard 或 strict;
|
|
52
|
+
# 省略时按 standard。
|
|
53
|
+
function(CompileSettings_SetWarnings target visibility)
|
|
54
|
+
cmake_parse_arguments(PARSE_ARGV 2 arg "" "LEVEL" "")
|
|
55
|
+
|
|
56
|
+
if(arg_UNPARSED_ARGUMENTS)
|
|
57
|
+
message(FATAL_ERROR
|
|
58
|
+
"CompileSettings_SetWarnings: unexpected arguments: "
|
|
59
|
+
"${arg_UNPARSED_ARGUMENTS}")
|
|
60
|
+
endif()
|
|
61
|
+
|
|
62
|
+
if(NOT TARGET "${target}")
|
|
63
|
+
message(FATAL_ERROR
|
|
64
|
+
"CompileSettings_SetWarnings: target '${target}' does not exist")
|
|
65
|
+
endif()
|
|
66
|
+
|
|
67
|
+
if(NOT visibility MATCHES "^(PRIVATE|INTERFACE)$")
|
|
68
|
+
message(FATAL_ERROR
|
|
69
|
+
"CompileSettings_SetWarnings: visibility must be PRIVATE or INTERFACE")
|
|
70
|
+
endif()
|
|
71
|
+
|
|
72
|
+
if(NOT arg_LEVEL)
|
|
73
|
+
set(arg_LEVEL standard)
|
|
74
|
+
endif()
|
|
75
|
+
|
|
76
|
+
if(MSVC)
|
|
77
|
+
set(basic_warnings /W4)
|
|
78
|
+
set(standard_warnings ${basic_warnings} /permissive- /WX)
|
|
79
|
+
set(strict_warnings
|
|
80
|
+
${standard_warnings}
|
|
81
|
+
/w14242 /w14254 /w14263 /w14265 /w14287 /w14296
|
|
82
|
+
/w14311 /w14545 /w14546 /w14547 /w14549 /w14555
|
|
83
|
+
/w14619 /w14640 /w14826
|
|
84
|
+
)
|
|
85
|
+
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
|
86
|
+
set(basic_warnings -Wall -Wextra)
|
|
87
|
+
set(standard_warnings
|
|
88
|
+
${basic_warnings}
|
|
89
|
+
-Werror # 把告警当错误
|
|
90
|
+
-Wshadow # 变量遮蔽
|
|
91
|
+
-Wold-style-cast # C 风格转换
|
|
92
|
+
-Wpedantic # 非标准扩展
|
|
93
|
+
-Wnon-virtual-dtor # 有虚函数但析构非虚
|
|
94
|
+
-Woverloaded-virtual
|
|
95
|
+
)
|
|
96
|
+
set(strict_warnings
|
|
97
|
+
${standard_warnings}
|
|
98
|
+
-Wcast-align
|
|
99
|
+
-Wcast-qual
|
|
100
|
+
-Wconversion
|
|
101
|
+
-Wsign-conversion
|
|
102
|
+
-Wdouble-promotion
|
|
103
|
+
-Wformat=2
|
|
104
|
+
-Wimplicit-fallthrough
|
|
105
|
+
-Wnull-dereference
|
|
106
|
+
-Wundef
|
|
107
|
+
)
|
|
108
|
+
else()
|
|
109
|
+
message(FATAL_ERROR
|
|
110
|
+
"CompileSettings_SetWarnings: unsupported compiler "
|
|
111
|
+
"'${CMAKE_CXX_COMPILER_ID}'")
|
|
112
|
+
endif()
|
|
113
|
+
|
|
114
|
+
if(arg_LEVEL STREQUAL "basic")
|
|
115
|
+
set(warnings ${basic_warnings})
|
|
116
|
+
elseif(arg_LEVEL STREQUAL "standard")
|
|
117
|
+
set(warnings ${standard_warnings})
|
|
118
|
+
elseif(arg_LEVEL STREQUAL "strict")
|
|
119
|
+
set(warnings ${strict_warnings})
|
|
120
|
+
else()
|
|
121
|
+
message(FATAL_ERROR
|
|
122
|
+
"CompileSettings_SetWarnings: LEVEL must be basic, standard, or strict")
|
|
123
|
+
endif()
|
|
124
|
+
|
|
125
|
+
target_compile_options("${target}" "${visibility}" ${warnings})
|
|
126
|
+
endfunction()
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# LinkSettings
|
|
2
|
+
#
|
|
3
|
+
# 设置构建期运行时路径,并为测试取回 GoogleTest。
|
|
4
|
+
#
|
|
5
|
+
# 用 include(LinkSettings) 载入。LinkSettings_FetchGoogleTest 是本文件
|
|
6
|
+
# 唯一会下载的函数,只在测试需要时调用。
|
|
7
|
+
include_guard(GLOBAL)
|
|
8
|
+
|
|
9
|
+
#-------------------------------------------------------------------------------
|
|
10
|
+
# 让 build/bin 里的程序找到同级 build/lib 下的库。
|
|
11
|
+
#
|
|
12
|
+
# 只改构建树,不改安装后的 RPATH。
|
|
13
|
+
#
|
|
14
|
+
# :param target: 已经存在的 CMake 目标。
|
|
15
|
+
function(LinkSettings_SetBuildRpath target)
|
|
16
|
+
if(NOT TARGET "${target}")
|
|
17
|
+
message(FATAL_ERROR
|
|
18
|
+
"LinkSettings_SetBuildRpath: target '${target}' does not exist")
|
|
19
|
+
endif()
|
|
20
|
+
|
|
21
|
+
if(APPLE)
|
|
22
|
+
set_target_properties("${target}" PROPERTIES
|
|
23
|
+
BUILD_RPATH "@loader_path/../lib")
|
|
24
|
+
else()
|
|
25
|
+
set_target_properties("${target}" PROPERTIES BUILD_RPATH "$ORIGIN/../lib")
|
|
26
|
+
endif()
|
|
27
|
+
endfunction()
|
|
28
|
+
|
|
29
|
+
#-------------------------------------------------------------------------------
|
|
30
|
+
# 取回 GoogleTest 并让其 target 可用。
|
|
31
|
+
#
|
|
32
|
+
# 固定 v1.17.0 与 SHA-256;只在 tests 目录调用,库与程序代码不调用。
|
|
33
|
+
function(LinkSettings_FetchGoogleTest)
|
|
34
|
+
include(FetchContent)
|
|
35
|
+
|
|
36
|
+
if(POLICY CMP0135)
|
|
37
|
+
cmake_policy(SET CMP0135 NEW)
|
|
38
|
+
endif()
|
|
39
|
+
|
|
40
|
+
FetchContent_Declare(
|
|
41
|
+
googletest
|
|
42
|
+
URL https://codeload.github.com/google/googletest/tar.gz/refs/tags/v1.17.0
|
|
43
|
+
URL_HASH
|
|
44
|
+
SHA256=65fab701d9829d38cb77c14acdc431d2108bfdbf8979e40eb8ae567edf10b27c
|
|
45
|
+
)
|
|
46
|
+
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
|
47
|
+
FetchContent_MakeAvailable(googletest)
|
|
48
|
+
endfunction()
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# 正反例:CMake
|
|
2
|
+
|
|
3
|
+
## 最小可用形状
|
|
4
|
+
|
|
5
|
+
```cmake
|
|
6
|
+
cmake_minimum_required(VERSION 3.20)
|
|
7
|
+
project(greeter VERSION 0.1.0 LANGUAGES CXX)
|
|
8
|
+
|
|
9
|
+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
10
|
+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
|
11
|
+
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
|
12
|
+
|
|
13
|
+
# 先把 assets/cmake/ 里的 CompileSettings.cmake 复制到工程的 cmake/。
|
|
14
|
+
include(CompileSettings)
|
|
15
|
+
|
|
16
|
+
add_library(greeting STATIC greeting/src/greeting.cpp)
|
|
17
|
+
target_include_directories(greeting PUBLIC greeting/include)
|
|
18
|
+
CompileSettings_SetCxxStandard(greeting PUBLIC c++23)
|
|
19
|
+
CompileSettings_SetWarnings(greeting PRIVATE LEVEL standard)
|
|
20
|
+
|
|
21
|
+
add_executable(app src/main.cpp)
|
|
22
|
+
CompileSettings_SetCxxStandard(app PRIVATE c++23)
|
|
23
|
+
CompileSettings_SetWarnings(app PRIVATE LEVEL standard)
|
|
24
|
+
target_link_libraries(app PRIVATE greeting)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
程序只写 `#include "greeting.h"`;公共 include 根由库的 `PUBLIC` 传过来。
|
|
28
|
+
|
|
29
|
+
## 全局 include
|
|
30
|
+
|
|
31
|
+
**差**:
|
|
32
|
+
|
|
33
|
+
```cmake
|
|
34
|
+
include_directories(include greeting/include)
|
|
35
|
+
add_executable(app src/main.cpp greeting/src/greeting.cpp)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
问题:所有 target 共享 include,边界消失;程序直接编译库源码,测试无法只链接库。
|
|
39
|
+
|
|
40
|
+
**好**:
|
|
41
|
+
|
|
42
|
+
```cmake
|
|
43
|
+
target_include_directories(greeting PUBLIC greeting/include)
|
|
44
|
+
target_link_libraries(app PRIVATE greeting)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## GLOB
|
|
48
|
+
|
|
49
|
+
**差**:
|
|
50
|
+
|
|
51
|
+
```cmake
|
|
52
|
+
file(GLOB SOURCES "src/*.cpp")
|
|
53
|
+
add_executable(app ${SOURCES})
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
新增文件不触发重新配置;不同机器上的文件集合可能不同。
|
|
57
|
+
|
|
58
|
+
**好**:
|
|
59
|
+
|
|
60
|
+
```cmake
|
|
61
|
+
add_executable(app
|
|
62
|
+
src/main.cpp
|
|
63
|
+
src/task_list.cpp
|
|
64
|
+
src/task_parser.cpp
|
|
65
|
+
)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
显式列表,新增文件时改 CMake;diff 能看出变化。
|
|
69
|
+
|
|
70
|
+
## 把 `main()` 编进库
|
|
71
|
+
|
|
72
|
+
**差**:
|
|
73
|
+
|
|
74
|
+
```cmake
|
|
75
|
+
add_library(core STATIC src/main.cpp src/core.cpp)
|
|
76
|
+
add_executable(app src/main.cpp) # 重复定义
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**好**:
|
|
80
|
+
|
|
81
|
+
```cmake
|
|
82
|
+
add_library(core STATIC src/core.cpp)
|
|
83
|
+
add_executable(app src/main.cpp)
|
|
84
|
+
target_link_libraries(app PRIVATE core)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
库不依赖 `main()`;测试链接库时不会碰到入口。
|
|
88
|
+
|
|
89
|
+
## 标准只写一半
|
|
90
|
+
|
|
91
|
+
**差**:
|
|
92
|
+
|
|
93
|
+
```cmake
|
|
94
|
+
target_compile_features(app PRIVATE cxx_std_20)
|
|
95
|
+
# 没写 CXX_STANDARD_REQUIRED;编译器不支持时可能静默降级
|
|
96
|
+
set_target_properties(app PROPERTIES CXX_STANDARD 20)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
问题:meta-feature 只保证“至少”,`CXX_STANDARD` 又允许 decay,实际标准可能不是 20。
|
|
100
|
+
|
|
101
|
+
**好**:
|
|
102
|
+
|
|
103
|
+
```cmake
|
|
104
|
+
CompileSettings_SetCxxStandard(app PRIVATE c++20)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
两套声明同时写;`CXX_STANDARD_REQUIRED ON` 禁止降级,`CXX_EXTENSIONS OFF` 把 `gnu++20` 收成 `c++20`。
|
|
108
|
+
|
|
109
|
+
## 警告等级
|
|
110
|
+
|
|
111
|
+
**差**:
|
|
112
|
+
|
|
113
|
+
```cmake
|
|
114
|
+
target_compile_options(app PRIVATE -Wall -Wextra -Werror)
|
|
115
|
+
target_compile_options(core PRIVATE -Wall -Wextra -Werror)
|
|
116
|
+
# 每个 target 复制一遍;想加 -Wshadow 时要逐处改
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**好**:
|
|
120
|
+
|
|
121
|
+
```cmake
|
|
122
|
+
CompileSettings_SetWarnings(app PRIVATE LEVEL standard)
|
|
123
|
+
CompileSettings_SetWarnings(core PRIVATE LEVEL strict)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`basic` 只开 `-Wall -Wextra`;`standard` 加 `-Werror`、`-Wshadow`、`-Wold-style-cast`、`-Wpedantic`、`-Wnon-virtual-dtor`、`-Woverloaded-virtual`;`strict` 再加转换、格式化与可移植性告警。警告只作用于传入 target,不通过 `INTERFACE` 传播。
|
|
127
|
+
|
|
128
|
+
## 编译数据库
|
|
129
|
+
|
|
130
|
+
**差**:
|
|
131
|
+
|
|
132
|
+
```cmake
|
|
133
|
+
# 没开导出
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
clang-tidy src/main.cpp # 没有编译参数,头路径和标准都不对
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**好**:
|
|
141
|
+
|
|
142
|
+
```cmake
|
|
143
|
+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
cmake -S . -B build/clang -G Ninja -DCMAKE_CXX_COMPILER=clang++
|
|
148
|
+
rm -f build/compile_commands.json
|
|
149
|
+
ln -s clang/compile_commands.json build/compile_commands.json
|
|
150
|
+
clang-tidy -p build/clang src/main.cpp
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## 共享库运行时路径
|
|
154
|
+
|
|
155
|
+
**差**:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
LD_LIBRARY_PATH=build/clang/lib ./build/clang/bin/app # 每次运行都要包一层
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**好**:
|
|
162
|
+
|
|
163
|
+
```cmake
|
|
164
|
+
# LinkSettings.cmake 提供 RPATH 与 GoogleTest 依赖函数。
|
|
165
|
+
include(LinkSettings)
|
|
166
|
+
|
|
167
|
+
add_library(greeting SHARED greeting/src/greeting.cpp)
|
|
168
|
+
set_target_properties(greeting PROPERTIES
|
|
169
|
+
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
|
170
|
+
|
|
171
|
+
add_executable(app src/main.cpp)
|
|
172
|
+
target_link_libraries(app PRIVATE greeting)
|
|
173
|
+
LinkSettings_SetBuildRpath(app)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
从 `build/<compiler>/bin/app` 直接启动即可找到同级 `../lib` 下的共享库;安装场景另配 RPATH。
|
|
177
|
+
|
|
178
|
+
## 输出目录
|
|
179
|
+
|
|
180
|
+
**差**:可执行文件生成在源码根,`git status` 出现 `app`、`*.o`。
|
|
181
|
+
|
|
182
|
+
**好**:
|
|
183
|
+
|
|
184
|
+
```cmake
|
|
185
|
+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
|
186
|
+
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
|
187
|
+
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
构建产物全在 `build/<compiler>/` 下。
|
|
191
|
+
|
|
192
|
+
## 注释
|
|
193
|
+
|
|
194
|
+
**差**:
|
|
195
|
+
|
|
196
|
+
```cmake
|
|
197
|
+
#[[.rst:
|
|
198
|
+
CompileSettings_SetWarnings
|
|
199
|
+
---------------------------
|
|
200
|
+
|
|
201
|
+
.. command:: CompileSettings_SetWarnings(target visibility)
|
|
202
|
+
|
|
203
|
+
:param target: 目标。
|
|
204
|
+
@param visibility: 可见性。
|
|
205
|
+
@return: 无。
|
|
206
|
+
]]
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
`#[[.rst:` 与 `.. command::` 是给要进 CMake 手册的模块用的抽取标记,本仓模块不进手册;`@param`、`@return` 是 C++ 的 Doxygen 标签,CMake 里不用。CMake 函数也没有返回值,`:return:` 同样不写。
|
|
210
|
+
|
|
211
|
+
**好**:
|
|
212
|
+
|
|
213
|
+
```cmake
|
|
214
|
+
# 给一个目标加上编译警告。
|
|
215
|
+
#
|
|
216
|
+
# 只改传入的目标。PRIVATE 不向使用方传播。
|
|
217
|
+
#
|
|
218
|
+
# :param target: 已经存在的 CMake 目标。
|
|
219
|
+
# :param visibility: 取 PRIVATE 或 INTERFACE。
|
|
220
|
+
# :keyword LEVEL: 可省略。取 basic、standard 或 strict;省略时按 standard。
|
|
221
|
+
function(CompileSettings_SetWarnings target visibility)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
普通 `#` 行,签名留在 `function()` 那一行;位置参数用 `:param`,`cmake_parse_arguments` 的关键字用 `:keyword`。
|