Skip to content

Commit 1a73820

Browse files
authored
Merge pull request intel#93 from elbeno/use-target-sources
✨ Support `target_sources`/`FILE_SET`s with `clang_tidy_interface`
2 parents 167a66e + f38592d commit 1a73820

File tree

3 files changed

+89
-22
lines changed

3 files changed

+89
-22
lines changed

cmake/clang-tidy.cmake

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -61,34 +61,70 @@ function(clang_tidy_header HEADER TARGET)
6161
add_dependencies(clang-tidy "${CT_NAME}")
6262
endfunction()
6363

64-
function(clang_tidy_interface)
65-
if(${ARGC} EQUAL 1)
66-
set(CT_TARGET ${ARGV0})
67-
else()
68-
set(options "")
69-
set(oneValueArgs TARGET)
70-
set(multiValueArgs EXCLUDE_DIRS EXCLUDE_FILES)
71-
cmake_parse_arguments(CT "${options}" "${oneValueArgs}"
72-
"${multiValueArgs}" ${ARGN})
73-
endif()
74-
75-
get_target_property(DIRS ${CT_TARGET} INTERFACE_INCLUDE_DIRECTORIES)
76-
get_target_property(SYSTEM_DIRS ${CT_TARGET}
64+
function(clang_tidy_dirs TARGET EXCLUDE_DIRS EXCLUDE_FILES)
65+
get_target_property(DIRS ${TARGET} INTERFACE_INCLUDE_DIRECTORIES)
66+
get_target_property(SYSTEM_DIRS ${TARGET}
7767
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES)
7868
foreach(DIR ${DIRS})
7969
if(NOT DIR IN_LIST SYSTEM_DIRS)
8070
file(GLOB_RECURSE HEADERS "${DIR}/*.hpp")
8171
foreach(HEADER ${HEADERS})
8272
file(RELATIVE_PATH CT_NAME ${CMAKE_SOURCE_DIR} ${HEADER})
83-
if(NOT CT_NAME IN_LIST CT_EXCLUDE_FILES)
73+
if(NOT CT_NAME IN_LIST EXCLUDE_FILES)
74+
get_filename_component(HEADER_DIR ${CT_NAME} DIRECTORY)
75+
if(NOT HEADER_DIR IN_LIST EXCLUDE_DIRS)
76+
clang_tidy_header(${HEADER} ${TARGET})
77+
endif()
78+
endif()
79+
endforeach()
80+
endif()
81+
endforeach()
82+
endfunction()
83+
84+
function(clang_tidy_header_sets TARGET EXCLUDE_DIRS EXCLUDE_FILES
85+
EXCLUDE_FILESETS)
86+
get_target_property(HEADER_SETS ${TARGET} INTERFACE_HEADER_SETS)
87+
foreach(SET ${HEADER_SETS})
88+
if(NOT SET IN_LIST EXCLUDE_FILESETS)
89+
get_target_property(HEADERS ${TARGET} HEADER_SET_${SET})
90+
foreach(HEADER ${HEADERS})
91+
file(RELATIVE_PATH CT_NAME ${CMAKE_SOURCE_DIR} ${HEADER})
92+
if(NOT CT_NAME IN_LIST EXCLUDE_FILES)
8493
get_filename_component(HEADER_DIR ${CT_NAME} DIRECTORY)
85-
if(NOT HEADER_DIR IN_LIST CT_EXCLUDE_DIRS)
86-
clang_tidy_header(${HEADER} ${CT_TARGET})
94+
if(NOT HEADER_DIR IN_LIST EXCLUDE_DIRS)
95+
clang_tidy_header(${HEADER} ${TARGET})
8796
endif()
8897
endif()
8998
endforeach()
9099
endif()
91100
endforeach()
101+
endfunction()
102+
103+
function(clang_tidy_interface)
104+
if(${ARGC} EQUAL 1)
105+
set(CT_TARGET ${ARGV0})
106+
else()
107+
set(options "")
108+
set(oneValueArgs TARGET)
109+
set(multiValueArgs EXCLUDE_DIRS EXCLUDE_FILES EXCLUDE_FILESETS)
110+
cmake_parse_arguments(CT "${options}" "${oneValueArgs}"
111+
"${multiValueArgs}" ${ARGN})
112+
endif()
113+
114+
get_target_property(HEADER_SETS ${CT_TARGET} INTERFACE_HEADER_SETS)
115+
if(HEADER_SETS)
116+
message(
117+
STATUS "Using INTERFACE_HEADER_SETS to clang-tidy ${CT_TARGET}.")
118+
clang_tidy_header_sets(${CT_TARGET} "${CT_EXCLUDE_DIRS}"
119+
"${CT_EXCLUDE_FILES}" "${CT_EXCLUDE_FILESETS}")
120+
else()
121+
message(
122+
NOTICE
123+
"${CT_TARGET} has no INTERFACE_HEADER_SETS, using INTERFACE_INCLUDE_DIRECTORIES instead. "
124+
"Use `target_sources` instead of `target_include_directories` to specify header sets for better control."
125+
)
126+
clang_tidy_dirs(${CT_TARGET} "${CT_EXCLUDE_DIRS}" "${CT_EXCLUDE_FILES}")
127+
endif()
92128

93129
compute_branch_diff(clang-tidy ".hpp")
94130
endfunction()

docs/quality.adoc

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,16 @@ Each such generated target is then rolled up into a single `clang-tidy` target.
8787
The upshot of this is that each header is linted correctly. It also has the side
8888
effect of checking that each header can be included on its own.
8989

90-
NOTE: Because constructing the clang-tidy targets globs the headers, an added
91-
file won't be included until CMake is re-run.
90+
The way that `clang_tidy_interface` works depends on the target properties. If
91+
https://cmake.org/cmake/help/latest/command/target_sources.html[`target_sources`]
92+
is used with
93+
https://cmake.org/cmake/help/latest/command/target_sources.html#file-sets[`FILE_SET`],
94+
`clang_tidy_interface` finds the headers using that method. Otherwise -- when
95+
https://cmake.org/cmake/help/latest/command/target_include_directories.html[`target_include_directories`]
96+
is used -- `clang_tidy_interface` globs the headers in the include directories.
97+
98+
NOTE: If `target_include_directories` is used to specify a target's headers,
99+
adding a header file won't clang-tidy it until CMake is re-run.
92100

93101
You can still take advantage of `clang_tidy_interface` even if not all your code
94102
is linting cleanly, by providing exclusions:
@@ -98,9 +106,13 @@ is linting cleanly, by providing exclusions:
98106
clang_tidy_interface(
99107
TARGET my_target
100108
EXCLUDE_DIRS mylib/A mylib/B
101-
EXCLUDE_FILES mylib/file.hpp)
109+
EXCLUDE_FILES mylib/file.hpp
110+
EXCLUDE_FILESETS exclusions)
102111
----
103112

