coreboot-kgpe-d16/util/abuild/abuild
Stefan Reinauer 14e2277962 Since some people disapprove of white space cleanups mixed in regular commits
while others dislike them being extra commits, let's clean them up once and
for all for the existing code. If it's ugly, let it only be ugly once :-)

Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
Acked-by: Stefan Reinauer <stepan@coresystems.de>



git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5507 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
2010-04-27 06:56:47 +00:00

644 lines
17 KiB
Bash
Executable file

#!/bin/bash
#
# coreboot autobuild
#
# This script builds coreboot images for all available targets.
#
# (C) 2004 by Stefan Reinauer <stepan@openbios.org>
# (C) 2006-2010 by coresystems GmbH <info@coresystems.de>
#
# This file is subject to the terms and conditions of the GNU General
# Public License. See the file COPYING in the main directory of this
# archive for more details.
#
#set -x # Turn echo on....
ABUILD_DATE="January 29th, 2010"
ABUILD_VERSION="0.9"
# Where shall we place all the build trees?
TARGET=coreboot-builds
XMLFILE=$( pwd )/abuild.xml
# path to payload. Should be more generic
PAYLOAD=/dev/null
# Lines of error context to be printed in FAILURE case
CONTEXT=6
TESTSUBMISSION="http://qa.coreboot.org/deployment/send.php"
# Number of CPUs to compile on per default
cpus=1
# Configure-only mode
configureonly=0
# One might want to adjust these in case of cross compiling
for i in make gmake gnumake nonexistant_make; do
$i --version 2>/dev/null |grep "GNU Make" >/dev/null && break
done
if [ "$i" = "nonexistant_make" ]; then
echo No GNU Make found.
exit 1
fi
MAKE=$i
# this can be changed to xml by -x
mode=text
# silent mode.. no compiler calls, only warnings in the log files.
# this is disabled per default but can be enabled with -s
silent=
# clang mode enabled by -sb option.
scanbuild=false
# use ccache
ccache=false
# stackprotect mode enabled by -ns option.
stackprotect=false
# loglevel changed with -l / --loglevel option
loglevel=default
# update existing image
update=false
# CBFS prefix
cbfs_prefix=fallback
ARCH=`uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
-e s/i86pc/i386/ \
-e s/arm.*/arm/ -e s/sa110/arm/ -e s/x86_64/amd64/ \
-e "s/Power Macintosh/ppc/"`
trap interrupt INT
function interrupt
{
printf "\n$0: execution interrupted manually.\n"
if [ "$mode" == "xml" ]; then
printf "$0: deleting incomplete xml output file.\n"
fi
exit 1
}
function debug
{
test "$verbose" == "true" && printf "$*\n"
}
function xml
{
test "$mode" == "xml" && printf "$*\n" >> $XMLFILE
return 0
}
function xmlfile
{
test "$mode" == "xml" && {
printf '<![CDATA[\n'
cat $1
printf ']]>\n'
} >> $XMLFILE
}
function vendors
{
# make this a function so we can easily select
# without breaking readability
ls -1 "$ROOT/src/mainboard" | grep -v Kconfig | grep -v Makefile
}
function mainboards
{
# make this a function so we can easily select
# without breaking readability
VENDOR=$1
ls -1 $ROOT/src/mainboard/$VENDOR | grep -v Kconfig
}
function architecture
{
VENDOR=$1
MAINBOARD=$2
ARCH=`cat $ROOT/src/mainboard/$VENDOR/$MAINBOARD/Kconfig | \
grep "select ARCH_"|cut -f2- -d_`
echo $ARCH | sed s/X86/i386/
}
function create_config
{
VENDOR=$1
MAINBOARD=$2
CONFIG=$3
build_dir=$TARGET/${VENDOR}_${MAINBOARD}
# get a working payload for the board if we have one.
# the --payload option expects a directory containing
# a shell script payload.sh
# Usage: payload.sh [VENDOR] [DEVICE]
# the script returns an absolute path to the payload binary.
if [ -f $payloads/payload.sh ]; then
PAYLOAD=`sh $payloads/payload.sh $VENDOR $MAINBOARD`
printf "Using payload $PAYLOAD\n"
fi
[ "$update" = "true" ] && mv ${build_dir}/coreboot.rom coreboot.rom.tmp
$MAKE distclean obj=${build_dir}
mkdir -p ${build_dir}
mkdir -p $TARGET/sharedutils
[ "$update" = "true" ] && mv coreboot.rom.tmp ${build_dir}/coreboot.rom
if [ "$CONFIG" != "" ]; then
printf " Using existing configuration $CONFIG ... "
xml " <config>$CONFIG</config>"
cp $CONFIG .config
else
printf " Creating config file... "
xml " <config>autogenerated</config>"
grep "depends[\t ]on[\t ]*VENDOR" src/mainboard/$VENDOR/$MAINBOARD/../Kconfig | \
sed "s,^.*\(VENDOR_.*\)[^A-Z0-9_]*,CONFIG_\1=y," > .config
grep "config[\t ]*BOARD" src/mainboard/$VENDOR/$MAINBOARD/Kconfig | \
sed "s,^.*\(BOARD_.*\)[^A-Z0-9_]*,CONFIG_\1=y," >> .config
grep "select[\t ]*ARCH" src/mainboard/$VENDOR/$MAINBOARD/Kconfig | \
sed "s,^.*\(ARCH_.*\)[^A-Z0-9_]*,CONFIG_\1=y," >> .config
echo "CONFIG_MAINBOARD_DIR=\"$VENDOR/$MAINBOARD\"" >> .config
echo "CONFIG_CBFS_PREFIX=\"$cbfs_prefix\"" >> .config
if [ "$PAYLOAD" != "/dev/null" ]; then
echo "# CONFIG_PAYLOAD_NONE is not set" >> .config
echo "CONFIG_PAYLOAD_ELF=y" >> .config
echo "CONFIG_FALLBACK_PAYLOAD_FILE=\"$PAYLOAD\"" >> .config
fi
if [ "$loglevel" != "default" ]; then
printf "(loglevel override) "
echo "CONFIG_MAXIMUM_CONSOLE_LOGLEVEL_$loglevel=y" >> .config
echo "CONFIG_MAXIMUM_CONSOLE_LOGLEVEL=$loglevel" >> .config
echo "CONFIG_DEFAULT_CONSOLE_LOGLEVEL_$loglevel=y" >> .config
echo "CONFIG_DEFAULT_CONSOLE_LOGLEVEL=$loglevel" >> .config
fi
if [ "$update" != "false" ]; then
printf "(update) "
echo "CONFIG_UPDATE_IMAGE=y" >> .config
fi
if [ "$ccache" = "true" ]; then
printf "(ccache enabled) "
echo "CONFIG_CCACHE=y" >> .config
fi
if [ "$scanbuild" = "true" ]; then
printf "(scan-build enabled) "
echo "CONFIG_SCANBUILD_ENABLE=y" >> .config
echo "CONFIG_SCANBUILD_REPORT_LOCATION=\"$TARGET/scan-build-results-tmp\"" >> .config
fi
fi
#yes "" | $MAKE oldconfig -j $cpus obj=${build_dir} objutil=$TARGET/sharedutils &> ${build_dir}/config.log
yes "" | $MAKE oldconfig obj=${build_dir} objutil=$TARGET/sharedutils &> ${build_dir}/config.log
ret=$?
mv .config.old $TARGET/${VENDOR}_${MAINBOARD}/config.in
if [ $ret -eq 0 ]; then
printf "ok; "
xml " <builddir>ok</builddir>"
xml " <log>"
xmlfile $build_dir/config.log
xml " </log>"
xml ""
return 0
else
# Does this ever happen?
printf "FAILED!\nLog excerpt:\n"
xml " <builddir>failed</builddir>"
xml " <log>"
xmlfile $build_dir/config.log
xml " </log>"
xml ""
tail -n $CONTEXT $build_dir/config.log 2> /dev/null || tail -$CONTEXT $build_dir/config.log
return 1
fi
}
function create_buildenv
{
VENDOR=$1
MAINBOARD=$2
CONFIG=$3
create_config $VENDOR $MAINBOARD $CONFIG
ret=$?
# Allow simple "make" in the target directory
MAKEFILE=$TARGET/${VENDOR}_${MAINBOARD}/Makefile
echo "# autogenerated makefile" > $MAKEFILE
echo "TOP=$ROOT" >> $MAKEFILE
echo "OUT=$TARGET/${VENDOR}_${MAINBOARD}" >> $MAKEFILE
echo "all:" >> $MAKEFILE
echo " cp config.build \$(TOP)/.config" >> $MAKEFILE
echo " cd \$(TOP); \$(MAKE) oldconfig obj=\$(OUT)" >> $MAKEFILE
echo " cd \$(TOP); \$(MAKE) obj=\$(OUT)" >> $MAKEFILE
return $ret
}
function compile_target
{
VENDOR=$1
MAINBOARD=$2
printf " Compiling image "
test "$cpus" == "" && printf "in parallel .. "
test "$cpus" == "1" && printf "on 1 cpu .. "
test 0$cpus -gt 1 && printf "on %d cpus in parallel .. " $cpus
CURR=$( pwd )
#stime=`perl -e 'print time();' 2>/dev/null || date +%s`
build_dir=$TARGET/${VENDOR}_${MAINBOARD}
eval $MAKE $silent -j $cpus obj=${build_dir} objutil=$TARGET/sharedutils \
&> ${build_dir}/make.log
ret=$?
mv .config ${build_dir}/config.build
mv .xcompile ${build_dir}/xcompile.build
cd $TARGET/${VENDOR}_${MAINBOARD}
etime=`perl -e 'print time();' 2>/dev/null || date +%s`
duration=$(( $etime - $stime ))
xml " <buildtime>${duration}s</buildtime>"
xml " <log>"
xmlfile make.log
xml " </log>"
if [ $ret -eq 0 ]; then
xml " <compile>ok</compile>"
printf "ok\n" > compile.status
printf "ok. (took ${duration}s)\n"
cd $CURR
return 0
else
xml " <compile>failed</compile>"
printf "FAILED after ${duration}s!\nLog excerpt:\n"
tail -n $CONTEXT make.log 2> /dev/null || tail -$CONTEXT make.log
cd $CURR
return 1
fi
}
function built_successfully
{
CURR=`pwd`
status="fail"
if [ -d "$TARGET/${VENDOR}_${MAINBOARD}" ]; then
cd $TARGET/${VENDOR}_${MAINBOARD}
if [ -r compile.status ] ; then
status=`cat compile.status`
fi
cd $CURR
fi
[ "$buildall" != "true" -a "$status" == "ok" ]
}
function build_broken
{
CURR=`pwd`
status="yes"
[ -r "$ROOT/src/mainboard/${VENDOR}/${MAINBOARD}/BROKEN" ] && status="no"
[ "$buildbroken" == "true" -o "$status" == "yes" ]
}
function build_target
{
VENDOR=$1
MAINBOARD=$2
CONFIG=$3
TARCH=$( architecture $VENDOR $MAINBOARD )
# Allow architecture override in an abuild.info file.
# This is used for the Motorola Sandpoint, which is not a real target
# but a skeleton target for the Sandpoint X3.
[ -r "$ROOT/src/mainboard/${VENDOR}/${MAINBOARD}/abuild.info" ] && \
source $ROOT/src/mainboard/${VENDOR}/${MAINBOARD}/abuild.info
# default setting
CC="${CROSS_COMPILE}gcc"
CROSS_COMPILE=""
found_crosscompiler=false
if which $TARCH-elf-gcc 2>/dev/null >/dev/null; then
# i386-elf target needs --divide, for i386-linux, that's the default
if [ "$TARCH" = "i386" ]; then
CC="$CC -Wa,--divide"
fi
CROSS_COMPILE="$TARCH-elf-"
CC=gcc
CROSS_TEXT=", using $CROSS_COMPILE$CC"
found_crosscompiler=true
fi
HOSTCC='gcc'
printf "Building $VENDOR/$MAINBOARD; "
xml "<mainboard>"
xml ""
xml " <vendor>$VENDOR</vendor>"
xml " <device>$MAINBOARD</device>"
xml ""
xml " <architecture>$TARCH</architecture>"
xml ""
if [ "$ARCH" = "$TARCH" -o $found_crosscompiler = true ]; then
printf "$TARCH: ok$CROSS_TEXT\n"
else
# FIXME this is basically the same as above.
found_crosscompiler=false
if [ "$ARCH" == amd64 -a "$TARCH" == i386 ]; then
CC="gcc -m32"
found_crosscompiler=true
fi
if [ "$ARCH" == ppc64 -a "$TARCH" == ppc ]; then
CC="gcc -m32"
found_crosscompiler=true
fi
if [ "$found_crosscompiler" == "false" -a "$TARCH" == ppc ];then
for prefix in powerpc-eabi- powerpc-linux- ppc_74xx- \
powerpc-7450-linux-gnu- powerpc-elf-; do
if ${prefix}gcc --version > /dev/null 2> /dev/null ; then
found_crosscompiler=true
CROSS_COMPILE=$prefix
fi
done
fi
# TBD: look for suitable cross compiler suite
# cross-$TARCH-gcc and cross-$TARCH-ld
# Check result:
if [ $found_crosscompiler == "false" ]; then
printf "$TARCH: skipped, we're $ARCH\n\n"
xml " <status>notbuilt</status>"
xml ""
xml "</mainboard>"
return 0
else
printf "$TARCH: ok, $ARCH using ${CROSS_COMPILE}gcc\n"
xml " <compiler>"
xml " <path>`which ${CROSS_COMPILE}gcc`</path>"
xml " <version>`${CROSS_COMPILE}gcc --version | head -1`</version>"
xml " </compiler>"
xml ""
fi
fi
CC=${CROSS_COMPILE}$CC
if [ "$stackprotect" = "true" ]; then
CC="$CC -fno-stack-protector"
fi
built_successfully $VENDOR $MAINBOARD && test $update = "false" && \
{
printf " ( mainboard/$VENDOR/$MAINBOARD previously ok )\n\n"
xml " <status>previouslyok</status>"
xml ""
xml "</mainboard>"
return 0
}
build_broken $VENDOR $MAINBOARD || \
{
printf " ( broken mainboard/$VENDOR/$MAINBOARD skipped )\n\n"
xml " <status>knownbroken</status>"
xml ""
xml "</mainboard>"
return 0
}
stime=`perl -e 'print time();' 2>/dev/null || date +%s`
create_buildenv $VENDOR $MAINBOARD $CONFIG
if [ $? -eq 0 -a $configureonly -eq 0 ]; then
if [ "$scanbuild" = "true" ]; then
rm -rf $TARGET/scan-build-results-tmp
fi
compile_target $VENDOR $MAINBOARD &&
xml " <status>ok</status>" ||
xml "<status>broken</status>"
if [ "$scanbuild" = "true" ]; then
rm -rf $TARGET/${VENDOR}_${MAINBOARD}-scanbuild
mv `dirname $TARGET/scan-build-results-tmp/*/index.html` $TARGET/${VENDOR}_${MAINBOARD}-scanbuild
fi
fi
# Not calculated here because we still print it in compile_target
#etime=`perl -e 'print time();' 2>/dev/null || date +%s`
#duration=$(( $etime - $stime ))
#xml " <buildtime>${duration}s</buildtime>"
xml ""
xml "</mainboard>"
printf "\n"
}
function test_target
{
VENDOR=$1
MAINBOARD=$2
if [ "$hwtest" != "true" ]; then
return 0
fi
# image does not exist. we silently skip the patch.
if [ ! -r "$TARGET/${VENDOR}_${MAINBOARD}/coreboot.rom" ]; then
return 0
fi
which curl &> /dev/null
if [ $? != 0 ]; then
printf "curl is not installed but required for test submission. skipping test.\n\n"
return 0
fi
CURR=`pwd`
if [ -r "$TARGET/${VENDOR}_${MAINBOARD}/tested" ]; then
printf "Testing image for board $VENDOR $MAINBOARD skipped (previously submitted).\n\n"
return 0
fi
# touch $TARGET/${VENDOR}_${MAINBOARD}/tested
printf "Submitting image for board $VENDOR $MAINBOARD to test system...\n"
curl -f -F "romfile=@$TARGET/${VENDOR}_${MAINBOARD}/coreboot.rom" \
-F "mode=abuild" -F "mainboard=${VENDOR}_${MAINBOARD}" -F "submit=Upload" \
"http://qa.coreboot.org/deployment/send.php"
printf "\n"
return 0
}
function remove_target
{
if [ "$remove" != "true" ]; then
return 0
fi
VENDOR=$1
MAINBOARD=$2
# Save the generated coreboot.rom file of each board.
if [ -r "$TARGET/${VENDOR}_${MAINBOARD}/coreboot.rom" ]; then
cp $TARGET/${VENDOR}_${MAINBOARD}/coreboot.rom \
${VENDOR}_${MAINBOARD}_coreboot.rom
fi
printf "Removing build dir for board $VENDOR $MAINBOARD...\n"
rm -rf $TARGET/${VENDOR}_${MAINBOARD}
return 0
}
function myhelp
{
printf "Usage: $0 [-v] [-a] [-b] [-r] [-t <vendor/board>] [-p <dir>] [lbroot]\n"
printf " $0 [-V|--version]\n"
printf " $0 [-h|--help]\n\n"
printf "Options:\n"
printf " [-v|--verbose] print more messages\n"
printf " [-a|--all] build previously succeeded ports as well\n"
printf " [-b|--broken] attempt to build ports that are known broken\n"
printf " [-r|--remove] remove output dir after build\n"
printf " [-t|--target <vendor/board>] attempt to build target vendor/board only\n"
printf " [-p|--payloads <dir>] use payloads in <dir> to build images\n"
printf " [-V|--version] print version number and exit\n"
printf " [-h|--help] print this help and exit\n"
printf " [-x|--xml] write xml log file \n"
printf " (defaults to $XMLFILE)\n"
printf " [-T|--test] submit image(s) to automated test system\n"
printf " [-c|--cpus <numcpus>] build on <numcpus> at the same time\n"
printf " [-s|--silent] omit compiler calls in logs\n"
printf " [-ns|--nostackprotect] use gcc -fno-stack-protector option\n"
printf " [-sb|--scan-build] use clang's static analyzer\n"
printf " [-y|--ccache] use ccache\n"
printf " [-C|--config] configure-only mode\n"
printf " [-l|--loglevel <num>] set loglevel\n"
printf " [-u|--update] update existing image\n"
printf " [-P|--prefix <name>] file name prefix in CBFS\n"
printf " [lbroot] absolute path to coreboot sources\n"
printf " (defaults to $ROOT)\n\n"
}
function myversion
{
cat << EOF
coreboot autobuild v$ABUILD_VERSION ($ABUILD_DATE)
Copyright (C) 2004 by Stefan Reinauer <stepan@openbios.org>
Copyright (C) 2006-2010 by coresystems GmbH <info@coresystems.de>
This program is free software; you may redistribute it under the terms
of the GNU General Public License. This program has absolutely no
warranty.
EOF
}
# default options
target=""
buildall=false
verbose=false
test -f util/sconfig/sconfig.l && ROOT=$( pwd )
test -f ../util/sconfig/sconfig.l && ROOT=$( cd ..; pwd )
test "$ROOT" = "" && ROOT=$( cd ../..; pwd )
# parse parameters.. try to find out whether we're running GNU getopt
getoptbrand="`getopt -V`"
if [ "${getoptbrand:0:6}" == "getopt" ]; then
# Detected GNU getopt that supports long options.
args=`getopt -l version,verbose,help,all,target:,broken,payloads:,test,cpus:,silent,xml,config,loglevel:,remove,prefix:,update,nostackprotect,scan-build,ccache Vvhat:bp:Tc:sxCl:rP:uy -- "$@"`
eval set "$args"
else
# Detected non-GNU getopt
args=`getopt Vvhat:bp:Tc:sxCl:rP:uy $*`
set -- $args
fi
if [ $? != 0 ]; then
myhelp
exit 1
fi
while true ; do
case "$1" in
-x|--xml) shift; mode=xml; rm -f $XMLFILE ;;
-t|--target) shift; target="$1"; shift;;
-a|--all) shift; buildall=true;;
-b|--broken) shift; buildbroken=true;;
-r|--remove) shift; remove=true; shift;;
-v|--verbose) shift; verbose=true; silent='V=1';;
-V|--version) shift; myversion; exit 0;;
-h|--help) shift; myversion; myhelp; exit 0;;
-p|--payloads) shift; payloads="$1"; shift;;
-T|--test) shift; hwtest=true;;
-c|--cpus) shift; cpus="$1"; test "$cpus" == "max" && cpus=""; shift;;
-s|--silent) shift; silent="-s";;
-ns|--nostackprotect) shift; stackprotect=true;;
-sb|--scan-build) shift; scanbuild=true;;
-y|--ccache) shift; ccache=true;;
-C|--config) shift; configureonly=1;;
-l|--loglevel) shift; loglevel="$1"; shift;;
-u|--update) shift; update="true";;
-P|--prefix) shift; cbfs_prefix="$1"; shift;;
--) shift; break;;
-*) printf "Invalid option\n\n"; myhelp; exit 1;;
*) break;;
esac
done
# /path/to/freebios2/
test -z "$1" || ROOT=$1
debug "ROOT=$ROOT"
xml '<?xml version="1.0" encoding="utf-8"?>'
xml '<abuild>'
if [ "$target" != "" ]; then
# build a single board
VENDOR=`printf $target|cut -f1 -d/`
MAINBOARD=`printf $target|cut -f2 -d/`
CONFIG=`printf $target|cut -f3 -d/`
if [ ! -r $ROOT/src/mainboard/$target ]; then
printf "No such target: $target\n"
xml '</abuild>'
exit 1
fi
build_target $VENDOR $MAINBOARD $CONFIG
test_target $VENDOR $MAINBOARD
else
# build all boards per default
for VENDOR in $( vendors ); do
for MAINBOARD in $( mainboards $VENDOR ); do
build_target $VENDOR $MAINBOARD
test_target $VENDOR $MAINBOARD
remove_target $VENDOR $MAINBOARD
done
done
fi
xml '</abuild>'