blob: 786df4e3d111bbb9eb442e90a8364b7e55a62963 [file] [log] [blame]
Soby Mathewb4c6df42022-11-09 11:13:29 +00001#
2# SPDX-License-Identifier: BSD-3-Clause
3# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4#
5
6#
7# This script is called from main CMakeLists.txt to determine if header files
8# included are in proper order
9#
10find_package(Git REQUIRED)
11find_package(Python3 REQUIRED)
12find_program(CHECKINCLUDES_EXECUTABLE "checkincludes.py"
13 PATHS ${CMAKE_SOURCE_DIR}
14 PATH_SUFFIXES tools/checkincludes
15 DOC "Path to checkincludes.py"
16 )
17
18list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/tools/common")
19include(GitUtils)
20
21# List of directories and files to exclude from checking for target
22list(APPEND glob_excludes "^.git")
23list(APPEND glob_excludes "^out")
24list(APPEND glob_excludes "^build")
25list(APPEND glob_excludes "^ext")
26list(APPEND glob_excludes "^tools")
27
28# checkincludes_get_stats: Parse and returns number of errors and warnings
29function(checkincludes_get_stats stats_arg errors_ret)
30 string(FIND "${stats_arg}" "total:" idx REVERSE)
31 if(NOT ${idx} EQUAL -1)
32 string(LENGTH "${stats_arg}" len)
33 string(SUBSTRING "${stats_arg}" ${idx} ${len} last_line)
34
35 string(REPLACE " " ";" last_line_list ${last_line})
36 list(GET last_line_list 1 errors)
37 else()
38 set(errors 1)
39 endif()
40
41 set(${errors_ret} ${errors} PARENT_SCOPE)
42endfunction()
43
44#
45# print_stats_and_exit: Print summary of all errors and warnings.
46# If there are errors call message(FATAL_ERROR)
47#
48function(print_stats_and_exit check_type total_errors)
49 message(STATUS "${check_type}: total errors: ${total_errors}")
50
51 if(${total_errors} GREATER 0)
52 message(FATAL_ERROR "${check_type}: FAILED")
53 endif()
54
55 message(STATUS "${check_type}: PASSED")
56endfunction()
57
58# filter all files except *.c/*.h/*.S files
59function(filter_source_files all_files source_files_ret)
60 foreach(exclude IN LISTS glob_excludes)
61 list(FILTER all_files EXCLUDE REGEX "${exclude}")
62 endforeach()
63
64 foreach(source_file ${all_files})
65 if(NOT source_file MATCHES ".c$" AND
66 NOT source_file MATCHES ".S$" AND
67 NOT source_file MATCHES ".h$")
68 list(REMOVE_ITEM all_files ${source_file})
69 endif()
70 endforeach()
71
72 set(${source_files_ret} ${all_files} PARENT_SCOPE)
73endfunction()
74
75# Run checkincludes.py on the list of files.
76function(run_checkincludes source_files errors_ret)
77 set(errors 0)
78
79 string(REPLACE ";" " " source_files "${source_files}")
80 separate_arguments(source_files NATIVE_COMMAND "${source_files}")
81
82 execute_process(
83 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
84 COMMAND ${CHECKINCLUDES_EXECUTABLE} ${source_files}
85 OUTPUT_VARIABLE checkincludes_output
86 RESULT_VARIABLE checkincludes_rc
87 ECHO_OUTPUT_VARIABLE
88 OUTPUT_STRIP_TRAILING_WHITESPACE
89 )
90
91 # checkincludes failed for this file. Collect no.of errors
92 if(${checkincludes_rc} GREATER 0)
93 checkincludes_get_stats("${checkincludes_output}" errors)
94 endif()
95
96 set(${errors_ret} ${errors} PARENT_SCOPE)
97endfunction()
98
99#
100# Run checkincludes on entire codebase. This verifies all files in this
101# repository in "GLOB_INCLUDES".
102#
103# Exits with FATAL_ERROR upon errors. Warnings are ignored (temporary)
104#
105if(CHECKINCLUDES_CODEBASE)
106 set(source_files "")
107
108 if (GIT_FOUND AND IS_DIRECTORY .git)
109 Git_Get_All_Files(all_files)
110 else()
111 file(GLOB_RECURSE all_files RELATIVE ${CMAKE_SOURCE_DIR} "*")
112 endif()
113
114 filter_source_files("${all_files}" source_files)
115
116 if(NOT source_files)
117 message(STATUS "checkincludes-codebase: No files to check")
118 return()
119 endif()
120
121 run_checkincludes("${source_files}" total_errors)
122 print_stats_and_exit("checkincludes-codebase" ${total_errors})
123endif()
124
125#
126# Check header files include order on pending commits.
127#
128# Exits with FATAL_ERROR upon errors.
129#
130if(CHECKINCLUDES_PATCH)
131 if(GIT_NOT_FOUND OR NOT IS_DIRECTORY .git)
132 message(FATAL_ERROR "Required dependencies Git not found")
133 endif()
134
135 # Get list of commits to check
136 Git_Get_Pending_Commits(pending_commits)
137
138 # Iterate throuth list of commit ids
139 set(total_errors 0)
140 foreach(commit IN LISTS pending_commits)
141 message(STATUS "Checking commit: ${commit}")
142
143 Git_Get_Files_In_Commit("${commit}" files_in_commit)
144
145 set(source_files "")
146 filter_source_files("${files_in_commit}" source_files)
147
148 run_checkincludes("${source_files}" errors)
149 MATH(EXPR total_errors "${total_errors}+${errors}")
150 endforeach()
151
152 print_stats_and_exit("checkincludes-patch" ${total_errors})
153endif()