1#!/usr/bin/env bash 2 3set -e 4 5function help() { 6 cat <<EOF 7Usage: ${0} [OPTION] ... -- <compiler arguments> 8 9This script is a wrapper for cppcheck that enables it to analyse the files that 10are the target for the build, it is used in place of a selected compiler and the 11make process will run it on every file that needs to be built. 12All the arguments passed to the original compiler are forwarded to it without 13modification, furthermore, they are used to improve the cppcheck analysis. 14 15Options: 16 --compiler= Use this compiler for the build 17 --cppcheck-cmd= Command line for the cppcheck analysis. 18 --cppcheck-html Prepare for cppcheck HTML output 19 --cppcheck-plat= Path to the cppcheck platform folder 20 --ignore-path= This script won't run cppcheck on the files having this 21 path, the compiler will run anyway on them. This argument 22 can be specified multiple times. 23 -h, --help Print this help 24EOF 25} 26 27BUILD_DIR="" 28CC_FILE="" 29COMPILER="" 30CPPCHECK_HTML="n" 31CPPCHECK_PLAT_PATH="" 32CPPCHECK_TOOL="" 33CPPCHECK_TOOL_ARGS="" 34FORWARD_FLAGS="" 35IGNORE_PATH="n" 36IGNORE_PATH_LIST="" 37JDB_FILE="" 38OBJTREE_PATH="" 39 40# Variable used for arg parsing 41forward_to_cc="n" 42sm_tool_args="n" 43obj_arg_content="n" 44 45for OPTION in "$@" 46do 47 if [ "${forward_to_cc}" = "y" ]; then 48 if [[ ${OPTION} == *.c ]] 49 then 50 CC_FILE="${OPTION}" 51 elif [ "${OPTION}" = "-o" ] 52 then 53 # After -o there is the path to the obj file, flag it 54 obj_arg_content="y" 55 elif [ "${obj_arg_content}" = "y" ] 56 then 57 # This must be the path to the obj file, turn off flag and save path 58 OBJTREE_PATH="$(dirname "${OPTION}")" 59 obj_arg_content="n" 60 fi 61 # Forward any argument to the compiler 62 FORWARD_FLAGS="${FORWARD_FLAGS} ${OPTION}" 63 continue 64 fi 65 case ${OPTION} in 66 -h|--help) 67 help 68 exit 0 69 ;; 70 --build-dir=*) 71 BUILD_DIR="${OPTION#*=}" 72 sm_tool_args="n" 73 ;; 74 --compiler=*) 75 COMPILER="${OPTION#*=}" 76 sm_tool_args="n" 77 ;; 78 --cppcheck-cmd=*) 79 CPPCHECK_TOOL="${OPTION#*=}" 80 sm_tool_args="y" 81 ;; 82 --cppcheck-html) 83 CPPCHECK_HTML="y" 84 sm_tool_args="n" 85 ;; 86 --cppcheck-plat=*) 87 CPPCHECK_PLAT_PATH="${OPTION#*=}" 88 sm_tool_args="n" 89 ;; 90 --ignore-path=*) 91 IGNORE_PATH_LIST="${IGNORE_PATH_LIST} ${OPTION#*=}" 92 sm_tool_args="n" 93 ;; 94 --) 95 forward_to_cc="y" 96 sm_tool_args="n" 97 ;; 98 *) 99 if [ "${sm_tool_args}" = "y" ]; then 100 CPPCHECK_TOOL_ARGS="${CPPCHECK_TOOL_ARGS} ${OPTION}" 101 else 102 echo "Invalid option ${OPTION}" 103 exit 1 104 fi 105 ;; 106 esac 107done 108 109if [ "${COMPILER}" = "" ] 110then 111 echo "--compiler arg is mandatory." 112 exit 1 113fi 114 115if [ "${BUILD_DIR}" = "" ] 116then 117 echo "--build-dir arg is mandatory." 118 exit 1 119fi 120 121function create_jcd() { 122 local line="${1}" 123 local arg_num=0 124 local same_line=0 125 126 { 127 echo "[" 128 echo " {" 129 echo " \"arguments\": [" 130 131 for arg in ${line}; do 132 # This code prevents to put comma in the last element of the list or 133 # on sequential lines that are going to be merged 134 if [ "${arg_num}" -ne 0 ] && [ "${same_line}" -eq 0 ] 135 then 136 echo "," 137 fi 138 if [ "${same_line}" -ne 0 ] 139 then 140 echo -n "${arg}\"" 141 same_line=0 142 elif [ "${arg}" = "-iquote" ] || [ "${arg}" = "-I" ] 143 then 144 # cppcheck doesn't understand -iquote, substitute with -I 145 echo -n " \"-I" 146 same_line=1 147 else 148 echo -n " \"${arg}\"" 149 fi 150 arg_num=$(( arg_num + 1 )) 151 done 152 echo "" 153 echo " ]," 154 echo " \"directory\": \"$(pwd -P)\"," 155 echo " \"file\": \"${CC_FILE}\"" 156 echo " }" 157 echo "]" 158 } > "${JDB_FILE}" 159} 160 161 162# Execute compiler with forwarded flags 163# Shellcheck complains about missing quotes on FORWARD_FLAGS, but they can't be 164# used here 165# shellcheck disable=SC2086 166${COMPILER} ${FORWARD_FLAGS} 167 168if [ -n "${CC_FILE}" ]; 169then 170 for path in ${IGNORE_PATH_LIST} 171 do 172 if [[ ${CC_FILE} == *${path}* ]] 173 then 174 IGNORE_PATH="y" 175 echo "${0}: ${CC_FILE} ignored by --ignore-path matching *${path}*" 176 fi 177 done 178 if [ "${IGNORE_PATH}" = "n" ] 179 then 180 JDB_FILE="${OBJTREE_PATH}/$(basename "${CC_FILE}".json)" 181 182 # Prepare the Json Compilation Database for the file 183 create_jcd "${COMPILER} ${FORWARD_FLAGS}" 184 185 out_file="${OBJTREE_PATH}/$(basename "${CC_FILE%.c}".cppcheck.txt)" 186 187 # Select the right target platform, ARCH is generated from Xen Makefile 188 case ${ARCH} in 189 arm64) 190 # arm64 has efi code compiled with -fshort-wchar 191 platform="${CPPCHECK_PLAT_PATH}/arm64-wchar_t2.xml" 192 ;; 193 arm32) 194 # arm32 has no efi code 195 platform="${CPPCHECK_PLAT_PATH}/arm32-wchar_t4.xml" 196 ;; 197 x86_64) 198 # x86_64 has efi code compiled with -fshort-wchar 199 platform="${CPPCHECK_PLAT_PATH}/x86_64-wchar_t2.xml" 200 ;; 201 *) 202 echo "ARCH: ${ARCH} not expected!" 203 exit 1 204 ;; 205 esac 206 207 if [ ! -f "${platform}" ] 208 then 209 echo "${platform} not found!" 210 exit 1 211 fi 212 213 # Generate build directory for the analysed file 214 cppcheck_build_dir="${BUILD_DIR}/${OBJTREE_PATH}" 215 mkdir -p "${cppcheck_build_dir}" 216 217 # Shellcheck complains about missing quotes on CPPCHECK_TOOL_ARGS, but 218 # they can't be used here 219 # shellcheck disable=SC2086 220 ${CPPCHECK_TOOL} ${CPPCHECK_TOOL_ARGS} \ 221 --project="${JDB_FILE}" \ 222 --output-file="${out_file}" \ 223 --platform="${platform}" \ 224 --cppcheck-build-dir=${cppcheck_build_dir} 225 226 if [ "${CPPCHECK_HTML}" = "y" ] 227 then 228 # Shellcheck complains about missing quotes on CPPCHECK_TOOL_ARGS, 229 # but they can't be used here 230 # shellcheck disable=SC2086 231 ${CPPCHECK_TOOL} ${CPPCHECK_TOOL_ARGS} \ 232 --project="${JDB_FILE}" \ 233 --output-file="${out_file%.txt}.xml" \ 234 --platform="${platform}" \ 235 --cppcheck-build-dir=${cppcheck_build_dir} \ 236 -q \ 237 --xml 238 fi 239 fi 240fi 241