Skip to content

fix: 为模块消费者恢复已有 PCM - #15

Draft
helantianshen wants to merge 2 commits into
mcpp-community:mainfrom
helantianshen:fix/restore-missing-module-pcm
Draft

fix: 为模块消费者恢复已有 PCM#15
helantianshen wants to merge 2 commits into
mcpp-community:mainfrom
helantianshen:fix/restore-missing-module-pcm

Conversation

@helantianshen

Copy link
Copy Markdown

问题

mcpp 可能为同一项目生成多个兼容的构建上下文。模块接口的 PCM 已在一个上下文中生成,但测试或其他消费者的 compile_commands.json 指向另一个 pcm.cache

插件此前只按 CDB 启动 clangd,不会恢复消费者目录缺少的模块产物,因此一键配置或刷新编译数据库后仍可能出现:

  • Module 'mcpplibs.cmp' not found
  • module file not found
  • clangd 无法加载所需模块产物

修复

  • 解析 CDB 时优先选择项目内的模块消费者,并记录模块源与消费者各自的 PCM 目录。
  • 只在同一项目、同一编译器和同一目标平台的兼容构建上下文之间复制 PCM。
  • 仅恢复消费者缺少或较旧的 PCM,不删除或改写已有的新版本。
  • 在自动协调、一键配置以及手动「检查/重新检查模块支持」之前执行恢复;发生复制时先重启 clangd,再运行模块检查。

插件不自行生成模块映射,也不会跨编译器或跨目标平台复用缓存。

验证

  • npm test:269/269 通过
  • npm run package:成功生成 VSIX
  • Extension Host E2E:1/1 通过
  • VS Code Remote: WSL:模块消费者缺少 PCM 时能够从兼容构建上下文恢复
  • Windows 原生环境:mcpp 2026.8.11.3、LLVM/clangd 22.1.8;mcpp buildmcpp build --configure-only 均成功
  • Windows CDB 参数没有多余双引号;模块检查不再以 module_not_found / ast_file_not_found 作为结果

环境说明

Windows 上 mcpp 2026.8.11.3 检查内置 xlings 时会使用 Linux 重定向写法,cmd.exe 因而输出 The system cannot find the path specified.。本机已按 mcpp 支持的配置改用 xlings.binary = "system",复用版本一致的 xlings 2026.8.11.2;该环境问题不需要由插件绕过。

项目是纯库目标,因此 mcpp run 返回 error: no binary target in this package 属于预期行为。

@helantianshen
helantianshen marked this pull request as ready for review August 12, 2026 08:53
@helantianshen

Copy link
Copy Markdown
Author

@wellwei

@wellwei wellwei left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审查结论:当前版本需要修改,暂不建议合并。问题本身是真实且有必要解决的,但扩展仅凭 CDB argv 无法证明两个 PCM 目录中的产物兼容,当前实现存在复制错误 PCM 的确定性路径。

阻塞问题

  1. moduleCompatibilityKey() 删除了全部 -I、模块映射和 PCM 路径,却把剩余参数作为兼容身份。include context 可以改变宏、头文件内容和模块导出接口,不能忽略。我用 debug/release 两套不同 -I 的命令复现:两个 source 目录都会被判定兼容,较新的 release PCM 最终会覆盖 debug 消费者目录中的同名 PCM。

  2. stageAvailableProjectPcms() 从每个 source 目录复制全部 .pcm,同名文件只按 mtime 决胜。mtime 不是 artifact identity,这会把不同构建 fingerprint 的 std.pcmstd.compat.pcm、项目模块和依赖模块混入同一目录。尤其 std.compat.pcm 依赖精确匹配的 std.pcm,不能分别按文件名和时间戳选择。

  3. “同一项目”边界实际没有建立。analyzeCompilationDatabase() 不接收当前 project.root,而是按每条记录自己的 directory 判断 projectSource。最小反例中,/other 项目的模块命令会成为 /work/app 消费者的 PCM source。-fprebuilt-module-path 也没有限制在当前项目或 target 下,因此异常或陈旧 CDB 可以让扩展创建并覆盖项目外的 .pcm 文件。

  4. copyFileSync() 直接覆盖目标文件,不具备原子发布和并发保护。clangd 可能正在 mmap 该 PCM;Windows 上文件锁也可能使覆盖失败。mcpp 已经有临时文件、rename、内容校验和 Windows 重试的 staging 实现,不宜在扩展中重新实现一套更弱的版本。

  5. 模块接口扩展名被硬编码为 .cppm/.ixx/.mpp/.ccm,与 mcpp 的 [build].module_extensions 契约不一致。使用合法的 .cxxm 反例时,source 目录为空,模块接口被当作消费者,恢复逻辑完全不执行。

测试边界

我在最新 main + f82bde9 上验证了 npm test 269/269、VSIX 打包和 archive 检查,均通过。但新增测试只验证文本文件复制和理想 CDB,没有覆盖真实 Clang PCM 加载、不同 fingerprint、多 source 同名文件、跨项目路径、文件锁或中断写入,因此不能证明这套复制规则在 PCM 语义上正确。

另外,当前 GitHub 绿色 CI 检出的是旧虚拟 merge 74f8032,其 base 为 fcd8296#14 合并后当前虚拟 merge 已变为 3d8b790(base ecf1448)。语义问题修复后还需要在最新 main 上重新跑 CI。

建议方向

更合适的修复位置是 mcpp 的 configure-only 路径:由掌握 BuildPlan、fingerprint、模块图和缓存元数据的 stage_configure_prerequisites() 暂存明确属于当前构建身份的项目 BMI;扩展只负责运行 configure-only、重启 clangd 和检查结果。

如果仍坚持在扩展侧实现,至少需要显式的 artifact provenance/fingerprint 元数据、严格的 project root 与目标目录约束、按模块依赖闭包选择文件、原子 staging,以及真实 clang 加载 PCM 的集成测试。单纯补充 argv 过滤规则或 mtime 判断不足以消除上述风险。

@helantianshen
helantianshen marked this pull request as draft August 13, 2026 15:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants