Skip to content

feat: mcpp emit build-database —— 不写工程目录的 S1 构建数据库(模块图、标准库模块、监视输入) #636

Description

@Sunrisepeak

概述

本需求新增一个命令,按公开格式输出 mcpp 构建计划中与 IDE 相关的事实:模块图、工具链与标准库模块,以及需要监视的输入。输出是 S1 构建数据库 IDE Profile 0.2.0 的等级 2 文档,放在机器输出协议 v1 的信封里。等级 3 所需的结构化语义选项不由 mcpp 输出,由消费方的 S1 库从参数得到(见“结构化语义选项”)。

mcpp emit build-database --format json

该命令与 mcpp build --configure-only 做同样的解析,区别是不写工程目录:不写 compile_commands.json、target/ 与 mcpp.lock,数据库只出现在标准输出中。

消费方是 lsp-mcpp,一个编译器无关的 C++ 模块语言服务器,以 clangd 23.1 为语义引擎,把各编译器的工程归一化成 clangd 能理解的输入。lsp-mcpp 的设计把 mcpp 作为第一个生产方。相关材料:

动机

编译数据库之外的事实

lsp-mcpp 目前以 mcpp build --configure-only(#387)生成的 compile_commands.json 作为 mcpp 工程的数据来源,在 Linux 与 macOS 主机上通过一致性测试。编译数据库只说明每个文件怎样编译,下表中其余的事实只能由服务端反推。这些事实 mcpp 在 BuildPlan、SourceUnit 与工具链指纹中都已经算出。

服务端需要的事实 服务端目前的做法 代价
每个单元提供与导入的模块 逐个源文件做词法扫描 条件编译中的模块声明扫描不准;scan_overrides 与 P1689 扫描结果无法取得
单元角色,包括接口分区与实现分区的区分 从源码文本推断 可能与 SourceUnit.providesInterface 的判定不一致
工具链、target、标准库及其模块清单 对每个驱动运行 -dumpmachine、-print-library-module-manifest-path 等查询 需要执行外部程序;LLVM 工具链以 -nostdinc++ -isystem <前缀>/include/c++/v1 显式选择 libc++ 时,驱动查询答不出清单,只能从包含目录推断 <前缀>/lib/libc++.modules.json
单元属于哪个包、哪些是测试、哪些是标准库模块 所有条目按一个集合处理 无法按包组织模块,也无法区分测试单元与 mcpp 构建的标准库模块
使模型失效的输入 服务端硬编码 mcpp.toml、mcpp.lock、**/*.cppm 等模式 多监视浪费资源,少监视则模型陈旧

工程目录的写入

按 docs/01-getting-started.md,--configure-only 是配置操作,会更新 compile_commands.json、构建目录元数据与锁文件元数据。lsp-mcpp 的设计要求不在用户工程目录中写文件;目前打开一个 mcpp 工程,工程根目录就会出现 compile_commands.json 与 target/。

与现有决定的关系

设计思路

命令与选择器

mcpp emit build-database --format json
    [--target <triple>] [--toolchain <spec>] [--profile <name>]
    [--member <name> | --workspace]

选择器与 mcpp build 相同。同一组参数下,解析出的构建计划必须与 mcpp build --configure-only 一致。

信封

{
  "schemaVersion": 1,
  "kind": "mcpp.build-database",
  "kindVersion": 1,
  "effects": ["read-project"],
  "mcpp": { "version": "…", "protocol": { "min": 1, "max": 1 } },
  "data": {
    "database": { /* S1 0.2.0 文档,见下节 */ },
    "watch": ["mcpp.toml", "mcpp.lock", "src/**/*.cppm"],
    "inputs-fingerprint": "…"
  },
  "diagnostics": []
}
字段 内容
data.database S1 0.2.0 文档本体,可以直接写成 build_database.json
data.watch 变化后可能改变数据库的输入:绝对路径,或相对工作区根目录、使用 LSP 3.18 glob 语法的模式
data.inputs-fingerprint 上述输入的内容指纹,消费方据此判断是否需要重新读取

