@chengzhao-dev/dsh-cpp-workflow 0.3.1 → 0.5.1
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 +10 -9
- package/README.md +10 -9
- package/lib/index.js +4 -4
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +2 -2
- package/skills/building-cpp/SKILL.md +32 -11
- package/skills/building-cpp/references/build-script.md +11 -0
- package/skills/building-cpp/references/linking.md +1 -1
- package/skills/building-cpp/references/standards/README.md +1 -1
- package/skills/building-cpp/steps/01-build.md +22 -35
- package/skills/configuring-cmake/SKILL.md +65 -0
- package/skills/configuring-cmake/assets/cmake/CompileSettings.cmake +126 -0
- package/skills/configuring-cmake/assets/cmake/LinkSettings.cmake +48 -0
- package/skills/{building-cpp → configuring-cmake}/examples/cmake.md +84 -10
- package/skills/{building-cpp → configuring-cmake}/references/cmake.md +49 -43
- 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 +9 -1
- package/skills/developing-cpp/examples/{comments.md → comments-declaration.md} +25 -51
- package/skills/developing-cpp/examples/comments-implementation.md +53 -0
- package/skills/developing-cpp/examples/exceptions.md +38 -19
- package/skills/developing-cpp/examples/structure.md +71 -0
- package/skills/developing-cpp/references/comments.md +49 -137
- package/skills/developing-cpp/references/exceptions.md +12 -13
- package/skills/developing-cpp/references/language.md +1 -0
- package/skills/developing-cpp/references/naming.md +2 -2
- package/skills/developing-cpp/references/standard-library.md +1 -0
- package/skills/developing-cpp/references/types.md +1 -2
- package/skills/developing-cpp/scripts/checking-comments.mjs +57 -2
- package/skills/developing-cpp/steps/03-declaration.md +4 -4
- package/skills/developing-cpp/steps/04-implementation.md +5 -4
- 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
|
@@ -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()
|
|
@@ -10,15 +10,17 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
|
10
10
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
|
11
11
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
|
12
12
|
|
|
13
|
+
# 先把 assets/cmake/ 里的 CompileSettings.cmake 复制到工程的 cmake/。
|
|
14
|
+
include(CompileSettings)
|
|
15
|
+
|
|
13
16
|
add_library(greeting STATIC greeting/src/greeting.cpp)
|
|
14
17
|
target_include_directories(greeting PUBLIC greeting/include)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
target_compile_options(greeting PRIVATE -Wall -Wextra -Werror)
|
|
18
|
+
CompileSettings_SetCxxStandard(greeting PUBLIC c++23)
|
|
19
|
+
CompileSettings_SetWarnings(greeting PRIVATE LEVEL standard)
|
|
18
20
|
|
|
19
21
|
add_executable(app src/main.cpp)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
CompileSettings_SetCxxStandard(app PRIVATE c++23)
|
|
23
|
+
CompileSettings_SetWarnings(app PRIVATE LEVEL standard)
|
|
22
24
|
target_link_libraries(app PRIVATE greeting)
|
|
23
25
|
```
|
|
24
26
|
|
|
@@ -84,6 +86,45 @@ target_link_libraries(app PRIVATE core)
|
|
|
84
86
|
|
|
85
87
|
库不依赖 `main()`;测试链接库时不会碰到入口。
|
|
86
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
|
+
|
|
87
128
|
## 编译数据库
|
|
88
129
|
|
|
89
130
|
**差**:
|
|
@@ -120,17 +161,16 @@ LD_LIBRARY_PATH=build/clang/lib ./build/clang/bin/app # 每次运行都要包
|
|
|
120
161
|
**好**:
|
|
121
162
|
|
|
122
163
|
```cmake
|
|
164
|
+
# LinkSettings.cmake 提供 RPATH 与 GoogleTest 依赖函数。
|
|
165
|
+
include(LinkSettings)
|
|
166
|
+
|
|
123
167
|
add_library(greeting SHARED greeting/src/greeting.cpp)
|
|
124
168
|
set_target_properties(greeting PROPERTIES
|
|
125
169
|
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
|
126
170
|
|
|
127
171
|
add_executable(app src/main.cpp)
|
|
128
172
|
target_link_libraries(app PRIVATE greeting)
|
|
129
|
-
|
|
130
|
-
set_target_properties(app PROPERTIES BUILD_RPATH "@loader_path/../lib")
|
|
131
|
-
else()
|
|
132
|
-
set_target_properties(app PROPERTIES BUILD_RPATH "$ORIGIN/../lib")
|
|
133
|
-
endif()
|
|
173
|
+
LinkSettings_SetBuildRpath(app)
|
|
134
174
|
```
|
|
135
175
|
|
|
136
176
|
从 `build/<compiler>/bin/app` 直接启动即可找到同级 `../lib` 下的共享库;安装场景另配 RPATH。
|
|
@@ -148,3 +188,37 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
|
|
148
188
|
```
|
|
149
189
|
|
|
150
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`。
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# CMake
|
|
2
2
|
|
|
3
|
-
目标:一个编译器、Ninja、target-based
|
|
3
|
+
目标:一个编译器、Ninja、target-based 规则、可用的编译数据库。下面是最小形状和常见边界;工程模板仍由 `building-cpp` 提供,在 `../../building-cpp/assets/templates/projects/`,可复用的 CMake 函数在本技能的 `assets/cmake/`:`CompileSettings.cmake` 收标准与警告,`LinkSettings.cmake` 收构建期 RPATH 与 GoogleTest 依赖。
|
|
4
4
|
|
|
5
5
|
## 排版
|
|
6
6
|
|
|
7
|
-
CMake
|
|
7
|
+
CMake 没有单独的官方风格指南文档,但官方仓库的 [.editorconfig](https://raw.githubusercontent.com/Kitware/CMake/master/.editorconfig) 明确规定:`CMakeLists.txt`、`*.cmake`、`*.rst` 使用 `indent_size = 2`、`indent_style = space`。这是官方代码风格的直接依据。行宽 80 列来自社区 `cmake-format` 约定([or-tools](https://github.com/google/or-tools/blob/stable/.cmake-format.py)、[draco](https://github.com/google/draco/blob/master/.cmake-format.py) 都设 `tab_size=2`、`line_width=80`),不是 CMake 官方强制值。命令行、列表和注释都按项目约定的宽度换行;`CMakeLists.txt` 与 `*.cmake` 一视同仁。
|
|
8
|
+
|
|
9
|
+
注释不用 `#[[.rst:`。那层标记只属于要进 CMake 手册的模块:Kitware 在 [documentation.rst](https://github.com/Kitware/CMake/blob/master/Help/dev/documentation.rst) 里用 `.. command::` 与参数段,供 Sphinx 从源码抽进手册;本仓的模块不进手册,读者也读不懂这层标记。公开函数上方写中文 `#` 契约:第一句说功能,空一行写边界,再用 `:param 名字:` 标位置参数、`:keyword 名字:` 标 `cmake_parse_arguments` 的关键字;CMake 函数没有返回值,不写 `:return:`,也不把 C++ 的 `@param`、`@return` 搬进来。字段取自 [CMinx](https://cmakepp.github.io/CMinx/documenting/function.html);本仓不跑 CMinx,注释保持普通 `#` 行。签名留在 `function()` 那一行,同一文件的函数组之间用一条 `#---` 短横线分隔;行注释只写原因,不画 `#===...===#` 方框。官方 [GoogleTest.cmake](https://github.com/Kitware/CMake/blob/master/Modules/GoogleTest.cmake) 在一个文件里放多个测试函数,可作“文件按职责聚合”的参照;社区 [CompilerWarnings.cmake](https://github.com/cpp-best-practices/cmake_template/blob/main/cmake/CompilerWarnings.cmake) 在每个警告 flag 后写它抓什么问题,可作参数注释的参照。
|
|
8
10
|
|
|
9
11
|
Shell 脚本用 2 个空格缩进、不用 tab,来源是 [Google Shell Style Guide](https://google.github.io/styleguide/shellguide.html#indentation)。
|
|
10
12
|
|
|
@@ -19,14 +21,12 @@ project({{PROJECT_NAME}} VERSION 0.1.0 LANGUAGES CXX)
|
|
|
19
21
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
20
22
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
|
21
23
|
|
|
24
|
+
# 先把 assets/cmake/ 里的 CompileSettings.cmake 复制到工程的 cmake/。
|
|
25
|
+
include(CompileSettings)
|
|
26
|
+
|
|
22
27
|
add_executable(app src/main.cpp)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
CXX_STANDARD 23
|
|
26
|
-
CXX_STANDARD_REQUIRED ON
|
|
27
|
-
CXX_EXTENSIONS OFF
|
|
28
|
-
)
|
|
29
|
-
target_compile_options(app PRIVATE -Wall -Wextra -Werror)
|
|
28
|
+
CompileSettings_SetCxxStandard(app PRIVATE c++23)
|
|
29
|
+
CompileSettings_SetWarnings(app PRIVATE LEVEL standard)
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
### 库 + 程序
|
|
@@ -40,42 +40,56 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
|
|
40
40
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
|
41
41
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
|
42
42
|
|
|
43
|
+
# 先把 assets/cmake/ 里的 CompileSettings.cmake 复制到工程的 cmake/。
|
|
44
|
+
include(CompileSettings)
|
|
45
|
+
|
|
43
46
|
add_subdirectory(greeting)
|
|
44
47
|
|
|
45
48
|
add_executable(app src/main.cpp)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
CXX_STANDARD 23
|
|
49
|
-
CXX_STANDARD_REQUIRED ON
|
|
50
|
-
CXX_EXTENSIONS OFF
|
|
51
|
-
)
|
|
49
|
+
CompileSettings_SetCxxStandard(app PRIVATE c++23)
|
|
50
|
+
CompileSettings_SetWarnings(app PRIVATE LEVEL standard)
|
|
52
51
|
target_link_libraries(app PRIVATE greeting)
|
|
53
|
-
target_compile_options(app PRIVATE -Wall -Wextra -Werror)
|
|
54
52
|
```
|
|
55
53
|
|
|
56
54
|
```cmake
|
|
57
55
|
# greeting/CMakeLists.txt
|
|
58
56
|
add_library(greeting STATIC src/greeting.cpp)
|
|
59
57
|
target_include_directories(greeting PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
CXX_STANDARD 23
|
|
63
|
-
CXX_STANDARD_REQUIRED ON
|
|
64
|
-
CXX_EXTENSIONS OFF
|
|
65
|
-
)
|
|
66
|
-
target_compile_options(greeting PRIVATE -Wall -Wextra -Werror -Wold-style-cast -Wshadow)
|
|
58
|
+
CompileSettings_SetCxxStandard(greeting PUBLIC c++23)
|
|
59
|
+
CompileSettings_SetWarnings(greeting PRIVATE LEVEL standard)
|
|
67
60
|
```
|
|
68
61
|
|
|
69
62
|
- 库的 `PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..` 让程序能从仓库根写 `#include "greeting/include/greeting.h"`,不需要程序再写 include 路径。
|
|
70
|
-
- `
|
|
71
|
-
- `CXX_EXTENSIONS OFF` 把 `-std=gnu++
|
|
63
|
+
- 标准用 `CompileSettings_SetCxxStandard`:库用 `PUBLIC` 传播,程序用 `PRIVATE`;函数内部同时写 `target_compile_features` 与 `CXX_STANDARD` 三属性。
|
|
64
|
+
- `CXX_STANDARD_REQUIRED ON` 防止 CMake 在编译器不支持时静默 decay;`CXX_EXTENSIONS OFF` 把 `-std=gnu++NN` 收成 `-std=c++NN`。configure 后检查 `compile_commands.json` 的最后一条 `-std=`。
|
|
72
65
|
- 程序 target 固定 `app`;库 target 用组件名。
|
|
73
66
|
|
|
67
|
+
## 标准与复用
|
|
68
|
+
|
|
69
|
+
C++11–C++23 的两层声明、可见性、常见错误与验证见 `references/cxx-standard.md`。通用函数 `CompileSettings_SetCxxStandard(target visibility c++NN)` 在 `assets/cmake/CompileSettings.cmake`:
|
|
70
|
+
|
|
71
|
+
```cmake
|
|
72
|
+
CompileSettings_SetCxxStandard(app PRIVATE c++23)
|
|
73
|
+
CompileSettings_SetCxxStandard(greeting PUBLIC c++20)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
函数名不绑定单一标准;新增档位只改函数里的支持列表。模块何时抽、文件怎么放、怎么导入与测试见 `references/modules.md`。
|
|
77
|
+
|
|
78
|
+
## 警告等级
|
|
79
|
+
|
|
80
|
+
`cmake/CompileSettings.cmake` 的 `CompileSettings_SetWarnings(<target> <visibility> LEVEL basic|standard|strict)` 把常用 flag 收成三档;`visibility` 用 `PRIVATE` 或 `INTERFACE`,`PRIVATE` 不向使用方传播。警告与标准写在同一份编译设置模块里。
|
|
81
|
+
|
|
82
|
+
- `basic`:`-Wall -Wextra`;适合刚开始接 CI 的旧代码。
|
|
83
|
+
- `standard`:`basic` 加 `-Werror`、`-Wshadow`、`-Wold-style-cast`、`-Wpedantic`、`-Wnon-virtual-dtor`、`-Woverloaded-virtual`;默认档。
|
|
84
|
+
- `strict`:`standard` 加 `-Wconversion`、`-Wsign-conversion`、`-Wcast-align`、`-Wcast-qual`、`-Wformat=2`、`-Wundef`、`-Wdouble-promotion`、`-Wimplicit-fallthrough`、`-Wnull-dereference`;适合新代码或质量闸门。
|
|
85
|
+
|
|
86
|
+
MSVC 分支用 `/W4`、`/permissive-`、`/WX`;其他编译器直接报错,避免静默地没有警告。警告是 target 的 `PRIVATE` 选项,库不把自己的策略强加给消费者。
|
|
87
|
+
|
|
74
88
|
## target-based 规则
|
|
75
89
|
|
|
76
90
|
- 每个 target 自己声明 include、标准、编译选项、链接库;不要用全局 `include_directories()`、`add_definitions()`、`CMAKE_CXX_FLAGS` 给所有 target 加料。
|
|
77
91
|
- `target_include_directories(<target> PUBLIC|PRIVATE <dir>)`:公共头给 `PUBLIC`,私有实现目录给 `PRIVATE`。
|
|
78
|
-
- `target_compile_features(<target> PUBLIC
|
|
92
|
+
- `target_compile_features(<target> PUBLIC cxx_std_NN)`:标准是 target 属性,不是全局开关;优先调用项目 `cmake/` 里的标准函数。
|
|
79
93
|
- `target_link_libraries(<target> PRIVATE|PUBLIC <lib>)`:实现依赖用 `PRIVATE`,接口依赖用 `PUBLIC`。
|
|
80
94
|
- 不要 `file(GLOB ...)`;显式列源文件,新增文件时改 CMake,构建系统才知道。`CONFIGURE_DEPENDS` 依赖构建系统每次检查目录,跨生成器行为也不完全一致,不作为工程规则。
|
|
81
95
|
- 不把 `main()` 编进库;程序只做装配和 I/O。
|
|
@@ -119,16 +133,14 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
|
|
119
133
|
## 共享库运行时路径
|
|
120
134
|
|
|
121
135
|
```cmake
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
else()
|
|
125
|
-
set_target_properties(app PROPERTIES BUILD_RPATH "$ORIGIN/../lib")
|
|
126
|
-
endif()
|
|
136
|
+
include(LinkSettings)
|
|
137
|
+
LinkSettings_SetBuildRpath(app)
|
|
127
138
|
```
|
|
128
139
|
|
|
140
|
+
- 函数按平台写 `BUILD_RPATH`:Linux 用 `$ORIGIN/../lib`,Apple 用 `@loader_path/../lib`。
|
|
129
141
|
- 只对需要直接运行构建产物的程序设置;安装规则另算。
|
|
130
142
|
- 不要用全局 `LD_LIBRARY_PATH` 包装所有命令;共享库的运行时路径由 target 的 RPATH 设置,不在脚本里全局改寻库路径。
|
|
131
|
-
- `$ORIGIN` 在 CMake
|
|
143
|
+
- `$ORIGIN` 在 CMake 双引号里不是 `${...}`,不会被展开,保持字面量;若遇到展开问题,用 `"\$ORIGIN/../lib"`。
|
|
132
144
|
|
|
133
145
|
## 标准库与编译器一致
|
|
134
146
|
|
|
@@ -147,21 +159,15 @@ endif()
|
|
|
147
159
|
|
|
148
160
|
## GoogleTest
|
|
149
161
|
|
|
150
|
-
需要测试框架时,用固定版本的 `
|
|
162
|
+
需要测试框架时,用固定版本的 `LinkSettings_FetchGoogleTest`:
|
|
151
163
|
|
|
152
164
|
```cmake
|
|
153
|
-
include(
|
|
154
|
-
|
|
155
|
-
googletest
|
|
156
|
-
URL https://codeload.github.com/google/googletest/tar.gz/refs/tags/v1.17.0
|
|
157
|
-
URL_HASH SHA256=65fab701d9829d38cb77c14acdc431d2108bfdbf8979e40eb8ae567edf10b27c
|
|
158
|
-
)
|
|
159
|
-
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
|
160
|
-
FetchContent_MakeAvailable(googletest)
|
|
165
|
+
include(LinkSettings)
|
|
166
|
+
LinkSettings_FetchGoogleTest()
|
|
161
167
|
```
|
|
162
168
|
|
|
163
|
-
-
|
|
164
|
-
- 只在 `tests/`
|
|
169
|
+
- 函数内部固定 GoogleTest v1.17.0 的 URL 与 SHA-256,避免供应链漂移;版本升级只改一处。
|
|
170
|
+
- 只在 `tests/` 需要时调用;库和程序不依赖测试框架。
|
|
165
171
|
- 没有网络时,项目可以自带 vendored 副本;不要构建时静默跳过测试。
|
|
166
172
|
|
|
167
173
|
## 模板选择
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# C++ 标准与 CMake
|
|
2
|
+
|
|
3
|
+
目标:一个 target 只声明一个标准,声明在 target 上,编译数据库里的实际参数与声明一致。
|
|
4
|
+
|
|
5
|
+
## 两层声明
|
|
6
|
+
|
|
7
|
+
CMake 有两套相关机制,必须同时写:
|
|
8
|
+
|
|
9
|
+
- `target_compile_features(target visibility cxx_std_NN)`:声明目标至少需要该标准。它是 meta-feature,编译器默认标准更高时可能不产生 `-std=`;只写这一项,不能保证实际使用哪个标准。
|
|
10
|
+
- `CXX_STANDARD NN` + `CXX_STANDARD_REQUIRED ON` + `CXX_EXTENSIONS OFF`:把请求标准写死,禁止不可用时静默降级,并关闭 `gnu++NN` 扩展。
|
|
11
|
+
|
|
12
|
+
| `standard` | meta-feature | `CXX_STANDARD` | `__cplusplus` | CMake 最低版本 |
|
|
13
|
+
| --- | --- | --- | --- | --- |
|
|
14
|
+
| `c++11` | `cxx_std_11` | `11` | `201103L` | 3.1 |
|
|
15
|
+
| `c++14` | `cxx_std_14` | `14` | `201402L` | 3.1 |
|
|
16
|
+
| `c++17` | `cxx_std_17` | `17` | `201703L` | 3.8 |
|
|
17
|
+
| `c++20` | `cxx_std_20` | `20` | `202002L` | 3.12 |
|
|
18
|
+
| `c++23` | `cxx_std_23` | `23` | `202302L` | 3.20 |
|
|
19
|
+
|
|
20
|
+
`cxx_std_23` 与 `CXX_STANDARD 23` 都要求 CMake 3.20;工程 `cmake_minimum_required` 低于该版本时先升最低版本,不要悄悄降到 C++20。
|
|
21
|
+
|
|
22
|
+
## 通用函数
|
|
23
|
+
|
|
24
|
+
`assets/cmake/CompileSettings.cmake` 提供:
|
|
25
|
+
|
|
26
|
+
```cmake
|
|
27
|
+
CompileSettings_SetCxxStandard(app PRIVATE c++23)
|
|
28
|
+
CompileSettings_SetCxxStandard(greeting PUBLIC c++20)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
第一个参数是已由 `add_library` 或 `add_executable` 创建的目标,第二个是 `PUBLIC` / `PRIVATE` / `INTERFACE`,第三个是 `c++11`–`c++23`。函数内部做三步:校验目标与参数,调用 `target_compile_features`,再设置 `CXX_STANDARD` 三属性。
|
|
32
|
+
|
|
33
|
+
扩展新标准时改函数里的 `supported_standards` 与错误提示;不要在目标目录复制第二份三属性。
|
|
34
|
+
|
|
35
|
+
## 可见性
|
|
36
|
+
|
|
37
|
+
- 库的公共接口需要该标准时用 `PUBLIC`,链接者自动继承。
|
|
38
|
+
- 程序、测试、实现文件用 `PRIVATE`。
|
|
39
|
+
- `INTERFACE` 只用于纯头文件 target;不要用它绕过「标准应写在有源文件的目标上」。
|
|
40
|
+
- `target_compile_features` 重复调用会追加特性;同一目标不要同时写两个不同标准。
|
|
41
|
+
|
|
42
|
+
## 常见错误
|
|
43
|
+
|
|
44
|
+
| 写法 | 问题 |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| 只写 `target_compile_features(... cxx_std_23)` | 编译器默认更高时可能不加 `-std`,实际标准不可见 |
|
|
47
|
+
| 只写 `CXX_STANDARD 23`,不写 `CXX_STANDARD_REQUIRED` | 编译器不支持时静默降级 |
|
|
48
|
+
| 不写 `CXX_EXTENSIONS OFF` | 得到 `-std=gnu++23`,用了非标准扩展 |
|
|
49
|
+
| 用 `CMAKE_CXX_STANDARD` 全局设一次 | 所有 target 被同一个值绑住,无法按组件降档 |
|
|
50
|
+
| 在 `CMAKE_CXX_FLAGS` 里手写 `-std=c++23` | 与 target 属性冲突,数据库不可信 |
|
|
51
|
+
| 把 `cxx_std_23` 写成 `cxx_std_2023` | meta-feature 名字错误,configure 失败 |
|
|
52
|
+
|
|
53
|
+
## 验证
|
|
54
|
+
|
|
55
|
+
configure 后读 `build/<compiler>/compile_commands.json`,取最后一条 `-std=`:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
grep -o -- '-std=[^ ]*' build/clang/compile_commands.json | sort -u
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
输出必须只有一条,且等于 `-std=c++NN`;出现 `gnu++NN`、两条不同值或没有 `-std=` 都回第 1 步。`CXX_STANDARD_REQUIRED ON` 与 `CXX_EXTENSIONS OFF` 同时存在时,主流编译器会给出精确的 `-std=c++NN`;仍以数据库为准,不靠猜。
|
|
62
|
+
|
|
63
|
+
## 官方依据
|
|
64
|
+
|
|
65
|
+
- [`target_compile_features`](https://cmake.org/cmake/help/latest/command/target_compile_features.html):meta-feature、scope 与追加语义。
|
|
66
|
+
- [`CXX_STANDARD`](https://cmake.org/cmake/help/latest/prop_tgt/CXX_STANDARD.html):支持值、3.20 起支持 23、`CXX_STANDARD_REQUIRED` 与 `CXX_EXTENSIONS`。
|
|
67
|
+
- [`cmake-compile-features(7)`](https://cmake.org/cmake/help/latest/manual/cmake-compile-features.7.html):meta-feature 的「至少」语义与编译器默认标准。
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# CMake 模块与函数
|
|
2
|
+
|
|
3
|
+
目标:同一段构建逻辑只有一份权威,函数可导入、可校验、可测试,目标目录只表达差异。
|
|
4
|
+
|
|
5
|
+
## 何时抽
|
|
6
|
+
|
|
7
|
+
抽函数的条件是「已经真实复用」或「需要统一校验」,不是「看起来可以复用」:
|
|
8
|
+
|
|
9
|
+
- 至少两个 target 或两个子目录重复同一段语义,并且这段语义已经稳定。
|
|
10
|
+
- 标准、警告、RPATH 这类横切规则需要一处升级、全仓生效。
|
|
11
|
+
- 逻辑有独立失败路径,需要 `message(FATAL_ERROR)` 把输入错误挡在 configure 阶段。
|
|
12
|
+
|
|
13
|
+
一次性三行属性、仍在频繁变化的实验代码、只服务一个 target 的私有设置不抽;等第二次复用出现再抽。
|
|
14
|
+
|
|
15
|
+
## 文件布局
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
project/
|
|
19
|
+
CMakeLists.txt
|
|
20
|
+
cmake/
|
|
21
|
+
CompileSettings.cmake
|
|
22
|
+
LinkSettings.cmake
|
|
23
|
+
component/
|
|
24
|
+
CMakeLists.txt
|
|
25
|
+
apps/
|
|
26
|
+
CMakeLists.txt
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- 一个文件放一组语义相近的函数,不为每个函数建单独文件;文件过大或出现无关职责时再拆。
|
|
30
|
+
- 文件名用 UpperCamelCase,与 CMake 官方 `Modules/` 一致;按职责命名,例如 `CompileSettings.cmake`、`LinkSettings.cmake`。不用 kebab-case,也不用现在分词。
|
|
31
|
+
- 函数名用 `<ModuleName>_` 加 PascalCase:`CompileSettings_SetCxxStandard`、`LinkSettings_FetchGoogleTest`。前缀取模块文件名的原样大小写,复制到工程后不改名。
|
|
32
|
+
- 工程自己新增、不准备回流的函数才用项目前缀加 snake_case,例如 `my_project_do_something`。
|
|
33
|
+
- 只有项目真的需要时才建 `cmake/`;一个函数都没有时不建空目录。
|
|
34
|
+
|
|
35
|
+
## 导入
|
|
36
|
+
|
|
37
|
+
根 `CMakeLists.txt` 在 `project()` 之后、`add_subdirectory()` 之前:
|
|
38
|
+
|
|
39
|
+
```cmake
|
|
40
|
+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
|
41
|
+
include(CompileSettings)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- `CMAKE_MODULE_PATH` 只在根追加一次。
|
|
45
|
+
- 子目录只调用函数,不重复 `include()`;重复导入靠模块里的 `include_guard(GLOBAL)` 兜底。
|
|
46
|
+
- 模块名与文件名一致;改名时全仓搜索旧 `include()` 与旧函数名。
|
|
47
|
+
- 不使用 `include()` 执行有副作用的脚本;模块只定义函数。
|
|
48
|
+
|
|
49
|
+
## 函数契约
|
|
50
|
+
|
|
51
|
+
```cmake
|
|
52
|
+
include_guard(GLOBAL)
|
|
53
|
+
|
|
54
|
+
function(CompileSettings_SetCxxStandard target visibility standard)
|
|
55
|
+
if(NOT TARGET ${target})
|
|
56
|
+
message(FATAL_ERROR "目标 ${target} 尚未创建")
|
|
57
|
+
endif()
|
|
58
|
+
# 校验 visibility 与 standard,再设置 target 属性。
|
|
59
|
+
endfunction()
|
|
60
|
+
|
|
61
|
+
# 同一文件的第二组函数前再放一条 #--- 分隔线。
|
|
62
|
+
function(CompileSettings_SetWarnings target visibility level)
|
|
63
|
+
# 校验 LEVEL,再调用 target_compile_options。
|
|
64
|
+
endfunction()
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
规则:
|
|
68
|
+
|
|
69
|
+
- 参数顺序稳定,调用处不靠位置猜;参数多时在注释里列出类型与取值范围。
|
|
70
|
+
- 先校验目标存在、可见性合法、标准在支持列表内,再调用 `target_*`。
|
|
71
|
+
- 失败用 `FATAL_ERROR`,消息带函数名与非法值;不要 `WARNING` 后继续。
|
|
72
|
+
- 只改传入 target 的属性;不写全局变量,不读环境变量,不下载依赖。`LinkSettings_FetchGoogleTest` 是唯一例外,调用点限制在测试需要它的时候。
|
|
73
|
+
- 函数体保持幂等:同一目标重复调用不产生两份冲突属性。
|
|
74
|
+
|
|
75
|
+
## 契约注释
|
|
76
|
+
|
|
77
|
+
公开函数上方写中文 `#` 契约:一句功能、空行、边界,再用 `:param` 标位置参数、`:keyword` 标关键字参数;不写 `#[[.rst:` 与 `.. command::`,那是进 CMake 手册的模块才用的标记。同一文件的函数组之间用一条 `#---` 分隔,行注释只写原因,不画 `#===...===#` 方框。完整写法见 `references/cmake.md`。
|
|
78
|
+
|
|
79
|
+
## 测试
|
|
80
|
+
|
|
81
|
+
模块不能只在真实工程里碰运气。建一个临时最小工程,复制模块并覆盖:
|
|
82
|
+
|
|
83
|
+
1. 合法目标 + 合法可见性 + 每个支持的标准,configure 与构建成功。
|
|
84
|
+
2. 未创建的目标,configure 失败且消息可读。
|
|
85
|
+
3. 非法可见性、非法标准,configure 失败。
|
|
86
|
+
4. 重复 `include()` 不报函数重定义。
|
|
87
|
+
5. `compile_commands.json` 出现对应 `-std=`。
|
|
88
|
+
|
|
89
|
+
测试完删除临时工程;不把测试用 `CMakeLists.txt` 留在仓库。真实工程里的验证由 `steps/03-check.md` 完成。
|
|
90
|
+
|
|
91
|
+
## 迁移旧模块
|
|
92
|
+
|
|
93
|
+
1. 先在新位置建立函数与文件,保留旧入口一个提交周期(如果项目要求兼容)。
|
|
94
|
+
2. 全仓搜索旧函数名与旧 `include()`,逐个替换。
|
|
95
|
+
3. 删除旧文件,更新 `docs/architecture.md` 的职责表与结构检查。
|
|
96
|
+
4. 重新 configure;缓存里残留的旧模块不会自动消失,必要时删构建目录。
|
|
97
|
+
|
|
98
|
+
## 官方依据
|
|
99
|
+
|
|
100
|
+
- [`function()`](https://cmake.org/cmake/help/latest/command/function.html):函数在调用时执行,拥有自己的作用域。
|
|
101
|
+
- [`include_guard()`](https://cmake.org/cmake/help/latest/command/include_guard.html):按目录或全局防止重复导入。
|
|
102
|
+
- [`CMAKE_MODULE_PATH`](https://cmake.org/cmake/help/latest/variable/CMAKE_MODULE_PATH.html):`include()` 的模块搜索路径。
|
|
103
|
+
- [CMake Source Code Guide](https://github.com/Kitware/CMake/blob/master/Help/dev/source.rst):只规定 C++ 风格,没有 CMake 语言风格章节。
|
|
104
|
+
- [Modules/GoogleTest.cmake](https://github.com/Kitware/CMake/blob/master/Modules/GoogleTest.cmake):官方模块的括号文档块、行注释与 `#---` 函数分隔实例。
|
|
105
|
+
- [cpp-best-practices CompilerWarnings.cmake](https://github.com/cpp-best-practices/cmake_template/blob/main/cmake/CompilerWarnings.cmake):社区警告模块的注释与命名参数写法。
|