Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← C++ 编程 / C++ Programming

构建、测试与 ABI / Build, Testing & ABI

1. C++ 工程构建质量、ABI 与发布证据路线 / C++ Build Quality, ABI, and Release Evidence Roadmap

2. 工程级 CMake Target 设计规范 / Engineering Modern CMake Target Design

3. 测试、静态分析与 Sanitizer 门禁 / Testing, Analysis, and Sanitizer Gates

4. 包、ABI 与性能证据总账 / Packaging, ABI, and Performance Evidence Ledger

5. 链接诊断、库边界与符号证据 / Link Diagnostics, Library Boundaries, and Symbol Evidence

6. ABI 边界与兼容策略 / ABI Boundaries and Compatibility Policy

7. 依赖、CI、制品与发布流程 / Dependencies, CI, Artifacts, and Release Flow

8. 工程构建综合复习:发布 Mesh::Core / Engineering Build Review: Releasing Mesh::Core

本页目录

测试、静态分析与 Sanitizer 门禁 / Testing, Analysis, and Sanitizer Gates ​

1. 质量门禁要覆盖不同风险层 ​

很多 C++ 项目把“能编译”和“跑了几个单测”当作质量结论。工程上更可靠的做法是把不同工具放到不同风险层:未运行路径靠静态分析,已运行路径靠 sanitizer,输入空间靠 fuzz,性能退化靠 benchmark。

2. 最简单心智模型 ​

质量门禁不是一个工具,而是一组互补证据。 每个门禁都要回答它能发现什么、发现不了什么、失败后谁处理。 Release 构建也必须验证,因为优化、NDEBUG、内联和运行库选择会改变行为。

text
compile warnings/static analysis -> pattern risks before running
unit/integration tests         -> expected behavior
sanitizers                     -> runtime memory/UB/thread errors
fuzz                           -> unexpected input and state space
benchmark/profile              -> performance budget evidence
1
2
3
4
5

3. 核心术语 ​

单元测试:验证一个小范围逻辑是否满足预期,适合覆盖纯函数、边界条件和容易回归的业务规则。

集成测试:让多个模块或外部依赖一起运行,检查接口连接、资源生命周期、配置和真实 I/O 路径。

静态分析:不运行程序就检查源码或编译中间信息,适合发现未初始化、悬空引用、可疑分支和编码规范问题。

ASan/UBSan/TSan:运行期插桩工具,分别关注内存错误、未定义行为和数据竞争。它们依赖测试把代码路径跑起来。

fuzz:用大量自动生成或变异输入持续冲击解析器、协议处理和状态机,寻找人手写用例不容易覆盖的崩溃路径。

benchmark:可重复的性能测量。它更关心趋势、预算和回归阈值,而不是某一次运行的漂亮数字。

4. 机制展开 ​

先定义门禁含义 ​

门禁不是为了让 CI 看起来严格,而是为了阻止风险进入主干、包和发布渠道。

一个门禁应有清晰失败消息、负责人、允许豁免的规则和回归测试要求。

Sanitizer 的边界 ​

ASan 关注越界和 use-after-free,UBSan 关注未定义行为,TSan 关注数据竞争。

它们只覆盖被执行路径;没有跑到的路径不会自动安全。

Sanitizer 构建常常改变内存布局和性能,因此不能把 sanitizer 性能当成 release 性能。

benchmark 不是跑得快截图 ​

性能证据要固定输入、机器条件、构建类型、统计方法和噪声阈值。

一次运行变快可能只是缓存或调度偶然;基线和趋势比单次数字更重要。

5. 最小示例 ​

下面的示例不是完整项目,而是为了把本篇概念落到可审查文本。阅读代码时关注它暴露了哪些边界,而不是照抄每个名字。

text
add_library(project_sanitizers INTERFACE)
target_compile_options(project_sanitizers INTERFACE
  $<$<CXX_COMPILER_ID:GNU,Clang>:-fsanitize=address,undefined;-fno-omit-frame-pointer>)
