Setting Up Compile Commands for C & C++ for Neovim

Use CMake to generate compile_commands.json for clangd

Quick tip on enabling Neovim LSP for C/C++ using Clangd

TL;DR: Add this to your CMakeLists.txt:

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

This will generate a compile_commands.json file in your build directory. Copy or symlink it into your project root so that clangd (and Neovim) can use it.


Language servers are wonderful for navigating large codebases. Being able to jump to a definition really speeds up understanding the code you’re staring at (especially in library heavy codebases). Neovim (especially with distros like LazyVim has excellent LSP support, but C and C++ require extra setup compared to languages like Python.

To use the LSP with C or C++ you’ll need a compile_commands.json file which clangd can use to navigate your code (this also enables you to use clang-tidy):

[{
  "directory": "/home/user/projects/laser/lc120-firmware",
  "command": "/usr/bin/c++  -I/home/user/projects/laser/lc120-firmware/source/common -I/home/user/projects/laser/lc120-firmware/source 
-Wall -O0 -g3 -ffreestanding -o CMakeFiles/source/shell.cpp.o -c /home/user/projects/laser/lc120-firmware/source/shell/sh
ell.cpp",
  "file": "/home/user/projects/laser/lc120-firmware/source/shell/shell.cpp",
  "output": "CMakeFiles/source/shell/shell.cpp.o"
}
]

CMake will generate this when the CMAKE_EXPORT_COMPILE_COMMANDS option is on:

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

If you are using a build directory then you’ll need to copy or link the file to the base directory:

ln -s build/compile_commands.json compile_commands.json

If you are using a managed tool to compile and link your code then you’ll want to have at a minimum something like this:

project(PROJECT LANGUAGES C CXX)
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

file(
  GLOB_RECURSE
  ALL_FILES
  "${CMAKE_CURRENT_SOURCE_DIR}/source/*.c",
  "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp",
)

include_directories(${PROJECT_INCLUDES})
add_executable(${CMAKE_PROJECT_NAME} ${ALL_FILES})
set_property(TARGET ${CMAKE_PROJECT_NAME} PROPERTY CXX_STANDARD 20)
set_property(TARGET ${CMAKE_PROJECT_NAME} PROPERTY C_STANDARD 11)

Additional Tools