效应

  1. mcpp --protocol-version 在 kinds 中声明 "mcpp.build-database": 1。
  2. 在 commands 中声明该命令可能产生的全部效应:read-project、network、write-global-cache、exec-build-script。解析与构建相同,可能下载依赖、安装工具链、运行依赖的构建程序,所以按 docs/50 对解析类命令的约定如实列出。
  3. 效应中没有 write-project,这是本命令存在的理由。每次实际发生的效应写在信封的 effects 中。
  4. 解析失败时输出带诊断的信封并以 1 退出;不支持的 --format 值按协议输出到标准错误并以 2 退出。

IDE 只在受信任的工作区中运行本命令,不受信任时不运行 mcpp。

S1 文档内容(等级 2)

规范正文:S1。Schema:s1-build-database.schema.json。按本 issue 形状写出的信封示例:s2-envelope.json(gcc@16.1.0,set 为 hello、hello:test、mcpp:std)。S1 的顶层结构兼容 P2977R2,IDE 相关字段都放在各层的 ide 对象中。

文档与工具链

S1 字段 mcpp 中的来源 要求
version、revision 固定为 1、0 必须
ide.profile-version 固定为 "0.2.0" 必须
ide.generator { "name": "mcpp", "version": <mcpp 版本> } 应当
ide.toolchains.<id> 工具链指纹;id 由 mcpp 决定,同一构建中保持稳定 必须
…family gcc、clang 或 msvc;clang++ 构建 MSVC ABI 时为 clang 必须
…version、…build-id 编译器版本;能取得时附带构建修订 版本必须
…driver 构建实际调用的驱动的绝对路径 必须
…target 编译器自身写法的目标三元组,例如 x86_64-pc-windows-msvc 必须
…sysroot 构建使用的 sysroot 可选
…stdlib name:libstdc++、libc++ 或 msvc-stl;version;module-metadata:标准库模块清单的绝对路径 有单元导入 std 或 std.compat 时必须
…config-files 驱动的隐式配置文件;传了 --no-default-config 时为空数组 应当

各工具链的 stdlib.module-metadata:

工具链 stdlib.module-metadata
gcc@X -print-file-name=libstdc++.modules.json 的结果
llvm@X,显式 -nostdinc++ -isystem <前缀>/include/c++/v1 <前缀>/lib[/<target>]/libc++.modules.json
msvc@system、msvc@<toolset>,以及 clang 以 MSVC STL 构建 工具集自带的 <tools>\modules\modules.json。它不是 P3286 形状,而是 {"version": 1, "revision": 0, "library": "microsoft/STL", "module-sources": ["std.ixx", "std.compat.ixx"]}(windows-2022 上的 14.44.35207 实测);lsp-mcpp 会让 S1 同时接受这种形状,mcpp 不需要另写文件

mcpp 构建的标准库模块作为翻译单元输出在 set mcpp:std 中:provides 为 std、std.compat,arguments 为 mcpp 构建它们时的实际命令。

  • 模块源来自工具链时,工具链照常写出上表的 stdlib.module-metadata。单元与清单同时给出同一模块时,消费方以单元为准(S1 6.1 节,S1-6.1-4)。
  • 模块源来自依赖包时没有清单文件,工具链的 stdlib.module-metadata 省略。例如 openkal-llvm-runtime 0.9.5 只带 llvm-generated/std.cppm 与 std.compat.cppm,mcpp 以 stdModuleFlags 构建它们。S1 0.2.0 已接受这种写法。

lsp-mcpp 打开它自己的仓库时实测:编译数据库只有 -fmodule-file=std=...pcm,服务端找不到 std 的源文件,109 个单元中 102 个无法解析 std。

set

set 按包划分,不按构建目标划分:每个包(包括依赖包)一个 set,包的测试另成一个 <package>:test,mcpp 构建的标准库模块成一个 mcpp:std。依赖包也作为 set 输出,IDE 才能跳转到依赖的模块源码。

S1 字段 mcpp 中的来源
name <package>、<package>:test、mcpp:std
family-name 包名;mcpp:std 为 mcpp
visible-sets 其余所有 set。mcpp 在一张扁平的模块图上解析 import,写得更窄就等于描述了一条构建并不执行的规则。这正是 S1 要求的完整可见性闭包
baseline-arguments 该 set 所有单元共有的参数
ide.toolchain 上表中的工具链 id
ide.configuration profile 名,例如 dev、release
ide.kind 包含可执行目标的包为 executable,其余包为 library;<package>:test 为 test;mcpp:std 为 library
ide.module-metadata 该 set 可见的预构建模块包的清单;标准库清单不在这里

