Static analysis tooling with CMake
Tags: cpp, tutorial, showdev, productivity
Published: 2022-11-05 07:19:51

Regardless of whether I am an experienced programmer or not, it is tough to write the `perfect code`. Ideally, I would like to detect every potential flaw, and bug and debug them to the appropriate standard in no time! But this is a tough concept, and relying only upon your `developer instincts` for analyzing code is insufficient, especially if you are writing in C++. 

While analyzing code yourself and self-proofing is a vital skill that every developer needs to practice, having a professional tool like [clang-tidy](https://clang.llvm.org/extra/clang-tidy/)  gives me more confidence that my code adheres to C++ standards.

### Setup clang-tidy ⚙️

I recently integrated `clang-tidy`  in [palpatine](https://github.com/batunpc/palpatine) using CMake modules, [you could browse the cmake directory](https://github.com/batunpc/palpatine/tree/main/cmake/modules) of palpatine where I kept the `StaticAnalyzers.cmake` module. 

To set this up from scratch, first install `clang-tidy` with `brew install clang-tidy` on macOS, or if you are on Linux install it with `sudo apt-get install clang-tidy`. 

After successfully installing, I have added the most commonly used `clang-tidy checks` into the [`.clang-tidy` dotfile](https://github.com/batunpc/palpatine/blob/main/.clang-tidy). 

> ***Note:*** Notice the  `WarningsAsErrors: ''`  field in this file, it is responsible for labeling the warnings as errors. Although, currently it is not active as I haven't provided any value. But if you would like to activate it, you could replace the empty value with `"*"`.

### Power of CMake  🧰

See the directory called `cmake` in the root directory of [palpatine](https://github.com/batunpc/palpatine). 
Having `cmake modules` within the directory `cmake` is commonly used, the purpose of doing is to [include()](https://cmake.org/cmake/help/v3.0/command/include.html) custom CMake functions to be used later in the project.

Mine looks like this - 

![cmake-modules-hierarchy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nnqx7a7tkwit6dtz56g8.png)

There are 2 files (`AddGitSubmodule.cmake`,  `StaticAnalyzers.cmake`) and 2 corresponding functions palpatine uses. Our attention will be on [StaticAnalyzers.cmake](https://github.com/batunpc/palpatine/blob/main/cmake/modules/StaticAnalyzers.cmake). 

After adding the module `StaticAnalyzers.cmake` we need to configure it in a way that `clang-tidy` will always run whenever we build the project using CMake (i.e. `cd build && cmake .. && make`).  However this might not be the "intended behavior" in every project, maybe you prefer running it at the end after you are satisfied with your implementation for reducing each CMake build time. That said, there is a _neat_ way of setting this as an option in the file CMakeLists.txt.

Navigate to the root CMakeLists.txt file of palpatine and see in [this line ](https://github.com/batunpc/palpatine/blob/c7dd5ac68e2e69ac41f9731e04e88fa448eed10d/CMakeLists.txt#L19) , I have defined a `CMake option` that lets me switch between weather I decide to use `clang-tidy` or not.

Now go back to the module `StaticAnalyzers.cmake` and notice the first line we are checking is if the option is turned ON or OFF (i.e. `if(ENABLE_CLANG_TIDY)`) If [this option](https://github.com/batunpc/palpatine/blob/c7dd5ac68e2e69ac41f9731e04e88fa448eed10d/CMakeLists.txt#L19) was set to OFF, CMake would ignore this module.


```cpp
if(ENABLE_CLANG_TIDY)
	find_program(CLANG_TIDY_COMMAND NAMES clang-tidy)
	
	if(NOT CLANG_TIDY_COMMAND)
		message(WARNING "🔴 CMake_RUN_CLANG_TIDY is ON but clang-tidy is not found!")
		set(CMAKE_CXX_CLANG_TIDY "" CACHE STRING "" FORCE)
	else()
		message(STATUS "🟢 CMake_RUN_CLANG_TIDY is ON")
		set(CLANGTIDY_EXTRA_ARGS
			"-extra-arg=-Wno-unknown-warning-option"
	)
	endif()
endif()
```

The `find_program()`  CMake command, will search for the clang-tidy that is already installed in your system. If it is unsuccessful in finding it, it will complain with big, fat, and red warning 🔴 in the terminal. Check if you indeed installed it in your system with; `clang-tidy --version`.  If it is successful, 🟢 will indicate your CMake configured `clang-tidy` with no trouble.

### clang-tidy in action 🚧
Run the traditional set of CMake build commands in your terminal in the root directory of palpatine.


```sh
mkdir build && cd build && cmake .. && make
```

A combination of these commands is one way of creating a build folder and configuring it with CMake; 

After CMake can see the command `clang-tidy` , finally configure it with the project.

```cpp
set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND};-p=${CMAKE_BINARY_DIR};${CLANGTIDY_EXTRA_ARGS}" CACHE STRING "" FORCE)

add_custom_target(clang-tidy
	COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ${CMAKE_PROJECT_NAME}
	COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target clang-tidy
	COMMENT "Running clang-tidy..."
	)
```

Delete the existing build folder and re-run this set of commands `mkdir build && cd build && cmake .. && make`  to test if clang-tidy produces any warnings in the terminal.

In project [palpatine](https://github.com/batunpc/palpatine), the output looks like the following -

![command-line-execution](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o4i6km4bh27eop6lbxnl.png)

There is also a vscode extension called [CMake Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) from Microsoft. It provides this set of buttons that automates the CMake build progress;

![status-bar-buttons](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8cwq0fv0x8obp8c9op54.png)

This is beneficial in a way if you want to integrate CMake and visualize the warnings in vscode before running it on CLI. 

If I build [palpatine](https://github.com/batunpc/palpatine) using [CMake Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) vscode displays the warning within the file.

![example-of-editor-warning](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7dvrm04nk9tzjyo4hu4h.png)


### Conclusion

C++ is developing rapidly and reviewing code is not enough to keep up with the latest standards. Using static analyzers like `clang-tidy` inevitably helps us to write defect-free code. You might as well learn from the warnings produced by `clang-tidy`.

![code-style-meme](https://imgs.xkcd.com/comics/code_quality.png)