1# 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 code complies 8# to coding standards as mentioned in docs/getting_started/coding-standard.rst 9# 10# Runs checkpatch.pl on entire codebase if variable CHECKCODEBASE_RUN is defined. 11# 12# Runs checkpatch.pl on new commits if variable CHECKCODEBASE_RUN is defined. 13# 14find_package(Git REQUIRED) 15find_package(Perl REQUIRED) 16find_program(CHECKPATCH_EXECUTABLE "checkpatch.pl" 17 PATHS ${CMAKE_SOURCE_DIR} 18 PATH_SUFFIXES tools/checkpatch 19 DOC "Path to checkpatch.pl" 20 ) 21 22list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/tools/common") 23include(GitUtils) 24 25# 26# List of directories and files to exclude from checking for target checkcodebase 27# 28list(APPEND glob_excludes "^.git") 29list(APPEND glob_excludes "^out") 30list(APPEND glob_excludes "^build") 31list(APPEND glob_excludes "^ext") 32list(APPEND glob_excludes "^tools") 33list(APPEND glob_excludes ".patch$") 34list(APPEND glob_excludes ".md$") 35list(APPEND glob_excludes "~$") 36list(APPEND glob_excludes ".swp$") 37list(APPEND glob_excludes "^cscope.") 38 39set(total_errors "0") 40set(total_warnings "0") 41 42# Check if pre-reqs met 43if(PERL_NOT_FOUND OR NOT EXISTS ${CHECKPATCH_EXECUTABLE}) 44 message(FATAL_ERROR "required dependencies not found") 45endif() 46 47# 48# checkpatch_get_stats: Parse and returns number of errors and warnings 49# 50function(checkpatch_get_stats stats_arg errors_ret warnings_ret) 51 string(FIND "${stats_arg}" "total:" idx REVERSE) 52 string(LENGTH "${stats_arg}" len) 53 string(SUBSTRING "${stats_arg}" ${idx} ${len} last_line) 54 55 string(REPLACE " " ";" last_line_list ${last_line}) 56 list(GET last_line_list 1 errors) 57 list(GET last_line_list 3 warnings) 58 59 set(${errors_ret} ${errors} PARENT_SCOPE) 60 set(${warnings_ret} ${warnings} PARENT_SCOPE) 61endfunction() 62 63# 64# print_stats_and_exit: Print summary of all errors and warnings. 65# If there are errors call message(FATAL_ERROR) 66# 67function(print_stats_and_exit check_type total_errors total_warnings) 68 message(STATUS "${check_type}: total errors: ${total_errors} " 69 "warnings: ${total_warnings}") 70 71 if(${total_errors} GREATER 0) 72 message(FATAL_ERROR "${check_type}: FAILED") 73 endif() 74 75 message(STATUS "${check_type}: PASSED") 76endfunction() 77 78# 79# Run checkpatch on entire codebase. This verifies all files in this repository 80# except the files listed in "glob_excludes". 81# 82# Exits with FATAL_ERROR upon errors. Warnings are ignored (temporary) 83# 84if(CHECKCODEBASE_RUN) 85 set(source_files "") 86 87 if (GIT_FOUND AND IS_DIRECTORY .git) 88 Git_Get_All_Files(source_files) 89 else() 90 file(GLOB_RECURSE source_files RELATIVE ${CMAKE_SOURCE_DIR} "*") 91 endif() 92 93 # Filter out 'glob_excludes' 94 foreach(exclude IN LISTS glob_excludes) 95 list(FILTER source_files EXCLUDE REGEX "${exclude}") 96 endforeach() 97 98 if(NOT source_files) 99 message(STATUS "checkcodebase: No files to check") 100 return() 101 endif() 102 103 foreach(source_file ${source_files}) 104 execute_process( 105 COMMAND ${CMAKE_COMMAND} -E echo "Checking file ${source_file}" 106 ) 107 108 execute_process( 109 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 110 COMMAND ${CHECKPATCH_EXECUTABLE} -f ${source_file} 111 OUTPUT_VARIABLE checkpatch_output 112 RESULT_VARIABLE checkpatch_rc 113 ECHO_OUTPUT_VARIABLE 114 OUTPUT_STRIP_TRAILING_WHITESPACE 115 ) 116 117 # checkpatch.pl failed for this file. Collect no.of errors and warnings 118 if(${checkpatch_rc}) 119 checkpatch_get_stats("${checkpatch_output}" errors warnings) 120 MATH(EXPR total_errors "${total_errors}+${errors}") 121 MATH(EXPR total_warnings "${total_warnings}+${warnings}") 122 endif() 123 endforeach() 124 125 print_stats_and_exit("checkcodebase" ${total_errors}, ${total_warnings}) 126endif() 127 128# 129# Run checkpatch on pending commits. 130# 131# Exits with FATAL_ERROR upon errors. 132# 133if(CHECKPATCH_RUN) 134 if(GIT_NOT_FOUND OR NOT IS_DIRECTORY .git) 135 message(FATAL_ERROR "Required dependencies Git not found") 136 endif() 137 138 # Get list of commits to check 139 Git_Get_Pending_Commits(pending_commits) 140 141 foreach(commit IN LISTS pending_commits) 142 message(STATUS "Checking commit: ${commit}") 143 144 execute_process( 145 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 146 COMMAND ${GIT_EXECUTABLE} diff --format=email "${commit}~..${commit}" 147 COMMAND ${CHECKPATCH_EXECUTABLE} - 148 OUTPUT_VARIABLE checkpatch_output 149 RESULT_VARIABLE checkpatch_rc 150 ECHO_OUTPUT_VARIABLE 151 ) 152 153 # checkpatch.pl failed for this commit. Collect no.of errors and warnings 154 if(${checkpatch_rc}) 155 checkpatch_get_stats("${checkpatch_output}" errors warnings) 156 MATH(EXPR total_errors "${total_errors}+${errors}") 157 MATH(EXPR total_warnings "${total_warnings}+${warnings}") 158 endif() 159 endforeach() 160 161 print_stats_and_exit("checkpatch" ${total_errors}, ${total_warnings}) 162endif() 163