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

本页目录

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

1. Target 是 CMake 的工程边界 ​

CMake 语法会写不等于工程能复用。真正的问题是:一个库被别人 find_package 后,能否自动获得正确头文件、编译特性、传递依赖和运行时要求,同时不继承你的私有警告、源码路径和本机缓存。

2. 最简单心智模型 ​

target 是构建图节点,也是使用要求的容器。 PUBLIC、PRIVATE、INTERFACE 描述要求怎样沿依赖图传播。 安装导出和 consumer project 是检验 CMake 设计的最终考场。

text
Mesh::Core
  |-- PRIVATE: src/, warnings, implementation-only deps
  |-- PUBLIC : include/, cxx_std_20, public dependency targets
  +-- INTERFACE on consumers after install/export
1
2
3
4

3. 核心术语 ​

target:CMake 构建图里的命名节点,可以是可执行文件、静态库、动态库或接口库。现代 CMake 主要围绕 target 描述工程关系。

usage requirements:一个 target 对使用者提出的要求,例如 include 路径、编译特性、宏定义和需要继续链接的依赖。

PUBLIC/PRIVATE/INTERFACE:控制要求如何传播的三个作用域。PRIVATE 只给自己,PUBLIC 给自己和消费者,INTERFACE 只给消费者。

install/export:把本仓库里的 target 变成可安装、可被外部项目 find_package 的包边界。

package config:安装包提供给 CMake 的入口文件,负责告诉消费者 target 在哪里、依赖怎样恢复、版本是否匹配。

consumer project:独立于源码树的小项目,用来验证安装后的包是否真的能被外部使用。

4. 机制展开 ​

先从反例看问题 ​

include_directories(${CMAKE_SOURCE_DIR}/include) 会让目录下所有目标都获得 include path,短期方便,长期无法解释依赖来自哪里。

set(CMAKE_CXX_FLAGS ...) 会让测试、工具、第三方子项目一起继承 flags,跨平台时很容易互相污染。

工程级写法要求每个 target 自己声明需求,让依赖流向可以被 code review 和 CI 观察。

最小 target 样例 ​

下面的例子只展示核心思想:公共头暴露的东西 PUBLIC,源文件内部使用的东西 PRIVATE,纯策略可以放在 INTERFACE target。

安装导出才是真正验收 ​

build tree 能用只能说明当前源码目录下可构建;install tree 能被一个全新 consumer 找到,才说明包配置、include 路径和传递依赖没有泄漏本机状态。

导出的 config 不应含开发机绝对路径,公共依赖应通过 find_dependency 重新定位。

5. 最小示例 ​

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

text
cmake_minimum_required(VERSION 3.24)
project(Mesh VERSION 1.2.0 LANGUAGES CXX)

add_library(mesh_core src/mesh.cpp)
add_library(Mesh::Core ALIAS mesh_core)

target_compile_features(mesh_core PUBLIC cxx_std_20)
target_include_directories(mesh_core
  PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
  PRIVATE
    src)
target_link_libraries(mesh_core PUBLIC fmt::fmt PRIVATE project_warnings)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

6. 工程取舍 ​

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

7. 常见错误 ​

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

8. 调试与验证方法 ​

定义公开承诺 ​

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

text
observe package config
  -> isolate consumer project
  -> run minimal proof
  -> store evidence
1
2
3
4

建立干净环境 ​

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

text
observe install/export
  -> isolate package config
  -> run minimal proof
  -> store evidence
1
2
3
4

固定工具版本 ​

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

text
observe PUBLIC/PRIVATE/INTERFACE
  -> isolate install/export
  -> run minimal proof
  -> store evidence
1
2
3
4

保存失败证据 ​

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

text
observe usage requirements
  -> isolate PUBLIC/PRIVATE/INTERFACE
  -> run minimal proof
  -> store evidence
1
2
3
4

区分私有与公开 ​

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

text
observe target
  -> isolate usage requirements
  -> run minimal proof
  -> store evidence
1
2
3
4

审查跨平台差异 ​

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

