= 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/main1.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