翻译单元

S1 字段 mcpp 中的来源
source、work-directory 绝对路径
arguments 完整命令行,驱动在首位,与 compile_commands.json 中对应条目一致
local-arguments 不在 baseline-arguments 中的参数
object 计划中的目标文件路径
private 该单元提供的模块是否只在本 set 内可见
provides SourceUnit.provides 映射到计划中的 BMI 路径;没有计划 BMI 时为空字符串
requires SourceUnit.requires_,分区写全名 M:P
ide.role 见下表
源码形式 ide.role mcpp 中的依据
export module M; module-interface provides 有值,providesInterface == true,名字不含 :
export module M:P; module-partition-interface 同上,名字含 :
module M:P; module-partition-implementation providesInterface == false
module M; module-implementation 模块实现单元
没有模块声明 non-module 普通源文件
无法判定 unknown providesInterface 为 nullopt,例如来自 scan_overrides;不猜测

结构化语义选项:交给 S1 库

mcpp 不写 set 与单元的 ide.options。等级 3 由消费方的 S1 库完成:set 的 options 由 baseline-arguments 结构化得到,没有 baseline-arguments 时取所有单元共有的参数;单元的差量取自 local-arguments,没有时取它比 set 多出的参数。构建专用的参数(输出、依赖文件、优化、调试信息、警告、BMI 定位)被丢弃,没有结构化字段的参数按原顺序放进 raw-semantic-arguments。这样得到的选项只是参数的重述,消费方仍以 arguments 编译。结构化规则只维护一份,GCC、Clang、MSVC 三种方言不需要在每个生产方各实现一遍。

S1 库的实现是 lsp-mcpp 的 lspmcpp.spec.options,S1 第 9 节与 11.1 节写明了这种做法。因此对 mcpp 的要求落在参数上:

  • arguments 与 compile_commands.json 中对应条目一致;
  • baseline-arguments 与 local-arguments 如实拆分:两者拼起来,就是 arguments 去掉驱动、-c、输入与输出之后的参数;
  • BMI 定位参数(-fmodule-file=、-fprebuilt-module-path=、/reference、/ifcOutput 等)只出现在 arguments 中。

第二阶段:进度流

lsp-mcpp 的 S2 发现协议 0.1 采用“标准输入一个请求、标准输出 JSONL 消息、生产方写数据库文件”的形式,与协议 v1 的约定不一致。lsp-mcpp 将把 S2 升到 0.2,增加单文档模式:发现命令输出一个信封,数据库内联在 data.database 中。本 issue 的第一阶段只需要 --format json。

大工程上解析耗时较长时,第二阶段启用协议保留的 --format ndjson:每行一个信封,若干 kind: "mcpp.progress",最后一行是 mcpp.build-database,或者一个带诊断的失败信封。

非目标

  • 不构建 BMI、目标文件或链接产物。
  • 不写工程目录。
  • 不做常驻进程或取消协议。
  • 不替代 compile_commands.json 与 --configure-only。

验收标准

  1. 以下工程上输出的 data.database 通过 S1 Schema 校验并满足等级 2:examples/ 中的示例、带 tests/ 与 dev-dependency 的工程、多成员工作区。
    • 满足等级 2 指:文档有 ide.profile-version 与 ide.toolchains,每个 set 有 ide.toolchain,每个单元有 ide.role,工程的全部翻译单元都在文档中。不写 ide.options。
    • set 为 <package>、<package>:test 与 mcpp:std;每个 set 的 visible-sets 列出其余所有 set。
    • 与同一选择器下 mcpp build --configure-only 生成的 compile_commands.json 逐条对应,arguments 相同。
  2. 命令执行前后,工程目录树的文件清单与内容哈希不变。
  3. 源码有语法错误、从未成功构建过的工程也能输出;provides 中的 BMI 路径允许为空字符串。
  4. 三个 CI 平台覆盖下列组合,stdlib.module-metadata 指向真实存在的清单(std 由依赖包提供时省略),std、std.compat 是 mcpp:std 的翻译单元:
    • Linux:gcc@16.1.0、llvm@22.1.8,以及依赖 openkal-llvm-runtime 的工程;
    • macOS:llvm@22.1.8;
    • Windows:gcc@16.1.0(x86_64-windows-gnu)、msvc@system、llvm@22.1.8(x86_64-windows-msvc)。
  5. mcpp --protocol-version 声明了该 kind 与命令的效应,效应中没有 write-project;不支持的 --format 按协议以 2 退出。
  6. kind 的字段名由契约测试覆盖,做法与现有 kind 相同。
  7. 以 mcpp 仓库自身为输入时,命令不编译任何单元,耗时与 --configure-only 同一量级。

