#!/bin/bash ######################################################################## # # $Id$ # # script to build and test the Apache C++ Standard Library # ######################################################################## # # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed # with this work for additional information regarding copyright # ownership. The ASF licenses this file to you under the Apache # License, Version 2.0 (the "License"); you may not use this file # except in compliance with the License. You may obtain a copy of # the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. See the License for the specific language governing # permissions and limitations under the License. # # Copyright 2007 Rogue Wave Software, Inc. # ######################################################################## # # USAGE: # # buildntest [ -e ] # [ -l ] # [ -o ] # [ -t ] # [ -u ] # [ -C ] # [ -B ] # [ -E ] # [ -L ] # [ -M ] # [ -P ] # [ -T ] # # OPTIONS: # # -e # Specifies the list of example programs to build. When omitted, # defaults to all. # # -l # Specifies the list of locales to build. When omitted, defaults # to all. # # -o # Specifies the name of the ouptut file to create. When omitted, # defaults to STDOUT and STDERR. # # -t # Specifies the list of tests to build. When omitted, defaults # to all. # # -B # Specifies the value of the BUILDTYPE variable to pass to # make. # # -C # Specifies the value of the CONFIG variable to pass to make. # # -M # Specifies the value of the BUILDMODE variable to pass to # make. # # -E # Specifies the list of example programs to run. When omitted, # defaults to . # # -L # Specifies the list of locales to exhaustively test. When # omittedm, defaults to . # # -P # Specifies the value for the PREFIX variable to pass to make. # When omitted, the test makefile target is not exercised. # # -T # Specifies the list of tests to run. When omitted, defaults # to . # # EXAMPLES: # # Example 1: # # buildntest -Cgcc.config -B15s \ # -e"accumulate money_put time_get" \ # -l"en_US.ISO-8859-1 de_DE.ISO-8859-15" \ # -t"21.string.append 21.string.replace" \ # -E"time_get" -L"de_DE.ISO-8859-15" \ # -Pinstall # # The command above will build the stdcxx library with gcc in the # 15s build type, then build the accumulate, money_put, and time_get # example programs, the en_US.ISO-8859-1 and de_DE.ISO-8859-15 # locales, and the tests 21.string.append and 21.string.replace. # Then it will run the time_get example, followed by running tests # for the de_DE.ISO-8859-15 locale, then run the two tests it built # and, finally, execute the install target with 'install' as the # installation directory. # # RESULT FILE FORMAT: # # When buildntest is run, it produces an output file named results.xml. # This name is an historical artifact, as the contents are actually a # Java-style (key=value pairs) property list. This file is used by the # nightly automated testing system, so extreme caution should be taken # when changing either the name of the file or the format of the # contents, as changes to the nightly testing system will likely be # required. The majority of this file is currently generated by the # parse_runlog.awk script (not in subversion), but generation should be # moved into the exec utility. # # The first property contained in this file must have the name # 'result.file.type' and a value of either 'stdcxx-short' or # 'stdcxx-extended'. The contents of a file taged as 'stdcxx-extended' # are a supserset of the contents of a file taged as 'stdcxx-short', # though all properties beyond the header property are optional. # # stdcxx-short files contain the following defined properties: # state # Denotes the state of the run. Valid values are 'C' (denoting a # catastrophic failure, such as a configuration filure), 'F' # (denoting a failure building the libstd library), 'E' (denoting # a failure building the rwtest library), 'L' (denoting a failure # building the exec utility), and 'T' (denoting no major # failures). # warnings # An integer, indicating the number of warnings produced during # the build and run process. # examples.run # An integer, indicating the total number of examples which the # infastructure attemted to build. # examples.good # An integer, indicating the total number of examples which ran # to completion and had output matching the expected output (if # available). # tests.run # An integer, indicating the total number of tests which the # infastructure attemted to build. # tests.good # An integer, indicating the number of tests which ran to # completion and reported no failing assertions. # locales.run # An integer, indicating the total number of locale tests which # the infastructure attemted to run. # locales.good # An integer, indicating the number of locale tests which ran to # completion and reported no failing assertions. # utils.run # An integer, indicating the total number of utilities which the # infastructure attemted to build. # utils.good # An integer, indicating the number of utilities which linked # successfully. # # stdcxx-extended files contain additional properties, with names in the # form '{test,example,locale}..{ret,warn,assert}'. The prefix # {test,example,locale} denotes the type of executable (test, example, # or locale test) that the executable is. The suffix {ret,warn,assert} # denotes the type of data (return code, warning count, assertion count) # the property contains. The values are mapped directly from the output # of the exec utility, with ret coresponding to the STATUS column, warn # coresponding to the WARN column, and assert coresponding to the # FAILED and ASSERTS columns, seperated by the '/' character. # ######################################################################## ########## # global constants # date format used to compute real time elapsed between stages # assumes 366 days/year for simplicity DATEFMT="((((%Y*366+1%j-100)*24+1%H-100)*60+1%M-100)*60+1%S-100)" OUTFILE=results.xml if [ -z "$MAKE" ]; then # let callers override the default gmake MAKE=gmake fi # the name of the top-level source directory (TOPDIR) TOPDIR=`pwd | sed -e "s/\//\\\\\\\\\\\//g"` #Mangle path for sed usage # script to replace the name of the top-level source and builr directories # with the respective symbols for brevity TRANS="s/${TOPDIR}\/build/\\\$(BUILDDIR)/g;s/${TOPDIR}/\\\$(TOPDIR)/g" # set the TMPDIR variable if not set [ -z $TMPDIR ] && TMPDIR=$TMP [ -z $TMPDIR ] && TMPDIR=/tmp ########## # global variables # by default (unless otherwise specified on the command line) build # and run all examples, locales, tests, and utilities build_examples="*" build_locales="*" build_rwtest="*" build_tests="*" build_utils="*" run_examples="*" run_locales="*" run_rwtest="*" run_tests="*" # script's own temporary directory tmpdir=$TMPDIR/stdcxx-tmp.$$ ########## # write_times(): writes the amount of real, user, and system time since # the last call, or the date and time if this is the first call write_times() { label=$1 if [ -z $startsec ]; then echo; echo "### date:" date else elapsed="`date +$DATEFMT`-$startsec" # compute the minutes and seconds elapsed of real time since # the last call to the function real_min=$((elapsed)) real_min=$((real_min / 60)) real_sec=$((elapsed)) real_sec=$((real_sec % 60)) # display the real, user, and system times since the last call echo; echo "### real, user, system time ($label):" echo "${real_min}m${real_sec}s" times fi # set the new start timestamp startsec=`date +$DATEFMT` } ########## # make_stage(): executes a stage of the build process, reports real, # user, and system times, and processes errors make_stage() { stagedir=$1 failstate=$2 stageargs=$3 # remove the longest prefix matching the pattern "*/" stagename="${stagedir##*/}" if [ "$failstate" = "" ]; then keep_going="-k" else keep_going="" fi if [ "$stagename" = "runall" ]; then runlog="$TMPDIR/run.$$.log" log=$runlog else buildlog="$TMPDIR/build.$$.log" log=$buildlog fi echo "### $MAKE $keep_going $stagedir $stageargs $MAKEVARS 2>&1 | sed -e \"${TRANS}\" | tee $log:" ( # start a subshell to measure user and system times # of the subshell commands only export TMPDIR=$tmpdir $MAKE $keep_going $stagedir $stageargs $MAKEVARS 2>&1 \ | sed -e "${TRANS}" | tee $log # save the status of the first command in the pipeline # and pass it to the parent shell after writing the real, # user, and system times for the subshell and its children status=${PIPESTATUS[0]} write_times $stagename exit $status ) status=$? if [ -r "$runlog" ]; then # Parse runall results $AWK -f parse_runlog.awk $runlog >>${OUTFILE} rm $runlog elif [ -r "$buildlog" ]; then # count warnings and errors in the stage warnings=`grep -i "warning" $buildlog | wc -l` errors=`grep -i "error" $buildlog | wc -l` diags=": $warnings warnings and $errors errors," rm $buildlog fi if [ $status -ne 0 ]; then if [ "$failstate" = "F" ]; then echo "### stage $stagename${diags} exiting with status $status" cat <> ${OUTFILE} state=F warnings=0 examples.run=0 examples.good=0 tests.run=0 tests.good=0 locales.run=0 locales.good=0 utils.run=0 utils.good=0 EOF exit $status elif [ "$failstate" != "" ]; then # if failstate is specified and the exit status is non-zero # write out the failstate and exit immediately with an error echo "state=$failstate" >> ${OUTFILE} echo "### stage $stagename${diags} exiting with status 1" exit 1 fi fi echo "### stage $stagename${diags} continuing with status $status" echo return $status } ########## # main body of script # write the name of the script and all arguments echo "### running $0 $* [$#]" # script's revision number myrev='$Revision$' myrev=${myrev#'$Revision: '} # strip leading text myrev=${myrev%' $'} # strip trailing text # URL to this version of the script in the repository myurl='$HeadURL$' myurl=${myurl#'$HeadURL: '} # strip leading text myurl=${myurl%' $'} # strip trailing text myurl="$myurl?view=markup&rev=$myrev" # write the URL to the version of the script that's running echo; echo "### script source: $myurl" # process command line options while getopts ":nv:e:l:o:t:B:C:E:L:M:P:T:" opt_name; do echo "$opt_name:$OPTARG" case $opt_name in # options with no arguments n) # avoid cleaning up temporary files no_clean=1 ;; v) # output all components (including passing ones) verbose=1 ;; # options with arguments e) # argument is a list of examples to build build_examples="$OPTARG" ;; l) # argument is a list of locales to build build_locales="$OPTARG" ;; o) # argument is the name of output file (stdout by default) outfile=$OPTARG ;; t) # argument is a list of tests to build build_tests="$OPTARG" ;; u) # argument is a list of utilities to process build_utils="$OPTARG" ;; B) # argument is the value of the BUILDTYPE variable MAKEVARS="$MAKEVARS BUILDTYPE=$OPTARG" ;; C) # argument is the value of the CONFIG file name MAKEVARS="$MAKEVARS CONFIG=$OPTARG" ;; E) # argument is a list of examples to run run_examples="$OPTARG" ;; L) # argument is a space-separated list of locales MAKEVARS="$MAKEVARS LOCALES=\"$OPTARG\"" run_locales="$OPTARG" ;; M) # argument is the value of the BUILDMODE variable MAKEVARS="$MAKEVARS BUILDMODE=$OPTARG" ;; P) # argument is the value of the PREFIX variable MAKEVARS="$MAKEVARS PREFIX=$OPTARG" prefix=$OPTARG ;; T) # argument is a list of tests to build run_tests="$OPTARG" ;; *) echo "$myname: unknown option : -$opt_name" >&2; exit 1;; esac; done # default to running the same set of components (examples, locales, # and tests) as those specified to be built if [ "$run_examples" = "*" ]; then run_examples="$build_examples" fi if [ "$run_locales" = "*" ]; then run_locales="$build_locales" fi if [ "$run_tests" = "*" ]; then run_tests="$build_tests" fi # remove command line options and their arguments from the command line shift $(($OPTIND - 1)) # Try to make certain we clean up the temp directory # This is an ugly workaround for an HPUX 11.23 glitch we haven't managed # to reproduce in manual testing. trap 'rm -rf $tmpdir' EXIT INT QUIT TERM mkdir $tmpdir # start by writing out information about the host to stdout echo; echo "### uname -a:" uname -a osname=`uname -s` AWK=awk case "$osname" in (AIX) # output the machine model name echo; echo "### Model name:" /usr/bin/uname -M # output the number of processors installed on the system echo; echo "### Number of processors:" /usr/sbin/lscfg -lproc\* | /usr/bin/wc -l # output the type of the processors echo; echo "### Processor type:" /usr/sbin/lscfg -lproc0 -p | /usr/bin/sed -n "s/ *Name: *\(.*\)/\1/p" # output processor clock speed echo; echo "### Processor clock speed:" /usr/sbin/lsconf -s | /usr/bin/cut -d' ' -f4- # output the kernel type (32-bit- uni or muli-processor, or # 64-bit multiprocessor) echo; echo "### /usr/sbin/lsconf -k" /usr/sbin/lsconf -k # output the amount of real memory installed on the host echo; echo "### Physical memory:" # one way of doing it: # /usr/sbin/lsattr -El sys0 -a realmem | /usr/bin/cut -d' ' -f2 # or the easy way: /usr/sbin/lsconf -m | /usr/bin/cut -d' ' -f3- ;; (HP-UX) # grep the system log for the amount of physical memory echo; echo "### grep Physical /var/adm/syslog/syslog.log:" grep Physical /var/adm/syslog/syslog.log ;; (Linux) # output the contents of the /etc/-release file # to identify the Linux distribution echo; echo "### cat " /etc/*-release ":" cat /etc/*-release # output the amount of installed physical memory and swap space echo; echo "### free -o:" free -o # output information about installed processors echo; echo "### cat /proc/cpuinfo:" cat /proc/cpuinfo ;; (SunOS) # use POSIX awk (nawk) rather than Solaris awk # using nawk rather than /usr/xpg4/bin/awk as the later has a bad bug AWK=nawk # output the amount of installed physical memory echo; echo "### prtconf | grep Memory:" /usr/sbin/prtconf | grep Memory # output information about installed processors echo; echo "### /usr/sbin/psrinfo -v:" /usr/sbin/psrinfo -v ;; esac # output the amount of installed, available, and used disk space # in all mounted filesystems echo; echo "### df -k:" df -k # echo today's date write_times # echo environment to stdout for refernce echo; echo "### env:" env echo # Start our output file echo "result.file.type=stdcxx-extended" > ${OUTFILE} ########## # Create build directory, set state to 'C' on failure make_stage "builddir" "C" # Configure build directory, set state to 'C' on failure make_stage "config" "C" # Build library, set state to 'F' on failure make_stage "-Cbuild/lib" "F" # show the library and its size echo; echo "### ls -l build/lib/lib*" ls -l build/lib/lib* echo # State is now 'L' or better # Build examples, ignore errors if [ "$build_examples" != "" ]; then if [ "$build_examples" = "*" ]; then unset list else list="$build_examples" fi make_stage "-Cbuild/examples" "" "$list" fi # Build utilities, save return code for later if [ "$build_utils" != "" ]; then if [ "$build_utils" = "*" ]; then unset list else list="$build_utils" fi make_stage "-Cbuild/bin" "" "$list" utils_status=$? else utils_status=1 fi # Build rwtest library, save return code for later if [ "$build_rwtest" != "" ]; then if [ "$build_rwtest" = "*" ]; then unset list else list="$build_rwtest" fi make_stage "-Cbuild/rwtest" "" "$list" rwtest_status=$? else rwtest_status=1 fi ########## # Create a counter so we can keep track of the number of 'good' utilities. # While not the most accurate, we're calling a utility good if it exists and # is executable. The utilities we check are the exec, locale and localedef, # all of which reside in the build/bin subdirectory and were built above. # The reason this definition isn't accurate is because it doesn't tell us if # the utility is behaving correctly. However, to make such checks would be # more difficult. UTILS=0 # We want to check that the exec utility is good prior to using it via # the $MAKE runall target if [ -x "build/bin/exec" ]; then if [ 0 == ${rwtest_status} ]; then echo "state=T" >> ${OUTFILE} # Build tests only if rwtest built, ignore errors if [ "$build_tests" = "*" ]; then unset list else list="$build_tests" fi make_stage "-Cbuild/tests" "" "$list" else echo "state=E" >> ${OUTFILE} if [ 0 == ${utils_status} ]; then utils_status=${rwtest_status} fi fi #Record it as good UTILS=`expr ${UTILS} + 1` # Run successfully built executables, ignore errors if [ "$run_examples" = "*" \ -a "$run_locales" = "*" \ -a "$run_tests" = "*" ]; then make_stage "runall" else if [ "$run_examples" != "" ]; then if [ "$run_examples" = "*" ]; then unset list else list="$run_examples" fi make_stage "-Cbuild/examples" "" "runall $list" fi if [ "$run_locales" != "" ]; then if [ "$run_locales" = "*" ]; then unset list else list="$run_locales" fi make_stage "-Cbuild/bin" "" "runall $list" fi if [ "$run_tests" != "" ]; then if [ "$run_tests" = "*" ]; then unset list else list="$run_tests" fi make_stage "-Cbuild/tests" "" "runall $list" fi fi else echo "state=L" >> ${OUTFILE} fi if [ -x "build/bin/locale" ]; then UTILS=`expr ${UTILS} + 1` fi if [ -x "build/bin/localedef" ]; then UTILS=`expr ${UTILS} + 1` fi echo "utils.run=3" >> ${OUTFILE} echo "utils.good="${UTILS} >> ${OUTFILE} if [ "$prefix" != "" ]; then make_stage "-Cbuild" "" "install" fi # write out the size of the buildspace and (when specified) # the installation directory BEFORE cleaning it up for reference echo; echo "### du -sk build build/* $prefix" du -sk build build/* $prefix # Clean up most of what we built. We don't want to clean/realclean include, # as clean deletes the config.log, and realclean deletes the config.h. # The top level realclean target affects the lib, rwtest, bin, test, # plumbhall, and example directories (via the .DEFAULT rule). echo; echo "### $MAKE realclean" $MAKE realclean # write out the size of the buildspace AFTER cleaning it up for reference echo; echo "### du -sk ./build/ ./build/*" du -sk ./build/ ./build/* # write the amount of real, user, and system time write_times "total" # Pass the captured return code from make util/make rwtest back out exit ${utils_status}