Skip to content

microsoft/msbuild-extractor-sample

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MSBuild Compile Commands Extractor

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.

Examples

Basic extraction

msbuild-extractor-sample --project myapp.vcxproj -c Debug -a x64

Solution with multiple projects

msbuild-extractor-sample --solution myapp.sln -c Debug -a x64 -o compile_commands.json

Auto-detect Visual Studio (no manual paths needed)

# 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 x64

Validate extracted commands (compile every file with cl.exe)

msbuild-extractor-sample --solution myapp.sln -c Debug -a x64 --validate

Multi-configuration extraction

# 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 --deduplicate

Merge multiple solutions

msbuild-extractor-sample --solution engine.sln --solution editor.sln -c Debug -a x64 -o compile_commands.json

Rich hierarchical format

# Structured output with solutions/projects/configurations/files
msbuild-extractor-sample --solution myapp.sln --format rich -o compile_database.json

Out-of-process mode (custom MSBuild)

msbuild-extractor-sample --solution myapp.sln --msbuild-path "C:\VS\MSBuild\Current\Bin\MSBuild.exe" -c Debug -a x64

Pin a specific toolchain (custom MSBuild, VC targets, and cl.exe)

Useful 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"

Features

  • Zero-config extraction - auto-detects Visual Studio via vswhere.exe, resolves VCTargetsPath, VCToolsInstallDir, and real cl.exe path automatically
  • No build required - design-time extraction only; evaluates projects and runs GetClCommandLines without compiling anything
  • Two extraction modes - in-process (MSBuild API) and out-of-process (spawns MSBuild.exe, parses binlog) for maximum compatibility
  • Multi-config - --all-configurations extracts every Configuration|Platform combination; --merge combines them; --deduplicate produces one smart entry per file for IntelliSense
  • Multi-input - specify multiple --solution and --project arguments to merge across solutions
  • Built-in validation - --validate compiles every extracted entry with cl.exe /c to prove correctness
  • Config validation - --strict rejects invalid configuration/platform combinations with available options listed
  • Rich format - --format rich outputs 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 ItemDefinitionGroup fallback
  • VS instance selection - --list-instances shows all VS installations; --vs-instance <id> selects by instance ID
  • LSP compatible - uses the real cl.exe path and adds -ferror-limit=0 and --target so C++ LSP tools work out of the box
  • Solution formats - .sln, .slnx, and GN-generated .sln files
  • C++/WinRT support - resolves WindowsTargetPlatformVersion (e.g., 10.010.0.26100.0) so UWP and WinRT projects like Windows Terminal and Calculator extract correctly
  • Response file expansion - transparently inlines @response.rsp files during tokenization
  • VS Code integration - --c-cpp-properties emits a matching .vscode/c_cpp_properties.json for the VS Code C/C++ extension
  • Extensively tested - validated across over 50 OSS projects (~77,000 compile commands)

Installation

Prerequisites

  • .NET 10 SDK or later
  • Visual Studio 2022/2026 with C++ workload (or Build Tools)

Build from source

git clone https://github.com/<owner>/msbuild-extractor-sample.git
cd msbuild-extractor-sample
dotnet build

Run

dotnet run -- --solution path/to/solution.sln -c Debug -a x64

Usage

msbuild-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.

Configuration file

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 --config is not passed, a msbuild-extractor.json in 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 projects or solutions entry 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.

Config keys

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.

How It Works

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.

Development

Building

dotnet build

Known Limitations

  • C++20 modules (.ixx/.cppm) are extracted but skipped during --validate (require /interface flag)
  • NuGet native packages must be restored before extraction (nuget restore or msbuild -t:Restore)
  • Build-generated files (MIDL proxies, code generators) won't exist until a full build is done
  • Precompiled headers are removed during --validate because PCH files require exact flag matching with the original build.
  • Windows-only, requires Visual Studio and MSVC toolchain

License

MIT

About

A .NET sample to extract compile commands from C++ MSBuild projects

Resources

License

Code of conduct

Security policy

Stars

20 stars

Watchers

1 watching

Forks

Contributors

Languages