CMake
Generate a compilation database with CMake
CMake is able to generate a compilation database by itself at configuration. When using a CMake project you have two ways of generating it:
Using CMAKE_EXPORT_COMPILE_COMMANDS variable globally (from CMake 3.5)
Using EXPORT_COMPILE_COMMANDS variable for the target you want to analyze and optimize with beLow (from CMake 3.20)
Compilation database generation with CMake is only available with Makefiles generators and Ninja generators. Any other generator will ignore these variables and the compilation database will not be generated.
The first variable can be set directly from CMake command using flag -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
, or directly in the root CMakeLists.txt
file:
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
However, if your CMake configuration has multiple targets, it is strongly recommended to activate compile commands generation only for your target, or it could lead to some undefined behaviour, if some sources are compiled multiple times with different commands in multiple targets.
To do that, start by forcing the global generation to off:
set(CMAKE_EXPORT_COMPILE_COMMANDS OFF)
Then, activate the generation for your target:
set_target_properties(mytarget PROPERTIES EXPORT_COMPILE_COMMANDS ON)
When running CMake command, compile_commands.json
is then generated in the build directory. E.g, when running command:
cmake -B build -DCMAKE_BUILD_TYPE=Release .
the file ./build/compile_commands.json
is generated.
In beLow, just enter the command as a Configure script when asked to, and beLow will find the file by name.
Try not to leave any compile_commands.json
file in your project directory if you are able to generate it at configuration or build time, or it could be used in priority and lead to potential issues if not up to date or using absolute paths in copy mode.
Windows specificities
On Windows, the CMake tool CMAKE_EXPORT_COMPILE_COMMANDS
has some limitations and may generate commands with an unexpected syntax, making confusions between escaping and unescaping backslashes. Here is an example of this problem, and how to fix it.
Let's imagine that you want to inject local includes with preprocessor directives. To do that, you may do:
#include LIB_HEADER_FILE
and define in your CMakeLists.txt
:
add_definitions(-DLIB_HEADER_FILE="lib.h")
or
target_compile_definitions(<your-target> PUBLIC LIB_HEADER_FILE="lib.h")
Unfortunately, CMake generates a faulty compilation database in this case, with an "overescaped" command which injects -DLIB_HEADER_FILE=\"lib.h\"
, making the injection faulty.
There are two possibilities to overcome this issue:
Modify the compilation database after generation, for instance with a specific script correcting the incriminated commands (not clean, not advised)
Rewrite the macro differently so adding the quotes in the include is done by the compiler itself (better). To do that, in your C/C++ file, use:
#define INCLUDE_FILE(x) #x #include INCLUDE_FILE(LIB_HEADER_FILE)
and in your
CMakeLists.txt
:add_definitions(-DLIB_HEADER_FILE=lib.h)
or
target_compile_definitions(<your-target> PUBLIC LIB_HEADER_FILE=lib.h)
With the second solution, after running CMake configuration, the generated compilation database is correct.
Last updated