涉及模块

  • src/cli.cppm:emit 下新增 build-database 子命令与选择器。
  • src/build/:从 BuildPlan 写出 S1 文档,可与 compile_commands.cppm 共用单元遍历。
  • src/modgraph/graph.cppm:读取 SourceUnit 的 provides、providesInterface、requires_。
  • src/toolchain/:工具链指纹与标准库清单定位。
  • src/wire.cppm、docs/50-machine-output.md:新 kind、效应声明、字段说明。
  • tests/:单元测试、契约测试与 e2e。

lsp-mcpp 侧的配合

  • 服务端读取 mcpp --protocol-version,kinds 中有 mcpp.build-database 时调用本命令,否则回退到 --configure-only。
  • 服务端加载 mcpp 的等级 2 文档时,由 S1 库补全为等级 3,状态中报告等级 3。
  • 模拟生产方的数据已按本 issue 的形状调整,specs/tools/validate.py 对每份模拟数据检查:不含 ide.options;set 只有 <package>、<package>:test 与 mcpp:std;每个 set 看见其余所有 set;std、std.compat 是 mcpp:std 的单元;<package>:test 的 ide.kind 为 test。mcpp-emit 夹具另有测试文件经 hello:test 跨 set 导入包的模块。
  • 一致性夹具 mcpp-gcc、mcpp-llvm、mcpp-msvc、mcpp-llvm-msvc 在真实 mcpp 支持本命令后,将断言模型等级 3 与工程目录不变。
  • lsp-mcpp 维护者可以实现本命令并提 PR。set 的划分与命名已由 mcpp 维护者确定(见上文),命令名(emit build-database 或并入 mcpp metadata)以维护者意见为准。

后续需求

IDE 打开工程时不知道应当使用哪个 target,只能得到主机默认目标的数据库。例如 lsp-mcpp 自身在 Windows 主机上以 --target x86_64-windows-gnu 构建,而主机默认目标是 x86_64-windows-msvc。docs/04-mcpp-toml.md 中没有找到工程级默认 target 的写法,这一点留待第一阶段落地后讨论。

相关:#371、#379、#385、#387。