text
observe consumer project
  -> isolate target
  -> run minimal proof
  -> store evidence
1
2
3
4

限制全局状态 ​

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

text
observe package config
  -> isolate consumer project
  -> run minimal proof
  -> store evidence
1
2
3
4

做升级测试 ​

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

text
observe install/export
  -> isolate package config
  -> run minimal proof
  -> store evidence
1
2
3
4

设置回滚入口 ​

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

text
observe PUBLIC/PRIVATE/INTERFACE
  -> isolate install/export
  -> run minimal proof
  -> store evidence
1
2
3
4

写入 CI ​

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

text
observe usage requirements
  -> isolate PUBLIC/PRIVATE/INTERFACE
  -> run minimal proof
  -> store evidence
1
2
3
4

管理例外 ​

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

text
observe target
  -> isolate usage requirements
  -> run minimal proof
  -> store evidence
1
2
3
4

保持证据总账 ​

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

text
observe consumer project
  -> isolate target
  -> run minimal proof
  -> store evidence
1
2
3
4

9. 本篇专属检查表 ​

  1. 公共头是否暴露该依赖类型。
  2. 警告 flags 是否 PRIVATE。
  3. 安装树是否可重定位。
  4. 是否有 consumer project。
  5. Presets 是否覆盖 Debug/Release。
检查点通过标准失败时优先看哪里
target有可重复命令、报告或 consumer 证明target 属性、CI 日志、符号报告、包元数据
usage requirements有可重复命令、报告或 consumer 证明target 属性、CI 日志、符号报告、包元数据
PUBLIC/PRIVATE/INTERFACE有可重复命令、报告或 consumer 证明target 属性、CI 日志、符号报告、包元数据
install/export有可重复命令、报告或 consumer 证明target 属性、CI 日志、符号报告、包元数据
package config有可重复命令、报告或 consumer 证明target 属性、CI 日志、符号报告、包元数据
consumer project有可重复命令、报告或 consumer 证明target 属性、CI 日志、符号报告、包元数据

10. 练习任务 ​

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

12. 总结 ​

《工程级 CMake Target 设计规范 / Engineering Modern CMake Target Design》的核心不是多记几个命令,而是把 target、usage requirements、PUBLIC/PRIVATE/INTERFACE、install/export、package config、consumer project 变成可审查、可复现、可回滚的工程证据。

返回 08 工程构建质量路线

深化问题 1:usage requirements 怎样变成证据 ​

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

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

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

深化问题 2:PUBLIC/PRIVATE/INTERFACE 怎样变成证据 ​

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

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

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

深化问题 3:install/export 怎样变成证据 ​

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

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

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

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

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

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

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

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

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

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

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

深化问题 6:target 怎样变成证据 ​

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

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

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

深化问题 7:usage requirements 怎样变成证据 ​

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

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

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

深化问题 8:PUBLIC/PRIVATE/INTERFACE 怎样变成证据 ​

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

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

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

深化问题 9:install/export 怎样变成证据 ​

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

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

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

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

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

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

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

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

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

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

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

深化问题 12:target 怎样变成证据 ​

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

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

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

深化问题 13:usage requirements 怎样变成证据 ​

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

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

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

深化问题 14:PUBLIC/PRIVATE/INTERFACE 怎样变成证据 ​

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

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

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

深化问题 15:install/export 怎样变成证据 ​

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

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

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

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

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

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

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

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

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

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

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

深化问题 18:target 怎样变成证据 ​

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

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

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

深化问题 19:usage requirements 怎样变成证据 ​

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

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

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

深化问题 20:PUBLIC/PRIVATE/INTERFACE 怎样变成证据 ​

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

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

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

深化问题 21:install/export 怎样变成证据 ​

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

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

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

最后更新于:

Pager
上一篇1. C++ 工程构建质量、ABI 与发布证据路线 / C++ Build Quality, ABI, and Release Evidence Roadmap
下一篇3. 测试、静态分析与 Sanitizer 门禁 / Testing, Analysis, and Sanitizer Gates

持续记录,持续成长

Copyright © Tidenflow