= CppCheck Static Analysis using Compile Commands
:toc:
:toc-placement!:

toc::[]

# Introduction

This example shows how to call the
http://cppcheck.sourceforge.net/[CppCheck] tool to do static analysis.
This shows how to use projects and a compile database.
Projects are available from cppcheck v1.77

It includes code to

  * Find the cppcheck binary
  * Generate an overall `make cppcheck-analysis` target to do static
analysis on all sub-projects.

The files included in this example are:

```
$ tree
.
├── cmake
│   └── modules
│       └── FindCppCheck.cmake
├── CMakeLists.txt
├── subproject1
│   ├── CMakeLists.txt
│   └── main1.cpp
└── subproject2
    ├── CMakeLists.txt
    └── main2.cpp
```

  * link:CMakeLists.txt[] - Top level CMakeLists.txt
  * link:cmake/modules/FindCppCheck.cmake[] - A custom package module to find CppCheck
  * link:subproject1/CMakeLists.txt[] - CMake commands for subproject 1
  * link:subproject1/main.cpp[] - source for a subproject with no errors
  * link:subproject2/CMakeLists.txt[] - CMake commands for subproject 2
  * link:subproject2/main2.cpp[] - source for a subproject that includes errors

# Requirements

To run this example you must have CppCheck of at least v1.77 installed. This is not
available by default on Ubuntu but can be compiled using the following command.

[source,bash]
----
$ wget https://github.com/danmar/cppcheck/archive/1.79.tar.gz \
    && tar xvf 1.79.tar.gz \
    && cd cppcheck-1.79 \
    && mkdir build \
    && cd build \
    && cmake .. \
    && sudo make install
----

# Concepts

## Adding Custom Package Modules

As with the previous example I use a custom module to find CppCheck. This version is slightly different to the previous one and 
will automatically add a `make cppcheck-analysis` target.

[source,cmake]
----
if(CPPCHECK_FOUND)
    file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/analysis/cppcheck)
    add_custom_target(cppcheck-analysis 
        COMMAND ${CPPCHECK_COMMAND})
    message("cppcheck found. Use cppccheck-analysis targets to run it")
else()
    message("cppcheck not found. No cppccheck-analysis targets")
endif()
---- 

The variables available have also changed. For full details on the commands see the `FindCppCheck.cmake` module. Below are a subset of the available options:

### Suppressions

Adding a suppression file called `.cppcheck-suppressions` which must be in your +CMAKE_SOURCE_DIR+

### Error Exitcode

When cppcheck finds an error it can cause it to exit with a specific error. In this 
example, by default, it will exit with `1`. To change this you can set the 
+CPPCHECK_ERROR_EXITCODE_ARG+ argument when running CMake.

### Exitcode suppressions

Sometimes you wish to display an error in the log, but to not have that error cause a failed build. To do this you can create a file `.cppcheck_exitcode_suppressions` and add suppressions to it. This file must be in your +CMAKE_SOURCE_DIR+

### CppCheck arguments

The default enabled checks are `--enabled=warning`. To change this you can override the `CPPCHECK_CHECK_ARGS` variable before calling `find(cppcheck)`.

### Excluding files / folders

Many projects include some vendored 3rd party code. To exclude this from you check you can create a list `CPPCHECK_EXCLUDES` before calling the find module. This will add all files and folders in the list into the list of excluded folders.

### CppCheck build dir

In this example, we set +CPPCHECK_BUILD_DIR_ARG+, to `${PROJECT_BINARY_DIR}/analysis/cppcheck`. This will output details of the build to this folder and can be used to 
increase the speed of rechecks if a file hasn't changed

## Compile Database

CMake allows you to export all https://cmake.org/cmake/help/v3.5/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html[compile commands] 
that are used to build the project into a file called `compile_commands.json`

This can be done by setting the +CMAKE_EXPORT_COMPILE_COMMANDS+ variable to +ON+ 
as below:

[source,cmake]
----
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
----

The JSON file will look like:

[source,json]
----
[
  {
    "directory": "/home/user/development/project",
    "command": "/usr/bin/c++ ... -c ../foo/foo.cc",
    "file": "../foo/foo.cc"
  },

  ...

  {
    "directory": "/home/user/development/project",
    "command": "/usr/bin/c++ ... -c ../foo/bar.cc",
    "file": "../foo/bar.cc"
  }
]
----

[NOTE]
====
This is only available for the `Makefile` and `ninja` generators.
====

## CppCheck Projects

Starting with CppCheck v1.77, you can pass the `--project` flag pointing to the 
compile database. This will cause CppCheck to run on al your cpp files using the same
include directories and compiler flags as your normal build.

[source,bash]
----
cppcheck --project=compile_comands.json
----

This will check all files in your project and sub-projects. There will be no analysis target per sub-project as with our previous example.

# Building the example

[source,bash]
----
$ mkdir build

$ cd build/

$ cmake ..
-- The C compiler identification is GNU 4.8.4
-- The CXX compiler identification is GNU 4.8.4
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found CPPCHECK: /usr/local/bin/cppcheck  
cppcheck found. Use cppccheck-analysis targets to run it
-- Configuring done
-- Generating done
-- Build files have been written to: /data/code/04-static-analysis/cppcheck-compile-commands/build

$ make cppcheck-analysis
Scanning dependencies of target cppcheck-analysis
[/data/code/04-static-analysis/cppcheck-compile-commands/subproject2/main2.cpp:7]: (error) Array 'tmp[10]' accessed at index 11, which is out of bounds.
make[3]: *** [CMakeFiles/cppcheck-analysis] Error 1
make[2]: *** [CMakeFiles/cppcheck-analysis.dir/all] Error 2
make[1]: *** [CMakeFiles/cppcheck-analysis.dir/rule] Error 2
make: *** [cppcheck-analysis] Error 2
