0.0.12 follow-ups: completion waits for missing modules, build.mcpp autosave drops the targets' flags, Windows warm starts rebuild modules, the mcpp version is lost

未关闭
#52 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
5/5
预计耗时
一周以上
新手友好度
20/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
cpp, vscode
领域
devtools

调研方向

Start with the issue’s eight findings and their proposals, then inspect the named entry point src/project/mcpp.cpp and the engine area identified as 0025. Reproduce the completion wait with a cold module cache first; the issue describes a fixture that opens an importer and requests completion every second. Done means missing prerequisites build in the background while completion answers within budget and becomes complete as modules finish; the issue also lists separate proposed fixes and tests for the other findings.

由索引模型根据 Issue 内容生成。

描述

Summary

The problems found in mcppls 0.0.12 after its release candidate passed CI. Sources: a user's diagnostic bundle (a Qt project with build.mcpp), and a real-project probe on GalTranslPP (Windows, MSVC STL, about 40 C++ modules mixed with <Shlwapi.h>, toml.hpp, proxy and nlohmann json; GalTranslPP#1, run 38148595488, digested by GalTranslPP#5) that compared 0.0.12 with 0.0.11 (stock clangd 23.1). Also the CI fixtures.

What 0.0.12 does better, for context: no clangd exit and no restart while typing on GalTranslPP (0.0.11: 4 exits on a cold start, 4 and 2 restarts while typing, 75 s degraded, a file set aside). Both versions report no false errors in the 7 heavy files. Every kill scenario recovers. The problems below are in order of how much a user feels them.

# problem where priority
1 completion waits for every missing prerequisite module engine (0025) high
2 a half-typed build.mcpp takes the targets' Qt flags away and restarts clangd product high
3 a warm start on Windows rebuilds most modules product / engine, cause to confirm high
4 the mcpp version is lost after the first describe product medium
5 "ready" while clangd still builds modules for the open files product medium
6 about 0.5 s per completion on Windows in files that mix heavy headers with imports engine / clang medium
7 preambles of heavy-header files are 3× larger on Windows engine low
8 one unexplained 15-minute event-loop stall after a clangd kill (local, not reproduced) product low

1. Completion waits for every missing prerequisite module (high)

Since 0025, completion builds a module newly needed by the file synchronously; only a dependency edit is bounded (250 ms). While a project is being prepared, this means completion waits for every missing prerequisite module.

GalTranslPP, warm typing session (200 s at 10 Hz, cache copied to a new directory, so about 25 modules are rebuilt):

0.0.12 0.0.11
prerequisite set of Run.cpp ready after 184–208 s 75 s
clangd completion answers under 1 s none (median 109 s) from 5–12 s in, about 0.5 s
completions with the expected names 6 of 21 6 of 21 (plain), 8 of 28

0.0.11 answers from the preamble while modules are missing. 0.0.12 is more correct once modules exist, but answers nothing in the meantime. On a cold start both versions are unusable for minutes: clangd's completion median is 8 s and its p95 190–240 s, and hover answers only at its 2 s budget.

Proposal: bound the wait for missing prerequisites the way dependency edits are bounded. Answer from the preamble and the modules that exist, keep building in the background, and let mcppls say "modules still being prepared" in the answer.
Test: a fixture that opens an importer on a cold module cache and asks completion every second. Clangd answers within the budget from the first seconds, and the results become complete once the modules are built.

2. A half-typed build.mcpp removes the targets' Qt flags and restarts clangd (high)

From the bundle (VS Code with autosave after 1 s, build.mcpp with mcpp.rules.qt):

  • 14:56:54. Autosave → mcpp emit build-database → mcpp compiles build.mcpp, which fails (build.mcpp:7:5: error: 'mcpp::mcpp' has not been declared). mcpp reports MCPP_BUILD_DATABASE_PROGRAM_FAILED and gives a partial description.
  • The partial description lacks everything build.mcpp contributes: the Qt include directories, and the generated moc_counter.cpp and qrc_demo.cpp (engine database changed: 0 added, 2 removed moc_counter.cpp, qrc_demo.cpp, 3 compiled otherwise).
  • mcppls adopts it. The units' arguments changed, so clangd restarts for the whole project (14:56:56). src/main.cpp then fails with fatal error: 'QtCore/QObject' file not found, and the status turns degraded.
  • 14:57:51. build.mcpp compiles again → the full model comes back → another restart (14:57:53).
  • 14:57:58. The next half-typed save ('vec' is not a member of 'std') → partial again → a third restart (14:58:13).

That is three clangd restarts in two minutes, with the target code losing its Qt headers the whole time build.mcpp is being typed.

Proposal: on MCPP_BUILD_DATABASE_PROGRAM_FAILED, keep the last complete model for the targets (no plan change, no restart). Show mcpp's compile error as a diagnostic on build.mcpp, and adopt the new description once it compiles.
Test: a fixture that autosaves a broken build.mcpp while a target file is open. No engine-restart; the target keeps its diagnostics and completion; build.mcpp shows the error.
(Open question for mcpp: could emit build-database keep the last successful build-program outputs for the targets when build.mcpp fails?)

