| #!/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 <examples-to-build> ] |
| # [ -l <locales-to-build> ] |
| # [ -o <output-file> ] |
| # [ -t <tests-to-build> ] |
| # [ -u <utilities-to-build> ] |
| # [ -C <config> ] |
| # [ -B <buildtype> ] |
| # [ -E <examples-to-run> ] |
| # [ -L <locales-to-run> ] |
| # [ -M <buildmode> ] |
| # [ -P <prefix> ] |
| # [ -T <tests-to-run> ] |
| # |
| # OPTIONS: |
| # |
| # -e <examples-to-build> |
| # Specifies the list of example programs to build. When omitted, |
| # defaults to all. |
| # |
| # -l <locales-to-build> |
| # Specifies the list of locales to build. When omitted, defaults |
| # to all. |
| # |
| # -o <output-file> |
| # Specifies the name of the ouptut file to create. When omitted, |
| # defaults to STDOUT and STDERR. |
| # |
| # -t <tests-to-build> |
| # Specifies the list of tests to build. When omitted, defaults |
| # to all. |
| # |
| # -B <buildtype> |
| # Specifies the value of the BUILDTYPE variable to pass to |
| # make. |
| # |
| # -C <config> |
| # Specifies the value of the CONFIG variable to pass to make. |
| # |
| # -M <buildmode> |
| # Specifies the value of the BUILDMODE variable to pass to |
| # make. |
| # |
| # -E <examples-to-run> |
| # Specifies the list of example programs to run. When omitted, |
| # defaults to <examples-to-build>. |
| # |
| # -L <locales-to-run> |
| # Specifies the list of locales to exhaustively test. When |
| # omittedm, defaults to <locales-to-build>. |
| # |
| # -P <prefix> |
| # Specifies the value for the PREFIX variable to pass to make. |
| # When omitted, the test makefile target is not exercised. |
| # |
| # -T <tests-to-run> |
| # Specifies the list of tests to run. When omitted, defaults |
| # to <tests-to-build>. |
| # |
| # 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}.<name>.{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 <<EOF >> ${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/<distro>-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} |