Generating a compile_commands.json
file, a JSON database of compile commands, using CMake isn’t something I run into as a web developer. But as somebody that’s recently gotten bitten by the game development bug, this was one of the first things I happened to have run into.
I’m not going to bore you too much with the details of my foray into game development. I’m trying to build a few small games, think Atari-era arcade games. The plan is to release them on Steam, and I’m focusing heavily on the native Steam Deck’s native screen resolution of 1280 by 800, as that will be my primary consumption device for these games.
Coincidentally, I’ve written games in the past, using web technologies as well as writing native games for Android and iOS. For a change of pace, I’m focusing on learning more about C++ this time around.
Syntax errors for days
Armed with my favorite text editor, Neovim, I set out to write my game. And within a few minutes, my syntax checking plugin, ALE, was not very happy at all:
The errors make sense, as it’s barking about things that aren’t explicitly in my code. In Node.js and TypeScript, developers must define exceptions for implied global variables, which I’m no stranger to.
But how the heck do I do this with a C++ program?
During some research, I found the missing piece to making clangd
and other C++ syntax checkers happy would be to provide it with a JSON database of compile commands. This typically lives in a file named compile_commands.json
, which can be generated when building your project.
While I had read that this file needs to be in the root of your project, I found that it was sufficient enough to leave the file inside of my build directory ./build
. This is a personal choice of mine, but if I were to distribute my code, I’d probably move the file out of the build directory, so that it could be picked up by version control and shared. That way other engineers wouldn’t need to build the program before trying to edit the code.
Configuring CMake to export compile commands
So how does one create this compile_commands.json
file? First, you will need to update your CMakeLists.txt
file:
cmake_minimum_required(VERSION 3.16)
project(Game LANGUAGES CXX)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# Add this line, to enable compile command export
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Other stuff...
CMakeLists.txtAlternatively you could pass this option along as arguments to the cmake
command, but that’s out of scope for how I’m building my program.
Finally, with the new option set, we can run our cmake
build commands:
% cmake -B build -DCMAKE_BUILD_TYPE=Release
-- Configuring done (0.7s)
-- Generating done (0.0s)
-- Build files have been written to: /Users/josh/Code/Game/build
% cmake --build build --config Release
[ 14%] Built target sfml-system
[ 48%] Built target sfml-window
[ 73%] Built target sfml-graphics
[ 74%] Built target Game
[ 82%] Built target sfml-network
[100%] Built target sfml-audio
ZshAnd inside of our build directory, mine being ./build
there is now a JSON database of compile commands in the compile_commands.json
file:
% head build/compile_commands.json
[
{
"directory": "/Users/josh/Code/Game/build",
"command": "/Library/Developer/CommandLineTools/usr/bin/c++ -DSFML_STATIC -I/Users/josh/Code/Game/build/_deps/sfml-src/include -O3 -DNDEBUG -std=gnu++17 -arch arm64 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX14.0.sdk -F/Users/josh/Code/Games/build/_deps/sfml-src/extlibs/libs-osx/Frameworks -o CMakeFiles/Game.dir/src/main.cpp.o -c /Users/josh/Code/Game/src/main.cpp",
"file": "/Users/josh/Code/Game/src/main.cpp",
"output": "CMakeFiles/Game.dir/src/main.cpp.o"
},
{
"directory": "/Users/josh/Code/Game/build/_deps/sfml-build/src/SFML/System",
"command": "/Library/Developer/CommandLineTools/usr/bin/c++ -DSFML_STATIC -I/Users/josh/Code/Game/build/_deps/sfml-src/include -I/Users/josh/Code/Game/build/_deps/sfml-src/src -O3 -DNDEBUG -arch arm64 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX14.0.sdk -fvisibility=hidden -Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wcast-align -Wunused -Woverloaded-virtual -Wconversion -Wsign-conversion -Wdouble-promotion -Wformat=2 -Wnull-dereference -Wold-style-cast -Wpedantic -Wno-unknown-warning-option -o CMakeFiles/sfml-system.dir/Clock.cpp.o -c /Users/josh/Code/Game/build/_deps/sfml-src/src/SFML/System/Clock.cpp",
ZshWith the compile commands JSON database created by CMake, my code is now free of all of the noisy errors and I’m free to resolve the actual errors in my code, and continue out my merry way.