target_link_options(project_sanitizers INTERFACE
  $<$<CXX_COMPILER_ID:GNU,Clang>:-fsanitize=address,undefined>)

add_executable(mesh_tests tests/mesh_tests.cpp)
target_link_libraries(mesh_tests PRIVATE Mesh::Core project_sanitizers)
1
2
3
4
5
6
7
8

6. 工程取舍 ​

选择收益风险需要的证据
只在本机验证反馈最快环境不可复现仅适合草稿,不适合作为发布结论
CI 快速门禁阻止常见错误覆盖不完整明确矩阵、日志和失败归属
完整发布门禁证据最强成本更高制品、符号、SBOM、ABI 和回滚记录
最小消费者测试最接近用户需要维护样例独立目录、安装包、运行输出

7. 常见错误 ​

  • 把“当前源码树能构建”误认为“安装包能被别人消费”。
  • 把 PRIVATE 实现细节通过头文件、导出符号或包配置泄漏出去。
  • 只保存最终二进制,不保存构建输入、依赖锁、调试符号和版本信息。
  • 只在 Debug 测试,不在 Release 或发布配置里测试。
  • 把 CI 缓存当成依赖管理,把绿色状态当成发布结论。
  • 遇到链接或 ABI 问题时只改 flags,不留下能够复盘的符号证据。

8. 调试与验证方法 ​

定义公开承诺 ​

写清楚本库承诺源码兼容、二进制兼容、协议兼容还是仅内部使用。承诺越模糊,升级事故越难判责。

text
observe 集成测试
  -> isolate 静态分析
  -> run minimal proof
  -> store evidence
1
2
3
4

建立干净环境 ​

用全新 build directory 和最小 consumer project 验证,不依赖源码树中的 include 路径和本机缓存。

text
observe 单元测试
  -> isolate 集成测试
  -> run minimal proof
  -> store evidence
1
2
3
4

固定工具版本 ​

记录编译器、CMake、Ninja、包管理器、系统镜像和关键 flags,避免把偶然环境当成规则。

text
observe benchmark
  -> isolate 单元测试
  -> run minimal proof
  -> store evidence
1
2
3
4

保存失败证据 ​

失败日志、符号报告、测试输出和构建命令要能被别人复现,而不是只留一句“CI failed”。

text
observe fuzz
  -> isolate benchmark
  -> run minimal proof
  -> store evidence
1
2
3
4

区分私有与公开 ​

私有实现可以快速迭代;公开头、导出符号、包元数据和 ABI policy 必须谨慎变更。

text
observe ASan/UBSan/TSan
  -> isolate fuzz
  -> run minimal proof
  -> store evidence
1
2
3
4

审查跨平台差异 ​

Windows 的 DLL/import lib/PDB 与 Linux 的 so/SONAME/RPATH/debug file 不同,不能用一个平台的经验套全部。

text
observe 静态分析
  -> isolate ASan/UBSan/TSan
  -> run minimal proof
  -> store evidence
1
2
3
4

限制全局状态 ​

全局 include、全局 flags、隐式环境变量和手工 PATH 修改都会让构建不可解释。

text
observe 集成测试
  -> isolate 静态分析
  -> run minimal proof
  -> store evidence
1
2
3
4

做升级测试 ​

old consumer + new library、new consumer + package install 是比单纯编译源码更接近用户现场的测试。

text
observe 单元测试
  -> isolate 集成测试
  -> run minimal proof
  -> store evidence
1
2
3
4

设置回滚入口 ​

发布前准备上一稳定制品、数据库或文件格式迁移策略、插件兼容说明和符号包。

text
observe benchmark
  -> isolate 单元测试
  -> run minimal proof
  -> store evidence
1
2
3
4

写入 CI ​

能自动检查的规则不要只写在文章里;把它变成 preset、脚本、workflow 或 release checklist。

