Repository navigation
mcpp-language-server v0.0.12
mcpp-language-server 0.0.12
What changed
The bundled clangd is now mcppls-clangd: LLVM 23.1.0 with 25 patches for C++ modules
(mcppls-clangd 0.0.12,
reporting 23.1.0-mcppls.0). Each patch maps to rows of the upstream-defects register (issue #24)
and carries a drop condition. The payload pins the engine by its binary SHA-256 and its source
identity, and the server checks both before it trusts what the engine declares.
Completion on files that import modules
- Completion answers from the semantic parser, quickly. On the Qt project fixture (12 contexts,
3 starts × 30 rounds each, Linux x64), warm completion has p95 53–91 ms and completion right after
an edit 133–168 ms. In the same measurement, completion after an edit is at least twice as fast
as with stock clangd 23.1. Completion loads from imported modules only the names that can match
what was typed, shares the draft's verified imports, and lists each constructor overload once. Module importers still answer about 30 ms slower than the same
project written with headers once warm; that gap is open. - Files that include heavy headers and import modules keep their preamble. A file that
includes Qt or<windows.h>and imports modules (whose own global module fragments include them
too) used to be parsed in full, headers and all, for every request: about 0.6 s per completion
for a Qt importer with stock clangd and before this release, and seconds per update with
<windows.h>. Its headers are now kept in a preamble that is checked against every input it
read, on Linux, Windows and macOS: 0.05 s per completion on the same Qt file. New conformance
fixturesux-modules-qt(Linux) andux-modules-windows(Windows) hold answers, latency while
typing, crashes and stalls on such projects. - Typing an import, or editing a module the file imports, no longer waits on a rebuild.
Completion on an import line, or on a blank line among the imports, uses the modules it has. An
import nothing in the project builds keeps them too. After a dependency is edited, completion
waits up to 250 ms for its rebuild and otherwise answers from the modules as they were, while
the rebuild goes on. A cached dependency scan no longer reads every header again. - Unsaved edits count. Dependency scans read the request's own buffers. A cached scan or BMI
verdict is reused only after every input it observed replays unchanged, including__DATE__-like
builtins and files that did not exist.
Building modules
- Prerequisite modules build as one bounded, cancellable graph. Independent modules compile in
parallel within a shared limit. A cycle fails before any BMI is built, and closing a document
cancels its waits. A module change rebuilds only the modules that depend on it. - On Linux, module compilers run in supervised worker processes. They stop when clangd dies,
are admitted against a shared memory budget, and the files they leave are collected once nothing
holds them. - Malformed module directives recover in place. A missing
;is reported on the directive
that lacks it, and a directive after a missing BMI no longer derails the rest of the file. The
product's own relocation of that diagnostic (WA-CLANGD-006) retires for an engine that declares
the fix. - An import of a module nothing provides is reported, and the file keeps answering. A module
unit whose import resolves to nothing no longer stalls clangd or the files that import it. For
an engine that declares this (unresolved-import-recovery), the product stops giving such an
import in a file that provides no module a stand-in, and stops setting a file aside while an
autosave has such an import on disk (WA-CLANGD-013). Typing an import with autosave on no longer
rewrites the engine database at each name it passes through. A module unit's own unresolved
import still gets a stand-in, once the unit has not been edited for a few seconds, so its
importers keep their features (WA-CLANGD-002). - A module built again to the same bytes keeps the modules that import it. A BMI that was
lost, evicted or damaged is built again, and when its bytes are the same its importers are
reused instead of being rebuilt one by one (ux-mcpp: 42 importers after one lost module).
Reusing a cached module no longer looks at every slot of the cache, which made each of a
request's prerequisites cost about 12 ms, and a file's last prerequisites stay with the engine
between requests, so typing an import no longer copies every module it needs again (1-2 s for a
completion right after an autosave). - The module cache follows the workspace's cache budget. On Linux, mcppls-clangd's own module
cache gets three quarters ofmcppls.cache.maxBytes(at least 1 GiB; unbounded when the budget
is) instead of a fixed 1 GiB, past which module builds waited for room: a profile change with
its modules beside the first profile's stalled the files that needed them. - Reusing a dependency scan no longer reads every header again. A header that is on disk with
the identity, size and modification time the scan saw, and was last modified well before it, is
taken as unchanged, as clang does for a module's inputs. A hit on the standard library module's
scan used to read and hash each libc++ header.
mcpp's build programs
build.mcpphas the features of target code (#51). From mcpp 2026.10.11.1 the build database
describes the build programs:build.mcpp, the libraries of[build-dependencies]and mcpp's
engine interface (import mcpp;), in sets of thebuild-programconfiguration.build.mcppis
read as C++ with the arguments mcpp compiles it with, so navigation, hover, completion and
diagnostics reach its libraries and the engine interface. Every editor integration treats.mcpp
files as C++.- The targets and the build programs stay apart. The default context reads a package in both
[dependencies]and[build-dependencies]as the targets build it, and the context
<package>:buildreads the build programs as mcpp compiles them; build programs with a toolchain
of their own, as in a cross build, are read there and say so. A target that importsmcppor a
library of[build-dependencies], and abuild.mcppthat imports a module of the targets, get an
error at the import, as mcpp refuses them. - The engine interface is read-only. Formatting, code actions and renames never edit
<MCPP_HOME>/engine/<version>/modules, and VS Code opens it read-only. - With an mcpp older than 2026.10.11.1,
build.mcppis not read, and a note in it names the mcpp
that describes it.
Editing
- Formatting has an mcpp fallback.
mcppls.format.fallbackStyle(defaultauto): a project
without.clang-formatthat is an mcpp project formats in the pinned mcpp style. A named style
overrides it, and a project.clang-formatalways wins. Other projects keep clangd's default. - Compiler extensions complete. Attribute syntax, cleanup functions and, on Windows targets,
SEH constructs are offered where they are valid. textDocument/semanticTokens/rangeis answered, andmisc-const-correctnessno longer suggests
constfor a range a pipeline consumes.
Fixes
- "preparation-stalled" no longer fires the moment preparation starts again (#49). Preparation
that had finished a while earlier and was given modules again — a model reloaded, a file opened
that imports a module nobody had prepared — measured its stall clock from the previous run's
last progress. It reported "made no progress for a minute (34/39 done)" seconds after starting,
and wrote a diagnostic bundle. - A file mcppls's own engine answers for a while (its module does not compile) is no longer taken
for one clangd will not finish once it goes back, and a syntax error in a file the editor opened
outside the workspace is no longer reported as a project issue.
VS Code
- A server that crashes while starting recovers cleanly. Recovery waits for the failed start
to settle, then starts a fresh client through the same queue as a manual restart, under the same
crash budget. A failed protocol write closes the connection instead of leaving an unhandled
rejection (WA-VSCODE-003, WA-VSCODE-004). A crash report keeps the log path the server announced.
Platforms and compatibility
- linux-arm64 runs on far more systems. Its clangd is the maintained engine built on an
Ubuntu 20.04 floor, so it needs glibc 2.31 (Ubuntu 20.04, Debian 11, RHEL 9 and later) instead
of 2.34 and GCC 12's libstdc++. - linux-x64's bundled clangd now needs glibc 2.31. Stock clangd needed 2.18. On an older system
(Ubuntu 18.04, Debian 10, RHEL 8) the bundled clangd cannot start. mcppls then keeps its own
module-level features and says why in its status, andmcppls.clangdcan point at another
clangd. - macOS needs 12 or later (was 11): the engine is built for macOS 12.
- An external server or clangd keeps working as before. Intel macOS still has no bundled build.
Files
| File | What it is | How to install it |
|---|---|---|
mcppls-linux-x64.vsix |
The VS Code extension for one platform, with that platform's payload inside it | code --install-extension <file>, or the Extensions view's “Install from VSIX…” |
mcppls-linux-arm64.vsix |
The VS Code extension for one platform, with that platform's payload inside it | code --install-extension <file>, or the Extensions view's “Install from VSIX…” |
mcppls-darwin-arm64.vsix |
The VS Code extension for one platform, with that platform's payload inside it | code --install-extension <file>, or the Extensions view's “Install from VSIX…” |
mcppls-win32-x64.vsix |
The VS Code extension for one platform, with that platform's payload inside it | code --install-extension <file>, or the Extensions view's “Install from VSIX…” |
payload-linux-x64.tar.gz |
The server, the clangd it drives and the semantic kit, as one tree. What every non-VS-Code editor needs | Unpack it and put payload/bin/ on PATH; mcppls serve speaks LSP over stdio |
payload-linux-arm64.tar.gz |
The server, the clangd it drives and the semantic kit, as one tree. What every non-VS-Code editor needs | Unpack it and put payload/bin/ on PATH; mcppls serve speaks LSP over stdio |
payload-darwin-arm64.tar.gz |
The server, the clangd it drives and the semantic kit, as one tree. What every non-VS-Code editor needs | Unpack it and put payload/bin/ on PATH; mcppls serve speaks LSP over stdio |
payload-win32-x64.tar.gz |
The server, the clangd it drives and the semantic kit, as one tree. What every non-VS-Code editor needs | Unpack it and put payload/bin/ on PATH; mcppls serve speaks LSP over stdio |
mcppls-zed-0.0.12.tar.gz |
The Zed extension directory mcppls-zed/: extension.toml, the compiled extension.wasm and the crate it was compiled from, which Zed's dev-extension install compiles again. Platform-independent; the server comes from the payload |
Unpack it, put the payload's payload/bin/ on PATH, then Zed's command palette: zed: install dev extension, and choose mcppls-zed (Zed compiles it, which needs Rust through rustup) |
mcppls-clion-0.0.12.zip |
The IntelliJ-platform plugin archive Gradle produces. Gradle and the JDK it compiles with come from the clion feature (xim:gradle, xim:jdk-temurin), so it does not depend on whatever JDK the machine happens to default to |
Put the payload's payload/bin/ on PATH, then CLion: Settings → Plugins → the gear menu → Install Plugin from Disk, and restart |
SHA256SUMS |
sha256 of every other file in the release | sha256sum -c SHA256SUMS |
Not in a release
- The Claude Code plugin: it is consumed from the repository through its marketplace file, not downloaded as an archive.
- xlings-res archives and the rendered xim-pkgindex descriptors: the ecosystem publish path is deliberately out of scope for this release, so
mcppls-devtools release xlingsis not run. - The model gateway: a separate package, built and tested on its own, not part of what a user installs.
Generated from packaging/release.manifest.json for 0.0.12.