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