Find stale paths and missing tools in your C++ compilation database.
cpp-doctor is a small, dependency-free C++17 command-line tool for the moment when
your editor, checkout, and build configuration stop agreeing. It reads
compile_commands.json, checks the local environment, and explains actionable
problems. It never runs commands from the database or modifies your project.
Version 0.1.0 is an initial POSIX release focused on Linux and GCC/Clang-style commands. macOS is included in the CI configuration; Windows is not yet supported.
Build with a C++17 compiler and Make:
make
./build/cpp-doctor --help
make test # Python 3 required for tests onlyOr use CMake 3.16+:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
cmake --build build --parallel
ctest --test-dir build --output-on-failure
./build/cpp-doctor check --build-dir buildUse -DBUILD_TESTING=OFF to configure without Python. Installation is optional:
cmake --install build --prefix "$HOME/.local"To inspect another CMake project, generate its database using a Makefiles or Ninja generator, then point the doctor at it:
cmake -S /path/to/project -B /path/to/project/build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
./build/cpp-doctor check --build-dir /path/to/project/buildExample output (paths and entry counts depend on the project):
C++ Environment Doctor 0.1.0
Database: "/workspace/app/build/compile_commands.json"
FAIL [compiler.missing] entry 1 "Compiler is missing or not executable: /opt/toolchain/bin/clang++"
"Install the toolchain, update PATH, or regenerate the database for this machine."
WARN [include.missing] entry 1 "Include directory is missing or inaccessible: /workspace/app/build/generated"
"Check the include flag or build the target that generates this directory."
1 entries checked; 1 errors, 1 warnings.
| Check | Result |
|---|---|
| JSON syntax, root shape, required entry fields | Error |
| Missing/inaccessible working directories | Error; dependent checks skipped |
| Missing source files, including generated sources | Error |
| Compiler or supported launcher absent/not executable | Error |
| Missing explicit sysroot | Error |
| Missing value for a supported directory flag | Error |
| Missing explicit include directories | Warning; may be optional or not generated yet |
| Relative working directories | Warning; resolved against the database directory |
| Response files, shell expressions, unsupported wrappers | Warning; affected checks skipped |
| Empty database | Warning |
Supported include flags: -I, -isystem, -iquote, and -idirafter, with joined
or separate values. Explicit sysroots support --sysroot=PATH, --sysroot PATH,
and -isysroot PATH/-isysrootPATH. Include paths starting with = or $SYSROOT
are resolved when an explicit sysroot is known and no response files are present.
Relative source, compiler, and include paths resolve against each entry's
directory, not the process's current directory. Compiler lookup uses the
current PATH; relative PATH entries resolve against the compilation working
directory. Simple ccache, sccache, and distcc launcher chains are recognized.
The arguments field takes precedence over command. An invalid arguments
field is reported rather than silently falling back to command. Multiple
commands for the same source file are valid and are checked independently.
cpp-doctor check # ./compile_commands.json
cpp-doctor check --build-dir build
cpp-doctor check --database out/compile_commands.json
cpp-doctor check --build-dir build --json
cpp-doctor check --build-dir build --strict # Fail on warnings too| Exit code | Meaning |
|---|---|
0 |
No errors; warnings allowed unless --strict is set |
1 |
Diagnostic errors, or warnings with --strict |
2 |
Usage, database loading, or JSON/root-format error |
--json emits one JSON object to standard output, including input errors. It has
schema_version, database, entries, errors, warnings, exit_code, and a
findings array. Findings contain severity, code, entry, message, and
hint. Entry numbers are one-based; zero denotes a database-level finding.
Consumers should use diagnostic codes rather than match English text.
Example healthy report:
{"schema_version":1,"database":"/workspace/app/build/compile_commands.json","entries":1,"errors":0,"warnings":0,"exit_code":0,"findings":[]}Once installed in a CI job, use:
cpp-doctor check --build-dir build --strict --json > doctor-report.jsonRun after configuration, or after code generation if the project generates sources and include directories. The included GitHub Actions workflow builds, tests, and inspects this project's own compilation database.
A clean report means the supported environment checks passed, not that code compiles or that clangd is configured correctly.
- Does not invoke compilers, discover implicit/system include paths, validate compiler flags generally, or inspect clangd configuration and logs.
- Does not identify toolchain versions, ABI compatibility, or whether a found executable is actually a compiler.
- Supports ordinary POSIX command quoting. Shell expansion, operators, environment assignments, and shell wrappers produce warnings instead of being evaluated.
- Does not expand
@responsefiles. Launcher-specific options and MSVC-style commands are outside the first release's scope. - Does not interpret every GCC/Clang path-affecting option, such as
-iprefix,-iwithprefix, framework search flags, or driver configuration files. - Relative working directories are an explicit fallback convention; generate absolute working directories for reliable portability.
- Checks current local filesystem state and
PATH; remote/container toolchains must be checked inside their own environment. - Limits database input to 64 MiB and JSON nesting to 128 levels. Duplicate JSON object keys are rejected. Terminal control characters are escaped in output.
- Reports per entry; large databases can produce repeated diagnostics.
make test
# Optional, with a supporting GCC/Clang toolchain:
g++ -std=c++17 -g -fsanitize=address,undefined -fno-omit-frame-pointer src/main.cpp -o build/cpp-doctor-sanitized
python3 tests/test_cli.py build/cpp-doctor-sanitizedThe integration tests use isolated temporary projects and fake compiler executables. They check path resolution, diagnostics, quoting, Unicode, malformed input, strict exit codes, and that database commands are never executed.
See CONTRIBUTING.md for contribution guidelines and ROADMAP.md for the next milestones.
Compilation database format reference: Clang's specification.
Copyright 2026 Ali Naqvi and cpp-doctor contributors. Licensed under the Apache License, Version 2.0; see LICENSE and NOTICE. See AUTHORS.md for attribution.