Skip to content

Latest commit

 

History

History
95 lines (75 loc) · 6.12 KB

library-interface.md

File metadata and controls

95 lines (75 loc) · 6.12 KB

SPEC-008:库的接口:公开模块、发布闭包与两种形态的一致

项 值
规范编号 SPEC-008
标题 库的接口:公开模块、发布闭包与两种形态的一致
状态 草案 v0.2
版本 0.2
最后修改 2026-10-11
对应实现 第一阶段(只警告)mcpp >= 2026.9.28.3;v0.2 的唯一定义、特性接口与 Form B lib mcpp >= 2026.10.11.1;第二阶段未实现
相关设计文档 .agents/docs/2026-09-28-build-cost-foreign-toolsets-and-library-surface-design.md(§5)
相关 issue mcpp#734、mcpp#797
使用文档 docs/04 - mcpp.toml([lib])、docs/12 - 二进制分发

本规范规定一个库包对消费方公开什么、mcpp pack 发布什么,以及同一个包以源码形态和打包形态 到达消费方时接口保持一致的条件。消费方包括目标与构建程序:构建程序使用的库(SPEC-007 §10) 的接口由本规范规定。

规范用语与实现状态标记见 规范索引。

1. 目标

性质 含义
语义清楚 消费方可以导入的、包随包发布的、包保留的,各有一个名字
一致 无论包以源码还是以打包形态到达,消费方看到同一个接口
稳定 接口是一个由包自己的声明决定的集合,消费方可以跨版本依赖它
可分发 打包形态完整(消费方可以基于它编译)且最小(接口闭包之外的单元不外泄)
简洁 每个包一处声明,以 C++ 本身表达(一个模块及其转出),不另维护列表
兼容 今天能构建的清单不因本规范停止构建

2. 定义

  • 接口根:[lib].path(Form B 描述符的 lib)所指的单元;未写时按约定为 src/<包名最后一段>.<模块接口扩展名>。它必须声明主模块接口(export module <name>;),不能是分区。
  • 公开模块:接口根的模块,以及它用 export import 传递地转出的模块与分区;加上每个已启用 特性的 sources 加入的主模块接口单元及其转出闭包。消费方可以依赖的就是这些名字。没有接口根 的包不陈述接口,它导出的每个主模块都是公开模块。
  • 可导入模块:包在该配置中编译的全部导出主模块。可导入而不公开的模块引起 W3。
  • 公开头文件:include/ 下的文件(docs/12)。
  • 接口:公开模块与公开头文件的合集。
  • 发布闭包:公开模块的接口传递地导入的每个单元,无论是否转出。消费方构建公开模块的 BMI 需要它们。
  • 保留单元:包的其余单元。它们编入库中,但不随包发布。

公开模块与发布闭包的区分是本规范的核心:前者是消费方可以依赖的契约,后者是 BMI 的构建需要。

3. 规则

  • I1 一个包的接口与它到达消费方的形态无关,也与消费方是目标还是构建程序无关。引擎以一个 函数(mcpp.modgraph.library_interface)回答,所有读者调用它。(第一阶段:由 W3 警告陈述, 源码构建不受限制;对构建程序同样适用,v0.2)
  • I2 一个包至多有一个接口根,因此它有一个与身份 (namespace, name) 对应的可导入名字。代码 组织为多个模块的包,由接口根以 export import 转出它们(门面形式)。不设接口根的列表。特性是 例外(v0.2):特性是否启用由消费方决定,export import 无法表达"只在特性启用时转出",因此特性 加入的接口单元就是该特性的接口;rule_module 必须是其中之一。
  • I6 [modules] exports(Form B 的 modules)是对公开模块的断言,不指定接口根:本包的构建中 未列出的公开模块是错误,strict 时列出而不公开的名字也是错误。(v0.2)
  • I3 公开模块的名字应当以包的身份为前缀:<namespace>.<name> 或其下的 <namespace>.<name>.<part>,因为模块名在一个程序中是全局的。(第一阶段:建议;引擎已拒绝同一 图中的同名模块)
  • I4 只发布头文件的接口是正当的。库可以用模块实现自己而只发布头文件,例如 C API。这样的库 没有接口根,公开模块为空。
  • I5 打包形态恰好包含发布闭包与公开头文件。(已实现)

4. 诊断(第一阶段:只警告,mcpp >= 2026.9.28.3)

每条诊断由读取接口的步骤发出,且只对能修改它的包发出。

编号 发出者 条件 陈述的后果
W1 mcpp build,只对当前构建的包 lib 目标导出模块且没有接口根 mcpp pack 发布的库不带模块接口
W2 mcpp pack 有未进入发布闭包的导出主模块,逐个写出 使用打包形态的消费方无法导入它们
W3 mcpp build,只对当前构建的包 包导入了某个有接口根的依赖的非公开模块;该依赖不是本包所在工作区的成员(同一工作区的成员总是与本包一起从源码构建) 从源码构建成功,对打包形态会失败
W4 mcpp build,对依赖 依赖以 [lib] path 写出的接口根不存在(本包自己的构建中为错误) 它不向消费方陈述接口根

mcpp pack 的 "Withheld" 一行列出每个未发布的单元,包括包没有接口根的情形。(已实现)

5. 第二阶段(条件,未设计)

W1 与 W2 在三个条件同时成立时成为错误,并提供声明"只发布头文件"的写法:

  1. mcpp-index 的扫描报告了导出模块而没有接口根的库,以及其中有意只发布头文件的库;
  2. 索引 min_mcpp 所指的引擎版本能读取该声明;更旧的引擎忽略 [lib] 中的未知键,因此声明不会 使旧客户端失败,但也不会在旧客户端上生效;
  3. 本规范进入评审状态。

扫描结果为零时,W1 与 W2 已完成它们的作用,第二阶段只剩报告。

6. 变更记录

版本 日期 变更
0.1 2026-09-28 首版草案(mcpp#734):定义、I1 至 I5、第一阶段的 W1 至 W3 与完整的 Withheld 报告。
0.2 2026-10-11 mcpp#797:接口由一个函数定义,目标、构建程序、mcpp pack 与校验共用(I1);特性接口(I2);exports 为断言(I6);Form B lib;W4。