text
observe fuzz
  -> isolate benchmark
  -> run minimal proof
  -> store evidence
1
2
3
4

管理例外 ​

允许临时豁免时必须记录原因、过期时间和补偿测试,否则门禁会慢慢失去意义。

text
observe ASan/UBSan/TSan
  -> isolate fuzz
  -> run minimal proof
  -> store evidence
1
2
3
4

保持证据总账 ​

把构建输入、依赖锁、测试、ABI、性能、SBOM、签名和制品 hash 放在同一发布记录中。

text
observe 静态分析
  -> isolate ASan/UBSan/TSan
  -> run minimal proof
  -> store evidence
1
2
3
4

9. 本篇专属检查表 ​

  1. 失败日志是否定位到文件行。
  2. 门禁是否覆盖 Debug 和 Release。
  3. TSan 是否单独 job。
  4. fuzz corpus 是否保存。
  5. 性能阈值是否有噪声区间。
检查点通过标准失败时优先看哪里
单元测试有可重复命令、报告或 consumer 证明target 属性、CI 日志、符号报告、包元数据
集成测试有可重复命令、报告或 consumer 证明target 属性、CI 日志、符号报告、包元数据
静态分析有可重复命令、报告或 consumer 证明target 属性、CI 日志、符号报告、包元数据
ASan/UBSan/TSan有可重复命令、报告或 consumer 证明target 属性、CI 日志、符号报告、包元数据
fuzz有可重复命令、报告或 consumer 证明target 属性、CI 日志、符号报告、包元数据
benchmark有可重复命令、报告或 consumer 证明target 属性、CI 日志、符号报告、包元数据

10. 练习任务 ​

  • 建立一个只有一个库和一个 consumer 的最小工程,证明安装树可用。
  • 故意破坏一个 PUBLIC/PRIVATE 作用域,观察消费者构建失败方式。
  • 保存一次链接或 ABI 报告,并写下它能证明什么、不能证明什么。
  • 把一个手工验证命令改成 CI 步骤,并让失败消息能指向具体文件或配置。
  • 写一份 release evidence 小清单,列出制品、符号、依赖、测试和回滚入口。

12. 总结 ​

《测试、静态分析与 Sanitizer 门禁 / Testing, Analysis, and Sanitizer Gates》的核心不是多记几个命令,而是把 单元测试、集成测试、静态分析、ASan/UBSan/TSan、fuzz、benchmark 变成可审查、可复现、可回滚的工程证据。

返回 08 工程构建质量路线

深化问题 1:集成测试 怎样变成证据 ​

围绕 集成测试 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:用全新 build directory 和最小 consumer project 验证,不依赖源码树中的 include 路径和本机缓存。

text
rule: 集成测试
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 2:静态分析 怎样变成证据 ​

围绕 静态分析 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:记录编译器、CMake、Ninja、包管理器、系统镜像和关键 flags,避免把偶然环境当成规则。

text
rule: 静态分析
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 3:ASan/UBSan/TSan 怎样变成证据 ​

围绕 ASan/UBSan/TSan 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:失败日志、符号报告、测试输出和构建命令要能被别人复现,而不是只留一句“CI failed”。

text
rule: ASan/UBSan/TSan
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 4:fuzz 怎样变成证据 ​

围绕 fuzz 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:私有实现可以快速迭代;公开头、导出符号、包元数据和 ABI policy 必须谨慎变更。

text
rule: fuzz
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 5:benchmark 怎样变成证据 ​

围绕 benchmark 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:Windows 的 DLL/import lib/PDB 与 Linux 的 so/SONAME/RPATH/debug file 不同,不能用一个平台的经验套全部。

text
rule: benchmark
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 6:单元测试 怎样变成证据 ​

围绕 单元测试 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:全局 include、全局 flags、隐式环境变量和手工 PATH 修改都会让构建不可解释。

