This repo contains a sample that demonstrates how to extract compile_commands.json from Visual C++ MSBuild projects (.vcxproj, .sln, .slnx) using the MSBuild API.
The generated compilation database can be used with VS Code and C++ LSP tools for IntelliSense, code navigation, and static analysis.
msbuild-extractor-sample --project myapp.vcxproj -c Debug -a x64msbuild-extractor-sample --solution myapp.sln -c Debug -a x64 -o compile_commands.json# List installed VS instances
msbuild-extractor-sample --list-instances
# Use a specific VS instance
msbuild-extractor-sample --vs-instance cdf4 --solution myapp.sln -c Debug -a x64msbuild-extractor-sample --solution myapp.sln -c Debug -a x64 --validate# Extract all configurations (Debug/Release × x64/Win32/ARM64)
msbuild-extractor-sample --project myapp.vcxproj --all-configurations
# Merge into single file with one entry per source file
msbuild-extractor-sample --project myapp.vcxproj --all-configurations --merge --deduplicatemsbuild-extractor-sample --solution engine.sln --solution editor.sln -c Debug -a x64 -o compile_commands.json# Structured output with solutions/projects/configurations/files
msbuild-extractor-sample --solution myapp.sln --format rich -o compile_database.jsonmsbuild-extractor-sample --solution myapp.sln --msbuild-path "C:\VS\MSBuild\Current\Bin\MSBuild.exe" -c Debug -a x64Useful when the build uses a non-Visual-Studio toolchain (e.g. a package-based
MSBuild/MSVC) and you want compile_commands.json to reference that exact compiler
instead of an auto-detected Visual Studio install. --cl-path is honored for both
--project and --solution inputs.
msbuild-extractor-sample --solution myapp.sln -c Debug -a x64 \
--msbuild-path "C:\path\to\MSBuild\Current\Bin\amd64\MSBuild.exe" \
--vc-targets-path "C:\path\to\MSBuild\Extensions\Microsoft\VC\v170\" \
--cl-path "C:\path\to\VisualCppTools\lib\native\bin\cl.exe"- Zero-config extraction - auto-detects Visual Studio via
vswhere.exe, resolvesVCTargetsPath,VCToolsInstallDir, and realcl.exepath automatically - No build required - design-time extraction only; evaluates projects and runs
GetClCommandLineswithout compiling anything - Two extraction modes - in-process (MSBuild API) and out-of-process (spawns MSBuild.exe, parses binlog) for maximum compatibility
- Multi-config -
--all-configurationsextracts everyConfiguration|Platformcombination;--mergecombines them;--deduplicateproduces one smart entry per file for IntelliSense - Multi-input - specify multiple
--solutionand--projectarguments to merge across solutions - Built-in validation -
--validatecompiles every extracted entry withcl.exe /cto prove correctness - Config validation -
--strictrejects invalid configuration/platform combinations with available options listed - Rich format -
--format richoutputs a hierarchical JSON schema with solutions, projects, configurations, structured includes/defines, and toolchain metadata - GN project support - extracts IntelliSense settings from GN-generated VS solutions (Chromium, Crashpad, WebRTC) via
ItemDefinitionGroupfallback - VS instance selection -
--list-instancesshows all VS installations;--vs-instance <id>selects by instance ID - LSP compatible - uses the real
cl.exepath and adds-ferror-limit=0and--targetso C++ LSP tools work out of the box - Solution formats -
.sln,.slnx, and GN-generated.slnfiles - C++/WinRT support - resolves
WindowsTargetPlatformVersion(e.g.,10.0→10.0.26100.0) so UWP and WinRT projects like Windows Terminal and Calculator extract correctly - Response file expansion - transparently inlines
@response.rspfiles during tokenization - VS Code integration -
--c-cpp-propertiesemits a matching.vscode/c_cpp_properties.jsonfor the VS Code C/C++ extension - Extensively tested - validated across over 50 OSS projects (~77,000 compile commands)
- .NET 10 SDK or later
- Visual Studio 2022/2026 with C++ workload (or Build Tools)
git clone https://github.com/<owner>/msbuild-extractor-sample.git
cd msbuild-extractor-sample
dotnet builddotnet run -- --solution path/to/solution.sln -c Debug -a x64msbuild-extractor-sample [options]
Options:
-p, --project <path> Path to .vcxproj file (repeatable)
-s, --solution <path> Path to .sln or .slnx file (repeatable)
-c, --configuration <name> Build configuration [default: Debug]
-a, --platform <name> Build platform [default: x64]
-o, --output <path> Output path [default: compile_commands.json]
--all-configurations Extract for all configuration/platform combos
--merge Merge all configs into single output file
--deduplicate Smart merge: one entry per file for IntelliSense
--prefer-configuration <name> Preferred config for dedup conflicts [default: Debug]
--prefer-platform <name> Preferred platform for dedup conflicts [default: x64]
--format <standard|rich> Output format [default: standard]
--validate Verify each entry compiles with cl.exe
--strict Treat config/platform warnings as errors
--emit-defaults Include the project-wide default compile entry in the output
--merge-defaults Merge project-wide default switches into each per-file entry
--vs-path <path> Path to Visual Studio installation
--vs-instance <id> Select VS by instance ID (see --list-instances)
--list-instances List all Visual Studio installations and exit
--vc-targets-path <path> VC targets directory (auto-detected)
--vc-tools-install-dir <path> VCToolsInstallDir property (auto-detected)
--cl-path <path> cl.exe path (overrides the resolved compiler; honored for --project and --solution)
--msbuild-path <path> MSBuild.exe path (enables out-of-process mode)
--use-dev-env Read Developer Command Prompt environment variables
--c-cpp-properties Emit .vscode/c_cpp_properties.json alongside the output
--logger Enable MSBuild console logger output
--config <path> JSON config file supplying option defaults (see below)
At least one --project or --solution must be specified (on the command line or in a config file). Both can be repeated and combined.
Options can be supplied from a JSON config file so the tool can run with no arguments:
# Uses ./msbuild-extractor.json automatically if it exists
msbuild-extractor-sample
# Or point at a config file explicitly
msbuild-extractor-sample --config path/to/config.json- Auto-detection: when
--configis not passed, amsbuild-extractor.jsonin the current directory is loaded automatically if present. - Precedence: command-line options override the config file, which overrides the built-in defaults.
- Inputs required: at least one
projectsorsolutionsentry must come from the config file or the command line. - Relative paths in the config file are resolved from the config file's own directory.
- The loader is lenient: keys match case-insensitively, and
//comments and trailing commas are allowed.
See msbuild-extractor.example.json for a ready-to-copy example that lists every supported key set to its default. Copy it to msbuild-extractor.json to get started.
At least one projects or solutions entry is required. All other keys are optional; an omitted key keeps its default.
| Key | Type | Default | Description |
|---|---|---|---|
projects |
string[] | [] |
Paths to .vcxproj files (equivalent to repeated --project). |
solutions |
string[] | [] |
Paths to .sln / .slnx files (equivalent to repeated --solution). |
configuration |
string | "Debug" |
Build configuration. |
platform |
string | "x64" |
Build platform. |
allConfigurations |
bool | false |
Extract every configuration/platform combination. |
merge |
bool | false |
With allConfigurations, merge into a single output file. |
output |
string | null |
Output path (defaults to compile_commands.json). |
format |
string | "standard" |
Output format: "standard" or "rich". |
emitCCppProperties |
bool | false |
Also emit .vscode/c_cpp_properties.json (not allowed with "rich"). |
deduplicate |
bool | false |
Merge duplicate entries per file for IntelliSense. |
preferConfiguration |
string | "Debug" |
Preferred configuration for dedup conflicts. |
preferPlatform |
string | "x64" |
Preferred platform for dedup conflicts. |
emitDefaults |
bool | false |
Include the synthetic __project_defaults.cpp entry. |
mergeDefaults |
bool | false |
Merge project-wide default switches into each per-file entry. |
validate |
bool | false |
Verify each entry by running cl.exe /c. |
strict |
bool | false |
Treat configuration/platform warnings as errors. |
logger |
bool | false |
Enable MSBuild console logger output. |
useDevEnv |
bool | false |
Read environment from a Developer Command Prompt. |
vsInstance |
string | null |
Select the VS installation by instance ID. |
vsPath |
string | null |
Path to a Visual Studio installation (auto-detected). |
msBuildPath |
string | null |
Path to msbuild.exe (enables out-of-process mode). |
vcTargetsPath |
string | null |
VC targets directory (auto-detected). |
clPath |
string | null |
Path to cl.exe (auto-resolved). |
vcToolsInstallDir |
string | null |
VCToolsInstallDir MSBuild property (auto-detected). |
solutionDir |
string | null |
SolutionDir MSBuild property (auto-derived with solutions). |
msBuildLauncher |
string | "auto" |
How to launch MSBuild: "auto", "cmd", "direct", or "dotnet". |
includePathOrder |
string | "auto" |
Include-path placement: "auto", "prepend", or "append". |
msBuildProperties |
object | {} |
MSBuild global properties as KEY: VALUE (merged with --msbuild-property). |
msBuildEnv |
object | {} |
Environment variables for the MSBuild process as KEY: VALUE (merged with --msbuild-env). |
The output includes a sentinel entry (.msbuild-extractor-sample) as the first element so consumers can identify the generator. Standard C++ LSP tools silently skip it since the file does not exist on disk.
The tool loads a .vcxproj file (or discovers all .vcxproj files in a solution) using the MSBuild API, runs a design-time build targeting GetClCommandLines (defined in Microsoft.Cpp.DesignTime.targets), and converts the results into the JSON Compilation Database format. No actual compilation occurs - only project evaluation and target execution.
For GN-generated projects (Chromium, Crashpad), where GetClCommandLines returns no items because source files aren't listed in the vcxproj, the tool falls back to reading ItemDefinitionGroup/ClCompile settings and scanning for source files on disk.
dotnet build- C++20 modules (
.ixx/.cppm) are extracted but skipped during--validate(require/interfaceflag) - NuGet native packages must be restored before extraction (
nuget restoreormsbuild -t:Restore) - Build-generated files (MIDL proxies, code generators) won't exist until a full build is done
- Precompiled headers are removed during
--validatebecause PCH files require exact flag matching with the original build. - Windows-only, requires Visual Studio and MSVC toolchain
MIT