7

I am working on a header only library and would like to use clang-tidy to make sure I am following the "C++ Core Guidelines" https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines

No matter what I try I can't seem to get clang-tidy to work on a header only library (probably because nothing is really compiled until the library is used)... But there has to be some workaround to make this work correctly. Surely someone else has written a header only library that they wanted to use clang-tidy on.

To try and simplify the issue I made a small test project to try and get it to work. This project is just two files. A CMakeLists.txt file and a header file.

CMakeLists.txt:

cmake_minimum_required(VERSION 3.11.4)

project(my_project LANGUAGES CXX)

# This does not seem to work at all for header only libraries
# I even tried messing with the "-header-filter" parameter and had no luck
set(CMAKE_CXX_CLANG_TIDY clang-tidy;-checks=-*,cppcoreguidelines-*)

add_library(my_project INTERFACE)

target_include_directories(my_project
  INTERFACE
    $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
)

include/my_project.hpp:

#include <iostream>

// I know it is bad to do this in a header file.
// This is intentional to give clang-tidy something to catch
using namespace std;

template <int N>
void print()
{
    for (int i = 0; i < N; ++i)
    {
        cout << "Hello, world!" << endl;
    }
}

When I run CMake with:

mkdir build
cd build
cmake ..
cmake --build .

I get no output from clang-tidy. How can I make clang-tidy parse header only libraries and report potential issues?

tjwrona1992
  • 8,614
  • 8
  • 35
  • 98
  • Surely you're writing tests for your library, and these tests are source files? Run clang-tidy on those! – rubenvb Dec 20 '20 at 22:17
  • I have tried that, and it does work on those .cpp files, but none of the headers get picked up. I tried multiple different values for "--header-filter" and nothing seemed to work. (They are all in an "include/" folder.) The other issue is that all of the test files use Catch2 and have lots of macros that set off all kinds of clang-tidy warnings. Ideally I'd like to ignore anything Catch2 related as well. (Or just ignore the test files while still processing the headers) – tjwrona1992 Dec 20 '20 at 22:32

2 Answers2

6

By default, clang-tidy will not check your header files. Thus, it is necessary to use -header-filter=.*, in order to specify the root path for header files.

Not verbose clang-tidy output does not mean it is not executing. That configuration is missing -header-filter=.*, but even with that flag, when you execute cmake --build ., it does not output anything. However, if you look for that command in the build path with grep (for instance), you should get something like:

❯ grep -nrw '.' -e "clang-tidy"
./CMakeFiles/my_project.dir/build.make:63:  $(CMAKE_COMMAND) -E __run_co_compile --tidy="clang-tidy;-checks=-*,cppcoreguidelines-*;-header-filter=.*" --source=/home/markoshorro/tmp/tidy/my_project.cpp -- /usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/my_project.dir/my_project.cpp.o -c /home/markoshorro/tmp/tidy/my_project.cpp

Which means that the clang-tidy command is considered. Actually, with your example:

❯ clang-tidy my_project.hpp
❯

I.e., I get nothing. Take a look at this example (even though your example seems fine to me); just clang-tidy has nothing to report.

horro
  • 1,262
  • 3
  • 20
  • 37
  • 1
    Hmm I assumed using a namespace in a header would definitely be picked up as an issue haha, I will take a look at your example and play around with it on Windows to see if it works for me. – tjwrona1992 Dec 21 '20 at 19:12
  • Oddly if I compile this within the Visual Studio IDE it does show warnings with clang-tidy output, but if I compile it from the command line I get nothing. – tjwrona1992 Dec 22 '20 at 16:12
  • Anyway, this is the real project I am trying to get this to work on: https://github.com/tnt-coders/cpp-dsp/tree/clang-tidy I am using Visual Studio 2019 Preview as an IDE to compile it and it generates warnings for all of the test ".cpp" files only but none of the headers no matter what I put for the "-header-filter". Ultimately I want it to ignore any "Catch2" related warnings and show everything else but I can't seem to find a good way to even get it to recognize my headers let alone ignore specific warnings for specific files. – tjwrona1992 Dec 22 '20 at 18:24
  • 1
    Actually, switching "-header-filter" to just "include" seemed to pick up everything! ...There's still the issue of all of the Catch2 macros causing a large number of warnings that I would like to suppress though since it is not my own code. – tjwrona1992 Dec 22 '20 at 18:51
  • For that you could use `-exclude-header-filter=...`, for instance. Another workaround would be to `set(CMAKE_CXX_CLANG_TIDY "")` before `find_package` and enable it again after. – horro Dec 23 '20 at 09:21
  • Thanks for the advice! Ideally I would like to just be able to set "-header-filter" to something like `include/tnt/dsp` that way it only picks up files in that specific include folder, but the second I add a `/` it then fails to find ALL of the headers... (I also tried escaping the slash with a backslash, and using backslashes, and using escaped backslashes, etc... lol). That doesn't seem right though because other examples I've seen are able to provide paths with slashes for the header filter and they apparently work fine. – tjwrona1992 Dec 23 '20 at 17:15
  • 1
    I am awarding the bounty to you because this answer has helped me the most, although I am still running into some problems. At this point it may be time to just reach out to the LLVM dev email list. – tjwrona1992 Dec 27 '20 at 23:23
0

The following command worked for me:

find . -type f \( -name "*.hpp" -o -name "*.cpp" \) \
   -exec clang-tidy -p . \
   --header-filter="/home/user/clang-tidy-include-headers/header.hpp" {} \;

It looks for header and CPP files, passes them to clang-tidy. The parameter --header-filter= accepts a regex for header file paths.

In your case it will be:

find . -type f \( -name "*.hpp" -o -name "*.cpp" \) \
   -exec clang-tidy -p . \
   --header-filter="include/" {} \;
fsquirrel
  • 800
  • 8
  • 18
  • This doesn't seem to work for me. I think it is because I am building on Windows. I tried running clang-tidy with those options and explicitly stating the files to run it on (since the find command doesn't work the same on Windows) and I get an error "Error while trying to load a compilation database"... Looking at the CMake documentation I can export a compilation database json file using `-DCMAKE_EXPORT_COMPILE_COMMANDS` but that doesn't seem to work with the Visual Studio generator for CMake. – tjwrona1992 Dec 20 '20 at 22:28
  • @tjwrona1992, I have never tried to run clang on Windows. However, I am sure there is a Visual Studio extension generating the compilation database(in the end it is just a JSON file with compilation flags for each compilation unit). Regarding the bash script, AFAIK new versions of Windows support bash and other Linux tools. – fsquirrel Dec 21 '20 at 10:02