3. A warm start on Windows rebuilds most modules (high, cause to confirm)

GalTranslPP, a restart on the same cache: the start begins at 6 of 25 modules prepared, and takes 188 s (0.0.12) or 177 s (0.0.11) to reach ready. Every start reports model-stale and producer-slow (mcpp's emit build-database takes 45–110 s on this project). For 0.0.12 the restart also ended degraded, with producer-partial, which 0.0.11 did not report. On Linux, a warm start rebuilds nothing (ux-mcpp U2: 0 modules rebuilt).

To find out:

  • why the cached model is stale at every start;
  • whether the new description changes the units' commands, which would key the BMIs differently;
  • whether Windows' legacy module cache (no owned cache there) loses BMIs across a clangd restart;
  • what the producer-partial of 0.0.12 says.

Test: a Windows fixture with modules that starts twice on one cache and requires 0 rebuilt modules on the second start, as ux-mcpp U2 does on Linux.

4. The mcpp version is lost after the first describe (medium)

src/project/mcpp.cpp, ProducerAnswers, caches only the "yes, this mcpp produces build databases" answer from mcpp --protocol-version. The version is not cached with it, so every later emit_build_database returns version = "":

  • report.json → project.producerVersion: "" (the bundle shows one --protocol-version run and six emit runs);
  • the build-program-context diagnostic for a .mcpp file no set describes says "this mcpp describes the targets only" without naming the version;
  • inputs_fingerprint includes the producer version, so the cached model's fingerprint changes between the first describe and later ones. This may also play a part in problem 3.

In that bundle the database had 3 sets and no qt-demo:build / mcpp:core, even when emit succeeded. mcpp 2026.10.8.1 through 2026.10.10.2 compile build.mcpp during emit (hence MCPP_BUILD_DATABASE_PROGRAM_FAILED) but do not describe build programs; only 2026.10.11.1 does (#51). The user's mcpp was too old for build.mcpp code intelligence, and mcppls could not tell them.

Proposal: cache the version with the answer (key → version) and fill it in on every describe. Test: two describes through a remembered answer both report the version.

5. "ready" while clangd still builds modules for the open files (medium)

GalTranslPP, cold start (0.0.12): the status was ready, with every open file diagnosed and quiet for 60 s, at 486 s. clangd built its last module at 522 s, and completion in the open files still took several seconds after "ready" (the probe's idle rounds were all at the 1 s budget, empty). A person who sees "ready" and types gets nothing.

Proposal: an open file whose prerequisite set clangd is still building is not ready. Report it, for example "preparing (modules for the open files)", until its set is built.

6. About 0.5 s per completion on Windows in files that mix heavy headers with imports (medium)

ux-modules-windows (<windows.h> in the global module fragments of two module units, and in a file that imports both): idle completion has a p95 of 0.46–0.71 s, and completion while typing has a p95 of 0.79–1.00 s. About a fifth of the completions land past the 1 s budget, depending on the runner. The fixture's budgets were set to p95 1.1 s and engine share 0.65 for 0.0.12. In the same fixture on Linux with Qt, completion takes 0.05 s.

From the debug logs: about 350 ms pass between the module validation and Sema's results. That is the parse of the body against a 28 MB preamble plus the module files whose GMFs hold <windows.h> again. --pch-storage=memory made no difference. Stock clangd has no preamble at all for such a file (seconds per request), so 0.0.12 is still far ahead. But the goal is the Linux number.

To find out: where clang spends those 350 ms on Windows (deserialization of the duplicated declarations of <windows.h> from the PCH and from each module, the merging of their redeclarations); compare with Qt on Linux; look for what can be skipped for a completion.

7. Preambles of heavy-header files are 3× larger on Windows (low)

GalTranslPP: 0.0.12 builds 53 MB preambles in about 7 s for these files. 0.0.11 built 17 MB in 1.4 s, or none at all. This is the intended textual preamble (the headers kept, the imports replayed), but it costs memory or disk per open file and time per rebuild.

To find out: what the extra 36 MB is, and whether the module files' copies of the same headers can be left out of it.

8. One unexplained event-loop stall after a clangd kill (low)

Once, locally, during ux-mcpp's U9 (kill clangd): the server logged the event loop took ... 911383 ms for its timers and never became ready again. Three later runs and CI all passed; the host was heavily loaded (load average 86, swap full). Kept in case it shows up again: if it does, take a stack of the server's threads during the stall.


Next evidence: a steady-state run of the GalTranslPP probe (run 38157130577, E-steady: measure only after clangd has built nothing for four minutes) will say how fast 0.0.12 is on a prepared big Windows project. It will be added here.

主要语言
C++
星标
25
派生
2
平均合并
21 小时 5 分钟
30 天内合并 PR
13

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

Sunrisepeak/mcpp-language-server 的其他 Issue

查看 Sunrisepeak/mcpp-language-server 的全部 Issue

相似的 Issue

更多 C++ Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。