Excluding FetchContent Sources from Clang-Tidy in CMake
Navigating the complexities of modern C++ project configurations can often feel like treading through a maze. One such complexity arises when integrating tools like Clang-Tidy into a project managed with CMake, particularly when combined with the FetchContent module. Today, let me walk you through a promising approach to ensure Clang-Tidy checks only your project’s source files, excluding any third-party libraries fetched via FetchContent.
Understanding the Setup
CMake’s FetchContent module is fantastic for handling dependencies, as it allows one to automatically download, build, and include external projects into your build process. The challenge arises when these fetched content sources are subjected to tools like Clang-Tidy, a linter and static analysis tool, which we might prefer only to apply to our own project’s sources.
Consider the simplified CMake snippet where we set up a custom target for running Clang-Tidy:
if(PROJECT_IS_TOP_LEVEL) set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) find_program(CLANG_TIDY_EXECUTABLE clang-tidy REQUIRED) find_program(RUN_CLANG_TIDY_EXECUTABLE run-clang-tidy REQUIRED) add_custom_target(run-clang-tidy COMMAND ${RUN_CLANG_TIDY_EXECUTABLE} -clang-tidy-binary ${CLANG_TIDY_EXECUTABLE} -p ${CMAKE_BINARY_DIR} ) endif()
In this configuration, run-clang-tidy
is expected to run Clang-Tidy across the whole project. However, it also includes any code pulled in via FetchContent, which might not be desirable.
The Attempt with SYSTEM property and Header Filters
One common suggestion is to utilize CMake 3.25’s SYSTEM
property on the include directories of the fetched content or filtering headers using Clang-Tidy’s -header-filter
option. However, these might not work effectively, depending on how the external libraries are structured or integrated into your build system. Specifically, if external headers aren’t clearly delineated or respect the SYSTEM
property, Clang-Tidy might still process them.
A Different Approach: Explicitly Specifying Source Files
A potentially more robust solution involves being explicit about which files Clang-Tidy should analyze. Here’s how we can adjust our approach:
- Identify Your Project’s Source Files: Instead of letting Clang-Tidy indiscriminately scan everything in the build directory, explicitly list your project’s source directories. This ensures only your files are checked.
- Modify
run-clang-tidy
Custom Target: Instead of a general blanket execution, we can adapt therun-clang-tidy
script or command invocation to include only specific source files or directories.
Here’s an adjusted version of the CMake:
if(PROJECT_IS_TOP_LEVEL) set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) find_program(CLANG_TIDY_EXECUTABLE clang-tidy REQUIRED) file(GLOB_RECURSE MY_PROJECT_SOURCES src/*.cpp) # Adjust the path as necessary add_custom_target(run-clang-tidy COMMAND ${CLANG_TIDY_EXECUTABLE} ${MY_PROJECT_SOURCES} -p ${CMAKE_BINARY_DIR} ) endif()
In this adjusted script, file(GLOB_RECURSE ...)
is utilized to selectively gather all C++ source files from specific directories (e.g., where your project’s code lives like src/
). Consequently, when the run-clang-tidy
target is invoked, it only processes files explicitly listed in ${MY_PROJECT_SOURCES}
.
Benefits of This Approach
This method does not rely on implicit behavior or properties that the external projects might not adhere to, offering clearer and more controlled behavior.
By explicitly specifying which files to check, there’s no ambiguity or misinterpretation in what gets analyzed by Clang-Tidy, ultimately providing a cleaner, more predictable static analysis routine in CMake-managed projects that leverage FetchContent for dependencies.
Leave a Reply