修订记录

  • 2026-09-14:按 mcpp 维护者的答复修订三处。

    1. mcpp 只输出等级 2,等级 3 交给 S1 库;原验收标准要求 mcpp 直接给出等级 3。
    2. visible-sets 列出其余所有 set;原文要求按目标写传递闭包。
    3. set 按包划分,另加 <package>:test 与 mcpp:std;原文按构建目标划分。

    S1 规范相应增加了说明性文字(第 7、9、11.1 节,无规范性改动),lsp-mcpp 的模拟数据与校验已随之调整(Sunrisepeak/lsp-mcpp-private#1)。

Activity

  1. Sunrisepeak commented on Sep 14, 2026

    @Sunrisepeak
    MemberAuthor

    lsp-mcpp 消费端的进展与契约补充

    2026-09-14 更新:按维护者的答复(只输出等级 2、set 按包划分、visible-sets 列出其余所有 set)调整了下文中等级与 set 的描述,issue 正文同步修订。

    lsp-mcpp 这一侧已按本 issue 的契约实现消费端,在 mcpp 实现命令之前先用模拟生产方验证,CI 在 Linux、macOS、Windows 上通过(Sunrisepeak/lsp-mcpp-private#1)。实现与测试中确认了几处契约细节,补充如下,供实现本命令时参考。

    消费端现状

    • 服务端先读 mcpp --protocol-version:kinds 中有 mcpp.build-database,且 emit build-database 的效应中没有 write-project 时,运行 mcpp emit build-database --format json,取 data.database 与 data.watch。数据库只写入服务端自己的缓存目录。
    • 旧版 mcpp 没有该 kind 时,仍回退到 --configure-only,状态中给出不降级的提示 producer-writes-project。
    • 模拟生产方是 src/tools/mockmcpp.cpp,它按夹具中记录的 mcpp-mock.json 输出信封。下列夹具的数据已用 S1 Schema 与本 issue 的契约(等级 2、set 按包划分、每个 set 看见其余所有 set)校验,可以作为 mcpp 契约测试的参考输出:
    夹具 断言
    mcpp-emit mcpp 输出等级 2,S1 库补全后模型为等级 3;跳转、悬停、补全、引用、诊断,测试文件经 hello:test 跨 set 导入;工作区文件不变
    mcpp-emit-package-std std、std.compat 是 mcpp:std 中来自依赖包的翻译单元,工具链不带 stdlib.module-metadata
    mcpp-emit-broken 命令失败时,状态显示 mcpp 自己的诊断;不回退到 --configure-only
    mcpp-emit-watch watch 中的输入变化后重新运行命令;再次失败时保留上次的数据库并提示可能过期;命令恢复后回到正常状态

    契约补充

    1. 失败时的输出。 解析失败时,标准输出仍然只有一个信封:diagnostics 中至少一条 severity 为 error,带稳定的 code 与面向用户的 message,日志只写标准错误。消费端对支持本命令的 mcpp 不再回退到 --configure-only:回退会写工程目录,还会掩盖真正的原因。因此失败信封是用户看到的唯一解释,状态中原样显示为 <code>: <message>。

    2. 耗时上限。 消费端给命令 5 分钟上限。依赖需要联网而网络不可用时,建议尽快返回失败信封,或用本地缓存完成解析并附带 warning 诊断,不要长时间阻塞。

    3. watch 的语义。

    • 消费端把条目注册为编辑器的文件监视:相对条目以工作区根为基准,绝对条目以其父目录为基准;编辑器不支持动态注册时,每 2 秒轮询一次。任一条目变化后,防抖 1.5 秒重新运行本命令。
    • 由此有一条约束:命令不得写入任何列在 watch 中的文件,否则会反复触发运行。例如 mcpp.lock 需要更新时,应当用诊断说明,而不是由本命令写入(与“不写工程目录”一致)。
    • 工作区之外、但会改变结果的输入,例如路径依赖包的 mcpp.toml 与 build.mcpp,请用绝对路径列出。
    • glob 语法按 LSP 3.17:*、**、?、{a,b}、[...]、[!...]。Windows 与 macOS 上大小写不敏感。

    4. 重复运行的耗时。 如果 watch 列出源文件模式(例如 src/**/*.cppm),用户每保存一次源文件就会触发一次运行。新增的 import 会改变模块图,这样列出本身是必要的。结果与上次相同时,消费端只替换模型,不重建索引与计划;但进程启动与解析本身的耗时用户仍能感到。建议 inputs-fingerprint 未变时直接复用上次的解析结果,目标是在 mcpp 仓库规模上数百毫秒内返回。验收标准 7 可以补充“输入未变时再次运行的耗时”。

    5. 路径写法一致。 所有路径为绝对路径,同一文档内同一文件只用一种写法:macOS 上不要混用 /var/... 与 /private/var/...,Windows 上不要混用 8.3 短文件名与长文件名。消费端会规范化,但两种写法混用会让 watch 匹配与编辑器缓冲区的对应变得脆弱。

    6. requires 的准确性。 消费端按 provides 与 requires 建立模块图,并据此并行准备模块。在 mcpp 仓库上,首次跨模块跳转在 32 线程机器上由逐个构建时的 38 秒降到约 25 秒。requires 应来自 mcpp 自己的扫描结果(含条件编译与 scan_overrides),分区写全名;与实际导入不一致会让准备顺序出错。

    7. 依赖包提供的 std。 本命令落地前,消费端临时从 mcpp 的 std 构建缓存读取 std-module.json(schema 1),取得 std、std.compat 的源文件与命令。这依赖 mcpp 的内部布局。本命令已在 mcpp 2026.9.15.1 中把这两个文件作为 mcpp:std 的翻译单元输出;由于工程可以通过 .xlings.json 固定更早的 mcpp,这条临时路径保留,只在回退到 --configure-only 时使用(见下方 2026-09-15 的评论)。

    验收方式的补充建议

    mcpp-emit 夹具本身是一个真实的 mcpp 工程(llvm@22.1.8),可以直接用真实的 mcpp 运行:删除场景中的 server-arguments(服务端会使用 PATH 上的 mcpp),然后运行

    lsp-mcpp-conformance run --server <lsp-mcpp> --payload <payload> --fixture conformance/fixtures/mcpp-emit
    

    期望同样是模型等级 3(mcpp 输出等级 2,由 S1 库补全)、工作区不变,以及各项语言功能通过。依赖包提供 std 的情形可以用夹具 self-lsp-mcpp(lsp-mcpp 自己的仓库,依赖 openkal-llvm-runtime)验证。mcpp-emit-package-std、mcpp-emit-broken 与 mcpp-emit-watch 依赖模拟生产方记录的数据,不适用于真实的 mcpp。

    后续需求的补充数据

    target 的选择仍是后续需求。lsp-mcpp 自己的仓库在 Windows 主机上需要 --target x86_64-windows-gnu 才能构建,而 IDE 目前没有渠道把 target 传给 mcpp,所以 lsp-mcpp 的 nightly 暂不在 Windows 上做自举测试。

  2. changed the title [-]feat: mcpp emit build-database —— 不写工程目录的 S1 构建数据库(模块图、标准库清单、结构化选项)[/-] [+]feat: mcpp emit build-database —— 不写工程目录的 S1 构建数据库(模块图、标准库模块、监视输入)[/+] on Sep 14, 2026
  3. Sunrisepeak commented on Sep 14, 2026

    @Sunrisepeak
    MemberAuthor

    已落地:mcpp 2026.9.15.1

    mcpp emit build-database 随 mcpp 2026.9.15.1 发布,实现见 #639,规则见 SPEC-005(docs/specs/build-database.md)。

    命令与文档

    • mcpp emit build-database 输出 S1「C++ Build Database: IDE Profile」0.2.0 文档。
    • --format json 输出 mcpp.build-database 信封,文档在 data.database,同时给出 data.watch 与 data.inputs-fingerprint。
    • --spec compile-commands 改为输出 compile_commands.json 的条目。
    • -o <file> 原子写入文件。
    • 选择器与 mcpp build 相同。

    保证

    • 命令不写工程目录。规划写到 $MCPP_HOME/cache/build-database/<key>。
    • 标准库模块只描述、不编译。
    • mcpp.lock 从工程读取,从不写回;与规划结果不一致时给出 MCPP_LOCK_WOULD_CHANGE。
    • --protocol-version 为该命令声明的效应不含 write-project。

    文档内容

    文档满足 S1 等级 2:

    • 每个包一个集合,另有 <包>:test 与 mcpp:std,visible-sets 列出其余所有集合。
    • ide.role 取自扫描器读到的声明形式。
    • arguments 与 compile_commands.json 取自同一条记录。
    • baseline-arguments 为集合内最长公共前缀,local-arguments 为各单元余下的部分。
    • private 为 false。
    • config-files 列出驱动在命令行之外读取的文件。
    • 标准库模块单元的命令从 mcpp 实际运行的构建命令中还原,对工具链自带的 std 与依赖包提供的 std.cppm 规则相同。

    发布与验证

    • mcpp 2026.9.15.1 与 xlings 2026.9.14.1 均已发布并镜像到 GitHub 与 GitCode;xim-pkgindex 的 latest 已指向这两个版本(bump(xlings): track 2026.9.14.1 as latest openxlings/xim-pkgindex#841、#842)。
    • 在 xlings subos use verify-636 --sandbox 中配置 CN mirror 后,对已发布的 mcpp 做生态验证:18 项通过,0 项失败(Windows 一节由 CI 的 e2e 687 覆盖)。
      • 全新 home 安装工具链、构建依赖 mcpplibs.cmdline 的工程后,store 中没有包目录混入其他下载物。
      • 两个工程的 emit build-database 输出符合 SPEC-005,工程目录不变。
      • xlings self doctor 能指出人为制造的污染包目录,--fix 后恢复。

    与 lsp-mcpp 的对照

    • lsp-mcpp 的 specs/tools/validate.py(s1_semantics、mcpp_contract)与 S1 schema 对三份真实输出无失败:GCC 16 工程、LLVM 22 工程、lsp-mcpp 仓库自身(11 个集合,std 来自 openkal-llvm-runtime)。
    • 用这个 mcpp 替换 lsp-mcpp-mock-mcpp 运行 conformance:
      • mcpp-emit 12/12;
      • mcpp-emit-package-std 13/13;
      • 基于真实清单的 watch 场景 10/10:改动清单触发重载;清单损坏时模型保留为 model-stale,诊断为 MCPP_BUILD_DATABASE_PLAN_FAILED;修复后恢复。

    实现中发现并一并修复

  4. added a commit that references this issue on Sep 14, 2026
  5. Sunrisepeak commented on Sep 14, 2026

    @Sunrisepeak
    MemberAuthor

    lsp-mcpp 侧用 mcpp 2026.9.15.1 做的闭环验证

    lsp-mcpp 的 CI、nightly 与发布流程已固定到 mcpp 2026.9.15.1,并在三个主机上用真实的 mcpp 分别验证了生产方与消费方两侧(Sunrisepeak/lsp-mcpp-private#1,CI run 34883539883)。

    验证内容

    方面 做法 结果
    生产方输出 每个主机对该主机的 mcpp 夹具运行 mcpp emit build-database --format json,把信封交给 specs/tools/validate.py。检查项:S2 信封 Schema、S1 Schema、S1 语义规则,以及本 issue 的契约(等级 2、set 按包划分、每个 set 看见其余所有 set、std 在 mcpp:std 中、<package>:test 为测试 set) Linux(gcc@16.1.0、llvm@22.1.8)、macOS(llvm@22.1.8)、Windows(msvc@system,以及 llvm@22.1.8 的 x86_64-windows-msvc)全部通过
    消费方 mcpp-gcc、mcpp-llvm、mcpp-msvc、mcpp-llvm-msvc 断言:S1 库补全后模型为等级 3;跨模块跳转、悬停、补全、引用正常;测试文件经 hello:test 跨 set 跳转;工程目录不变 通过
    监视 新夹具 mcpp-watch:新增模块接口后重新加载;写坏 mcpp.toml 后保留上次的模型,状态为 degraded,并显示 MCPP_BUILD_DATABASE_PLAN_FAILED;修复后恢复 ready 三个主机通过,Linux 另以轮询模式通过
    自举 lsp-mcpp 仓库自身:11 个 set,std 为 openkal-llvm-runtime 提供的 mcpp:std 单元 本地通过

    耗时(开发机):示例工程 0.55–0.60 秒,lsp-mcpp 仓库 1.6 秒。运行前后,工程目录的文件清单与内容哈希不变。lsp-mcpp 的模拟夹具也已改为录制这个版本的真实输出。

    两点观察(不需要改动 mcpp,供参考)

    1. 标准库单元的 local-arguments 带有输入与输出(--precompile <源文件> -o <BMI>)。S1 把 local-arguments 定义为“不在 baseline-arguments 中的参数”,这样写符合规范。lsp-mcpp 的 S1 库原先把源文件当作语义参数,已按这种写法修正。
    2. .xlings.json 固定的版本。 mcpp 仓库根目录的 .xlings.json 固定 "mcpp": "2026.9.14.3",xlings 在仓库目录中运行的是这个版本。因此在编辑器中打开 mcpp 仓库时,仍会回退到 --configure-only 并写入 compile_commands.json 与 target/;固定版本升到 2026.9.15.1 或以后即可避免。固定的版本没有安装时,xlings 对所有命令返回 1;lsp-mcpp 现在会把 xlings 的说明原样显示在状态中。

    对之前评论的更正

    之前的评论说,命令落地后删除从 std-module.json 读取 std 的临时路径。考虑到工程可以通过 .xlings.json 固定更早的 mcpp,这条路径保留,只在回退到 --configure-only 时使用,支持本命令的 mcpp 不会走到这里。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions