compile_commands.json with CMake

Kent - April 20, 2024

compile_commands.json is a file capturing the exact commands files have been compiled with, regardless of the build system. It captures the compiler, source file, include path and definitions used to build a certain source file. With this information, external tools can “rebuild” the source file as it is. It is very useful for source code tools like and clang-tidy.

With CMake, only the generators Ninja and Makefiles will generate compile_commands.json. Any other generator will silently ignore it.

Since the feature is controlled by an environment flag, there are 3 ways of telling CMake that is should create that file.

  1. Using the environment block in CMakePresets.json.
  2. Permanently alter your environment with .bashrc or Windows User Environment.
  3. Invoke CMake with -D and or export/set.

Number 1. is by far the easiest and most portable solution. The other will not be transferred to other systems automatically.

A minimal CMakePresets.json with support for vcpkg with automatic bootstrapping. The important bit to enable compile_commands.json is CMAKE_EXPORT_COMPILE_COMMANDS.

If vcpkg is not needed, remove the linje with toolChainFile.

{
  "version": 6,
  "cmakeMinimumRequired": {
    "major": 3,
    "minor": 25,
    "patch": 0
  },
  "configurePresets": [
    {
      "name": "default",
      "hidden": true,
      "displayName": "Default Parent Configuration",
      "binaryDir": "${sourceDir}/build-cmake/${presetName}",
      "toolchainFile": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake",
      "installDir": "${sourceDir}/build-cmake/${presetName}-install",
      "environment": {
        "CMAKE_EXPORT_COMPILE_COMMANDS": "1"
      }
    },
    {
      "name": "linux",
      "inherits": "default",
      "cacheVariables": {
        "VCPKG_TARGET_TRIPLET": "x64-linux"
      },
      "generator": "Unix Makefiles",
      "condition": {
        "type": "equals",
        "lhs": "${hostSystemName}",
        "rhs": "Linux"
      }
    },
    {
      "name": "darwin",
      "inherits": "default",
      "cacheVariables": {
        "VCPKG_TARGET_TRIPLET": "x64-linux"
      },
      "generator": "Unix Makefiles",
      "condition": {
        "type": "equals",
        "lhs": "${hostSystemName}",
        "rhs": "Darwin"
      }
    }
  ]
}

Minimal CMakeLists.txt:

cmake_minimum_required (VERSION 3.25.0)
project (compile_commands_example)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(compiler-cmd compiler-cmd.cpp)

Minimal C++23 source file:

#include <print>

auto main() -> int
{
    std::print("foo {:d}\n\n", 42);
    return 0;
}

Configure with cmake --preset linux or cmake --preset darwin.

Program output:

foo 42

Example output from compile_commands.json (truncated) built on a Mac:

[
{
  "directory": "/Users/kent/src/build-cmake/darwin",
  "command": "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++   -std=gnu++2b -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.5.sdk -o CMakeFiles/compiler-cmd.dir/compiler-cmd.cpp.o -c /Users/kent/src/compiler-cmd.cpp",
  "file": "/Users/kent/src/compiler-cmd.cpp",
  "output": "CMakeFiles/compiler-cmd.dir/compiler-cmd.cpp.o"
}
]

See Also

Comments

Any comments? Create a new discussion on GitHub.
There used to be an inline comment form here, but it was removed.