Skip to content

Commit b50faf5

Browse files
committed
fix(manifest): 自动推断的 lib 备注要说出实际找到的那个扩展名
macOS e2e 抓到的:我把备注从「lib from .cppm in src/」改成了「lib from module interface in src/」,25_convention_mode.sh 断言的是前者。 这条我判断为文案改得不够好,而不是测试过时。备注该说的是**实际找到了什么**: .cppm 工程输出与从前逐字不变(那条断言原样通过),而声明了 module_extensions 的工程会看到「lib from .ixx in src/」—— 说 .cppm 才是名不副实。 顺带 CHANGELOG 补 2026.8.11.1 条目。
1 parent 968e06f commit b50faf5

2 files changed

Lines changed: 89 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,85 @@
33
> 本文件追踪 `mcpp-community/mcpp` 公开仓的版本演进。
44
> 格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)
55
6+
## [2026.8.11.1] — 2026-08-11
7+
8+
### 新增
9+
10+
- **`[build] module_extensions` —— 哪些扩展名是模块接口,由工程声明。**
11+
12+
```toml
13+
[build]
14+
module_extensions = [".ixx", ".ccm"]
15+
```
16+
17+
追加到内置的 `.cppm`。声明一个扩展名会**同时**做三件事:默认 sources glob 跟着
18+
变宽(文件才能被**找到**)、这些单元走**模块**规则(产 BMI、`.o` 无条件进链接)、
19+
新鲜度快路径**扫描**它们(加 `import` 会让构建图作废)。一个键而不是三处配置。
20+
21+
任何扩展名都接受,唯独拒绝已代表其他角色的(`.cpp` `.c` `.h` `.S` …)——
22+
manifest **错误**而非警告,因为宣称 `.c` 是模块接口会把 C 文件送进 C++ 模块规则,
23+
最终失败在一个既不提文件也不提这个键的地方。
24+
25+
⚠️ `.ccm`/`.cxxm`/`.ixx` **不进内置默认**。进了的话默认 glob 会跟着变宽,
26+
于是 `src/` 下躺着 vendored MSVC-only `.ixx`**已发布包会在一次 mcpp 升级后
27+
突然开始编译它** —— 而包作者改不了已经发出去的 tarball。
28+
29+
- **`[build] build_program_timeout` —— `build.mcpp` 的运行上限可配置。**
30+
31+
优先级 `MCPP_BUILD_PROGRAM_TIMEOUT` > **该包自己的** manifest > 内置 600s,
32+
`macos_deployment_target` 同构。超时报错**点名要改的那份 `mcpp.toml`** ——
33+
依赖超时时改自己的那份不会有任何效果,这正是 [#410](https://github.com/mcpp-community/mcpp/issues/410)
34+
从外面看到的样子。不写这个键与写 `0` 不是一回事:不写=用默认上限,`0`=不设上限。
35+
36+
- **`mcpp self doctor` 报告构建策略。** 生效的模块接口扩展名表、生效的超时值
37+
**及其来源**、以及本平台的 deadline 是否**真的**强制执行。
38+
另外 `module_extensions` 里零命中的条目会告警 —— 否则打字错误(`.ixxx`)与
39+
「这个工程还没有」无法区分。
40+
41+
### 修复
42+
43+
- **超时上限在 Windows 上从来就是空操作。** `capture_exec_deadline` 只在 POSIX
44+
生效,其余平台直接回落到无界启动器 —— 于是 `mcpp test --timeout`
45+
`--build-timeout`、以及这个新键在 Windows 上**设了等于没设**。现在两侧各有实现:
46+
Windows 把子进程放进 **Job 对象**并在到期时关闭它,杀掉的是**整棵进程树**而不只是
47+
直接子进程(否则一个还攥着捕获管道的孙进程会让杀掉之后的读取一直挂住)。
48+
49+
- **`.mm`(Objective-C++)的对象编了但永远不进链接** —— `is_implementation_source`
50+
的清单漏了它。
51+
52+
- **stage 一个含汇编的依赖会静默丢掉那些源文件** —— 兜底 glob 漏了全部三种汇编扩展名。
53+
54+
### 架构
55+
56+
- **「扩展名 → 角色」此前在 9 个文件 20 处推导,分成 8 份互不一致的清单**
57+
(三份「什么算实现单元」、四份「什么算源文件」)。
58+
[#272](https://github.com/mcpp-community/mcpp/pull/272) 修了链接侧,却漏了
59+
`pick_rule` —— 边上**声明**了 BMI 产物(那行读 `providesModule`),命令行却丢了
60+
`-fmodule-output=`
61+
62+
收敛的形状不是「大家都调同一个函数」,而是**分类只发生一次**(文件进图时),
63+
之后当数据传递(`SourceUnit::kind``CompileUnit::kind`)。扫描器手里本来就有
64+
所属包的 manifest,所以这一步没有新增任何管道。
65+
66+
- **mcpp 现在每次都显式告诉编译器某个单元是模块接口**(`-x c++` / `-x c++-module` /
67+
`/interface /TP`),而不是去维护「哪个驱动认哪个后缀」。实测(GCC 16.1 / Clang 22.1):
68+
**Clang 根本不认 `.ixx`** —— 把它当链接输入、警告、**退出码 0 且不产 BMI**;
69+
而显式旗标在已识别后缀上**幂等**(Clang 的 `.cppm` BMI 逐字节相同)。
70+
一张会过期、错了还静默的表不该存在。
71+
72+
- `src/platform/` 拆成 `unix/ windows/ linux/ macos/`;`mcpp.platform.process`
73+
对有界运行**单点 `if constexpr` 分派**,取代此前散落的平台分支。
74+
75+
### 兼容性
76+
77+
- 未配置时**构建图零差分**:同样的文件被编、同样的 BMI、同样的对象进链接、
78+
同样的指纹目录。
79+
- `module_extensions` ****指纹(它改图的形态);`build_program_timeout` **不进**
80+
(它不改任何一条边 —— 进了会让「抬高超时」重建全世界)。
81+
- ⚠️ 旧版 mcpp 遇到 `module_extensions` 会警告+忽略,然后把那些文件当普通翻译单元
82+
编译 —— **错误的构建**而不是干净的失败。发布用了这个键的包必须声明 mcpp 版本下限
83+
(见 `docs/10-publishing-a-library.md`)。
84+
685
## [2026.8.10.3] — 2026-08-10
786

887
### 修复

src/manifest/toml.cppm

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1668,16 +1668,23 @@ void apply_defaults_and_infer(Manifest& m, const std::filesystem::path& root) {
16681668
// "Is there a module interface under src/" — asked through the table,
16691669
// so a library whose interfaces are all `.ixx` still infers a lib
16701670
// target instead of silently having none.
1671-
bool hasModuleInterface = false;
1671+
//
1672+
// The extension that answered is kept for the inferred-note: saying
1673+
// ".cppm" when the project's interfaces are `.ixx` would be a note that
1674+
// names the wrong thing, and a `.cppm` project still prints exactly
1675+
// what it always did.
1676+
std::string moduleInterfaceExt;
16721677
if (std::filesystem::is_directory(root / "src", ec)) {
16731678
for (auto& e : std::filesystem::recursive_directory_iterator(root / "src", ec)) {
16741679
if (ec) break;
16751680
if (e.is_regular_file(ec) && !ec
16761681
&& mcpp::produces_bmi(mcpp::classify(e.path(), extTable))) {
1677-
hasModuleInterface = true; break;
1682+
moduleInterfaceExt = e.path().extension().string();
1683+
break;
16781684
}
16791685
}
16801686
}
1687+
const bool hasModuleInterface = !moduleInterfaceExt.empty();
16811688

16821689
if (hasMain) {
16831690
Target t;
@@ -1693,7 +1700,7 @@ void apply_defaults_and_infer(Manifest& m, const std::filesystem::path& root) {
16931700
t.kind = Target::Library;
16941701
m.targets.push_back(std::move(t));
16951702
m.inferredNotes.push_back(
1696-
std::format("target {} (lib from module interface in src/)", m.package.name));
1703+
std::format("target {} (lib from {} in src/)", m.package.name, moduleInterfaceExt));
16971704
}
16981705
// If neither, no auto-target — caller will error if it needs one.
16991706
}

0 commit comments

Comments
 (0)