text
rule: 单元测试
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 7:集成测试 怎样变成证据 ​

围绕 集成测试 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:old consumer + new library、new consumer + package install 是比单纯编译源码更接近用户现场的测试。

text
rule: 集成测试
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 8:静态分析 怎样变成证据 ​

围绕 静态分析 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:发布前准备上一稳定制品、数据库或文件格式迁移策略、插件兼容说明和符号包。

text
rule: 静态分析
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 9:ASan/UBSan/TSan 怎样变成证据 ​

围绕 ASan/UBSan/TSan 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:能自动检查的规则不要只写在文章里;把它变成 preset、脚本、workflow 或 release checklist。

text
rule: ASan/UBSan/TSan
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 10:fuzz 怎样变成证据 ​

围绕 fuzz 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:允许临时豁免时必须记录原因、过期时间和补偿测试,否则门禁会慢慢失去意义。

text
rule: fuzz
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 11:benchmark 怎样变成证据 ​

围绕 benchmark 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:把构建输入、依赖锁、测试、ABI、性能、SBOM、签名和制品 hash 放在同一发布记录中。

text
rule: benchmark
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 12:单元测试 怎样变成证据 ​

围绕 单元测试 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:写清楚本库承诺源码兼容、二进制兼容、协议兼容还是仅内部使用。承诺越模糊,升级事故越难判责。

text
rule: 单元测试
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 13:集成测试 怎样变成证据 ​

围绕 集成测试 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:用全新 build directory 和最小 consumer project 验证,不依赖源码树中的 include 路径和本机缓存。

text
rule: 集成测试
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 14:静态分析 怎样变成证据 ​

围绕 静态分析 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:记录编译器、CMake、Ninja、包管理器、系统镜像和关键 flags,避免把偶然环境当成规则。

text
rule: 静态分析
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 15:ASan/UBSan/TSan 怎样变成证据 ​

围绕 ASan/UBSan/TSan 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:失败日志、符号报告、测试输出和构建命令要能被别人复现,而不是只留一句“CI failed”。

text
rule: ASan/UBSan/TSan
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 16:fuzz 怎样变成证据 ​

围绕 fuzz 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:私有实现可以快速迭代;公开头、导出符号、包元数据和 ABI policy 必须谨慎变更。

text
rule: fuzz
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 17:benchmark 怎样变成证据 ​

围绕 benchmark 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:Windows 的 DLL/import lib/PDB 与 Linux 的 so/SONAME/RPATH/debug file 不同,不能用一个平台的经验套全部。

text
rule: benchmark
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 18:单元测试 怎样变成证据 ​

围绕 单元测试 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:全局 include、全局 flags、隐式环境变量和手工 PATH 修改都会让构建不可解释。

text
rule: 单元测试
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 19:集成测试 怎样变成证据 ​

围绕 集成测试 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:old consumer + new library、new consumer + package install 是比单纯编译源码更接近用户现场的测试。

text
rule: 集成测试
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 20:静态分析 怎样变成证据 ​

围绕 静态分析 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:发布前准备上一稳定制品、数据库或文件格式迁移策略、插件兼容说明和符号包。

text
rule: 静态分析
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

深化问题 21:ASan/UBSan/TSan 怎样变成证据 ​

围绕 ASan/UBSan/TSan 写一个项目规则:谁可以修改,修改后跑什么命令,失败时保存哪些输出。

对应的工程动作是:能自动检查的规则不要只写在文章里;把它变成 preset、脚本、workflow 或 release checklist。

text
rule: ASan/UBSan/TSan
owner: module maintainer
proof: command + report + artifact
failure: block merge or require documented exception
1
2
3
4

最后更新于:

Pager
上一篇2. 工程级 CMake Target 设计规范 / Engineering Modern CMake Target Design
下一篇4. 包、ABI 与性能证据总账 / Packaging, ABI, and Performance Evidence Ledger

持续记录,持续成长

Copyright © Tidenflow