When building a program, seldom do we only invoke the compiler passing a source file and an output binary name. In most cases, we must supply several compiler flags such as include paths or macro definitions. A program is usually built by compiling different source files where each may require different compiler flags.
One of the biggest challenges of static code analysis is having all this information available to analyze source codes. Just like a compiler will fail to build a code without proper compiler flags, the effectiveness of a static code analysis tool will be reduced without them. Parallelware Analyzer is no exception but, luckily, one of its goals is to be easily integrable with other tools. This blog post shows an example: how Parallelware Analyzer can consume a JSON Compilation Database produced by CMake.
What is a JSON Compilation Database?
A JSON Compilation Database is a file containing a list of build commands in JSON format. Each build command contains the compiler invocation to build a file, including all required compiler flags.
It has its origin in the LLVM Clang compiler. In its documentation we can find a more technical definition:
A compilation database is a JSON file, which consists of an array of “command objects”, where each command object specifies one way a translation unit is compiled in the project.
Each command object contains the translation unit’s main file, the working directory of the compile run and the actual compile command.
Typically, the JSON compilation Database is stored in a file named compile_commands.json. You can generate it using build systems such as CMake, Ninja or Meson. Additionally, you can use the Bear interception tool to generate it from other build tools such as Make.
An example using CMake
Let’s create a very minimal CMake project to exemplify the use of CMake and Parallelware Analyzer together. We will use a simple “hello world” program including a header file, deliberately avoiding any parallel code or loops: the goal is showing how to generate a compile_commands.json for a CMake project and how to make Parallelware Analyzer consume it to analyze the source code!
Create the demo CMake project
First, let’s create the basic structure: a demo directory containing an include subdirectory:
$ mkdir -p demo/include
$ cd demo
Create a main.h file inside the include directory including the standard input/output header and defining a simple macro:
$ vim include/main.h
#define MESSAGE "Hello world!"
Now create a main.c file including the main.h file and printing the MESSAGE macro:
$ vim main.c
Finally, create the demo CMake project:
$ vim CMakeLists.txt
This should be the contents of your demo directory by now:
$ tree .
│ └── main.h
You can now build your project and run the demo program. We’ll do that in a build subdirectory:
$ mkdir build && cd build
$ cmake ..
$ cmake --build .
Generating compile_commands.json with CMake
CMake supports the generation of compilation databases when using the Makefile or Ninja generators. It is enabled by setting the CMAKE_EXPORT_COMPILE_COMMANDS variable to ON. Edit the CMakeLists.txt file and add a line to do so:
$ vim CMakeLists.txt
Now you can go back to the build directory and reconfigure CMake. Note that you don’t need to actually build the program, the compile_commands.json file is created during the configuration stage:
$ cd build
$ cmake ..
$ cat compile_commands.json
Notice the flags passed to the cc compiler in the command field: these are the compiler flags that Parallelware Analyzer will use to analyze main.c.
Consuming compile_commands.json with Parallelware Analyzer
If you try to analyze main.c with Parallelware Analyzer it will fail since it won’t be able to find the header file:
$ pwreport main.c --show-failures
main.c:1:10: fatal error: 'main.h' file not found
This example is so trivial that you could simply pass the compiler flag to Parallelware Analyzer through the command line by appending “— -Iinclude”. However, this will hardly be a viable option for non-trivial projects.
Create a config.json file specifying the location of the compile_commands.json file:
$ vim demo.json
Invoke a Parallware Analyzer tool such as pwreport using the –config argument to specify the configuration file we have just created:
$ pwreport --config demo.json main.c
1 file successfully analyzed and 0 failures in 22 ms
Parallelware Analyzer performs static code analysis which requires not only access to the source code itself but also to compiler flags such as macro definition or include paths. Most projects use build systems to take care of all the build dependencies and required compiler flags. The JSON Compilation Database format allows build systems to export all that information so that it can be consumed by other tools. In this article we have seen how through a simple two-line configuration file, you can instruct Parallelware Analyzer to consume a JSON Compilation Database generated by CMake.
You can find the configuration file documentation in the docs/ directory of your Parallelware Analyzer installation. Also check the examples/config/ directory for various configuration file examples including one for compile_commands.json.
Early Access Program is now open!
Enter the program to have access to all versions of Parallelware Analyzer until the official release.