Skip to content

Using clang-tidy with CMake

Clang-tidy is a C++ static analysis tool from the LLVM project that is particularly helpful when modernizing your code base or when checking your code for compliance with established guidelines and best practices.

Typically, you need to run clang-tidy with the same options and compiler flags you use for compilation. Doing this manually can be quite a hassle.

One way to help with this is to use a compilation database. However, I always found this to be rather complicated by itself.

Luckily, if you are using CMake, there is a simpler alternative: You can directly use clang-tidy from CMake.

You need to do two steps:

  1. Find and setup the clang-tidy command
  2. Tell CMake to use clang-tidy

For the first step, you only need to use CMake’s find_program() and set the corresponding CMake variable to the command and options you want to use:

find_program(CLANG_TIDY_EXE NAMES "clang-tidy")
set(CLANG_TIDY_COMMAND "${CLANG_TIDY_EXE}" "-checks=-*,modernize-*")

In the above, I disable all default checks (-*) and only enable checks that advocate the use of modern C++ language constructs (modernize-*).

For the second step, you tell CMake to use clang-tidy by setting the CXX_CLANG_TIDY property for your build target:

set_target_properties(target PROPERTIES CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND}")

That’s all! Run your build as usual and clang-tidy will report suggestions for modernization as warnings.

Here’s a fully self-contained CMakeLists.txt file for demonstration purposes:

cmake_minimum_required(VERSION 3.6)
project(clang-tidy-example)

# generate hello world file
file(
  GENERATE
  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/hello.cpp
  CONTENT
    "#include <iostream>\n int main(void) { std::cout << \"Hello World\" << std::endl; exit(0); }"
)

# search for clang-tidy
find_program(CLANG_TIDY_EXE NAMES "clang-tidy" REQUIRED)

# setup clang-tidy command from executable + options
set(CLANG_TIDY_COMMAND "${CLANG_TIDY_EXE}" "-checks=-*,modernize-*")

# add target using generated source file
add_executable(hello ${CMAKE_CURRENT_BINARY_DIR}/hello.cpp)

# set CXX_CLANG_TIDY property after defining the target
set_target_properties(hello PROPERTIES CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND}")

Run this with the usual cmake build steps:

mkdir build && cd build && cmake .. && make

And you’ll see something like this:

hello.cpp:2:6: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
 int main(void) { std::cout << "Hello World" << std::endl; exit(0); }
 ~~~ ^
 auto           -> int
hello.cpp:2:11: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
 int main(void) { std::cout << "Hello World" << std::endl; exit(0); }
          ^~~~

I’ll leave it up to you to decide whether the advice of clang-tidy makes sense in this particular case. ;-)

Hope this helps.