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. 112if(NOT CODECHECKER_PARSE_EXIT_STATUS) 113 set(CODECHECKER_PARSE_OPTS ${CODECHECKER_PARSE_OPTS} || ${CMAKE_COMMAND} -E true) 114endif() 115 116if(DEFINED CODECHECKER_EXPORT) 117 string(REPLACE "," ";" export_list ${CODECHECKER_EXPORT}) 118 119 foreach(export_item IN LISTS export_list) 120 message(STATUS "CodeChecker export: ${CMAKE_BINARY_DIR}/codechecker.${export_item}") 121 122 add_custom_target(codechecker-report-${export_item} ALL 123 COMMAND ${CODECHECKER_EXE} parse 124 ${output_dir}/codechecker.plist 125 --export ${export_item} 126 --output ${output_dir}/codechecker.${export_item} 127 ${CODECHECKER_CONFIG_FILE} 128 ${CODECHECKER_TRIM_PATH_PREFIX} 129 ${CODECHECKER_PARSE_OPTS} 130 BYPRODUCTS ${output_dir}/codechecker.${export_item} 131 VERBATIM 132 USES_TERMINAL 133 COMMAND_EXPAND_LISTS 134 ) 135 add_dependencies(codechecker-report-${export_item} codechecker) 136 add_dependencies(codechecker-cleanup codechecker-report-${export_item}) 137 endforeach() 138elseif(NOT CODECHECKER_PARSE_SKIP) 139 # Output parse results 140 add_custom_target(codechecker-parse ALL 141 COMMAND ${CODECHECKER_EXE} parse 142 ${output_dir}/codechecker.plist 143 ${CODECHECKER_CONFIG_FILE} 144 ${CODECHECKER_TRIM_PATH_PREFIX} 145 ${CODECHECKER_PARSE_OPTS} 146 VERBATIM 147 USES_TERMINAL 148 COMMAND_EXPAND_LISTS 149 ) 150 add_dependencies(codechecker-parse codechecker) 151 add_dependencies(codechecker-cleanup codechecker-parse) 152endif() 153 154if(DEFINED CODECHECKER_STORE OR DEFINED CODECHECKER_STORE_OPTS) 155 add_custom_target(codechecker-store ALL 156 COMMAND ${CODECHECKER_EXE} store 157 ${CODECHECKER_CONFIG_FILE} 158 ${CODECHECKER_STORE_TAG} 159 ${CODECHECKER_TRIM_PATH_PREFIX} 160 ${CODECHECKER_STORE_OPTS} 161 ${output_dir}/codechecker.plist 162 VERBATIM 163 USES_TERMINAL 164 COMMAND_EXPAND_LISTS 165 ) 166 add_dependencies(codechecker-store codechecker) 167 add_dependencies(codechecker-cleanup codechecker-store) 168endif() 169