|  | #!/bin/sh | 
|  |  | 
|  | #  Multi-build script for testing compilation of all maintained | 
|  | #  configs of GDB. | 
|  |  | 
|  | #  Copyright (C) 2002-2020 Free Software Foundation, Inc. | 
|  |  | 
|  | #  Contributed by Richard Earnshaw  (rearnsha@arm.com) | 
|  |  | 
|  | #  This program is free software; you can redistribute it and/or modify | 
|  | #  it under the terms of the GNU General Public License as published by | 
|  | #  the Free Software Foundation; either version 3 of the License, or | 
|  | #  (at your option) any later version. | 
|  | # | 
|  | #  This program is distributed in the hope that it will be useful, | 
|  | #  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | #  GNU General Public License for more details. | 
|  | # | 
|  | #  You should have received a copy of the GNU General Public License | 
|  | #  along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
|  |  | 
|  | # Make certain that the script is not running in an internationalized | 
|  | # environment. | 
|  | LANG=c ; export LANG | 
|  | LC_ALL=c ; export LC_ALL | 
|  |  | 
|  | usage() | 
|  | { | 
|  | cat <<EOF | 
|  | Usage: gdb_mbuild.sh [ <options> ... ] <srcdir> <builddir> | 
|  | Options: | 
|  | -j <makejobs>  Run <makejobs> in parallel.  Passed to make. | 
|  | On a single cpu machine, 2 is recommended. | 
|  | -k             Keep going.  Do not stop after the first build fails. | 
|  | --keep         Keep builds.  Do not remove each build when finished. | 
|  | -e <regexp>    Regular expression for selecting the targets to build. | 
|  | -f             Force rebuild.  Even rebuild previously built directories. | 
|  | -v             Be more (and more, and more) verbose. | 
|  | Arguments: | 
|  | <srcdir>       Source code directory. | 
|  | <builddir>     Build directory. | 
|  | Environment variables examined (with default if not defined): | 
|  | MAKE (make)" | 
|  | EOF | 
|  | exit 1; | 
|  | cat <<NOTYET | 
|  | -b <maxbuilds> Run <maxbuild> builds in parallel. | 
|  | On a single cpu machine, 1 is recommended. | 
|  | NOTYET | 
|  | } | 
|  |  | 
|  | ### COMMAND LINE OPTIONS | 
|  |  | 
|  | makejobs= | 
|  | maxbuilds=1 | 
|  | keepgoing= | 
|  | force=false | 
|  | targexp="" | 
|  | verbose=0 | 
|  | keep=false | 
|  | while test $# -gt 0 | 
|  | do | 
|  | case "$1" in | 
|  | -j ) | 
|  | # Number of parallel make jobs. | 
|  | shift | 
|  | test $# -ge 1 || usage | 
|  | makejobs="-j $1" | 
|  | ;; | 
|  | -b | -c ) | 
|  | # Number of builds to fire off in parallel. | 
|  | shift | 
|  | test $# -ge 1 || usage | 
|  | maxbuilds=$1 | 
|  | ;; | 
|  | -k ) | 
|  | # Should we soldier on after the first build fails? | 
|  | keepgoing=-k | 
|  | ;; | 
|  | --keep ) | 
|  | keep=true | 
|  | ;; | 
|  | -e ) | 
|  | # A regular expression for selecting targets | 
|  | shift | 
|  | test $# -ge 1 || usage | 
|  | targexp="${targexp} -e ${1}" | 
|  | ;; | 
|  | -f ) | 
|  | # Force a rebuild | 
|  | force=true ; | 
|  | ;; | 
|  | -v ) | 
|  | # Be more, and more, and more, verbose | 
|  | verbose=`expr ${verbose} + 1` | 
|  | ;; | 
|  | -* ) usage ;; | 
|  | *) break ;; | 
|  | esac | 
|  | shift | 
|  | done | 
|  |  | 
|  |  | 
|  | ### COMMAND LINE PARAMETERS | 
|  |  | 
|  | if test $# -ne 2 | 
|  | then | 
|  | usage | 
|  | fi | 
|  |  | 
|  | # Convert these to absolute directory paths. | 
|  |  | 
|  | # Where the sources live | 
|  | srcdir=`cd $1 && /bin/pwd` || exit 1 | 
|  |  | 
|  | # Where the builds occur | 
|  | builddir=`cd $2 && /bin/pwd` || exit 1 | 
|  |  | 
|  | ### ENVIRONMENT PARAMETERS | 
|  |  | 
|  | # Version of make to use | 
|  | make=${MAKE:-make} | 
|  | MAKE=${make} | 
|  | export MAKE | 
|  |  | 
|  |  | 
|  | # Where to look for the list of targets to test | 
|  | maintainers=${srcdir}/gdb/MAINTAINERS | 
|  | if [ ! -r ${maintainers} ] | 
|  | then | 
|  | echo Maintainers file ${maintainers} not found | 
|  | exit 1 | 
|  | fi | 
|  |  | 
|  | # Get the list of targets and the build options | 
|  | alltarg=`cat ${maintainers} | tr -s '[\t]' '[ ]' | sed -n ' | 
|  | /^[ ]*[-a-z0-9\.]*[ ]*[(]*--target=.*/ !d | 
|  | s/^.*--target=// | 
|  | s/).*$// | 
|  | h | 
|  | :loop | 
|  | g | 
|  | /^[^ ]*,/ !b end | 
|  | s/,[^ ]*// | 
|  | p | 
|  | g | 
|  | s/^[^,]*,// | 
|  | h | 
|  | b loop | 
|  | :end | 
|  | p | 
|  | ' | if test "${targexp}" = "" | 
|  | then | 
|  | grep -v -e broken -e OBSOLETE | 
|  | else | 
|  | grep ${targexp} | 
|  | fi` | 
|  |  | 
|  |  | 
|  | # Usage: fail <message> <test-that-should-succeed>.  Should the build | 
|  | # fail?  If the test is true, and we don't want to keep going, print | 
|  | # the message and shoot everything in sight and abort the build. | 
|  |  | 
|  | fail () | 
|  | { | 
|  | msg="$1" ; shift | 
|  | if test "$@" | 
|  | then | 
|  | echo "${target}: ${msg}" | 
|  | if test "${keepgoing}" != "" | 
|  | then | 
|  | #exit 1 | 
|  | continue | 
|  | else | 
|  | kill $$ | 
|  | exit 1 | 
|  | fi | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | # Usage: log <level> <logfile>.  Write standard input to <logfile> and | 
|  | # stdout (if verbose >= level). | 
|  |  | 
|  | log () | 
|  | { | 
|  | if test ${verbose} -ge $1 | 
|  | then | 
|  | tee $2 | 
|  | else | 
|  | cat > $2 | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | # Warn the user of what is coming, print the list of targets | 
|  |  | 
|  | echo "$alltarg" | 
|  | echo "" | 
|  |  | 
|  |  | 
|  | # For each target, configure, build and test it. | 
|  |  | 
|  | echo "$alltarg" | while read target gdbopts simopts | 
|  | do | 
|  |  | 
|  | trap "exit 1"  1 2 15 | 
|  | dir=${builddir}/${target} | 
|  |  | 
|  | # Should a scratch rebuild be forced, for perhaps the entire | 
|  | # build be skipped? | 
|  |  | 
|  | if ${force} | 
|  | then | 
|  | echo forcing ${target} ... | 
|  | rm -rf ${dir} | 
|  | elif test -f ${dir} | 
|  | then | 
|  | echo "${target}" | 
|  | continue | 
|  | else | 
|  | echo ${target} ... | 
|  | fi | 
|  |  | 
|  | # Did the previous configure attempt fail?  If it did | 
|  | # restart from scratch. | 
|  |  | 
|  | if test -d ${dir} -a ! -r ${dir}/Makefile | 
|  | then | 
|  | echo ... removing partially configured ${target} | 
|  | rm -rf ${dir} | 
|  | if test -d ${dir} | 
|  | then | 
|  | echo "${target}: unable to remove directory ${dir}" | 
|  | exit 1 | 
|  | fi | 
|  | fi | 
|  |  | 
|  | # From now on, we're in this target's build directory | 
|  |  | 
|  | mkdir -p ${dir} | 
|  | cd ${dir} || exit 1 | 
|  |  | 
|  | # Configure, if not already.  Should this go back to being | 
|  | # separate and done in parallel? | 
|  |  | 
|  | if test ! -r Makefile | 
|  | then | 
|  | # Default SIMOPTS to GDBOPTS. | 
|  | test -z "${simopts}" && simopts="${gdbopts}" | 
|  | # The config options | 
|  | __target="--target=${target}" | 
|  | __enable_gdb_build_warnings=`test -z "${gdbopts}" \ | 
|  | || echo "--enable-gdb-build-warnings=${gdbopts}"` | 
|  | __enable_sim_build_warnings=`test -z "${simopts}" \ | 
|  | || echo "--enable-sim-build-warnings=${simopts}"` | 
|  | __configure="${srcdir}/configure \ | 
|  | ${__target} \ | 
|  | ${__enable_gdb_build_warnings} \ | 
|  | ${__enable_sim_build_warnings}" | 
|  | echo ... ${__configure} | 
|  | trap "echo Removing partially configured ${dir} directory ...; rm -rf ${dir}; exit 1" 1 2 15 | 
|  | ${__configure} 2>&1 | log 2 Config.log | 
|  | trap "exit 1"  1 2 15 | 
|  | fi | 
|  | fail "configure failed" ! -r Makefile | 
|  |  | 
|  | # Build, if not built. | 
|  |  | 
|  | if test ! -x gdb/gdb -a ! -x gdb/gdb.exe | 
|  | then | 
|  | # Iff the build fails remove the final build target so that | 
|  | # the follow-on code knows things failed.  Stops the follow-on | 
|  | # code thinking that a failed rebuild succeeded (executable | 
|  | # left around from previous build). | 
|  | echo ... ${make} ${keepgoing} ${makejobs} ${target} | 
|  | ( ${make} ${keepgoing} ${makejobs} all-gdb || rm -f gdb/gdb gdb/gdb.exe | 
|  | ) 2>&1 | log 1 Build.log | 
|  | fi | 
|  | fail "compile failed" ! -x gdb/gdb -a ! -x gdb/gdb.exe | 
|  |  | 
|  | # Check that the built GDB can at least print it's architecture. | 
|  |  | 
|  | echo ... run ${target} | 
|  | rm -f core gdb.core ${dir}/gdb/x | 
|  | cat <<EOF > x | 
|  | maint print architecture | 
|  | quit | 
|  | EOF | 
|  | ./gdb/gdb -batch -nx -x x 2>&1 | log 1 Gdb.log | 
|  | fail "gdb dumped core" -r core -o -r gdb.core | 
|  | fail "gdb printed no output" ! -s Gdb.log | 
|  | grep -e internal-error Gdb.log && fail "gdb panic" 1 | 
|  |  | 
|  | echo ... cleanup ${target} | 
|  |  | 
|  | # Create a sed script that cleans up the output from GDB. | 
|  | rm -f mbuild.sed | 
|  | touch mbuild.sed || exit 1 | 
|  | # Rules to replace <0xNNNN> with the corresponding function's | 
|  | # name. | 
|  | sed -n -e '/<0x0*>/d' -e 's/^.*<0x\([0-9a-f]*\)>.*$/0x\1/p' Gdb.log \ | 
|  | | sort -u \ | 
|  | | while read addr | 
|  | do | 
|  | func="`addr2line -f -e ./gdb/gdb -s ${addr} | sed -n -e 1p`" | 
|  | test ${verbose} -gt 0 && echo "${addr} ${func}" 1>&2 | 
|  | echo "s/<${addr}>/<${func}>/g" | 
|  | done >> mbuild.sed | 
|  | # Rules to strip the leading paths off of file names. | 
|  | echo 's/"\/.*\/gdb\//"gdb\//g' >> mbuild.sed | 
|  | # Run the script | 
|  | sed -f mbuild.sed Gdb.log > Mbuild.log | 
|  |  | 
|  | # Replace the build directory with a file as semaphore that stops | 
|  | # a rebuild. (should the logs be saved?) | 
|  |  | 
|  | cd ${builddir} | 
|  |  | 
|  | if ${keep} | 
|  | then | 
|  | : | 
|  | else | 
|  | rm -f ${target}.tmp | 
|  | mv ${target}/Mbuild.log ${target}.tmp | 
|  | rm -rf ${target} | 
|  | mv ${target}.tmp ${target} | 
|  | fi | 
|  |  | 
|  | # Success! | 
|  | echo ... ${target} built | 
|  |  | 
|  | done | 
|  |  | 
|  | exit 0 |