Skip to content

Commit bd80e53

Browse files
committed
docs(agents): post-0.0.89 roadmap — std dialect-flags consistency (#210) + leftover optimization plan
D1 (priority, issue #210): dialect-class flags (-freflection et al) become module-graph-global via -std='s existing channels (global $cxxflags, std BMI build commands, scan commands); known-list extraction + [build] dialect_cxxflags escape hatch; fingerprint already keys them. Also: Part C startup checklist vs 0.0.89 state, Part A debt closure, MinGW polish items, release-infra validation plan.
1 parent a769497 commit bd80e53

1 file changed

Lines changed: 164 additions & 0 deletions

File tree

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# 0.0.89 后路线:std 模块方言旗标一致性(#210)+ 遗留优化清单 — 设计方案
2+
3+
> 2026-07-13 · 基于 0.0.89(f6fd39e,Part A 抽象层 + Part B MinGW 已落地)
4+
> 输入:issue #210(`-freflection` 未进 std BMI 预构建)+ 0.0.89 交付后的遗留清单
5+
> 前置文档:`2026-07-13-toolchain-backend-abstraction-msvc-mingw-design.md`(主设计,Part C 未动)
6+
> + `2026-07-13-compiler-dialect-touchpoint-audit.md`
7+
8+
## 0. 一句话
9+
10+
最高优先是 **D1:方言类编译旗标(`-freflection` 一类"改变标准库头暴露什么声明"的 flag)
11+
必须成为模块图全局属性,走 `-std=` 已有的通道**——进 std/std.compat BMI 预构建命令、
12+
进全局 `$cxxflags`、进扫描命令;指纹早已把它算进缓存键,漏的只是命令构造(#210 根因,
13+
报告者定位完全正确)。其余为 Part C(MSVC 原生构建)启动核对表、Part A 债务收尾、
14+
MinGW 打磨与发布基建四组小项。
15+
16+
## 1. D1 — std 模块 BMI 方言旗标一致性(issue #210)
17+
18+
### 1.1 根因(代码落地)
19+
20+
- `prepare.cppm:2636` `ensure_built(*tc, fp.hex, standard, m->cppStandard.flag, …)`
21+
std BMI 预构建**只接收语言标准 flag**(#98/#100 的成果),用户 `[build].cxxflags`
22+
不在形参里;gcc/clang 的 `std_module_build_command(s)` 相应只拼 `cppStandardFlag`
23+
- 用户 cxxflags 的既有通道是 **per-unit** `$unit_cxxflags`(ninja_backend.cppm:512)——
24+
只到项目自身 TU,std BMI 与依赖包 BMI 都看不到。
25+
- 指纹**已经**包含它(`canonical_compile_flags(*m)`,prepare.cppm:2624)→ 缓存键正确、
26+
目录会分裂,但分裂出的目录里装的仍是不带该 flag 的 std BMI——**缓存不背锅,
27+
命令构造背锅**(与 issue 的诊断一致)。
28+
- 为什么 `-freflection` 致命:libstdc++ 的 `<meta>` 整体被
29+
`__cpp_impl_reflection >= 202603L` 守卫,该宏仅由 `-freflection` 定义——不带它编出的
30+
std BMI **结构上**不含 `std::meta`
31+
32+
### 1.2 关键推论:只修 std 不够(报告者的 fmt.gcm 二次错误)
33+
34+
报告者手工给 std BMI 加上 `-freflection` 后,混合构建立刻在 `fmt.gcm` 上撞出 BMI 兼容
35+
错误:依赖包的模块 TU 仍按包自有 flags(无 `-freflection`)编译,导入"带反射的 std"
36+
时 GCC 的模块方言校验拒绝。结论:**这类 flag 与 `-std=` 同性质——是整张模块图的方言,
37+
不是某个 TU 的私货**。修法必须让它落在 `-std=` 走过的每一处:
38+
39+
| `-std=` 今天到达的地方 | 机制 | D1 后方言旗标同样到达 |
40+
|---|---|---|
41+
| 项目/依赖所有 TU | 全局 `$cxxflags`(flags.cppm `cxx_std_flag`) ||
42+
| std / std.compat BMI 预构建 | `ensure_built(cpp_standard_flag)` ||
43+
| P1689 扫描命令 | scan 规则里的 `$cxxflags` ||
44+
| 指纹 / BMI 缓存键 | `fpi.cppStandard` + canonical flags | ✓(已在,无需改) |
45+
46+
依赖包的**其余** cxxflags 仍是包所有制(0.0.72 接口宏传播模型不动)——全图化的只有
47+
方言子集。
48+
49+
### 1.3 机制设计
50+
51+
**a. 提取(known-list,数据表)**:`manifest`/`prepare` 层新增
52+
`extract_dialect_flags(buildConfig.cxxflags) → std::vector<std::string>`,识别表初始值:
53+
54+
```
55+
-freflection -fno-reflection (P2996;GCC 16+)
56+
-fcontracts -fno-contracts (P2900)
57+
-fchar8_t -fno-char8_t
58+
-fno-exceptions -fno-rtti
59+
-D_GLIBCXX_USE_CXX11_ABI=<v> (libstdc++ ABI 开关)
60+
```
61+
62+
判据:**改变标准库头声明集或模块方言校验参与项**的 flag 才入表;`-O/-g/-W*/-I/-fPIC`
63+
等永不入表(它们要么无害要么本就该 per-unit)。命中的 flag **不从 per-unit 里移除**
64+
(重复无害,语义幂等),只是additionally 全图化——实现最小、行为可解释。
65+
66+
**b. 显式逃生舱**:`[build] dialect_cxxflags = [...]`(manifest 新键)——用户可显式
67+
声明"这几个 flag 是全图方言",绕过识别表滞后(新编译器新 flag 出现时不必等 mcpp
68+
发版)。`dialect_cxxflags ∪ extract(cxxflags)` 去重后为最终 `dialectFlags`
69+
70+
**c. 注入点(全部现成通道,无新管线)**:
71+
- `BuildPlan``dialectFlags`(plan.cppm:316 旁,与 cppStandardFlag 同源填充);
72+
- flags.cppm:`f.cxx` 拼接 `cxx_std_flag` 处追加(→ 全局 `$cxxflags`,自动覆盖
73+
项目 TU、依赖 TU、模块规则、scan 规则);`f.cc` 不加(C 无此类方言;若来日有,
74+
按需拆 c/cxx 两表);
75+
- `ensure_built` 增一个 `dialect_flags` 形参 → gcc/clang(未来 msvc)的
76+
`std_module_build_commands` 拼进命令;`metadata_for` 哈希的是完整命令串 →
77+
**std-module.json 自然失效重建,无需新缓存逻辑**;
78+
- `std_build_commands` 记录进 std-module.json(现状已记录命令,自动带上)。
79+
80+
**d. 诊断(轻量)**:`mcpp why toolchain`/`self doctor` 输出 dialectFlags 与
81+
std-module.json 里记录的构建命令,便于人工核对;不做"猜测性 mismatch 告警"
82+
(有了 c 之后 mismatch 在结构上不可能,残留场景只有手改缓存)。
83+
84+
### 1.4 测试
85+
86+
- 单测:`extract_dialect_flags`(命中/不命中/去重/`dialect_cxxflags` 合并)。
87+
- e2e `98_reflection_import_std.sh`(`# requires: gcc`,gcc 16.1.0 支持 `-freflection`):
88+
复刻 #210 的最小工程(`[build] cxxflags=["-freflection"]` + `std::meta` 遍历成员),
89+
断言 build+run 输出;再断言 std-module.json 的命令串含 `-freflection`
90+
加一个带依赖模块的变体(本地 path dep 提供一个 `import std;` 的模块)覆盖 1.2 的
91+
全图一致性(fmt.gcm 类回归)。
92+
- 现有 85/98 号 host-aware 教训:断言写平台无关。
93+
94+
### 1.5 非目标
95+
96+
- 把任意 root cxxflags 传给依赖(包所有制不变;只有方言子集全图化)。
97+
- Clang 侧反射 flag 的字面支持(机制 flag-无关;Clang 落地 P2996 后往表里加一行)。
98+
- `[package].standard` 之外再造第二个"标准"概念——`dialect_cxxflags` 是 flag 直传,
99+
不做语义化(`reflection = true` 这类糖等用户需求明确再加)。
100+
101+
## 2. Part C — MSVC 原生构建:启动核对表(引用主设计 §5,补 0.0.89 后现状)
102+
103+
|| 主设计 | 0.0.89 现状 | 剩余 |
104+
|---|---|---|---|
105+
| CommandDialect msvc 行 | §5.2 | **数据已在**(dialect.cppm) ||
106+
| BmiTraits ifc 行 + 拼写 | §3/§5 | **已在**(model.cppm) ||
107+
| envOverrides 缝 | §5.1 | **已在**(ninja child env) | fast-path 缓存不持久化 envOverrides(C1 一并处理:fast path 重新 derive) |
108+
| C1 find_windows_sdk + INCLUDE/LIB/PATH 合成 | §5.1 | 未做 | 全部 |
109+
| C2 ninja 发射:SeparateLinker / rspfile / deps=msvc | §5.2 | **只有字段,无发射逻辑**(ninja_backend 注释着 TODO) | 全部;VSLANG=1033 细节 |
110+
| C3 std.ixx staging | §5.3 | 未做(stdmod 第三分支;std.compat staging 的 clang 硬编码同时 registry 化) | 全部 |
111+
| C4 .ifc + /scanDependencies | §5.4 | dyndep 参数化已就绪 | scan 驱动接线 |
112+
| C5 link.exe/lib.exe | §5.5 | linkmodel PE 空模型已在(target 键控) | 链接后端 |
113+
| C6/C7 e2e + 删门 | §5.6 | 95 号已断言门信息 | 全部;删门时改 95 |
114+
| cppStandardFlag GNU 拼写 | 审计表 | `normalize_cpp_standard` 仍产 `-std=…` | C2 时经 dialect.stdPrefix 产出 |
115+
116+
## 3. Part A 债务收尾(可并入 C 的第一个 PR)
117+
118+
- **A4 后半**:std 模块命令 / p1689 scan 的 `env LD_LIBRARY_PATH=…` shell 前缀迁到
119+
argv+env(clang.cppm `_WIN32` 引号 workaround 随之可删);stdmod 的 `shellEsc`
120+
单引号硬编码 → `shq`(平台感知)。
121+
- **A6 清零**:`build_program.cppm host_base_flags` 的 is_clang 双路 → caps/dialect;
122+
`p1689.cppm scan_file` GCC 专属 flags → 与 ninja scan 规则共用 dialect/caps 判定。
123+
124+
## 4. MinGW 打磨(一个杂项 PR)
125+
126+
1. Linux(及 macOS)上 `toolchain install/default mingw` → 明确报
127+
"mingw is a Windows-only toolchain"(现:不带版本时 `invalid xpkg target 'xim:mingw-gcc@'`)。
128+
落点:lifecycle`to_xim_package` 后对 `mingw-gcc` 加平台门。
129+
2. e2e 97 的 objdump 路径去硬编码(从 `toolchain list`/安装目录 glob 版本)。
130+
3. doctor 增 mingw 段(Windows:已装版本 / 未装一行提示)。
131+
4. abi 细化:`is_mingw_target` → libc `ucrt`(评估对既有 ABI 兼容门的影响后再动;
132+
0.0.89 刻意跳过)。
133+
5. mingw-gcc 版本跟踪:xim-pkgindex 的 version-check.py 增加 winlibs 源
134+
(releases API → 重打包脚本化:`.agents/tools/repack-winlibs.sh`,把 0.0.89 手工
135+
流程固化)——等 winlibs 下个 GCC 版本时一并做。
136+
137+
## 5. 发布基建
138+
139+
- **mirror_res.sh 修复版(b4c25ad)待实战检验**:下一个 release(0.0.90)的
140+
publish-ecosystem 是真考,预期 2-4 分钟;若仍紧张,`timeout-minutes: 20 → 30`
141+
兜底(一行)。验收:该 job 全自动成功(镜像+索引 PR),无人工介入。
142+
- **gtc 的 python3 shim 断链**(xlings 侧):`~/.xlings` 的 python3 shim 指向缺失的
143+
xim python payload;本机一直用 `/usr/bin/python3` 绕。根因修复属 xlings 仓
144+
(shim 目标校验/重装提示),单独 issue 过去。
145+
- publish-ecosystem 的索引 bump 步骤在 job 被杀时不可重入拉起——本次 0.0.89 手工补了
146+
#383;修复版脚本 + timeout 兜底后应不再发生,不另做机制。
147+
148+
## 6. 排期建议(PR 粒度)
149+
150+
1. **PR-1(0.0.90,优先——用户在 #210 等)**:D1 全量(提取器 + dialect_cxxflags +
151+
三注入点 + e2e 98 两变体)+ §5 的 timeout 兜底一行。发布走全自动闭环,
152+
顺带完成 mirror 修复版的实战验收。
153+
2. **PR-2 起(0.0.91+)**:Part C 按 C1+C2 → C3 → C4 → C5 → C6/C7 切 2-3 个 PR
154+
(临时单 CI 分支迭代,同 0.0.88/89 流程),A 债务(§3)并入第一个。
155+
3. **杂项 PR**:MinGW 打磨 §4 的 1-3(4/5 视时机)。
156+
157+
## 7. 风险
158+
159+
| 风险 | 对策 |
160+
|---|---|
161+
| dialectFlags 全图化改变依赖 BMI 缓存键 → 首次升级全量重建 | 本来就该重建(旧缓存语义错);CHANGELOG 说明 |
162+
| 识别表滞后于新编译器 flag | `dialect_cxxflags` 逃生舱;表是纯数据,补一行发补丁版 |
163+
| `-fno-exceptions/-fno-rtti` 全图化影响依赖包(包可能假设异常可用) | 这两项入表与否单独评审;首版可只收 reflection/contracts/char8_t/ABI 宏,保守起步 |
164+
| e2e 98 依赖 gcc16 的 -freflection 在 CI 工具链可用 | 报告者已在 xlings gcc@16.1.0 复现语法路径;e2e 标 `requires: gcc` 并在 flag 不被驱动接受时 SKIP(探测 `g++ -freflection -E -x c++ /dev/null`) |

0 commit comments

Comments
 (0)