113+
In particular the `EXCLUDE_FILESETS` argument can be used together with
114+
`target_sources`, separating excluded headers into a separate `FILE_SET`.
115+
104116
NOTE: `clang-tidy` is only a useful target when building with a clang toolchain.
105117
If you are not building with clang, the `clang-tidy` target will do nothing.
106118

test/library/CMakeLists.txt

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,29 @@ cpmaddpackage(NAME infra SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../.." GIT_TAG
77

88
add_library(test_lib INTERFACE)
99
target_compile_features(test_lib INTERFACE cxx_std_20)
10-
target_include_directories(test_lib INTERFACE include)
10+
target_sources(
11+
test_lib
12+
INTERFACE FILE_SET
13+
test_lib
14+
TYPE
15+
HEADERS
16+
BASE_DIRS
17+
include
18+
FILES
19+
include/test_lib/test.hpp)
20+
target_sources(
21+
test_lib
22+
INTERFACE FILE_SET
23+
exclusions
24+
TYPE
25+
HEADERS
26+
BASE_DIRS
27+
include
28+
FILES
29+
include/test_lib/exclude.hpp
30+
include/exclude/bad.hpp)
1131

1232
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
1333
add_docs(docs)
14-
clang_tidy_interface(TARGET test_lib EXCLUDE_DIRS include/exclude
15-
EXCLUDE_FILES include/test_lib/exclude.hpp)
34+
clang_tidy_interface(TARGET test_lib EXCLUDE_FILESETS exclusions)
1635
endif()

0 commit comments

Comments
 (0)