From af69f0d6a4a291cbb29cf6080b4f2286a8f5b92f Mon Sep 17 00:00:00 2001 From: Ben McMorran Date: Tue, 16 Jun 2026 17:55:37 -0700 Subject: [PATCH 01/15] Set plugin source --- plugins/cpp-language-server/.github/plugin/plugin.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/cpp-language-server/.github/plugin/plugin.json b/plugins/cpp-language-server/.github/plugin/plugin.json index a0dbdad..6dd636e 100644 --- a/plugins/cpp-language-server/.github/plugin/plugin.json +++ b/plugins/cpp-language-server/.github/plugin/plugin.json @@ -20,6 +20,9 @@ "args": [ "@microsoft/cpp-language-server" ], + "env": { + "MSCPPLS_PLUGIN_SOURCE": "public" + }, "fileExtensions": { ".cpp": "cpp", ".cxx": "cpp", From dd6cdad133cda71a3b972220ea712ac2b7d37fb8 Mon Sep 17 00:00:00 2001 From: Ion Todirel Date: Wed, 17 Jun 2026 17:52:13 -0700 Subject: [PATCH 02/15] Add generate-compile-commands skill to cpp-language-server plugin Adds a skill that generates compile_commands.json (clang compilation database) for MSBuild (.sln/.slnx/.vcxproj) and CMake C++ projects, and registers it in the plugin manifest's skills array. --- .../.github/plugin/plugin.json | 4 +- .../skills/generate-compile-commands/SKILL.md | 187 ++++++++++++++++++ 2 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md diff --git a/plugins/cpp-language-server/.github/plugin/plugin.json b/plugins/cpp-language-server/.github/plugin/plugin.json index 6dd636e..e13cd40 100644 --- a/plugins/cpp-language-server/.github/plugin/plugin.json +++ b/plugins/cpp-language-server/.github/plugin/plugin.json @@ -13,7 +13,9 @@ "lsp", "language-server" ], - "skills": [], + "skills": [ + "./skills/generate-compile-commands" + ], "lspServers": { "cpp": { "command": "npx", diff --git a/plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md b/plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md new file mode 100644 index 0000000..5a8ad22 --- /dev/null +++ b/plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md @@ -0,0 +1,187 @@ +--- +name: generate-compile-commands +description: Generate compile_commands.json (clang compilation database) for the C++ language server. Covers MSBuild (.sln, .slnx, .vcxproj) via microsoft/msbuild-extractor-sample and CMake projects via CMAKE_EXPORT_COMPILE_COMMANDS. Use whenever the user asks to "regenerate compile commands", "regenerate the project", "reload the project", "load the project", "refresh compile commands", or otherwise needs a fresh compilation database for mscppls. +--- + +# Generate compile_commands.json + +The C++ language server needs a `compile_commands.json` (clang compilation database) to understand a project. How you produce one depends on the build system: CMake can export it directly, MSBuild needs an external extractor. + +Always regenerate `compile_commands.json` when this skill runs, even if one already exists for the project. For MSBuild, write it to `.mscppls\compile_commands.json` at the workspace root (the examples below do this); mscppls auto-discovers any `compile_commands.json` within the workspace, so no `cpp-lsp.json` is required. Add `.mscppls/` to `.gitignore` so it does not get committed. mscppls hot-reloads the file content; `/restart` is only needed after changing the plugin's `lsp.json` or the workspace `cpp-lsp.json` (those are read once at LSP startup). + +## CMake projects + +CMake writes `compile_commands.json` itself; no external extractor needed. Enable it at configure time: + +```bash +cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON +cmake --build build +``` + +Or persist it in the project so every configure picks it up: + +```cmake +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +``` + +The file lands at `/compile_commands.json` (whatever directory you passed to `-B`). Point the workspace `cpp-lsp.json` at it: + +```json +{ + "version": 1, + "repositoryPath": "../", + "compileCommands": "../build/compile_commands.json" +} +``` + +CMake regenerates the file on the next configure (e.g. running `cmake -B build` again, or `cmake --build build` after editing `CMakeLists.txt`). The refresh story for CMake is "re-run cmake configure"; the MSBuild-specific sections below do not apply. + +## MSBuild projects + +For MSBuild (`.sln`, `.slnx`, `.vcxproj`), generate `compile_commands.json` with [`microsoft/msbuild-extractor-sample`](https://github.com/microsoft/msbuild-extractor-sample). Extraction is design-time: it evaluates projects and runs `GetClCommandLines`, it does **not** compile anything. + +### Get the extractor + +Download the pinned release and verify its SHA256 before trusting it. The binary is self-contained, with no .NET runtime needed. + +```powershell +$version = 'v0.2.0' +$expected = '01a5e2d399c3cb84d3136d0b6ef7b84a05900838ddc3b1f710b9394c8c2936ce' +$exe = ".tools\msbuild-extractor-sample.exe" + +if (-not (Test-Path $exe) -or (Get-FileHash $exe -Algorithm SHA256).Hash -ne $expected.ToUpper()) { + New-Item -ItemType Directory -Path ".tools" -Force | Out-Null + $tmp = "$exe.download" + Invoke-WebRequest -Uri "https://github.com/microsoft/msbuild-extractor-sample/releases/download/$version/msbuild-extractor-sample.exe" -OutFile $tmp + $actual = (Get-FileHash $tmp -Algorithm SHA256).Hash + if ($actual -ne $expected.ToUpper()) { + Remove-Item $tmp -Force + throw "SHA256 mismatch`n expected: $expected`n actual: $actual" + } + Move-Item $tmp $exe -Force +} +``` + +When upgrading the pinned version, get the new SHA256 from the `digest` field of the asset at `https://api.github.com/repos/microsoft/msbuild-extractor-sample/releases/latest`. + +### Run it + +For a typical project on a workstation with Visual Studio installed, the extractor auto-detects Visual Studio via `vswhere.exe` and resolves `VCTargetsPath`, `VCToolsInstallDir`, and `cl.exe` automatically. Solution-based extraction is the simplest entry point: + +```powershell +New-Item -ItemType Directory -Path .mscppls -Force | Out-Null +.tools\msbuild-extractor-sample.exe ` + --solution myapp.sln ` + -c Debug -a x64 ` + -o .mscppls\compile_commands.json +``` + +`-c` is `--configuration` (default `Debug`), `-a` is `--platform` (e.g. `x64`, `Win32`, `ARM64`), `-o` is `--output`. `--solution` accepts `.sln` and `.slnx`; it is repeatable for cross-solution work. `--project` works the same way for individual `.vcxproj` files (also repeatable, deduplicates entries). + +#### From a Developer Command Prompt or activated vcvars shell + +If you launched a Developer Command Prompt / Developer PowerShell for VS, or ran `vcvarsall.bat x64`, the toolchain env vars (`VCINSTALLDIR`, `VCToolsInstallDir`, `INCLUDE`, `LIB`, etc.) are already set in the current shell. Pass `--use-dev-env` to make the extractor honor them rather than re-resolving via `vswhere`: + +```powershell +.tools\msbuild-extractor-sample.exe ` + --use-dev-env ` + --solution myapp.sln ` + -c Debug -a x64 ` + -o .mscppls\compile_commands.json +``` + +This guarantees the LSP indexes against the exact same toolchain the developer is building with. Use it whenever the project depends on a specific VS version, SDK, or side-by-side toolchain that the default `vswhere` heuristic might not pick. + +#### Multiple VS installs + +If `vswhere` picks the wrong one, list and select explicitly: + +```powershell +.tools\msbuild-extractor-sample.exe --list-instances +.tools\msbuild-extractor-sample.exe --vs-instance --solution myapp.sln -c Debug -a x64 +``` + +#### Multi-configuration projects + +Prefer the built-in flags over manual merging; they produce one IntelliSense-friendly entry per source file across all configurations: + +```powershell +.tools\msbuild-extractor-sample.exe ` + --solution myapp.sln ` + --all-configurations --merge --deduplicate ` + -o .mscppls\compile_commands.json +``` + +Skip `--validate` during normal LSP setup. It compiles every TU with `cl.exe /c` and is slow. Reach for it only when debugging the extractor itself. + +### Advanced: out-of-process mode for vendored or hermetic-toolchain repos + +Some repos vendor a hermetic toolchain (MSBuild, the C++ compiler, Windows SDK headers, targets files) into the repo itself, for example as NuGet packages, a mounted toolchain ISO, or a `.tools\` directory. Builds are driven by a wrapper or environment-activation script (`build.cmd`, `init.cmd`, `LaunchBuildEnv.cmd`, etc.) that sets `PATH`, `VCTargetsPath`, `INCLUDE`, and `LIB` to point at the vendored versions. A fully public example is [`microsoft/Windows-driver-samples`](https://github.com/microsoft/Windows-driver-samples) built with the Enterprise WDK (EWDK), a self-contained command-line toolchain you mount and activate with `LaunchBuildEnv.cmd`. + +If you let the extractor's default **in-process** MSBuild evaluation run in such a repo: + +- It loads the MSBuild API from the running .NET host, which then probes the system Visual Studio install for targets, not the repo's vendored MSBuild. +- The compile commands point at the system `cl.exe`, which is a different version than the one the repo actually builds with. The LSP then fails to find the right intrinsics, conformance flags, or module `.ifc` files and reports phantom errors. +- Tightly integrated environments may fail outright with `REGDB_E_INVALIDVALUE` because the in-proc API tries to read VS COM registration that the vendored toolchain doesn't provide. + +The fix is **out-of-process mode**: spawn the repo's own MSBuild.exe via `--msbuild-path`, and pin the targets and compiler paths to match what the repo's normal build uses. + +| Flag | Why | +|---|---| +| `--msbuild-path ` | Drive the repo's own MSBuild (e.g. `build.cmd`) out-of-proc, so vendored targets/SDKs resolve correctly | +| `--vc-targets-path ` | Point at the vendored VC targets so MSBuild does not probe a global VS | +| `--cl-path ` | Pin the LSP to the same compiler version the repo builds with. Critical for matching intrinsics, std-lib paths, and module IFCs | +| `--msbuild-property BuildProjectReferences=false` | Skip transitive project-reference evaluation; vendored-toolchain repos often have deep graphs where this otherwise hangs | +| `--msbuild-property =` | Some repos need extra properties to evaluate correctly. Check the repo's build docs | + +Example (the Windows driver samples built with the Enterprise WDK; the version folders track the EWDK build, here `18` / `v180` / `14.50.35717`, so confirm them after mounting): + +```powershell +.tools\msbuild-extractor-sample.exe ` + --msbuild-path "D:\Program Files\Microsoft Visual Studio\18\BuildTools\MSBuild\Current\Bin\MSBuild.exe" ` + --solution general\echo\kmdf\kmdfecho.sln ` + -c Debug -a x64 ` + --vc-targets-path "D:\Program Files\Microsoft Visual Studio\18\BuildTools\MSBuild\Microsoft\VC\v180" ` + --cl-path "D:\Program Files\Microsoft Visual Studio\18\BuildTools\VC\Tools\MSVC\14.50.35717\bin\Hostx64\x64\cl.exe" ` + -o .mscppls\compile_commands.json +``` + +When the toolchain is already activated in the current shell (for example after running the EWDK's `LaunchBuildEnv.cmd`), pass `--use-dev-env` instead of the explicit `--msbuild-path`, `--vc-targets-path`, and `--cl-path`, and the extractor reads those paths from the environment. + +The extractor cannot consume `dirs.proj` or aggregate `.proj` files; point it at a real leaf `.vcxproj` (or `.sln`). + +If the repo needs initialization for its props, targets, and dependencies to resolve, initialize it once, then run the extractor. + +> **Note:** Verify initialization at most once; avoid re-checking the same state (for example a build environment variable) or re-requesting approval in a loop. +> If you can't confirm initialization, initialize the repo (or ask the user once), then run the extractor. Use `--msbuild-path` to select the intended MSBuild for vendored toolchains, but don’t treat it as a substitute for repo initialization. + +### Manual merge fallback + +`--all-configurations --merge --deduplicate` handles almost every multi-config case. Reach for a manual merge only when projects genuinely need conflicting `--platform`, `--configuration`, or `--msbuild-property` flags and have to be extracted in separate invocations. Write each invocation's output to a distinct file under `.mscppls\` (e.g. `.mscppls\compile_commands_debug.json`), then merge: + +```powershell +$all = @{} +Get-ChildItem .mscppls\compile_commands_*.json | ForEach-Object { + (Get-Content $_ -Raw | ConvertFrom-Json) | ForEach-Object { + $key = $_.file.ToLowerInvariant() + if (-not $all.ContainsKey($key)) { $all[$key] = $_ } + } +} +ConvertTo-Json -InputObject @($all.Values) -Depth 6 | Set-Content .mscppls\compile_commands.json -Encoding UTF8 +``` + +`@($all.Values)` forces an array even with a single entry; otherwise `ConvertTo-Json` emits a bare object and the file is not a valid compilation database. + +## Troubleshooting + +These cover the MSBuild extractor path. For CMake, build-system errors come from `cmake` itself. + +| Symptom | Cause | Fix | +|---|---|---| +| `REGDB_E_INVALIDVALUE`, or compile commands point at the wrong `cl.exe` | In-proc MSBuild picked up a system VS install instead of the repo's vendored toolchain | Switch to out-of-process mode with `--msbuild-path` and pin `--vc-targets-path` / `--cl-path` | +| Extractor hangs | Transitive project-reference evaluation on a deep build graph | Add `--msbuild-property BuildProjectReferences=false` | +| `--validate` reports missing module `.ifc` | Module producer not built | Build dependencies first, or just skip `--validate` | +| LSP doesn't see newly extracted entries | mscppls observer is still hashing the new file | Wait a few seconds; mscppls hot-reloads, so do **not** `/restart` | +| `vswhere` picks the wrong VS install | Multiple VS instances present | `--list-instances` then `--vs-instance ` | + +For extractor diagnostics, re-run the same command and read its stderr inline; don't redirect to a file. From 5314f2246206364741ca6e9c51ae994c5ff67ef5 Mon Sep 17 00:00:00 2001 From: Ion Todirel Date: Wed, 17 Jun 2026 18:27:16 -0700 Subject: [PATCH 03/15] Add guide for authoring a custom-build-system extractor skill Adds AUTHORING_EXTRACTOR_SKILL.md: guidance for configuring microsoft/msbuild-extractor-sample and authoring a per-repo extraction skill for projects that build with a custom, vendored, or hermetic toolchain (with a public Windows-driver-samples / EWDK example). --- AUTHORING_EXTRACTOR_SKILL.md | 170 +++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 AUTHORING_EXTRACTOR_SKILL.md diff --git a/AUTHORING_EXTRACTOR_SKILL.md b/AUTHORING_EXTRACTOR_SKILL.md new file mode 100644 index 0000000..98412e6 --- /dev/null +++ b/AUTHORING_EXTRACTOR_SKILL.md @@ -0,0 +1,170 @@ +# Configuring the MSBuild Extractor for Custom Build Systems + +[`microsoft/msbuild-extractor-sample`](https://github.com/microsoft/msbuild-extractor-sample) +generates a `compile_commands.json` (a clang compilation database) from MSBuild C++ projects so +C++ language services can initialize their LSP server and provide code intelligence. For a normal +`.sln`/`.vcxproj` built with an installed Visual Studio it auto-detects the toolchain through +`vswhere.exe` and usually needs no configuration. Other MSBuild setups can still need configuration +(for example multiple Visual Studio installs, a specific platform toolset or SDK, or projects that +must be restored first); the `generate-compile-commands` skill covers those. The setup below is for +a **custom** toolchain: a +hermetic or vendored toolset that ships inside the repo and is activated by a wrapper script, +which the automatic detection won't find on its own. + +## Signs you need a configuration skill + +You probably need one if the default setup does not just work for your repo. The first sign is +visible up front, before you run anything; the rest show up after extraction: + +- Up front, in how the repo builds: it vendors its own toolchain (a checked-in or + package-restored compiler, Windows SDK, and MSBuild/targets) and builds through a wrapper or + environment-activation script rather than an installed Visual Studio, so stock `vswhere` + auto-detection will not match it. +- The extractor finishes but produces an empty or nearly empty `compile_commands.json`. +- Your editor shows red squiggles and errors on code that builds fine normally. +- IntelliSense can't find standard headers, or seems to use the wrong compiler version. +- The optional `--validate` check (it runs the real compiler on the extracted commands) fails on + sources that build fine in your normal build, with a toolchain error rather than an error in + your own code. +- The extractor seems to hang or takes a very long time on a large project. + +These usually mean the extractor found a different toolchain than the one your repo actually +builds with. The fix is to point it at your repo's own build tools (out-of-process mode), which +the example below shows how to do. + +To verify, inspect the generated `compile_commands.json` before assuming the toolchain is wrong: + +- Check it is not empty: it should have roughly one entry per translation unit. In PowerShell, + `(Get-Content .mscppls\compile_commands.json -Raw | ConvertFrom-Json).Count`. +- Open one entry and confirm its `command`/`arguments` reference the compiler you actually build + with (your repo's `cl.exe`, not a system Visual Studio one) and include your project's include + paths and defines. +- In the CLI, run `/lsp show` to confirm the `cpp` server is configured, then ask a navigation + question (for example where a symbol is defined); if it resolves, the database is being used. + +## Settings to capture + +| Flag | Why | +|---|---| +| `--msbuild-path` | Run the repo's own MSBuild out-of-process so its targets and SDK resolve | +| `--vc-targets-path` | Pin the vendored VC targets (use an absolute path) | +| `--cl-path` | Pin the same compiler the repo builds with (use an absolute path) | +| `--use-dev-env` | Read toolchain paths from an activated developer environment instead of relying on `vswhere.exe` auto-detection | +| `-c` / `-a` | The repo's configuration and platform | +| `--msbuild-property BuildProjectReferences=false` | Skip deep reference graphs that otherwise hang | +| `--msbuild-property KEY=VALUE` | Any repo-specific property the build needs | + +Point the extractor at a real `.sln`, `.slnx`, or `.vcxproj` file. + +## Designing the SKILL + +A skill is a folder with a `SKILL.md`: YAML frontmatter (`name`, `description`) plus a body with +the pinned extraction command and any project lookup. Keep it generic and document only what is +different about your repo. The `description` is what makes the assistant auto-invoke the skill, +so phrase it with the words users type (generate, regenerate, or refresh compile commands; set +up C++ IntelliSense). + +## What to put in your SKILL + +These keep the generated database matched to your real build, so encode them in your `SKILL.md`. + +Bake into the extraction command: + +- Use absolute paths for `--vc-targets-path` and `--cl-path`. +- Prefer out-of-process mode (`--msbuild-path`) in a vendored repo; when you have an activated developer environment (for example EWDK), `--use-dev-env` can also pin extraction to the intended toolchain. +- Point at a `.sln` or a specific `.vcxproj`, not a generated or aggregate project file. + +Capture as prerequisites or notes in the skill body: + +- Restore first if the project's targets come from a package: `msbuild /t:restore`. +- Omit `--validate` for IntelliSense setup; it recompiles every file and is slow. +- Always regenerate fresh; never reuse a stale `compile_commands.json`. +- Pin the extractor version and verify its SHA256 (releases ship a self-contained single-file exe). + +## Example: Windows driver samples with the EWDK + +[`microsoft/Windows-driver-samples`](https://github.com/microsoft/Windows-driver-samples) built +with the **Enterprise WDK (EWDK)** is a fully public version of this case. The EWDK is a free, +self-contained command-line toolchain (an ISO you mount) that bundles MSBuild, the compiler, +the Windows SDK, and the WDK, and is activated by `LaunchBuildEnv.cmd`. Because it ships its +own tools, point the extractor at the EWDK explicitly. + +The driver projects pull their build logic in through `$(VCTargetsPath)` (the +`WindowsKernelModeDriver10.0` toolset) and reference no NuGet packages, so the EWDK already +provides everything and there is no `/t:restore` step. + +Where things live (EWDK mounted at `D:\`, repo at `C:\src\Windows-driver-samples`). Folder names +track the EWDK release, so confirm them after mounting. This example is build 28000.1839, which +ships Visual Studio 18 Build Tools, MSVC 14.50.35717, and WDK 10.0.28000.0: + +| Item | Path | +|---|---| +| Activation wrapper | `D:\LaunchBuildEnv.cmd` | +| MSBuild | `D:\Program Files\Microsoft Visual Studio\18\BuildTools\MSBuild\Current\Bin\MSBuild.exe` | +| VC targets | `D:\Program Files\Microsoft Visual Studio\18\BuildTools\MSBuild\Microsoft\VC\v180` | +| Compiler | `D:\Program Files\Microsoft Visual Studio\18\BuildTools\VC\Tools\MSVC\14.50.35717\bin\Hostx64\x64\cl.exe` | +| Example solution | `C:\src\Windows-driver-samples\general\echo\kmdf\kmdfecho.sln` | + +The reliable way to run it is from an activated EWDK shell, so the extractor uses the EWDK +toolchain instead of any Visual Studio that also happens to be installed on the machine. + +A skill that captures it: + +````markdown +--- +name: wdk-samples-generate-compile-commands +description: Generate compile_commands.json for the Windows driver samples built with the EWDK. Use when setting up C++ IntelliSense or extracting compile commands from WDK .vcxproj/.sln files. +--- + +# Generate compile_commands.json for the Windows driver samples (EWDK) + +The EWDK is self-contained and bundles the WDK, so there is no NuGet restore step. Run from an +activated EWDK shell and let the extractor read the toolchain from the environment. + +## Prerequisites + +- Mount the EWDK ISO (for example as `D:`) and start its shell: `D:\LaunchBuildEnv.cmd`. +- Confirm the toolchain is active: `where cl.exe` resolves under the mounted EWDK. + +## Extraction command + +From the activated EWDK shell, in the repo root: + +```powershell +.tools\msbuild-extractor-sample.exe ` + --use-dev-env ` + --solution general\echo\kmdf\kmdfecho.sln ` + -c Debug -a x64 ` + -o compile_commands.json +``` + +`--use-dev-env` reads the toolchain environment the EWDK exports (`VCToolsInstallDir`, +`VCTargetsPath`, `WindowsSdkDir`, `INCLUDE`, `LIB`), which pins extraction to the EWDK. + +## Alternative: explicit paths + +If you cannot use an activated shell, pin the EWDK tools by hand. On a machine that also has +Visual Studio installed, prefer the activated shell so the extractor does not pick up the system +toolchain. + +```powershell +.tools\msbuild-extractor-sample.exe ` + --msbuild-path "D:\Program Files\Microsoft Visual Studio\18\BuildTools\MSBuild\Current\Bin\MSBuild.exe" ` + --solution general\echo\kmdf\kmdfecho.sln ` + -c Debug -a x64 ` + --vc-targets-path "D:\Program Files\Microsoft Visual Studio\18\BuildTools\MSBuild\Microsoft\VC\v180" ` + --cl-path "D:\Program Files\Microsoft Visual Studio\18\BuildTools\VC\Tools\MSVC\14.50.35717\bin\Hostx64\x64\cl.exe" ` + -o compile_commands.json +``` + +## Notes + +- The EWDK bundles the WDK, so the driver `.vcxproj` files resolve their targets without a NuGet restore. +- The version folders (`18`, `v180`, `14.50.35717`, `10.0.28000.0`) track the EWDK build; confirm them after mounting. +- Point at the `.sln` or a specific `.vcxproj`, not a generated or aggregate project file. +```` + +### Invoking the skill to generate compile_commands.json + +- "Generate compile_commands.json for the kmdfecho driver sample" +- "Set up C++ IntelliSense for the Windows driver samples using the EWDK" From 759c9fc84d8b47e8720a622154b5e56af068828c Mon Sep 17 00:00:00 2001 From: Sinem Akinci Date: Thu, 18 Jun 2026 11:33:33 -0700 Subject: [PATCH 04/15] update readme for latest plugins, skills, and guidance --- README.md | 56 +++++++++++++++++-------------------------------------- 1 file changed, 17 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 0015269..e47ef94 100644 --- a/README.md +++ b/README.md @@ -6,46 +6,22 @@ _The Microsoft C++ Language Server is currently in preview and may be subject to # πŸš€ Quick start -1. Run `npm install -g @microsoft/cpp-language-server`. +1. Install the [`cpp-language-server` plugin from the copilot-plugin marketplace](https://github.com/github/copilot-plugin). From GitHub Copilot CLI, run: + + ```text + /plugin install cpp-language-server@awesome-copilot + ``` + + This bundles the language server and auto-updates with the latest version, so you don't need to install the npm package manually. 2. Run `mscppls --accept-eula --login` to accept the [license terms](https://www.npmjs.com/package/@microsoft/cpp-language-server?activeTab=code) and login to GitHub. An active GitHub Copilot subscription is required. -3. Create a [`compile_commands.json` file](https://clang.llvm.org/docs/JSONCompilationDatabase.html) for your project. For CMake projects, try [adding `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`](https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html) during configuration, which will create a `compile_commands.json` in the CMake binary (output) directory, or use [this skill](./skills/setup-cpp-language-server/SKILL.md). For MSBuild (vcxproj) projects, see [this sample application](https://github.com/microsoft/msbuild-extractor-sample) to extract `compile_commands.json` from C++ MSBuild projects. -4. [Create `.github/lsp.json` to configure GitHub Copilot CLI](https://github.com/github/copilot-cli?tab=readme-ov-file#-configuring-lsp-servers) to use the language server. - -```json -{ - "lspServers": { - "cpp": { - "command": "mscppls", - "args": ["--lsp-config", ".mscppls/cpp-lsp.json"], - "fileExtensions": { - ".cpp": "cpp", - ".cxx": "cpp", - ".c": "cpp", - ".cc": "cpp", - ".hpp": "cpp", - ".hxx": "cpp", - ".hh": "cpp", - ".h": "cpp" - }, - "requestTimeoutMs": 1000000 - } - } -} -``` - -5. Create `.mscppls/cpp-lsp.json` to set the path to `compile_commands.json` and the project root directory. All paths in this example are relative to `.mscppls`. Adjust the `compileCommands` path to match your project's build output directory. - -```json -{ - "version": 1, - "repositoryPath": "../", - "compileCommands": "../build/compile_commands.json" -} -``` - -6. Launch GitHub Copilot CLI from your project root directory. -7. Within GitHub Copilot CLI, run `/lsp show`. You should see a "cpp" server running. -8. Use GitHub Copilot CLI like normal, now with enhanced C++ capabilities. To nudge the agent to use the tools, try adding phrases like "use LSP tools" to your prompt. +3. Create a [`compile_commands.json` file](https://clang.llvm.org/docs/JSONCompilationDatabase.html) for your project. If your CMake or MSBuild (vcxproj) project doesn't already have a `compile_commands.json`, run the [`setup-cpp-language-server` skill](./plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md) in GitHub Copilot CLI with a prompt like "regenerate compile commands" or "load project" to generate one and configure the language server. If you don't wantf to use the skill, you can [add `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`](https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html) during configuration for CMake projects, or follow [this sample application](https://github.com/microsoft/msbuild-extractor-sample) to generate the file for MSBuild projects. + + > [!NOTE] + > For custom build systems, we recommend [following the guidance provided to generate a project-specific skill](./AUTHORING_EXTRACTOR_SKILL.md) so the steps are reproducible for your team across each build. + +4. Launch GitHub Copilot CLI from your project root directory. +5. Within GitHub Copilot CLI, run `/lsp show`. You should see a "cpp" server running. +6. Use GitHub Copilot CLI like normal, now with enhanced C++ capabilities. To nudge the agent to use the tools, try adding phrases like "use LSP tools" to your prompt. # πŸ“’ Reporting feedback @@ -127,6 +103,8 @@ For now, refer to [this sample application](https://github.com/microsoft/msbuild Refer to your build system vendor's documentation. +For custom or non-standard builds, we recommend capturing the steps to generate `compile_commands.json` in a project-specific skill so the process is reproducible for you and your team. Once you've worked out the commands needed to produce the file, save them as a skill (for example, in your project's `skills/` directory) following the [GitHub Copilot CLI skills documentation](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/create-skills). The [`setup-cpp-language-server` skill](./skills/setup-cpp-language-server/SKILL.md) is a good starting template to adapt. + # Command line options for `mscppls` | Option | Description | From bc537de4ebd22970144b3da72e5903ec5907361e Mon Sep 17 00:00:00 2001 From: Sinem Akinci <99284450+sinemakinci1@users.noreply.github.com> Date: Mon, 22 Jun 2026 07:47:28 -0700 Subject: [PATCH 05/15] Update README with demo image and quick start instructions --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e47ef94..0386148 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ _The Microsoft C++ Language Server is currently in preview and may be subject to # πŸš€ Quick start -1. Install the [`cpp-language-server` plugin from the copilot-plugin marketplace](https://github.com/github/copilot-plugin). From GitHub Copilot CLI, run: +1. Install the [`cpp-language-server` plugin from the copilot-plugins marketplace](https://github.com/github/copilot-plugins). From within GitHub Copilot CLI, run: ```text - /plugin install cpp-language-server@awesome-copilot + /plugin install cpp-language-server@copilot-plugins ``` This bundles the language server and auto-updates with the latest version, so you don't need to install the npm package manually. From 903e21dfee374ece07b3505a33b8b9ee5183cdad Mon Sep 17 00:00:00 2001 From: Sinem Akinci Date: Mon, 22 Jun 2026 07:55:19 -0700 Subject: [PATCH 06/15] adding pre-requisities, customizing logic, and fixing typos --- README.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0386148..1ff1a49 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,14 @@ _The Microsoft C++ Language Server is currently in preview and may be subject to **Microsoft C++ Language Server** brings the same C++ code intelligence used in Visual Studio and VS Code to GitHub Copilot CLI on Windows, macOS, and Linux. It provides fast, accurate understanding of C++ codebases with features like symbol search and semantic navigation. +# Prerequisites + +Before you get started, make sure you have: + +- An active [GitHub Copilot](https://github.com/features/copilot) subscription +- [GitHub Copilot CLI](https://docs.github.com/en/copilot/how-tos/copilot-cli/set-up-copilot-cli/install-copilot-cli) +- [npm](https://www.npmjs.com/package/npm?activeTab=readme) + # πŸš€ Quick start 1. Install the [`cpp-language-server` plugin from the copilot-plugins marketplace](https://github.com/github/copilot-plugins). From within GitHub Copilot CLI, run: @@ -14,7 +22,7 @@ _The Microsoft C++ Language Server is currently in preview and may be subject to This bundles the language server and auto-updates with the latest version, so you don't need to install the npm package manually. 2. Run `mscppls --accept-eula --login` to accept the [license terms](https://www.npmjs.com/package/@microsoft/cpp-language-server?activeTab=code) and login to GitHub. An active GitHub Copilot subscription is required. -3. Create a [`compile_commands.json` file](https://clang.llvm.org/docs/JSONCompilationDatabase.html) for your project. If your CMake or MSBuild (vcxproj) project doesn't already have a `compile_commands.json`, run the [`setup-cpp-language-server` skill](./plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md) in GitHub Copilot CLI with a prompt like "regenerate compile commands" or "load project" to generate one and configure the language server. If you don't wantf to use the skill, you can [add `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`](https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html) during configuration for CMake projects, or follow [this sample application](https://github.com/microsoft/msbuild-extractor-sample) to generate the file for MSBuild projects. +3. Create a [`compile_commands.json` file](https://clang.llvm.org/docs/JSONCompilationDatabase.html) for your project. If your CMake or MSBuild (vcxproj) project doesn't already have a `compile_commands.json`, run the [`generate-compile-commands` skill](./plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md) in GitHub Copilot CLI with a prompt like "regenerate compile commands" or "load project" to generate one and configure the language server. If you don't want to use the skill, you can [add `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`](https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html) during configuration for CMake projects, or follow [this sample application](https://github.com/microsoft/msbuild-extractor-sample) to generate the file for MSBuild projects. > [!NOTE] > For custom build systems, we recommend [following the guidance provided to generate a project-specific skill](./AUTHORING_EXTRACTOR_SKILL.md) so the steps are reproducible for your team across each build. @@ -87,6 +95,17 @@ The Microsoft C++ Language Server depends on 3 configuration files: By default, logs and caches are stored in a workspace-specific directory under `$TEMP/mscppls`. The log directory can be overridden with the `--log-dir` argument. +## Customizing Copilot CLI launch flags + +To customize the command-line flags that GitHub Copilot CLI passes to the Microsoft C++ Language Server, edit `.github/lsp.json`. + +The server can be launched with additional flags using either: + +- `npx @microsoft/cpp-language-server [additional flags]` +- `mscppls [additional flags]` (if installed globally via npm) + +If you install the package globally, npm adds the `mscppls` executable to your `PATH`. + ## Creating compile_commands.json for CMake-based projects CMake projects that use the Ninja or Makefile generators can easily create a `compile_commands.json` by setting the [`CMAKE_EXPORT_COMPILE_COMMANDS` variable](https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html) during configuration. For CMake projects that typically use other generators, first check if it is possible as a one-off to configure the project using the Ninja or Makefile generator, as this is the easiest way to get `compile_commands.json`. From 8658cc07d2c306430f9eb1edf5673acc03d3df22 Mon Sep 17 00:00:00 2001 From: Sinem Akinci Date: Mon, 22 Jun 2026 08:26:13 -0700 Subject: [PATCH 07/15] adding link to lsp.json --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ff1a49..e3696c9 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ By default, logs and caches are stored in a workspace-specific directory under ` ## Customizing Copilot CLI launch flags -To customize the command-line flags that GitHub Copilot CLI passes to the Microsoft C++ Language Server, edit `.github/lsp.json`. +To customize the command-line flags that GitHub Copilot CLI passes to the Microsoft C++ Language Server, edit [`.github/lsp.json`](https://github.com/github/copilot-cli?tab=readme-ov-file#-configuring-lsp-servers). The server can be launched with additional flags using either: From 272e24a345eef654b1201ae196e495a8f50382f8 Mon Sep 17 00:00:00 2001 From: Ben McMorran Date: Tue, 23 Jun 2026 08:06:51 -0700 Subject: [PATCH 08/15] Apply README updates for v0.2.1 --- README.md | 103 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 82 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index e3696c9..7a47fe6 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ _The Microsoft C++ Language Server is currently in preview and may be subject to Before you get started, make sure you have: - An active [GitHub Copilot](https://github.com/features/copilot) subscription -- [GitHub Copilot CLI](https://docs.github.com/en/copilot/how-tos/copilot-cli/set-up-copilot-cli/install-copilot-cli) -- [npm](https://www.npmjs.com/package/npm?activeTab=readme) +- [GitHub Copilot CLI](https://docs.github.com/en/copilot/how-tos/copilot-cli/set-up-copilot-cli/install-copilot-cli) +- [npm](https://www.npmjs.com/package/npm?activeTab=readme) # πŸš€ Quick start @@ -21,7 +21,8 @@ Before you get started, make sure you have: ``` This bundles the language server and auto-updates with the latest version, so you don't need to install the npm package manually. -2. Run `mscppls --accept-eula --login` to accept the [license terms](https://www.npmjs.com/package/@microsoft/cpp-language-server?activeTab=code) and login to GitHub. An active GitHub Copilot subscription is required. + +2. Run `npx @microsoft/cpp-language-server --accept-eula --login` to accept the [license terms](https://www.npmjs.com/package/@microsoft/cpp-language-server?activeTab=code) and login to GitHub. An active GitHub Copilot subscription is required. 3. Create a [`compile_commands.json` file](https://clang.llvm.org/docs/JSONCompilationDatabase.html) for your project. If your CMake or MSBuild (vcxproj) project doesn't already have a `compile_commands.json`, run the [`generate-compile-commands` skill](./plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md) in GitHub Copilot CLI with a prompt like "regenerate compile commands" or "load project" to generate one and configure the language server. If you don't want to use the skill, you can [add `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`](https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html) during configuration for CMake projects, or follow [this sample application](https://github.com/microsoft/msbuild-extractor-sample) to generate the file for MSBuild projects. > [!NOTE] @@ -75,22 +76,37 @@ server will prompt with alternative options. # Logging in to GitHub -Before using the Microsoft C++ Language Server, you must accept the end-user license agreement (EULA), which is distributed as [`EULA/LICENSE.txt`](https://www.npmjs.com/package/@microsoft/cpp-language-server?activeTab=code) in the npm package. Accept the agreement by running `mscppls --accept-eula`. You only need to accept the EULA once. +Before using the Microsoft C++ Language Server, you must accept the end-user license agreement (EULA), which is distributed as [`EULA/LICENSE.txt`](https://www.npmjs.com/package/@microsoft/cpp-language-server?activeTab=code) in the npm package. Accept the agreement by running `npx @microsoft/cpp-language-server --accept-eula` (or `mscppls --accept-eula` if installed directly). You only need to accept the EULA once. -Using the Microsoft C++ Language Server requires an active GitHub Copilot subscription. Before using the language server for the first time, log in to GitHub by running `mscppls --login` and following the on-screen instructions. +Using the Microsoft C++ Language Server requires an active GitHub Copilot subscription. Before using the language server for the first time, log in to GitHub by running `npx @microsoft/cpp-language-server --login` (or `mscppls --login` if installed directly) and following the on-screen instructions. ## Alternative authentication methods -By default, the language server stores your GitHub tokens in system secret storage. On Linux, this requires `libsecret`. If you are running the language server in a constrained environment where system secret storage is unavailable, run `mscppls --login --allow-plaintext-secret-storage` to allow storing the tokens in plaintext. +By default, the language server stores your GitHub tokens in system secret storage. On Linux, this requires `libsecret`. If you are running the language server in a constrained environment where system secret storage is unavailable, run `npx @microsoft/cpp-language-server --login --allow-plaintext-secret-storage` (or `mscppls --login --allow-plaintext-secret-storage` if installed directly) to allow storing the tokens in plaintext. Alternatively, you can independently generate a GitHub token (such as a PAT) and save it in the `MSCPPLS_GITHUB_TOKEN` environment variable. The token does not need to have any scopes. +### Using the GitHub CLI (GitHub Enterprise Cloud) + +If no token is found in system secret storage or the `MSCPPLS_GITHUB_TOKEN` environment variable, the language server will fall back to the [GitHub CLI](https://cli.github.com/) and run `gh auth token` to obtain a token for the current session. This requires the GitHub CLI (`gh`) to already be installed and on your `PATH`, and that you have authenticated with it (for example, via `gh auth login`). The token is used only for the current session and is not stored by the language server. + +This is the recommended way to use the language server with **GitHub Enterprise Cloud**. Authenticate the GitHub CLI against your enterprise host and then point the language server at the same host with `--login-hostname`: + +``` +gh auth login --hostname myenterprise.ghe.com +mscppls --login-hostname myenterprise.ghe.com +``` + +The `--login-hostname` value is passed through to `gh auth token --hostname `. If omitted, the GitHub CLI's default host (`github.com`) is used. Classic personal access tokens (those beginning with `ghp_`) returned by the GitHub CLI are rejected. + +`--login-hostname` can be added to the `args` in `lsp.json` to pass it every time the language server launches. + # Configuration The Microsoft C++ Language Server depends on 3 configuration files: -1. `.github/lsp.json` [configures GitHub Copilot CLI](https://github.com/github/copilot-cli?tab=readme-ov-file#-configuring-lsp-servers) to use the Microsoft C++ Language Server for C++ files, and sets the command line arguments passed to `mscppls`. See the quick start example for how to create this file. -2. `.mscppls/cpp-lsp.json` sets the path to the project root and the path to the `compile_commands.json` file. See the quick start example for how to set the `repositoryPath` and `compileCommands` properties in this file. `repositoryPath` and `compileCommands` can be relative or absolute paths. If relative, they are resolved relative to the directory containing `cpp-lsp.json`. By changing the `--lsp-config` argument in `.github/lsp.json`, `cpp-lsp.json` can be stored at any user-defined path. `version` must always be `1`. +1. `.github/lsp.json` [configures GitHub Copilot CLI](https://github.com/github/copilot-cli?tab=readme-ov-file#-configuring-lsp-servers) to use the Microsoft C++ Language Server for C++ files, and sets the command line arguments passed to `mscppls`. +2. `.mscppls/cpp-lsp.json` is optional and sets the path to the project root and the path to the `compile_commands.json` file. `repositoryPath` and `compileCommands` can be relative or absolute paths. If relative, they are resolved relative to the directory containing `cpp-lsp.json`. By changing the `--lsp-config` argument in `.github/lsp.json`, `cpp-lsp.json` can be stored at any user-defined path. `version` must always be `1`. 3. [`compile_commands.json` specifies the command line to build each target](https://clang.llvm.org/docs/JSONCompilationDatabase.html) in the project. Details for how to generate this file depend on the build system the project uses. By default, logs and caches are stored in a workspace-specific directory under `$TEMP/mscppls`. The log directory can be overridden with the `--log-dir` argument. @@ -106,6 +122,48 @@ The server can be launched with additional flags using either: If you install the package globally, npm adds the `mscppls` executable to your `PATH`. +## Minimal configuration (automatic discovery) + +If you omit the `--lsp-config` argument (or pass `--allow-missing-lsp-config`), the language server automatically searches each workspace folder for a single `compile_commands.json` and infers the repository root from the workspace folder. In this mode you don't need a `cpp-lsp.json` file or a `repositoryPath`: + +```json +{ + "lspServers": { + "cpp": { + "command": "mscppls", + "args": [], + "fileExtensions": { + ".cpp": "cpp", + ".c": "cpp", + ".h": "cpp", + ".hpp": "cpp" + }, + "requestTimeoutMs": 1000000 + } + } +} +``` + +The discovered configuration is cached, so later startups skip the search. Discovery fails if no `compile_commands.json` is found or if more than one is found; in that case, use an explicit `cpp-lsp.json`. + +## Excluding files and customizing indexed directories + +The language server always parses and indexes every translation unit listed in `compile_commands.json`. These translation units are **not** affected by the exclude settings below. On top of that, the directories containing those translation units are scanned to discover additional files (such as headers) to index for browsing and symbol search, and this scan applies a small set of default excludes. The settings in `cpp-lsp.json` customize only this additional directory scan: + +- **Add exclude globs** via `filesExclude` (hides files from the browse/symbol-index scan) and `searchExclude` (excludes files from search). These apply only to the directory scan; they do not remove the translation units listed in `compile_commands.json`. Your entries merge on top of the defaults; set a pattern to `false` to un-exclude a default. +- **Include additional directories** in the scan via `browse.path`. The scanned directories are always derived from the `compile_commands.json` entries; `browse.path` specifies further directories to index/parse on top of those. Entries support `${workspaceFolder}` substitution (resolves to `repositoryPath`). + +```json +{ + "version": 1, + "repositoryPath": "../", + "compileCommands": "../build/compile_commands.json", + "filesExclude": { "**/out": true, "**/third_party": true }, + "searchExclude": { "**/*.generated.h": true }, + "browse": { "path": ["${workspaceFolder}/src"] } +} +``` + ## Creating compile_commands.json for CMake-based projects CMake projects that use the Ninja or Makefile generators can easily create a `compile_commands.json` by setting the [`CMAKE_EXPORT_COMPILE_COMMANDS` variable](https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html) during configuration. For CMake projects that typically use other generators, first check if it is possible as a one-off to configure the project using the Ninja or Makefile generator, as this is the easiest way to get `compile_commands.json`. @@ -126,19 +184,21 @@ For custom or non-standard builds, we recommend capturing the steps to generate # Command line options for `mscppls` -| Option | Description | -| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--help` or `-h` | Shows a help message with a description of all options. | -| `--version` | Shows version information and exits. | -| `--accept-eula` | Permanently accepts the end-user license agreement (EULA). The EULA only needs to be accepted once. However, it is safe to redundantly include this option with any other option, which can be helpful in automated environments. | -| `--stderr` | Do not redirect stderr to `/dev/null`. Useful for debugging. | -| `--login` | Interactively log in to GitHub. | -| `--force-login` | Force interactive login, even if the user has already logged in. | -| `--allow-plaintext-secret-storage` | Allow storing credentials in plaintext if secure system storage is unavailable. | -| `--log-dir ` | Specify the directory for log files. If unspecified, the system temp directory is used. | -| `--log-level ` | Set the logging verbosity from 0 (errors only) to 9 (verbose). | -| `--lsp-config ` | Path to the `cpp-lsp.json` file. If relative, the path will be resolved relative to the current working directory of the `mscppls` process, which is typically the project root when launched from GitHub Copilot CLI. | -| `--disable-telemetry` | Permanently disables sending telemetry data. | +| Option | Description | +| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--help` or `-h` | Shows a help message with a description of all options. | +| `--version` | Shows version information and exits. | +| `--accept-eula` | Permanently accepts the end-user license agreement (EULA). The EULA only needs to be accepted once. However, it is safe to redundantly include this option with any other option, which can be helpful in automated environments. | +| `--stderr` | Do not redirect stderr to `/dev/null`. Useful for debugging. | +| `--login` | Interactively log in to GitHub. | +| `--force-login` | Force interactive login, even if the user has already logged in. | +| `--allow-plaintext-secret-storage` | Allow storing credentials in plaintext if secure system storage is unavailable. | +| `--login-hostname ` | GitHub hostname to use when obtaining a token from the GitHub CLI (`gh auth token`). Enables GitHub Enterprise Cloud support; requires the GitHub CLI to be installed and authenticated. If unspecified, the GitHub CLI's default host is used. | +| `--log-dir ` | Specify the directory for log files. If unspecified, the system temp directory is used. | +| `--log-level ` | Set the logging verbosity from 0 (errors only) to 9 (verbose). | +| `--lsp-config ` | Optional path to the `cpp-lsp.json` file. If relative, the path will be resolved relative to the current working directory of the `mscppls` process, which is typically the project root when launched from GitHub Copilot CLI. | +| `--allow-missing-lsp-config` | Enables fallback to automatic `compile_commands.json` discovery when `--lsp-config` is specified but the configuration file does not exist. | +| `--disable-telemetry` | Permanently disables sending telemetry data. | # Supported LSP features @@ -162,6 +222,7 @@ For custom or non-standard builds, we recommend capturing the steps to generate | Go to Declaration | βœ… | | | Go to Type Definition | βœ… | | | Call Hierarchy | βœ… | | +| Pull Diagnostics | βœ… | | # Data collection From cc954e2c3f5f835bf692855f126067b582015749 Mon Sep 17 00:00:00 2001 From: Ben McMorran Date: Mon, 6 Jul 2026 11:43:25 -0700 Subject: [PATCH 09/15] Add lsp.json to plugin definition --- .../.github/plugin/plugin.json | 2 +- plugins/cpp-language-server/lsp.json | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 plugins/cpp-language-server/lsp.json diff --git a/plugins/cpp-language-server/.github/plugin/plugin.json b/plugins/cpp-language-server/.github/plugin/plugin.json index e13cd40..364f693 100644 --- a/plugins/cpp-language-server/.github/plugin/plugin.json +++ b/plugins/cpp-language-server/.github/plugin/plugin.json @@ -2,7 +2,7 @@ "$schema": "https://json-schema.org/draft-07/schema", "name": "cpp-language-server", "description": "Navigate and interact with your C++ code using the Microsoft C++ Language Server.", - "version": "0.1.0", + "version": "0.1.1", "license": "See EULA/LICENSE.txt in @microsoft/cpp-language-server NPM package", "repository": "https://github.com/microsoft/cpp-language-server", "keywords": [ diff --git a/plugins/cpp-language-server/lsp.json b/plugins/cpp-language-server/lsp.json new file mode 100644 index 0000000..78aa42c --- /dev/null +++ b/plugins/cpp-language-server/lsp.json @@ -0,0 +1,24 @@ +{ + "lspServers": { + "cpp": { + "command": "npx", + "args": [ + "@microsoft/cpp-language-server" + ], + "env": { + "MSCPPLS_PLUGIN_SOURCE": "public" + }, + "fileExtensions": { + ".cpp": "cpp", + ".cxx": "cpp", + ".c": "cpp", + ".cc": "cpp", + ".hpp": "cpp", + ".hxx": "cpp", + ".hh": "cpp", + ".h": "cpp" + }, + "requestTimeoutMs": 1000000 + } + } +} \ No newline at end of file From 73f31d100bf64aeeebb2b8112daf1e15e97caf9a Mon Sep 17 00:00:00 2001 From: Garrett Campbell Date: Mon, 20 Jul 2026 12:10:30 -0400 Subject: [PATCH 10/15] update skill to prefer committed msbuild-extractor.json files --- .../skills/generate-compile-commands/SKILL.md | 110 ++++++++++++++++-- 1 file changed, 101 insertions(+), 9 deletions(-) diff --git a/plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md b/plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md index 5a8ad22..8631826 100644 --- a/plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md +++ b/plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md @@ -1,13 +1,13 @@ --- name: generate-compile-commands -description: Generate compile_commands.json (clang compilation database) for the C++ language server. Covers MSBuild (.sln, .slnx, .vcxproj) via microsoft/msbuild-extractor-sample and CMake projects via CMAKE_EXPORT_COMPILE_COMMANDS. Use whenever the user asks to "regenerate compile commands", "regenerate the project", "reload the project", "load the project", "refresh compile commands", or otherwise needs a fresh compilation database for mscppls. +description: Generate compile_commands.json (clang compilation database) for the C++ language server. Covers MSBuild (.sln, .slnx, .vcxproj) via microsoft/msbuild-extractor-sample β€” driven by a committed msbuild-extractor.json config file β€” and CMake projects via CMAKE_EXPORT_COMPILE_COMMANDS. Use whenever the user asks to "regenerate compile commands", "regenerate the project", "reload the project", "load the project", "refresh compile commands", set up an msbuild-extractor.json / extractor config, or otherwise needs a fresh compilation database for mscppls. --- # Generate compile_commands.json The C++ language server needs a `compile_commands.json` (clang compilation database) to understand a project. How you produce one depends on the build system: CMake can export it directly, MSBuild needs an external extractor. -Always regenerate `compile_commands.json` when this skill runs, even if one already exists for the project. For MSBuild, write it to `.mscppls\compile_commands.json` at the workspace root (the examples below do this); mscppls auto-discovers any `compile_commands.json` within the workspace, so no `cpp-lsp.json` is required. Add `.mscppls/` to `.gitignore` so it does not get committed. mscppls hot-reloads the file content; `/restart` is only needed after changing the plugin's `lsp.json` or the workspace `cpp-lsp.json` (those are read once at LSP startup). +Always regenerate `compile_commands.json` when this skill runs, even if one already exists for the project. For MSBuild, write it to `.mscppls\compile_commands.json` at the workspace root (the examples below do this); mscppls auto-discovers any `compile_commands.json` within the workspace, so no `cpp-lsp.json` is required. Add `.mscppls/` to `.gitignore` so the generated database is not committed β€” but do **commit** the `msbuild-extractor.json` config file (see below) so the whole team regenerates identically. mscppls hot-reloads the file content; `/restart` is only needed after changing the plugin's `lsp.json` or the workspace `cpp-lsp.json` (those are read once at LSP startup). ## CMake projects @@ -64,7 +64,81 @@ if (-not (Test-Path $exe) -or (Get-FileHash $exe -Algorithm SHA256).Hash -ne $ex When upgrading the pinned version, get the new SHA256 from the `digest` field of the asset at `https://api.github.com/repos/microsoft/msbuild-extractor-sample/releases/latest`. -### Run it +### Recommended: a committed `msbuild-extractor.json` + +**This is the primary MSBuild workflow.** Instead of memorizing extractor flags and re-passing them on every run, commit a single `msbuild-extractor.json` at the workspace root that captures the project inputs and toolchain settings. Everyone (and every agent run) then regenerates the database identically. + +The extractor auto-discovers this file: when `--config` is not passed, it loads `msbuild-extractor.json` from the current directory if present. So a committed config reduces the whole invocation to running the exe with no arguments. + +**Decision path:** if a `msbuild-extractor.json` already exists, run the extractor with no flags (below). If it does **not** exist, fall back to the raw CLI flags to get a working run, then write out a `msbuild-extractor.json` capturing those settings so it can be committed (see [Fallback: raw CLI flags](#fallback-raw-cli-flags)). + +- **Auto-detection:** `msbuild-extractor.json` in the current directory is used automatically; pass `--config ` only if it lives elsewhere. +- **Precedence:** command-line flags override the config file, which overrides built-in defaults. Use flags for one-off overrides, the config for the committed baseline. +- **Relative paths** in the config resolve from the config file's own directory (so a workspace-root config can reference `src\app\app.vcxproj`, `.mscppls\compile_commands.json`, etc.). +- At least one `projects` or `solutions` entry is required (in the config or on the command line). + +Author (or update) `msbuild-extractor.json` at the workspace root and commit it. Point `output` at `.mscppls\compile_commands.json` so it lands where mscppls auto-discovers it: + +```jsonc +{ + // Inputs: at least one solutions[] or projects[] entry is required. + "solutions": ["myapp.sln"], + "configuration": "Debug", + "platform": "x64", + "output": ".mscppls\\compile_commands.json", + + // Optional but recommended for IntelliSense across configs: + // "allConfigurations": true, + // "merge": true, + // "deduplicate": true +} +``` + +Then generate β€” no flags needed, the config is auto-detected: + +```powershell +New-Item -ItemType Directory -Path .mscppls -Force | Out-Null +.tools\msbuild-extractor-sample.exe # uses ./msbuild-extractor.json +# or, if the config lives elsewhere: +.tools\msbuild-extractor-sample.exe --config path\to\msbuild-extractor.json +``` + +Remember: commit `msbuild-extractor.json`, but keep `.mscppls/` in `.gitignore` (the generated database is not committed). + +#### CLI flag β†’ config key reference + +Every flag in the fallback sections below has a config-file equivalent. Set the committed baseline as keys; reach for the flag only to override for a single run. + +| Concern | CLI flag(s) | Config key | +|---|---|---| +| Inputs | `--project`, `--solution` (repeatable) | `projects: []`, `solutions: []` | +| Configuration / platform | `-c`/`--configuration`, `-a`/`--platform` | `configuration`, `platform` | +| Output / format | `-o`/`--output`, `-f`/`--format` | `output`, `format` (`"standard"`/`"rich"`) | +| Multi-config | `--all-configurations`, `--merge`, `--deduplicate`, `--prefer-configuration`, `--prefer-platform` | `allConfigurations`, `merge`, `deduplicate`, `preferConfiguration`, `preferPlatform` | +| Dev-env toolchain | `--use-dev-env` | `useDevEnv` | +| VS selection | `--vs-instance`, `--vs-path` | `vsInstance`, `vsPath` | +| Vendored / out-of-process toolchain | `--msbuild-path`, `--vc-targets-path`, `--cl-path`, `--vc-tools-install-dir`, `--solution-dir` | `msBuildPath`, `vcTargetsPath`, `clPath`, `vcToolsInstallDir`, `solutionDir` | +| MSBuild launch / includes | `--msbuild-launcher`, `--include-path-order` | `msBuildLauncher`, `includePathOrder` | +| MSBuild properties / env | `--msbuild-property KEY=VALUE`, `--msbuild-env KEY=VALUE` (repeatable) | `msBuildProperties: {}`, `msBuildEnv: {}` (objects) | + +`msBuildProperties` and `msBuildEnv` are objects that **merge** with their CLI counterparts (`--msbuild-property` / `--msbuild-env`), with the CLI winning on key collisions β€” so a committed baseline can be topped up on the command line for a single run. + +### Fallback: raw CLI flags + +Use these when you don't want a committed config (a one-off run) or need to override the config for a single invocation. Each example below has a config-key equivalent per the table above; prefer moving durable settings into the committed `msbuild-extractor.json`. + +**When no `msbuild-extractor.json` exists yet, use the CLI to get a working run β€” then persist it.** After the extractor succeeds with a given set of flags, write those exact settings out as a `msbuild-extractor.json` at the workspace root (translating each flag to its config key via the table above) and tell the user to commit it. Subsequent runs then need no flags. For example, after a successful `--solution myapp.sln -c Debug -a x64 -o .mscppls\compile_commands.json`, create: + +```jsonc +{ + "solutions": ["myapp.sln"], + "configuration": "Debug", + "platform": "x64", + "output": ".mscppls\\compile_commands.json" +} +``` + +Only persist flags that succeeded, and omit machine-specific absolute paths that won't be valid on a teammate's checkout (prefer relative paths, which resolve from the config's directory; for an activated hermetic toolchain prefer `"useDevEnv": true` over absolute `msBuildPath`/`clPath`). Don't overwrite an existing `msbuild-extractor.json` without confirming with the user. For a typical project on a workstation with Visual Studio installed, the extractor auto-detects Visual Studio via `vswhere.exe` and resolves `VCTargetsPath`, `VCToolsInstallDir`, and `cl.exe` automatically. Solution-based extraction is the simplest entry point: @@ -76,7 +150,7 @@ New-Item -ItemType Directory -Path .mscppls -Force | Out-Null -o .mscppls\compile_commands.json ``` -`-c` is `--configuration` (default `Debug`), `-a` is `--platform` (e.g. `x64`, `Win32`, `ARM64`), `-o` is `--output`. `--solution` accepts `.sln` and `.slnx`; it is repeatable for cross-solution work. `--project` works the same way for individual `.vcxproj` files (also repeatable, deduplicates entries). +`-c` is `--configuration` (default `Debug`), `-a` is `--platform` (e.g. `x64`, `Win32`, `ARM64`), `-o` is `--output`. `--solution` accepts `.sln` and `.slnx`; it is repeatable for cross-solution work. `--project` works the same way for individual `.vcxproj` files (also repeatable, deduplicates entries). Config equivalents: `solutions`/`projects`, `configuration`, `platform`, `output`. #### From a Developer Command Prompt or activated vcvars shell @@ -90,7 +164,7 @@ If you launched a Developer Command Prompt / Developer PowerShell for VS, or ran -o .mscppls\compile_commands.json ``` -This guarantees the LSP indexes against the exact same toolchain the developer is building with. Use it whenever the project depends on a specific VS version, SDK, or side-by-side toolchain that the default `vswhere` heuristic might not pick. +This guarantees the LSP indexes against the exact same toolchain the developer is building with. Use it whenever the project depends on a specific VS version, SDK, or side-by-side toolchain that the default `vswhere` heuristic might not pick. Config equivalent: `"useDevEnv": true`. #### Multiple VS installs @@ -101,6 +175,8 @@ If `vswhere` picks the wrong one, list and select explicitly: .tools\msbuild-extractor-sample.exe --vs-instance --solution myapp.sln -c Debug -a x64 ``` +Config equivalent: pin `"vsInstance": ""` (or `"vsPath"`) in the committed config so every run selects the same install. + #### Multi-configuration projects Prefer the built-in flags over manual merging; they produce one IntelliSense-friendly entry per source file across all configurations: @@ -112,6 +188,8 @@ Prefer the built-in flags over manual merging; they produce one IntelliSense-fri -o .mscppls\compile_commands.json ``` +Config equivalent: `"allConfigurations": true`, `"merge": true`, `"deduplicate": true` (see the recommended example above). + Skip `--validate` during normal LSP setup. It compiles every TU with `cl.exe /c` and is slow. Reach for it only when debugging the extractor itself. ### Advanced: out-of-process mode for vendored or hermetic-toolchain repos @@ -148,6 +226,20 @@ Example (the Windows driver samples built with the Enterprise WDK; the version f When the toolchain is already activated in the current shell (for example after running the EWDK's `LaunchBuildEnv.cmd`), pass `--use-dev-env` instead of the explicit `--msbuild-path`, `--vc-targets-path`, and `--cl-path`, and the extractor reads those paths from the environment. +Config equivalent: these are exactly the settings to **commit** so every checkout resolves the same toolchain. Because the EWDK paths above are absolute and machine-specific, the portable committed form is to activate the toolchain first and set `"useDevEnv": true` in `msbuild-extractor.json`: + +```jsonc +{ + "solutions": ["general\\echo\\kmdf\\kmdfecho.sln"], + "configuration": "Debug", + "platform": "x64", + "useDevEnv": true, + "output": ".mscppls\\compile_commands.json" +} +``` + +If a repo genuinely pins fixed toolchain paths, set `msBuildPath`, `vcTargetsPath`, `clPath`, and any `msBuildProperties` in the config instead β€” but keep them relative where possible so teammates' checkouts resolve them. + The extractor cannot consume `dirs.proj` or aggregate `.proj` files; point it at a real leaf `.vcxproj` (or `.sln`). If the repo needs initialization for its props, targets, and dependencies to resolve, initialize it once, then run the extractor. @@ -170,7 +262,7 @@ Get-ChildItem .mscppls\compile_commands_*.json | ForEach-Object { ConvertTo-Json -InputObject @($all.Values) -Depth 6 | Set-Content .mscppls\compile_commands.json -Encoding UTF8 ``` -`@($all.Values)` forces an array even with a single entry; otherwise `ConvertTo-Json` emits a bare object and the file is not a valid compilation database. +`@($all.Values)` forces an array even with a single entry; otherwise `ConvertTo-Json` emits a bare object and the file is not a valid compilation database. Because these invocations use conflicting flags they can't be captured by a single config file; keep the shared settings in `msbuild-extractor.json` and pass only the conflicting `--configuration` / `--platform` / `--msbuild-property` overrides on each command line. ## Troubleshooting @@ -178,10 +270,10 @@ These cover the MSBuild extractor path. For CMake, build-system errors come from | Symptom | Cause | Fix | |---|---|---| -| `REGDB_E_INVALIDVALUE`, or compile commands point at the wrong `cl.exe` | In-proc MSBuild picked up a system VS install instead of the repo's vendored toolchain | Switch to out-of-process mode with `--msbuild-path` and pin `--vc-targets-path` / `--cl-path` | -| Extractor hangs | Transitive project-reference evaluation on a deep build graph | Add `--msbuild-property BuildProjectReferences=false` | +| `REGDB_E_INVALIDVALUE`, or compile commands point at the wrong `cl.exe` | In-proc MSBuild picked up a system VS install instead of the repo's vendored toolchain | Switch to out-of-process mode: set `msBuildPath` and pin `vcTargetsPath` / `clPath` in the committed `msbuild-extractor.json` (or pass `--msbuild-path` / `--vc-targets-path` / `--cl-path`) | +| Extractor hangs | Transitive project-reference evaluation on a deep build graph | Set `"msBuildProperties": { "BuildProjectReferences": "false" }` in the config (or `--msbuild-property BuildProjectReferences=false`) | | `--validate` reports missing module `.ifc` | Module producer not built | Build dependencies first, or just skip `--validate` | | LSP doesn't see newly extracted entries | mscppls observer is still hashing the new file | Wait a few seconds; mscppls hot-reloads, so do **not** `/restart` | -| `vswhere` picks the wrong VS install | Multiple VS instances present | `--list-instances` then `--vs-instance ` | +| `vswhere` picks the wrong VS install | Multiple VS instances present | `--list-instances`, then pin `"vsInstance": ""` in the config (or `--vs-instance `) | For extractor diagnostics, re-run the same command and read its stderr inline; don't redirect to a file. From 0caf7035e3be6afeee65f909620d8530d82830a3 Mon Sep 17 00:00:00 2001 From: Garrett Campbell Date: Mon, 20 Jul 2026 12:10:50 -0400 Subject: [PATCH 11/15] update the example invocation to prefer the committed file --- skills/setup-cpp-language-server/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skills/setup-cpp-language-server/SKILL.md b/skills/setup-cpp-language-server/SKILL.md index 6cff6b2..ee26a69 100644 --- a/skills/setup-cpp-language-server/SKILL.md +++ b/skills/setup-cpp-language-server/SKILL.md @@ -45,7 +45,7 @@ Your job is to ensure these configuration files are correctly set up. 1. If all required files exist and appear correct, stop. All checks have passed and it's okay to run the C++ LSP tools. Note that your built-in search tools often ignore files in the build directory, so double-check using terminal commands. 2. If `compile_commands.json` does not exist, help the user create the file for their project. Don't complete any other tasks and ensure the `compile_commands.json` file is created before continuing. a. For CMake projects, it's often possible to produce the file by including `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`. This option is not supported when using the Visual Studio generators (default for CMake on Windows), but it is supported with Ninja and Makefile generators. - b. For MSBuild-based C++ projects (`.vcxproj`, `.sln`, `.slnx`), use [`msbuild-extractor-sample`](https://github.com/microsoft/msbuild-extractor-sample/releases) to generate the file, e.g. `msbuild-extractor-sample.exe --solution path\to\app.sln -c Debug -a x64 -o compile_commands.json`. + b. For MSBuild-based C++ projects (`.vcxproj`, `.sln`, `.slnx`), use [`msbuild-extractor-sample`](https://github.com/microsoft/msbuild-extractor-sample/releases) to generate the file. Prefer committing a `msbuild-extractor.json` config file at the workspace root so the tool runs with no arguments (`msbuild-extractor-sample.exe`, which auto-detects `./msbuild-extractor.json`); otherwise pass flags directly, e.g. `msbuild-extractor-sample.exe --solution path\to\app.sln -c Debug -a x64 -o compile_commands.json`. 3. If `.mscppls/cpp-lsp.json` does not exist, create it based on the path to the `compile_commands.json` file. 4. If `.github/lsp.json` does not exist or does not have an entry for C++, create or update it to include the configuration shown above. Make sure the `args` field points to the correct path to `cpp-lsp.json`. 5. If you made any changes to `compile_commands.json`, `.mscppls/cpp-lsp.json`, or `.github/lsp.json`, guide the user to restart their chat session before using the C++ LSP tools. The tools need to be restarted. \ No newline at end of file From 47bea25b41d952aa0d53b401d01c3ead58cc18be Mon Sep 17 00:00:00 2001 From: Garrett Campbell Date: Mon, 20 Jul 2026 12:12:10 -0400 Subject: [PATCH 12/15] update authoring extractor skill --- AUTHORING_EXTRACTOR_SKILL.md | 58 +++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/AUTHORING_EXTRACTOR_SKILL.md b/AUTHORING_EXTRACTOR_SKILL.md index 98412e6..eada240 100644 --- a/AUTHORING_EXTRACTOR_SKILL.md +++ b/AUTHORING_EXTRACTOR_SKILL.md @@ -59,19 +59,23 @@ Point the extractor at a real `.sln`, `.slnx`, or `.vcxproj` file. ## Designing the SKILL A skill is a folder with a `SKILL.md`: YAML frontmatter (`name`, `description`) plus a body with -the pinned extraction command and any project lookup. Keep it generic and document only what is -different about your repo. The `description` is what makes the assistant auto-invoke the skill, -so phrase it with the words users type (generate, regenerate, or refresh compile commands; set -up C++ IntelliSense). +the extraction setup and any project lookup. Prefer a committed `msbuild-extractor.json` config file +(the extractor auto-detects `./msbuild-extractor.json`, so the skill can run it with no arguments) +and document only what is different about your repo. The `description` is what makes the assistant +auto-invoke the skill, so phrase it with the words users type (generate, regenerate, or refresh +compile commands; set up C++ IntelliSense). ## What to put in your SKILL -These keep the generated database matched to your real build, so encode them in your `SKILL.md`. +These keep the generated database matched to your real build, so encode them in your `SKILL.md` β€” +preferably as keys in a committed `msbuild-extractor.json` (each flag below has a config-key +equivalent: `msBuildPath`, `vcTargetsPath`, `clPath`, `useDevEnv`, `configuration`, `platform`, +`msBuildProperties`), falling back to flags on the extraction command. -Bake into the extraction command: +Bake into the config (or extraction command): -- Use absolute paths for `--vc-targets-path` and `--cl-path`. -- Prefer out-of-process mode (`--msbuild-path`) in a vendored repo; when you have an activated developer environment (for example EWDK), `--use-dev-env` can also pin extraction to the intended toolchain. +- Use absolute paths for `--vc-targets-path`/`vcTargetsPath` and `--cl-path`/`clPath`. +- Prefer out-of-process mode (`--msbuild-path`/`msBuildPath`) in a vendored repo; when you have an activated developer environment (for example EWDK), `--use-dev-env`/`"useDevEnv": true` can also pin extraction to the intended toolchain. - Point at a `.sln` or a specific `.vcxproj`, not a generated or aggregate project file. Capture as prerequisites or notes in the skill body: @@ -128,8 +132,28 @@ activated EWDK shell and let the extractor read the toolchain from the environme ## Extraction command +Commit a `msbuild-extractor.json` at the repo root so the extractor runs with no arguments (it +auto-detects `./msbuild-extractor.json`). For the EWDK, let it read the activated toolchain from the +environment with `useDevEnv`: + +```jsonc +{ + "solutions": ["general\\echo\\kmdf\\kmdfecho.sln"], + "configuration": "Debug", + "platform": "x64", + "useDevEnv": true, + "output": "compile_commands.json" +} +``` + From the activated EWDK shell, in the repo root: +```powershell +.tools\msbuild-extractor-sample.exe # uses ./msbuild-extractor.json +``` + +Equivalent one-off invocation with explicit flags (no committed config): + ```powershell .tools\msbuild-extractor-sample.exe ` --use-dev-env ` @@ -138,14 +162,28 @@ From the activated EWDK shell, in the repo root: -o compile_commands.json ``` -`--use-dev-env` reads the toolchain environment the EWDK exports (`VCToolsInstallDir`, +`--use-dev-env` / `"useDevEnv": true` reads the toolchain environment the EWDK exports (`VCToolsInstallDir`, `VCTargetsPath`, `WindowsSdkDir`, `INCLUDE`, `LIB`), which pins extraction to the EWDK. ## Alternative: explicit paths If you cannot use an activated shell, pin the EWDK tools by hand. On a machine that also has Visual Studio installed, prefer the activated shell so the extractor does not pick up the system -toolchain. +toolchain. As a committed config (`msbuild-extractor.json`): + +```jsonc +{ + "solutions": ["general\\echo\\kmdf\\kmdfecho.sln"], + "configuration": "Debug", + "platform": "x64", + "msBuildPath": "D:\\Program Files\\Microsoft Visual Studio\\18\\BuildTools\\MSBuild\\Current\\Bin\\MSBuild.exe", + "vcTargetsPath": "D:\\Program Files\\Microsoft Visual Studio\\18\\BuildTools\\MSBuild\\Microsoft\\VC\\v180", + "clPath": "D:\\Program Files\\Microsoft Visual Studio\\18\\BuildTools\\VC\\Tools\\MSVC\\14.50.35717\\bin\\Hostx64\\x64\\cl.exe", + "output": "compile_commands.json" +} +``` + +Or the equivalent one-off invocation: ```powershell .tools\msbuild-extractor-sample.exe ` From c2531aec9c5aff62006168bb7cd5e0f5307e3583 Mon Sep 17 00:00:00 2001 From: Garrett Campbell Date: Mon, 20 Jul 2026 14:00:18 -0400 Subject: [PATCH 13/15] make it more clear that it's upt to the user where to store their committed msbuild-extractor.json --- AUTHORING_EXTRACTOR_SKILL.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/AUTHORING_EXTRACTOR_SKILL.md b/AUTHORING_EXTRACTOR_SKILL.md index eada240..d7bcc37 100644 --- a/AUTHORING_EXTRACTOR_SKILL.md +++ b/AUTHORING_EXTRACTOR_SKILL.md @@ -60,8 +60,13 @@ Point the extractor at a real `.sln`, `.slnx`, or `.vcxproj` file. A skill is a folder with a `SKILL.md`: YAML frontmatter (`name`, `description`) plus a body with the extraction setup and any project lookup. Prefer a committed `msbuild-extractor.json` config file -(the extractor auto-detects `./msbuild-extractor.json`, so the skill can run it with no arguments) -and document only what is different about your repo. The `description` is what makes the assistant +and document only what is different about your repo. **Where the config lives is the user's choice.** +The extractor auto-detects `./msbuild-extractor.json` in the current directory, so a config at the +workspace root lets the skill run the exe with no arguments. But users are free to keep it elsewhere +(a subdirectory, a shared `build\` or `tools\` folder, a path outside the repo) and point the +extractor at it with `--config `; command-line flags take precedence over the config file. +Write the skill to accommodate both β€” document the auto-detected default, and note that a +non-standard location just means passing `--config`. The `description` is what makes the assistant auto-invoke the skill, so phrase it with the words users type (generate, regenerate, or refresh compile commands; set up C++ IntelliSense). @@ -132,9 +137,10 @@ activated EWDK shell and let the extractor read the toolchain from the environme ## Extraction command -Commit a `msbuild-extractor.json` at the repo root so the extractor runs with no arguments (it -auto-detects `./msbuild-extractor.json`). For the EWDK, let it read the activated toolchain from the -environment with `useDevEnv`: +Commit a `msbuild-extractor.json` so the extractor picks it up. Placing it at the repo root lets the +extractor auto-detect `./msbuild-extractor.json` and run with no arguments; if you prefer to keep it +elsewhere, point at it with `--config ` β€” it's your choice. For the EWDK, let it read the +activated toolchain from the environment with `useDevEnv`: ```jsonc { @@ -150,6 +156,8 @@ From the activated EWDK shell, in the repo root: ```powershell .tools\msbuild-extractor-sample.exe # uses ./msbuild-extractor.json +# or, if the config lives elsewhere: +.tools\msbuild-extractor-sample.exe --config path\to\msbuild-extractor.json ``` Equivalent one-off invocation with explicit flags (no committed config): From 05963c4f26658b11b590a1d1de18fb4412d253f2 Mon Sep 17 00:00:00 2001 From: Garrett Campbell Date: Mon, 20 Jul 2026 14:23:59 -0400 Subject: [PATCH 14/15] update version and sha --- .../skills/generate-compile-commands/SKILL.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md b/plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md index 8631826..5f6f477 100644 --- a/plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md +++ b/plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md @@ -45,8 +45,8 @@ For MSBuild (`.sln`, `.slnx`, `.vcxproj`), generate `compile_commands.json` with Download the pinned release and verify its SHA256 before trusting it. The binary is self-contained, with no .NET runtime needed. ```powershell -$version = 'v0.2.0' -$expected = '01a5e2d399c3cb84d3136d0b6ef7b84a05900838ddc3b1f710b9394c8c2936ce' +$version = 'v0.3.0' +$expected = '543c5cc6b57a1b3eb46b11e56b8f35a9ca8676106426bde6041ca2dc2e06f13c' $exe = ".tools\msbuild-extractor-sample.exe" if (-not (Test-Path $exe) -or (Get-FileHash $exe -Algorithm SHA256).Hash -ne $expected.ToUpper()) { From fc13cbe77972d97ab3b2f61b327d1735009d9dec Mon Sep 17 00:00:00 2001 From: Garrett Campbell <86264750+gcampbell-msft@users.noreply.github.com> Date: Tue, 21 Jul 2026 10:36:00 -0400 Subject: [PATCH 15/15] Revert "Update generate-compile-commands SKILLs to use msbuild-extractor.json" --- AUTHORING_EXTRACTOR_SKILL.md | 66 ++-------- .../skills/generate-compile-commands/SKILL.md | 114 ++---------------- skills/setup-cpp-language-server/SKILL.md | 2 +- 3 files changed, 22 insertions(+), 160 deletions(-) diff --git a/AUTHORING_EXTRACTOR_SKILL.md b/AUTHORING_EXTRACTOR_SKILL.md index d7bcc37..98412e6 100644 --- a/AUTHORING_EXTRACTOR_SKILL.md +++ b/AUTHORING_EXTRACTOR_SKILL.md @@ -59,28 +59,19 @@ Point the extractor at a real `.sln`, `.slnx`, or `.vcxproj` file. ## Designing the SKILL A skill is a folder with a `SKILL.md`: YAML frontmatter (`name`, `description`) plus a body with -the extraction setup and any project lookup. Prefer a committed `msbuild-extractor.json` config file -and document only what is different about your repo. **Where the config lives is the user's choice.** -The extractor auto-detects `./msbuild-extractor.json` in the current directory, so a config at the -workspace root lets the skill run the exe with no arguments. But users are free to keep it elsewhere -(a subdirectory, a shared `build\` or `tools\` folder, a path outside the repo) and point the -extractor at it with `--config `; command-line flags take precedence over the config file. -Write the skill to accommodate both β€” document the auto-detected default, and note that a -non-standard location just means passing `--config`. The `description` is what makes the assistant -auto-invoke the skill, so phrase it with the words users type (generate, regenerate, or refresh -compile commands; set up C++ IntelliSense). +the pinned extraction command and any project lookup. Keep it generic and document only what is +different about your repo. The `description` is what makes the assistant auto-invoke the skill, +so phrase it with the words users type (generate, regenerate, or refresh compile commands; set +up C++ IntelliSense). ## What to put in your SKILL -These keep the generated database matched to your real build, so encode them in your `SKILL.md` β€” -preferably as keys in a committed `msbuild-extractor.json` (each flag below has a config-key -equivalent: `msBuildPath`, `vcTargetsPath`, `clPath`, `useDevEnv`, `configuration`, `platform`, -`msBuildProperties`), falling back to flags on the extraction command. +These keep the generated database matched to your real build, so encode them in your `SKILL.md`. -Bake into the config (or extraction command): +Bake into the extraction command: -- Use absolute paths for `--vc-targets-path`/`vcTargetsPath` and `--cl-path`/`clPath`. -- Prefer out-of-process mode (`--msbuild-path`/`msBuildPath`) in a vendored repo; when you have an activated developer environment (for example EWDK), `--use-dev-env`/`"useDevEnv": true` can also pin extraction to the intended toolchain. +- Use absolute paths for `--vc-targets-path` and `--cl-path`. +- Prefer out-of-process mode (`--msbuild-path`) in a vendored repo; when you have an activated developer environment (for example EWDK), `--use-dev-env` can also pin extraction to the intended toolchain. - Point at a `.sln` or a specific `.vcxproj`, not a generated or aggregate project file. Capture as prerequisites or notes in the skill body: @@ -137,31 +128,8 @@ activated EWDK shell and let the extractor read the toolchain from the environme ## Extraction command -Commit a `msbuild-extractor.json` so the extractor picks it up. Placing it at the repo root lets the -extractor auto-detect `./msbuild-extractor.json` and run with no arguments; if you prefer to keep it -elsewhere, point at it with `--config ` β€” it's your choice. For the EWDK, let it read the -activated toolchain from the environment with `useDevEnv`: - -```jsonc -{ - "solutions": ["general\\echo\\kmdf\\kmdfecho.sln"], - "configuration": "Debug", - "platform": "x64", - "useDevEnv": true, - "output": "compile_commands.json" -} -``` - From the activated EWDK shell, in the repo root: -```powershell -.tools\msbuild-extractor-sample.exe # uses ./msbuild-extractor.json -# or, if the config lives elsewhere: -.tools\msbuild-extractor-sample.exe --config path\to\msbuild-extractor.json -``` - -Equivalent one-off invocation with explicit flags (no committed config): - ```powershell .tools\msbuild-extractor-sample.exe ` --use-dev-env ` @@ -170,28 +138,14 @@ Equivalent one-off invocation with explicit flags (no committed config): -o compile_commands.json ``` -`--use-dev-env` / `"useDevEnv": true` reads the toolchain environment the EWDK exports (`VCToolsInstallDir`, +`--use-dev-env` reads the toolchain environment the EWDK exports (`VCToolsInstallDir`, `VCTargetsPath`, `WindowsSdkDir`, `INCLUDE`, `LIB`), which pins extraction to the EWDK. ## Alternative: explicit paths If you cannot use an activated shell, pin the EWDK tools by hand. On a machine that also has Visual Studio installed, prefer the activated shell so the extractor does not pick up the system -toolchain. As a committed config (`msbuild-extractor.json`): - -```jsonc -{ - "solutions": ["general\\echo\\kmdf\\kmdfecho.sln"], - "configuration": "Debug", - "platform": "x64", - "msBuildPath": "D:\\Program Files\\Microsoft Visual Studio\\18\\BuildTools\\MSBuild\\Current\\Bin\\MSBuild.exe", - "vcTargetsPath": "D:\\Program Files\\Microsoft Visual Studio\\18\\BuildTools\\MSBuild\\Microsoft\\VC\\v180", - "clPath": "D:\\Program Files\\Microsoft Visual Studio\\18\\BuildTools\\VC\\Tools\\MSVC\\14.50.35717\\bin\\Hostx64\\x64\\cl.exe", - "output": "compile_commands.json" -} -``` - -Or the equivalent one-off invocation: +toolchain. ```powershell .tools\msbuild-extractor-sample.exe ` diff --git a/plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md b/plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md index 5f6f477..5a8ad22 100644 --- a/plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md +++ b/plugins/cpp-language-server/skills/generate-compile-commands/SKILL.md @@ -1,13 +1,13 @@ --- name: generate-compile-commands -description: Generate compile_commands.json (clang compilation database) for the C++ language server. Covers MSBuild (.sln, .slnx, .vcxproj) via microsoft/msbuild-extractor-sample β€” driven by a committed msbuild-extractor.json config file β€” and CMake projects via CMAKE_EXPORT_COMPILE_COMMANDS. Use whenever the user asks to "regenerate compile commands", "regenerate the project", "reload the project", "load the project", "refresh compile commands", set up an msbuild-extractor.json / extractor config, or otherwise needs a fresh compilation database for mscppls. +description: Generate compile_commands.json (clang compilation database) for the C++ language server. Covers MSBuild (.sln, .slnx, .vcxproj) via microsoft/msbuild-extractor-sample and CMake projects via CMAKE_EXPORT_COMPILE_COMMANDS. Use whenever the user asks to "regenerate compile commands", "regenerate the project", "reload the project", "load the project", "refresh compile commands", or otherwise needs a fresh compilation database for mscppls. --- # Generate compile_commands.json The C++ language server needs a `compile_commands.json` (clang compilation database) to understand a project. How you produce one depends on the build system: CMake can export it directly, MSBuild needs an external extractor. -Always regenerate `compile_commands.json` when this skill runs, even if one already exists for the project. For MSBuild, write it to `.mscppls\compile_commands.json` at the workspace root (the examples below do this); mscppls auto-discovers any `compile_commands.json` within the workspace, so no `cpp-lsp.json` is required. Add `.mscppls/` to `.gitignore` so the generated database is not committed β€” but do **commit** the `msbuild-extractor.json` config file (see below) so the whole team regenerates identically. mscppls hot-reloads the file content; `/restart` is only needed after changing the plugin's `lsp.json` or the workspace `cpp-lsp.json` (those are read once at LSP startup). +Always regenerate `compile_commands.json` when this skill runs, even if one already exists for the project. For MSBuild, write it to `.mscppls\compile_commands.json` at the workspace root (the examples below do this); mscppls auto-discovers any `compile_commands.json` within the workspace, so no `cpp-lsp.json` is required. Add `.mscppls/` to `.gitignore` so it does not get committed. mscppls hot-reloads the file content; `/restart` is only needed after changing the plugin's `lsp.json` or the workspace `cpp-lsp.json` (those are read once at LSP startup). ## CMake projects @@ -45,8 +45,8 @@ For MSBuild (`.sln`, `.slnx`, `.vcxproj`), generate `compile_commands.json` with Download the pinned release and verify its SHA256 before trusting it. The binary is self-contained, with no .NET runtime needed. ```powershell -$version = 'v0.3.0' -$expected = '543c5cc6b57a1b3eb46b11e56b8f35a9ca8676106426bde6041ca2dc2e06f13c' +$version = 'v0.2.0' +$expected = '01a5e2d399c3cb84d3136d0b6ef7b84a05900838ddc3b1f710b9394c8c2936ce' $exe = ".tools\msbuild-extractor-sample.exe" if (-not (Test-Path $exe) -or (Get-FileHash $exe -Algorithm SHA256).Hash -ne $expected.ToUpper()) { @@ -64,81 +64,7 @@ if (-not (Test-Path $exe) -or (Get-FileHash $exe -Algorithm SHA256).Hash -ne $ex When upgrading the pinned version, get the new SHA256 from the `digest` field of the asset at `https://api.github.com/repos/microsoft/msbuild-extractor-sample/releases/latest`. -### Recommended: a committed `msbuild-extractor.json` - -**This is the primary MSBuild workflow.** Instead of memorizing extractor flags and re-passing them on every run, commit a single `msbuild-extractor.json` at the workspace root that captures the project inputs and toolchain settings. Everyone (and every agent run) then regenerates the database identically. - -The extractor auto-discovers this file: when `--config` is not passed, it loads `msbuild-extractor.json` from the current directory if present. So a committed config reduces the whole invocation to running the exe with no arguments. - -**Decision path:** if a `msbuild-extractor.json` already exists, run the extractor with no flags (below). If it does **not** exist, fall back to the raw CLI flags to get a working run, then write out a `msbuild-extractor.json` capturing those settings so it can be committed (see [Fallback: raw CLI flags](#fallback-raw-cli-flags)). - -- **Auto-detection:** `msbuild-extractor.json` in the current directory is used automatically; pass `--config ` only if it lives elsewhere. -- **Precedence:** command-line flags override the config file, which overrides built-in defaults. Use flags for one-off overrides, the config for the committed baseline. -- **Relative paths** in the config resolve from the config file's own directory (so a workspace-root config can reference `src\app\app.vcxproj`, `.mscppls\compile_commands.json`, etc.). -- At least one `projects` or `solutions` entry is required (in the config or on the command line). - -Author (or update) `msbuild-extractor.json` at the workspace root and commit it. Point `output` at `.mscppls\compile_commands.json` so it lands where mscppls auto-discovers it: - -```jsonc -{ - // Inputs: at least one solutions[] or projects[] entry is required. - "solutions": ["myapp.sln"], - "configuration": "Debug", - "platform": "x64", - "output": ".mscppls\\compile_commands.json", - - // Optional but recommended for IntelliSense across configs: - // "allConfigurations": true, - // "merge": true, - // "deduplicate": true -} -``` - -Then generate β€” no flags needed, the config is auto-detected: - -```powershell -New-Item -ItemType Directory -Path .mscppls -Force | Out-Null -.tools\msbuild-extractor-sample.exe # uses ./msbuild-extractor.json -# or, if the config lives elsewhere: -.tools\msbuild-extractor-sample.exe --config path\to\msbuild-extractor.json -``` - -Remember: commit `msbuild-extractor.json`, but keep `.mscppls/` in `.gitignore` (the generated database is not committed). - -#### CLI flag β†’ config key reference - -Every flag in the fallback sections below has a config-file equivalent. Set the committed baseline as keys; reach for the flag only to override for a single run. - -| Concern | CLI flag(s) | Config key | -|---|---|---| -| Inputs | `--project`, `--solution` (repeatable) | `projects: []`, `solutions: []` | -| Configuration / platform | `-c`/`--configuration`, `-a`/`--platform` | `configuration`, `platform` | -| Output / format | `-o`/`--output`, `-f`/`--format` | `output`, `format` (`"standard"`/`"rich"`) | -| Multi-config | `--all-configurations`, `--merge`, `--deduplicate`, `--prefer-configuration`, `--prefer-platform` | `allConfigurations`, `merge`, `deduplicate`, `preferConfiguration`, `preferPlatform` | -| Dev-env toolchain | `--use-dev-env` | `useDevEnv` | -| VS selection | `--vs-instance`, `--vs-path` | `vsInstance`, `vsPath` | -| Vendored / out-of-process toolchain | `--msbuild-path`, `--vc-targets-path`, `--cl-path`, `--vc-tools-install-dir`, `--solution-dir` | `msBuildPath`, `vcTargetsPath`, `clPath`, `vcToolsInstallDir`, `solutionDir` | -| MSBuild launch / includes | `--msbuild-launcher`, `--include-path-order` | `msBuildLauncher`, `includePathOrder` | -| MSBuild properties / env | `--msbuild-property KEY=VALUE`, `--msbuild-env KEY=VALUE` (repeatable) | `msBuildProperties: {}`, `msBuildEnv: {}` (objects) | - -`msBuildProperties` and `msBuildEnv` are objects that **merge** with their CLI counterparts (`--msbuild-property` / `--msbuild-env`), with the CLI winning on key collisions β€” so a committed baseline can be topped up on the command line for a single run. - -### Fallback: raw CLI flags - -Use these when you don't want a committed config (a one-off run) or need to override the config for a single invocation. Each example below has a config-key equivalent per the table above; prefer moving durable settings into the committed `msbuild-extractor.json`. - -**When no `msbuild-extractor.json` exists yet, use the CLI to get a working run β€” then persist it.** After the extractor succeeds with a given set of flags, write those exact settings out as a `msbuild-extractor.json` at the workspace root (translating each flag to its config key via the table above) and tell the user to commit it. Subsequent runs then need no flags. For example, after a successful `--solution myapp.sln -c Debug -a x64 -o .mscppls\compile_commands.json`, create: - -```jsonc -{ - "solutions": ["myapp.sln"], - "configuration": "Debug", - "platform": "x64", - "output": ".mscppls\\compile_commands.json" -} -``` - -Only persist flags that succeeded, and omit machine-specific absolute paths that won't be valid on a teammate's checkout (prefer relative paths, which resolve from the config's directory; for an activated hermetic toolchain prefer `"useDevEnv": true` over absolute `msBuildPath`/`clPath`). Don't overwrite an existing `msbuild-extractor.json` without confirming with the user. +### Run it For a typical project on a workstation with Visual Studio installed, the extractor auto-detects Visual Studio via `vswhere.exe` and resolves `VCTargetsPath`, `VCToolsInstallDir`, and `cl.exe` automatically. Solution-based extraction is the simplest entry point: @@ -150,7 +76,7 @@ New-Item -ItemType Directory -Path .mscppls -Force | Out-Null -o .mscppls\compile_commands.json ``` -`-c` is `--configuration` (default `Debug`), `-a` is `--platform` (e.g. `x64`, `Win32`, `ARM64`), `-o` is `--output`. `--solution` accepts `.sln` and `.slnx`; it is repeatable for cross-solution work. `--project` works the same way for individual `.vcxproj` files (also repeatable, deduplicates entries). Config equivalents: `solutions`/`projects`, `configuration`, `platform`, `output`. +`-c` is `--configuration` (default `Debug`), `-a` is `--platform` (e.g. `x64`, `Win32`, `ARM64`), `-o` is `--output`. `--solution` accepts `.sln` and `.slnx`; it is repeatable for cross-solution work. `--project` works the same way for individual `.vcxproj` files (also repeatable, deduplicates entries). #### From a Developer Command Prompt or activated vcvars shell @@ -164,7 +90,7 @@ If you launched a Developer Command Prompt / Developer PowerShell for VS, or ran -o .mscppls\compile_commands.json ``` -This guarantees the LSP indexes against the exact same toolchain the developer is building with. Use it whenever the project depends on a specific VS version, SDK, or side-by-side toolchain that the default `vswhere` heuristic might not pick. Config equivalent: `"useDevEnv": true`. +This guarantees the LSP indexes against the exact same toolchain the developer is building with. Use it whenever the project depends on a specific VS version, SDK, or side-by-side toolchain that the default `vswhere` heuristic might not pick. #### Multiple VS installs @@ -175,8 +101,6 @@ If `vswhere` picks the wrong one, list and select explicitly: .tools\msbuild-extractor-sample.exe --vs-instance --solution myapp.sln -c Debug -a x64 ``` -Config equivalent: pin `"vsInstance": ""` (or `"vsPath"`) in the committed config so every run selects the same install. - #### Multi-configuration projects Prefer the built-in flags over manual merging; they produce one IntelliSense-friendly entry per source file across all configurations: @@ -188,8 +112,6 @@ Prefer the built-in flags over manual merging; they produce one IntelliSense-fri -o .mscppls\compile_commands.json ``` -Config equivalent: `"allConfigurations": true`, `"merge": true`, `"deduplicate": true` (see the recommended example above). - Skip `--validate` during normal LSP setup. It compiles every TU with `cl.exe /c` and is slow. Reach for it only when debugging the extractor itself. ### Advanced: out-of-process mode for vendored or hermetic-toolchain repos @@ -226,20 +148,6 @@ Example (the Windows driver samples built with the Enterprise WDK; the version f When the toolchain is already activated in the current shell (for example after running the EWDK's `LaunchBuildEnv.cmd`), pass `--use-dev-env` instead of the explicit `--msbuild-path`, `--vc-targets-path`, and `--cl-path`, and the extractor reads those paths from the environment. -Config equivalent: these are exactly the settings to **commit** so every checkout resolves the same toolchain. Because the EWDK paths above are absolute and machine-specific, the portable committed form is to activate the toolchain first and set `"useDevEnv": true` in `msbuild-extractor.json`: - -```jsonc -{ - "solutions": ["general\\echo\\kmdf\\kmdfecho.sln"], - "configuration": "Debug", - "platform": "x64", - "useDevEnv": true, - "output": ".mscppls\\compile_commands.json" -} -``` - -If a repo genuinely pins fixed toolchain paths, set `msBuildPath`, `vcTargetsPath`, `clPath`, and any `msBuildProperties` in the config instead β€” but keep them relative where possible so teammates' checkouts resolve them. - The extractor cannot consume `dirs.proj` or aggregate `.proj` files; point it at a real leaf `.vcxproj` (or `.sln`). If the repo needs initialization for its props, targets, and dependencies to resolve, initialize it once, then run the extractor. @@ -262,7 +170,7 @@ Get-ChildItem .mscppls\compile_commands_*.json | ForEach-Object { ConvertTo-Json -InputObject @($all.Values) -Depth 6 | Set-Content .mscppls\compile_commands.json -Encoding UTF8 ``` -`@($all.Values)` forces an array even with a single entry; otherwise `ConvertTo-Json` emits a bare object and the file is not a valid compilation database. Because these invocations use conflicting flags they can't be captured by a single config file; keep the shared settings in `msbuild-extractor.json` and pass only the conflicting `--configuration` / `--platform` / `--msbuild-property` overrides on each command line. +`@($all.Values)` forces an array even with a single entry; otherwise `ConvertTo-Json` emits a bare object and the file is not a valid compilation database. ## Troubleshooting @@ -270,10 +178,10 @@ These cover the MSBuild extractor path. For CMake, build-system errors come from | Symptom | Cause | Fix | |---|---|---| -| `REGDB_E_INVALIDVALUE`, or compile commands point at the wrong `cl.exe` | In-proc MSBuild picked up a system VS install instead of the repo's vendored toolchain | Switch to out-of-process mode: set `msBuildPath` and pin `vcTargetsPath` / `clPath` in the committed `msbuild-extractor.json` (or pass `--msbuild-path` / `--vc-targets-path` / `--cl-path`) | -| Extractor hangs | Transitive project-reference evaluation on a deep build graph | Set `"msBuildProperties": { "BuildProjectReferences": "false" }` in the config (or `--msbuild-property BuildProjectReferences=false`) | +| `REGDB_E_INVALIDVALUE`, or compile commands point at the wrong `cl.exe` | In-proc MSBuild picked up a system VS install instead of the repo's vendored toolchain | Switch to out-of-process mode with `--msbuild-path` and pin `--vc-targets-path` / `--cl-path` | +| Extractor hangs | Transitive project-reference evaluation on a deep build graph | Add `--msbuild-property BuildProjectReferences=false` | | `--validate` reports missing module `.ifc` | Module producer not built | Build dependencies first, or just skip `--validate` | | LSP doesn't see newly extracted entries | mscppls observer is still hashing the new file | Wait a few seconds; mscppls hot-reloads, so do **not** `/restart` | -| `vswhere` picks the wrong VS install | Multiple VS instances present | `--list-instances`, then pin `"vsInstance": ""` in the config (or `--vs-instance `) | +| `vswhere` picks the wrong VS install | Multiple VS instances present | `--list-instances` then `--vs-instance ` | For extractor diagnostics, re-run the same command and read its stderr inline; don't redirect to a file. diff --git a/skills/setup-cpp-language-server/SKILL.md b/skills/setup-cpp-language-server/SKILL.md index ee26a69..6cff6b2 100644 --- a/skills/setup-cpp-language-server/SKILL.md +++ b/skills/setup-cpp-language-server/SKILL.md @@ -45,7 +45,7 @@ Your job is to ensure these configuration files are correctly set up. 1. If all required files exist and appear correct, stop. All checks have passed and it's okay to run the C++ LSP tools. Note that your built-in search tools often ignore files in the build directory, so double-check using terminal commands. 2. If `compile_commands.json` does not exist, help the user create the file for their project. Don't complete any other tasks and ensure the `compile_commands.json` file is created before continuing. a. For CMake projects, it's often possible to produce the file by including `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`. This option is not supported when using the Visual Studio generators (default for CMake on Windows), but it is supported with Ninja and Makefile generators. - b. For MSBuild-based C++ projects (`.vcxproj`, `.sln`, `.slnx`), use [`msbuild-extractor-sample`](https://github.com/microsoft/msbuild-extractor-sample/releases) to generate the file. Prefer committing a `msbuild-extractor.json` config file at the workspace root so the tool runs with no arguments (`msbuild-extractor-sample.exe`, which auto-detects `./msbuild-extractor.json`); otherwise pass flags directly, e.g. `msbuild-extractor-sample.exe --solution path\to\app.sln -c Debug -a x64 -o compile_commands.json`. + b. For MSBuild-based C++ projects (`.vcxproj`, `.sln`, `.slnx`), use [`msbuild-extractor-sample`](https://github.com/microsoft/msbuild-extractor-sample/releases) to generate the file, e.g. `msbuild-extractor-sample.exe --solution path\to\app.sln -c Debug -a x64 -o compile_commands.json`. 3. If `.mscppls/cpp-lsp.json` does not exist, create it based on the path to the `compile_commands.json` file. 4. If `.github/lsp.json` does not exist or does not have an entry for C++, create or update it to include the configuration shown above. Make sure the `args` field points to the correct path to `cpp-lsp.json`. 5. If you made any changes to `compile_commands.json`, `.mscppls/cpp-lsp.json`, or `.github/lsp.json`, guide the user to restart their chat session before using the C++ LSP tools. The tools need to be restarted. \ No newline at end of file