| # common definitions used by other sanity check scripts |
| |
| # Copyright (c) 2015 Wind River Systems, Inc. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are met: |
| # |
| # 1) Redistributions of source code must retain the above copyright notice, |
| # this list of conditions and the following disclaimer. |
| # |
| # 2) Redistributions in binary form must reproduce the above copyright notice, |
| # this list of conditions and the following disclaimer in the documentation |
| # and/or other materials provided with the distribution. |
| # |
| # 3) Neither the name of Wind River Systems nor the names of its contributors |
| # may be used to endorse or promote products derived from this software without |
| # specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| # POSSIBILITY OF SUCH DAMAGE. |
| # |
| |
| # shell commands used in scripts |
| AWK="/usr/bin/awk" |
| BASENAME="/usr/bin/basename" |
| CD="cd" |
| DATE="/bin/date" |
| DIRNAME="/usr/bin/dirname" |
| ECHO="/bin/echo" |
| GREP="/bin/grep" |
| KILL="/bin/kill" |
| LS="/bin/ls" |
| MAKE="make-ll" |
| # MAKE="/usr/bin/make" |
| MV="/bin/mv" |
| PS="/bin/ps" |
| RM="/bin/rm" |
| SED="/bin/sed" |
| CP="/bin/cp" |
| MKDIR="/bin/mkdir" |
| SLEEP="/bin/sleep" |
| ABS_PATH="/bin/readlink -m" |
| |
| # record how script was invoked |
| SCRIPT_NAME=`${BASENAME} $0` |
| |
| # assume log files are not to be kept |
| KEEP_LOGS=0 |
| |
| # log filename where QEMU console output is redirected to |
| SANITY_CHK_LOG="sanity_chk.log" |
| |
| # directory containing code coverage results |
| CC_DIR=${ZEPHYR_BASE}/codecoverage/`${BASENAME} $0`/ |
| HTML_CC_DIR=${ZEPHYR_BASE}/codecoverage_html/`${BASENAME} $0`/ |
| |
| # temporary files used when selecting projects to be sanitized |
| TEMP_AWK_PROG="${ZEPHYR_BASE}/.tempawkprog" |
| TEMP_PRJ_LIST="${ZEPHYR_BASE}/.tempprojlist" |
| |
| # maximum time (in seconds) to allow QEMU to execute a project |
| QEMU_TIME_LIMIT=300 |
| |
| # console output that indicates termination of a project that is being run, |
| # and what indicates successful termination |
| # (note: output string is allowed to contain spaces!) |
| RUN_UNTIL="PROJECT EXECUTION" |
| RUN_PASSED="PROJECT EXECUTION SUCCESSFUL" |
| RUN_FAILED="PROJECT EXECUTION FAILED" |
| |
| # architecture BSP lists |
| arm_BSP_LIST="fsl_frdm_k64f ti_lm3s6965" |
| x86_BSP_LIST="pentium4 minuteia atom quark" |
| _BSP_LIST="${arc_BSP_LIST} ${arm_BSP_LIST} ${x86_BSP_LIST}" |
| |
| # header used to identify script output during execution |
| # |
| print_header() { |
| ${ECHO} "*-=*-=*-=*-=*-=*-=*-=*-=*-=*-=*-=*-=*-=*-=" |
| } |
| |
| # routine that prints error message and exits with error code |
| # |
| # PARAMETERS: $1 is exit value |
| # $2 is function name to print |
| # $3 is line number where script failed |
| # $4 is optional error msg |
| # |
| fail_exit() { |
| if [ -z "$4" ] ; then |
| msg="" |
| else |
| msg="$4" |
| fi |
| |
| # print full script pathname to help in case of issues with $PATH |
| ${ECHO} "$0 line $3 $2 failed: ($1) ${msg}" |
| |
| exit $1 |
| } |
| |
| # restore a project to its pristine state |
| # |
| # PARAMETERS: $1 is project directory name |
| # |
| # ON ENTRY: ${PRJ_PATH} is path to master project directory |
| # |
| clean_project() { |
| ${ECHO} "* Cleaning project $1" |
| |
| ${CD} ${PRJ_PATH}/$1 |
| [ $? -eq 0 ] || fail_exit $? $FUNCNAME $LINENO |
| |
| ${MAKE} distclean |
| [ $? -eq 0 ] || fail_exit $? $FUNCNAME $LINENO |
| } |
| |
| # restore all projects to their pristine state |
| # |
| # ON ENTRY: ${PRJ_LIST} is pseudo-file of project information |
| # |
| # Note that routine will clean a project multiple times if it appears multiple |
| # times in ${PRJ_LIST}. It's not worth optimizing to prevent this ... |
| # |
| clean_all_projects() { |
| project_dirs=`${ECHO} -e ${PRJ_LIST} | ${AWK} '!/#/ {print $1}'` |
| for project in ${project_dirs} |
| do |
| clean_project ${project} |
| done |
| } |
| |
| # set up environment info used to build projects |
| # |
| # ON ENTRY: ${BSP_NAME} is BSP to use (empty => use per-project default) |
| # |
| # ON EXIT: ${BUILD_INFO} specifies build options |
| # |
| build_info_set() { |
| # ensure BSP name isn't a script option that was entered by mistake |
| if [ x${BSP_NAME:0:1} = "x-" ] ; then |
| ${ECHO} "invalid BSP '${BSP_NAME}' specified" |
| exit 1 |
| fi |
| |
| # set up toolchain-specific build environment stuff |
| BUILD_INFO="EXTRA_CFLAGS=-Werror EXTRA_ASMFLAGS=-Wa,--fatal-warnings EXTRA_LFLAGS=--fatal-warnings" |
| } |
| |
| # set up project info used to build projects |
| # |
| # ON ENTRY: ${PRJ_PATH} is path to master project directory |
| # ${PRJ_LIST} is pseudo-file of project information |
| # ${BSP_NAME} is BSP to use (empty => use per-project default) |
| # ${ARCH_NAME} is architecture to use (empty => no arch restrictions) |
| # |
| # ON EXIT: ${PRJ_NAME} array specifies project directory name |
| # ${PRJ_ARGS} array specifies any additional project build arguments |
| # ${PRJ_TYPE} array specifies project type ("nanokernel" or "microkernel") |
| # ${PRJ_FLAG} array specifies project flags ('u' or 'n'; optional 'q') |
| # ${BSP_INFO} array specifies project BSP and BSP_VARIANT |
| # ${BSP_FLAG} array specifies optional BSP flag ('!' or empty) |
| # ${NUM_PROJ} specifies number of projects described in arrays |
| # |
| proj_info_set() { |
| # clean up any stale temporary files from an earlier run |
| ${RM} -f ${TEMP_AWK_PROG} ${TEMP_PRJ_LIST} |
| |
| # create list of projects to sanitize |
| # - specified BSP: choose only projects that support that BSP, |
| # then filter out info about all other BSPs for those projects |
| # - no specified BSP: choose all projects, then filter out info |
| # about all BSPs except the first one listed |
| # note: ignores any comment lines in the project information file |
| # (i.e. any lines containing a '#' character) |
| dollar='$' |
| if [ x${BSP_NAME} != x ] ; then |
| awk_string="!/#/ && /${BSP_NAME}/ {match(${dollar}0,/.+[>]/); \ |
| prjpart = substr(${dollar}0,RSTART,RLENGTH); \ |
| bsppart = substr(${dollar}0,RLENGTH+1); |
| match(bsppart,/${BSP_NAME}!?/); \ |
| bsp = substr(bsppart,RSTART,RLENGTH); \ |
| if(length(bsp) > 0) \ |
| print prjpart \" \" bsp}" |
| else |
| awk_string="!/#/ {match(${dollar}0,/.+[>]/); \ |
| prjpart = substr(${dollar}0,RSTART,RLENGTH); \ |
| bsppart = substr(${dollar}0,RLENGTH+1); |
| match(bsppart,/[-a-zA-Z0-9_]+!?/); \ |
| bsp = substr(bsppart,RSTART,RLENGTH); \ |
| print prjpart \" \" bsp}" |
| fi |
| |
| ${ECHO} "${awk_string}" > ${TEMP_AWK_PROG} |
| ${ECHO} -e ${PRJ_LIST} | ${AWK} -f ${TEMP_AWK_PROG} > ${TEMP_PRJ_LIST} |
| |
| # deconstruct the filtered project list file |
| # into a set of arrays containing project info |
| let NUM_PROJ=0 |
| while read line ; do |
| let NUM_PROJ++ |
| |
| PRJ_NAME[${NUM_PROJ}]=`${AWK} '{match($0,/[^ ]+[ <]/); \ |
| print substr($0,RSTART,RLENGTH-1)}' <<< ${line}` |
| |
| PRJ_ARGS[${NUM_PROJ}]=`${AWK} '{match($0,/ .*[<]/); \ |
| print substr($0,RSTART+1,RLENGTH-2)}' <<< ${line}` |
| |
| PRJ_FLAG[${NUM_PROJ}]=`${AWK} '{match($0,/<.*>/); \ |
| print substr($0,RSTART+1,RLENGTH-2)}' <<< ${line}` |
| if [ ${PRJ_FLAG[${NUM_PROJ}]:0:1} = "u" ] ; then |
| PRJ_TYPE[${NUM_PROJ}]="microkernel" |
| elif [ ${PRJ_FLAG[${NUM_PROJ}]:0:1} = "n" ] ; then |
| PRJ_TYPE[${NUM_PROJ}]="nanokernel" |
| else |
| ${ECHO} "unrecognized project type" |
| exit 1 |
| fi |
| |
| bsp2use_tmp=`${AWK} '{match($0,/[>] [-a-zA-Z0-9_]+/); \ |
| print substr($0,RSTART+1,RLENGTH-1)}' <<< ${line}` |
| bsp2use="$(${ECHO} -e "${bsp2use_tmp}" | ${SED} -e 's/^[[:space:]]*//')" |
| |
| ${ECHO} ${_BSP_LIST} | ${GREP} -q -w ${bsp2use} |
| if [ $? -ne 0 ]; then |
| ${ECHO} "Unrecognized BSP or BSP variant" |
| exit 1 |
| fi |
| |
| if [ x${ARCH_NAME} != x ] ; then |
| # An architecture has been specified. |
| bsp_list=${ARCH_NAME}_BSP_LIST |
| ${ECHO} ${!bsp_list} | ${GREP} -q -w ${bsp2use} |
| if [ $? -ne 0 ] ; then |
| # The specified architecture does not support the |
| # BSP or BSP variant ${bsp2use} |
| let NUM_PROJ-- |
| continue |
| fi |
| fi |
| |
| if [ ${bsp2use} = "pentium4" ] ; then |
| BSP_INFO[${NUM_PROJ}]="BSP=generic_pc BSP_VARIANT=pentium4" |
| BSP[${NUM_PROJ}]=generic_pc |
| elif [ ${bsp2use} = "minuteia" ] ; then |
| BSP_INFO[${NUM_PROJ}]="BSP=generic_pc BSP_VARIANT=minuteia" |
| BSP[${NUM_PROJ}]=generic_pc |
| elif [ ${bsp2use} = "atom" ] ; then |
| BSP_INFO[${NUM_PROJ}]="BSP=generic_pc BSP_VARIANT=atom_n28xx" |
| BSP[${NUM_PROJ}]=generic_pc |
| elif [ ${bsp2use} = "quark" ] ; then |
| BSP_INFO[${NUM_PROJ}]="BSP=quark" |
| BSP[${NUM_PROJ}]=quark |
| else |
| BSP_INFO[${NUM_PROJ}]="BSP=${bsp2use}" |
| BSP[${NUM_PROJ}]=${bsp2use} |
| fi |
| |
| BSP_FLAG[${NUM_PROJ}]=`${AWK} '/!/ {print "!"}' <<< ${line}` |
| done < ${TEMP_PRJ_LIST} |
| |
| # clean up temporary files |
| ${RM} -f ${TEMP_AWK_PROG} ${TEMP_PRJ_LIST} |
| } |
| |
| # skip building of a standard project |
| # |
| # PARAMETERS: $1 is project array entry to use |
| # |
| # ON ENTRY: ${PRJ_PATH} is path to master project directory |
| # ${PRJ_NAME} array specifies project directory name |
| # ${PRJ_ARGS} array specifies any additional project build arguments |
| # ${PRJ_TYPE} array specifies project type ("nanokernel" or "microkernel") |
| # ${PRJ_FLAG} array specifies project flags ('u' or 'n'; optional 'q') |
| # ${BSP_INFO} array specifies project BSP and BSP_VARIANT |
| # ${BUILD_INFO} specifies build options |
| # ${NUM_PROJ} specifies # of projects described in arrays |
| # ${PRJ_CLASS} specifies type of projects being sanitized |
| # |
| skip_project() { |
| proj_name=`${BASENAME} ${PRJ_NAME[$1]}` |
| |
| ${ECHO} "Skipping ${proj_name} [${PRJ_CLASS} project $1 of ${NUM_PROJ}]" |
| ${ECHO} |
| } |
| |
| # build a standard project |
| # |
| # PARAMETERS: $1 is project array entry to use |
| # $2 if set, tells the routine not to check for an elf file |
| # |
| # ON ENTRY: ${PRJ_PATH} is path to master project directory |
| # ${PRJ_NAME} array specifies project directory name |
| # ${PRJ_ARGS} array specifies any additional project build arguments |
| # ${PRJ_TYPE} array specifies project type ("nanokernel" or "microkernel") |
| # ${PRJ_FLAG} array specifies project flags ('u' or 'n'; optional 'q') |
| # ${BSP_INFO} array specifies project BSP and BSP_VARIANT |
| # ${BUILD_INFO} specifies build options |
| # ${NUM_PROJ} specifies # of projects described in arrays |
| # ${PRJ_CLASS} specifies type of projects being sanitized |
| # |
| build_project() { |
| proj_name=`${BASENAME} ${PRJ_NAME[$1]}` |
| |
| ${ECHO} "Building ${proj_name} [${PRJ_CLASS} project $1 of ${NUM_PROJ}]" |
| ${ECHO} |
| ${ECHO} "target: ${BSP_INFO[$1]}" |
| ${ECHO} "arguments: ${PRJ_ARGS[$1]}" |
| ${ECHO} |
| |
| ${CD} ${PRJ_PATH}/${PRJ_NAME[$1]} |
| [ $? -eq 0 ] || fail_exit $? $FUNCNAME $LINENO |
| |
| # build project from scratch |
| ${MAKE} distclean |
| [ $? -eq 0 ] || fail_exit $? $FUNCNAME $LINENO |
| |
| if [[ $arm_BSP_LIST == *"${BSP[$1]}"* ]]; then |
| arch=arm |
| else |
| arch=x86 |
| fi |
| if [ ! -z ${ARCH_NAME} ]; then |
| arch=${ARCH_NAME} |
| fi |
| |
| ${MAKE} ARCH=${arch} ${BUILD_INFO} ${PRJ_ARGS[$1]} ${BSP_INFO[$1]} |
| [ $? -eq 0 ] || fail_exit $? $FUNCNAME $LINENO |
| |
| if [ x$2 == x ] ; then |
| elf_name=`${LS} outdir/${PRJ_TYPE[$1]}.elf` |
| [ x${elf_name} != "x" ] || \ |
| fail_exit $? $FUNCNAME $LINENO "couldn't build ${proj_name}" |
| fi |
| } |
| |
| # use QEMU to run a standard project that is already built |
| # |
| # PARAMETERS: $1 is project array entry to use |
| # |
| # ON ENTRY: ${PRJ_PATH} is path to master project directory |
| # ${PRJ_NAME} array specifies project directory name |
| # ${PRJ_ARGS} array specifies any additional project build arguments |
| # ${PRJ_TYPE} array specifies project type ("nanokernel" or "microkernel") |
| # ${PRJ_FLAG} array specifies project flags ('u' or 'n'; optional 'q') |
| # ${BSP_INFO} array specifies project BSP and BSP_VARIANT |
| # ${BUILD_INFO} specifies build options |
| # ${NUM_PROJ} specifies # of projects described in arrays |
| # ${PRJ_CLASS} specifies type of projects being sanitized |
| # |
| qemu_project() { |
| proj_name=`${BASENAME} ${PRJ_NAME[$1]}` |
| |
| ${ECHO} |
| ${ECHO} "Running ${proj_name} using QEMU [${PRJ_CLASS} project $1 of ${NUM_PROJ}]" |
| ${ECHO} |
| ${ECHO} "target: ${BSP_INFO[$1]}" |
| ${ECHO} "arguments: ${PRJ_ARGS[$1]}" |
| ${ECHO} |
| |
| ${CD} ${PRJ_PATH}/${PRJ_NAME[$1]} |
| [ $? -eq 0 ] || fail_exit $? $FUNCNAME $LINENO $1 |
| |
| # create empty log now so the grep loop below can access the file |
| # right away for the case where QEMU did had a chance to run and |
| # create the file by the time the grep loop starts |
| ${RM} -f ${SANITY_CHK_LOG} |
| :> ${SANITY_CHK_LOG} |
| if [[ $arm_BSP_LIST == *"${BSP[$1]}"* ]]; then |
| arch=arm |
| else |
| arch=x86 |
| fi |
| if [ ! -z ${ARCH_NAME} ]; then |
| arch=${ARCH_NAME} |
| fi |
| # launch a separate process to run ELF file in QEMU, |
| # and append the logs into the empty log file created above |
| # (supply all build-related arguments to allow final linking |
| # to be done using the same arguments as the original build) |
| ( ${MAKE} ARCH=${arch} qemu ${PRJ_ARGS[$1]} ${BSP_INFO[$1]} \ |
| ${BUILD_INFO} | tee ${SANITY_CHK_LOG} )& |
| |
| # get QEMU's pid |
| # (wait for QEMU process to be spawned by examining list of tasks |
| # associated with this script's terminal, then grab the pid) |
| while ! [ -f outdir/qemu.pid ] |
| do |
| ${SLEEP} 1 |
| done |
| |
| qemu_pid=$(<outdir/qemu.pid) |
| |
| # assume execution will fail |
| let RESULT=1 |
| |
| # wait up for project to complete (or time limit to be reached) |
| let loop_cnt=0 |
| while [ "${loop_cnt}" -le "${QEMU_TIME_LIMIT}" ] |
| do |
| ${GREP} -q -E "${RUN_PASSED}" ${SANITY_CHK_LOG} |
| if [ $? -eq 0 ] ; then |
| let RESULT=0 |
| break |
| fi |
| ${GREP} -q -E "${RUN_FAILED}" ${SANITY_CHK_LOG} |
| if [ $? -eq 0 ] ; then |
| break |
| fi |
| let loop_cnt++ |
| ${SLEEP} 1 |
| done |
| |
| # kill QEMU, otherwise it continues running forever |
| # (tee will SIGPIPE when qemu is killed, |
| # and the subshell will exit when both its children exit) |
| ${KILL} ${qemu_pid} |
| |
| # keep log if requested or when there is an error |
| if [ ${KEEP_LOGS} = 1 -o ${RESULT} -ne 0 ] ; then |
| # append info identifying how log file was generated |
| $ECHO >> ${SANITY_CHK_LOG} |
| $ECHO "Project name: ${PRJ_NAME[$1]}" >> ${SANITY_CHK_LOG} |
| $ECHO "Project arguments: ${PRJ_ARGS[$1]}" >> ${SANITY_CHK_LOG} |
| $ECHO "BSP info: ${BSP_INFO[$1]}" >> ${SANITY_CHK_LOG} |
| $ECHO "Build info: ${BUILD_INFO}" >> ${SANITY_CHK_LOG} |
| |
| # ensure log file name is unique to avoid overwriting |
| # a previously generated log file |
| # (note: assumes identical test isn't re-run within 60 seconds) |
| new_name=${SANITY_CHK_LOG}_project$1_`${DATE} +%F_%R` |
| ${ECHO} |
| ${ECHO} "saving log file ${PRJ_PATH}/${PRJ_NAME[$1]}/${new_name}" |
| ${MV} -f ${SANITY_CHK_LOG} ${new_name} |
| else |
| ${RM} -f ${SANITY_CHK_LOG} |
| fi |
| |
| [ ${RESULT} -eq 0 ] || fail_exit 1 $FUNCNAME $LINENO \ |
| "error running ${proj_name}" |
| } |