Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clang-tidy parsing external header includes (in cmake project)

Tags:

c++

cmake

Context

Full project source

I'm trying to setup a CMake project with clang-tidy. However, when transitively analyzing my includes it seems to go into external header files. For example:

  • CMakeLists.txt (root-level)
# ...
find_program(CLANG_TIDY_EXE NAMES "clang-tidy")
if(CLANG_TIDY_EXE)
    message(STATUS "Found clang-tidy: ${CLANG_TIDY_EXE}")
else()
    message(FATAL_ERROR "clang-tidy not found!")
endif()

function(enable_clang_tidy target)
    set_target_properties(${target} PROPERTIES
        CXX_CLANG_TIDY "${CLANG_TIDY_EXE};--quiet"
    )
endfunction()
# ...
  • src/CMakeLists.txt
find_path(TCLAP_INCLUDE_DIR tclap/CmdLine.h
    HINTS /opt/homebrew/include /usr/local/include /usr/include
)

if(NOT TCLAP_INCLUDE_DIR)
    message(FATAL_ERROR "TCLAP not found. Please install it with `brew install tclap`.")
endif()

add_executable(ccwc main.cpp)
target_include_directories(ccwc SYSTEM PRIVATE ${TCLAP_INCLUDE_DIR})
target_link_libraries(ccwc)
enable_clang_tidy(ccwc)

Error

/opt/homebrew/include/tclap/Arg.h:473:53: error: Call to virtual method 'Arg::toString' during construction bypasses virtual dispatch [clang-analyzer-optin.cplusplus.VirtualCall,-warnings-as-errors]
  473 |                                 "Argument flag can only be one character long", toString() ) );

Workaround

With the above I currently use the line:

#include <tclap/CmdLine.h>

TCLAP::CmdLine myCmd("Count bytes in file", ' ', "0.1");  // NOLINT

Other things I tried

  • Using cmake_cxx_clang_tidy: This goes worse as it begins analyzing the gtest source as well.

  • Using targets instead of directly linking the library:

find_path(TCLAP_INCLUDE_DIR tclap/CmdLine.h
    HINTS /opt/homebrew/include /usr/local/include /usr/include
)

add_library(tclap INTERFACE)
target_include_directories(tclap INTERFACE ${TCLAP_INCLUDE_DIR})

add_executable(ccwc main.cpp)
target_link_libraries(ccwc PRIVATE tclap)

Question

  • How can I fix my configuration so this works without the NOLINT?
  • How can I use cmake_cxx_clang_tidy, which is expected to be a standard way to configure following best practices?
like image 982
tangy Avatar asked Nov 30 '25 10:11

tangy


1 Answers

Starting with Clang-Tidy version 19, there's a new option:

--exclude-header-filter

This flag allows you to specify a regular expression to exclude header files from static analysis. You can integrate it into your CMake setup like this to skip checks on headers from specific directories:

set_target_properties(${target} PROPERTIES CXX_CLANG_TIDY 
                      "${CLANG_TIDY_EXE};--quiet;--exclude-header-filter=${HEADERS_TO_EXCLUDE}")

To make this work, define a CMake variable like HEADERS_TO_EXCLUDE containing a regex pattern that matches the paths of the header files or directories you want to ignore. (Or, you can simply list them directly in a CMake variable — which, in my experience, is often much simpler than trying to craft the perfect regex.)

For example:

set(HEADERS_TO_EXCLUDE ".*third_party/.*")

This tells Clang-Tidy to skip analysis on any headers under the third_party/ directory.

like image 171
Matin Kourepaz Avatar answered Dec 02 '25 22:12

Matin Kourepaz