1# SPDX-License-Identifier: Apache-2.0 2# 3# Copyright (c) 2023, Basalte bv 4 5include(boards) 6include(git) 7include(extensions) 8include(west) 9 10find_program(CODECHECKER_EXE NAMES CodeChecker codechecker REQUIRED) 11message(STATUS "Found SCA: CodeChecker (${CODECHECKER_EXE})") 12 13# Get CodeChecker specific variables 14zephyr_get(CODECHECKER_ANALYZE_JOBS) 15zephyr_get(CODECHECKER_ANALYZE_OPTS) 16zephyr_get(CODECHECKER_CLEANUP) 17zephyr_get(CODECHECKER_CONFIG_FILE) 18zephyr_get(CODECHECKER_EXPORT) 19zephyr_get(CODECHECKER_NAME) 20zephyr_get(CODECHECKER_PARSE_EXIT_STATUS) 21zephyr_get(CODECHECKER_PARSE_OPTS) 22zephyr_get(CODECHECKER_PARSE_SKIP) 23zephyr_get(CODECHECKER_STORE) 24zephyr_get(CODECHECKER_STORE_OPTS) 25zephyr_get(CODECHECKER_STORE_TAG) 26zephyr_get(CODECHECKER_TRIM_PATH_PREFIX MERGE VAR CODECHECKER_TRIM_PATH_PREFIX WEST_TOPDIR) 27 28# Get twister runner specific variables 29zephyr_get(TC_RUNID) 30zephyr_get(TC_NAME) 31 32if(NOT CODECHECKER_NAME) 33 if(TC_NAME) 34 set(CODECHECKER_NAME "${BOARD}${BOARD_QUALIFIERS}:${TC_NAME}") 35 else() 36 set(CODECHECKER_NAME zephyr) 37 endif() 38endif() 39 40if(CODECHECKER_ANALYZE_JOBS) 41 set(CODECHECKER_ANALYZE_JOBS "--jobs;${CODECHECKER_ANALYZE_JOBS}") 42elseif(TC_RUNID) 43 set(CODECHECKER_ANALYZE_JOBS "--jobs;1") 44endif() 45 46if(CODECHECKER_CONFIG_FILE) 47 set(CODECHECKER_CONFIG_FILE "--config;${CODECHECKER_CONFIG_FILE}") 48endif() 49 50if(CODECHECKER_STORE_TAG) 51 set(CODECHECKER_STORE_TAG "--tag;${CODECHECKER_STORE_TAG}") 52else() 53 git_describe(${APPLICATION_SOURCE_DIR} app_version) 54 if(app_version) 55 set(CODECHECKER_STORE_TAG "--tag;${app_version}") 56 endif() 57endif() 58 59if(CODECHECKER_TRIM_PATH_PREFIX) 60 set(CODECHECKER_TRIM_PATH_PREFIX "--trim-path-prefix;${CODECHECKER_TRIM_PATH_PREFIX}") 61endif() 62 63# CodeChecker uses the compile_commands.json as input 64set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 65 66# Create an output directory for our tool 67set(output_dir ${CMAKE_BINARY_DIR}/sca/codechecker) 68file(MAKE_DIRECTORY ${output_dir}) 69 70# Use a dummy file to let CodeChecker know we can start analyzing 71set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND 72 ${CMAKE_COMMAND} -E touch ${output_dir}/codechecker.ready) 73set_property(GLOBAL APPEND PROPERTY extra_post_build_byproducts 74 ${output_dir}/codechecker.ready) 75 76add_custom_target(codechecker ALL 77 COMMAND ${CODECHECKER_EXE} analyze 78 --keep-gcc-include-fixed 79 --keep-gcc-intrin 80 --output ${output_dir}/codechecker.plist 81 --name ${CODECHECKER_NAME} # Set a default metadata name 82 ${CODECHECKER_CONFIG_FILE} 83 ${CODECHECKER_ANALYZE_JOBS} 84 ${CODECHECKER_ANALYZE_OPTS} 85 ${CMAKE_BINARY_DIR}/compile_commands.json 86 || ${CMAKE_COMMAND} -E true # allow to continue processing results 87 DEPENDS ${CMAKE_BINARY_DIR}/compile_commands.json ${output_dir}/codechecker.ready 88 VERBATIM 89 USES_TERMINAL 90 COMMAND_EXPAND_LISTS 91) 92 93# Cleanup dummy file 94add_custom_command( 95 TARGET codechecker POST_BUILD 96 COMMAND ${CMAKE_COMMAND} -E rm ${output_dir}/codechecker.ready 97) 98 99if(CODECHECKER_CLEANUP) 100 add_custom_target(codechecker-cleanup ALL 101 COMMAND ${CMAKE_COMMAND} -E rm -r ${output_dir}/codechecker.plist 102 ) 103else() 104 add_custom_target(codechecker-cleanup) 105endif() 106 107add_dependencies(codechecker-cleanup codechecker) 108 109# If 'codechecker parse' returns an exit status of '2', it means more than 0 110# issues were detected. Suppress the exit status by default, but permit opting 111# in to the failure. 112set(CODECHECKER_PARSE_OPTS ${CODECHECKER_PARSE_OPTS} || ${CMAKE_COMMAND} -E touch ${output_dir}/codechecker.failed) 113if(CODECHECKER_PARSE_EXIT_STATUS) 114 add_custom_target(codechecker-parse-check ALL 115 COMMAND ! ${CMAKE_COMMAND} -E rm ${output_dir}/codechecker.failed 2>/dev/null 116 ) 117else() 118 add_custom_target(codechecker-parse-check ALL 119 COMMAND ${CMAKE_COMMAND} -E rm -f ${output_dir}/codechecker.failed 2>/dev/null 120 ) 121endif() 122add_dependencies(codechecker-cleanup codechecker-parse-check) 123 124if(DEFINED CODECHECKER_EXPORT) 125 string(REPLACE "," ";" export_list ${CODECHECKER_EXPORT}) 126 127 foreach(export_item IN LISTS export_list) 128 message(STATUS "CodeChecker export: ${CMAKE_BINARY_DIR}/codechecker.${export_item}") 129 130 add_custom_target(codechecker-report-${export_item} ALL 131 COMMAND ${CODECHECKER_EXE} parse 132 ${output_dir}/codechecker.plist 133 --export ${export_item} 134 --output ${output_dir}/codechecker.${export_item} 135 ${CODECHECKER_CONFIG_FILE} 136 ${CODECHECKER_TRIM_PATH_PREFIX} 137 ${CODECHECKER_PARSE_OPTS} 138 BYPRODUCTS ${output_dir}/codechecker.${export_item} 139 VERBATIM 140 USES_TERMINAL 141 COMMAND_EXPAND_LISTS 142 ) 143 add_dependencies(codechecker-report-${export_item} codechecker) 144 add_dependencies(codechecker-parse-check codechecker-report-${export_item}) 145 endforeach() 146endif() 147 148if(NOT CODECHECKER_PARSE_SKIP) 149 # Output parse results 150 add_custom_target(codechecker-parse ALL 151 COMMAND ${CODECHECKER_EXE} parse 152 ${output_dir}/codechecker.plist 153 ${CODECHECKER_CONFIG_FILE} 154 ${CODECHECKER_TRIM_PATH_PREFIX} 155 ${CODECHECKER_PARSE_OPTS} 156 VERBATIM 157 USES_TERMINAL 158 COMMAND_EXPAND_LISTS 159 ) 160 add_dependencies(codechecker-parse codechecker) 161 add_dependencies(codechecker-parse-check codechecker-parse) 162endif() 163 164if(DEFINED CODECHECKER_STORE OR DEFINED CODECHECKER_STORE_OPTS) 165 add_custom_target(codechecker-store ALL 166 COMMAND ${CODECHECKER_EXE} store 167 ${CODECHECKER_CONFIG_FILE} 168 ${CODECHECKER_STORE_TAG} 169 ${CODECHECKER_TRIM_PATH_PREFIX} 170 ${CODECHECKER_STORE_OPTS} 171 ${output_dir}/codechecker.plist 172 VERBATIM 173 USES_TERMINAL 174 COMMAND_EXPAND_LISTS 175 ) 176 add_dependencies(codechecker-store codechecker) 177 add_dependencies(codechecker-cleanup codechecker-store) 178endif() 179