6d2cbb9e58
The full path to the passed/failed build lists needs to be specified. On the builders, the absolute path is passed in, which conflicted with the ${TOP} value, causing this to fail on the builders. When TOP was removed from the path, the builders worked correctly, but it failed when run locally. This fixes the path in either case. Change-Id: Ia4370f4a2b84991edccfc723a3136b88ca27db7d Signed-off-by: Martin Roth <martinroth@google.com> Reviewed-on: https://review.coreboot.org/20660 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net> Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org> Reviewed-by: Patrick Georgi <pgeorgi@google.com>
856 lines
25 KiB
Bash
Executable file
856 lines
25 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>
|
|
# (C) 2013-2014 Sage Electronic Engineering, LLC
|
|
# (C) 2014 Patrick Georgi <patrick@georgi-clan.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="Mar 28, 2017"
|
|
ABUILD_VERSION="0.10.03"
|
|
|
|
TOP=$PWD
|
|
|
|
# Where shall we place all the build trees?
|
|
TARGET=${COREBOOT_BUILD_DIR:-coreboot-builds}
|
|
XMLFILE=$TOP/abuild.xml
|
|
REAL_XMLFILE=$XMLFILE
|
|
|
|
export KCONFIG_OVERWRITECONFIG=1
|
|
|
|
# path to payload. Should be more generic
|
|
PAYLOAD=/dev/null
|
|
|
|
# get path to coreboot XGCC if it's not already set
|
|
if [ -z "$XGCCPATH" ]; then
|
|
XGCCPATH="${TOP}/util/crossgcc/xgcc/bin/"
|
|
fi
|
|
|
|
# Add XGCC to the path.
|
|
if [ -d "$XGCCPATH" ] && [[ ":$PATH:" != *":$XGCCPATH:"* ]]; then
|
|
PATH="$XGCCPATH:$PATH"
|
|
fi
|
|
|
|
# Lines of error context to be printed in FAILURE case
|
|
CONTEXT=12
|
|
|
|
# Configure-only mode
|
|
configureonly=0
|
|
|
|
# Did any board fail to build?
|
|
failed=0
|
|
|
|
# default: don't save checksums
|
|
checksum_file=""
|
|
|
|
# default: single CPU build
|
|
cpus=1
|
|
|
|
# change with -d <directory>
|
|
configdir="$TOP/configs"
|
|
|
|
# Timeless builds
|
|
TIMELESS=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 junit by -J
|
|
mode=text
|
|
|
|
# quiet mode: only print pass, failure, and 'skipped' messages
|
|
quiet=false
|
|
|
|
# clang mode enabled by -sb option.
|
|
scanbuild=false
|
|
|
|
# Mark whether abuild was called recursively
|
|
recursive=false
|
|
|
|
trap interrupt INT
|
|
|
|
function interrupt
|
|
{
|
|
printf "\n%s: execution interrupted manually.\n" "$0"
|
|
if [ "$mode" == "junit" ]; then
|
|
printf "%s: deleting incomplete xml output file.\n" "$0"
|
|
fi
|
|
exit 1
|
|
}
|
|
|
|
function debug
|
|
{
|
|
test "$verbose" == "true" && echo "$*"
|
|
}
|
|
|
|
function junit
|
|
{
|
|
test "$mode" == "junit" && echo "$*" >> "$XMLFILE"
|
|
return 0
|
|
}
|
|
|
|
function junitfile
|
|
{
|
|
test "$mode" == "junit" && {
|
|
printf '<![CDATA[\n'
|
|
cat "$1"
|
|
printf ']]>\n'
|
|
} >> "$XMLFILE"
|
|
}
|
|
|
|
# Return mainboard descriptors.
|
|
# By default all mainboards are listed, but when passing a two-level path
|
|
# below src/mainboard, such as emulation/qemu-i440fx, or emulation/*, it
|
|
# returns all board descriptors in that hierarchy.
|
|
function get_mainboards
|
|
{
|
|
local search_space=${1-*/*}
|
|
# shellcheck disable=SC2086
|
|
grep -h "^[[:space:]]*config\>[[:space:]]*\<BOARD_" \
|
|
${ROOT}/src/mainboard/${search_space}/Kconfig.name 2>/dev/null | \
|
|
sed "s,^.*\<BOARD_\([A-Z0-9_]*\)\>.*$,\1,"
|
|
}
|
|
|
|
# Given a mainboard descriptor, return its directory below src/mainboard
|
|
function mainboard_directory
|
|
{
|
|
local MAINBOARD=$1
|
|
|
|
# shellcheck disable=SC2086
|
|
grep -l "^[[:space:]]*config\>[[:space:]]*\<BOARD_${MAINBOARD}\>" \
|
|
${ROOT}/src/mainboard/*/*/Kconfig.name | \
|
|
sed "s:^$ROOT/src/mainboard/\(.*\)/Kconfig.name$:\1:"
|
|
}
|
|
|
|
# Given a mainboard descriptor, return its vendor (CONFIG_VENDOR_*)
|
|
function mainboard_vendor
|
|
{
|
|
local MAINBOARD=$1
|
|
local kconfig_file
|
|
|
|
# shellcheck disable=SC2086
|
|
kconfig_file=$( \
|
|
grep -l "^[[:space:]]*config\>[[:space:]]*\<BOARD_${MAINBOARD}\>" \
|
|
${ROOT}/src/mainboard/*/*/Kconfig.name | \
|
|
sed "s:^\(${ROOT}/src/mainboard/.*\)/.*/\(Kconfig.name\)$:\1/\2:" )
|
|
if [ ! -f "$kconfig_file" ]; then
|
|
exit 1
|
|
fi
|
|
grep "^[[:space:]]*config\>[[:space:]]*\<VENDOR_" "$kconfig_file" | \
|
|
sed "s,^.*\<VENDOR_\([A-Z0-9_]*\)\>.*$,\1,"
|
|
}
|
|
|
|
# Accepts directory names (eg. emulation/qemu-i440fx) and mainboard
|
|
# descriptors (eg. EMULATION_QEMU_X86_I440F} and returns the latter
|
|
# format.
|
|
# If a directory contains multiple boards, returns them all.
|
|
function normalize_target
|
|
{
|
|
local targets
|
|
|
|
targets=$(get_mainboards "$1")
|
|
if [ -n "$targets" ]; then
|
|
echo "$targets"
|
|
return
|
|
fi
|
|
|
|
targets=$(echo "$1" | tr ',' ' ')
|
|
for i in $targets; do
|
|
if [ -n "$(mainboard_directory "$i")" ]; then
|
|
echo "$i"
|
|
else
|
|
echo "$i is not a valid target" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
# shellcheck disable=SC2129
|
|
function create_config
|
|
{
|
|
local BUILD_NAME=$1
|
|
local build_dir=$2
|
|
local board_srcdir
|
|
|
|
local config_file="${build_dir}/config.build"
|
|
board_srcdir="$(mainboard_directory "${BUILD_NAME}")"
|
|
|
|
mkdir -p "${build_dir}"
|
|
mkdir -p "$TARGET/sharedutils"
|
|
|
|
if [ "$quiet" == "false" ]; then echo " Creating config file for $BUILD_NAME..."; fi
|
|
echo "CONFIG_VENDOR_$(mainboard_vendor "${BUILD_NAME}")=y" > "${config_file}"
|
|
echo "CONFIG_BOARD_${BUILD_NAME}=y" >> "${config_file}"
|
|
grep "select[\t ]*ARCH" "${ROOT}/src/mainboard/${board_srcdir}/Kconfig" | \
|
|
sed "s,^.*\(ARCH_.*\)[^A-Z0-9_]*,CONFIG_\1=y," >> "${config_file}"
|
|
echo "CONFIG_MAINBOARD_DIR=\"${board_srcdir}\"" >> "${config_file}"
|
|
|
|
update_config "$BUILD_NAME" "$build_dir" "$config_file"
|
|
|
|
ret=$?
|
|
if [ $ret -eq 0 ]; then
|
|
if [ "$quiet" == "false" ]; then echo " $BUILD_NAME config created."; fi
|
|
return 0
|
|
else
|
|
# Does this ever happen?
|
|
if [ "$quiet" == "false" ]; then printf "%s config creation FAILED!\nLog excerpt:\n" "$BUILD_NAME"; fi
|
|
tail -n $CONTEXT "$build_dir/config.log" 2> /dev/null || tail -$CONTEXT "$build_dir/config.log"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
function update_config
|
|
{
|
|
local BUILD_NAME=$1
|
|
local build_dir=$2
|
|
local config_file=$3
|
|
|
|
local PAYLOAD
|
|
local defconfig_file
|
|
defconfig_file=${build_dir}/config.$(echo "${BUILD_NAME}" | tr '[:upper:]' '[:lower:]').default
|
|
|
|
# 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 [BOARD]
|
|
# the script returns an absolute path to the payload binary.
|
|
|
|
if [ -f "$payloads/payload.sh" ]; then
|
|
PAYLOAD=$(sh "$payloads/payload.sh" "$BUILD_NAME")
|
|
local PAYLOAD_OK=$?
|
|
if [ $PAYLOAD_OK -gt 0 ]; then
|
|
echo "problem with payload"
|
|
exit 1
|
|
fi
|
|
if [ "$quiet" == "false" ]; then printf "Using payload %s\n" "$PAYLOAD"; fi
|
|
elif [ "$payloads" = "none" ]; then
|
|
PAYLOAD=none
|
|
fi
|
|
|
|
if [ "$PAYLOAD" = "none" ]; then
|
|
{
|
|
echo "CONFIG_PAYLOAD_NONE=y"
|
|
echo "# CONFIG_PAYLOAD_SEABIOS is not set"
|
|
echo "# CONFIG_PAYLOAD_ELF is not set"
|
|
echo "# CONFIG_PAYLOAD_BAYOU is not set"
|
|
echo "# CONFIG_PAYLOAD_FILO is not set"
|
|
echo "# CONFIG_PAYLOAD_GRUB2 is not set"
|
|
echo "# CONFIG_PAYLOAD_OPENBIOS is not set"
|
|
echo "# CONFIG_PAYLOAD_DEPTHCHARGE is not set"
|
|
echo "# CONFIG_PAYLOAD_UBOOT is not set"
|
|
echo "# CONFIG_PAYLOAD_TIANOCORE is not set"
|
|
} >> "${config_file}"
|
|
elif [ "$PAYLOAD" != "/dev/null" ]; then
|
|
{
|
|
echo "# CONFIG_PAYLOAD_NONE is not set"
|
|
echo "# CONFIG_PAYLOAD_SEABIOS is not set"
|
|
echo "CONFIG_PAYLOAD_ELF=y"
|
|
echo "CONFIG_PAYLOAD_FILE=\"$PAYLOAD\""
|
|
} >> "${config_file}"
|
|
fi
|
|
|
|
if [ "$quiet" == "false" ]; then echo " $MAINBOARD ($customizing)"; fi
|
|
# shellcheck disable=SC2059
|
|
printf "$configoptions" >> "${config_file}"
|
|
|
|
yes "" 2>/dev/null | $MAKE oldconfig "$verboseopt" "DOTCONFIG=${config_file}" "obj=${build_dir}" "objutil=$TARGET/sharedutils" &> "${build_dir}/config.log" ; \
|
|
CONFIG_OK=$?
|
|
if [ $CONFIG_OK -eq 0 ]; then
|
|
$MAKE savedefconfig "$verboseopt" DEFCONFIG="${defconfig_file}" DOTCONFIG="${config_file}" obj="${build_dir}" objutil="$TARGET/sharedutils" &>> "${build_dir}/config.log"
|
|
return $?
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# shellcheck disable=SC2129
|
|
function create_buildenv
|
|
{
|
|
local BUILD_NAME=$1
|
|
local build_dir=$2
|
|
local config_file=$3
|
|
|
|
if [ -z "$config_file" ]; then
|
|
create_config "$BUILD_NAME" "$build_dir"
|
|
else
|
|
local new_config_file="${build_dir}/config.build"
|
|
cp "$config_file" "$new_config_file"
|
|
update_config "$BUILD_NAME" "$build_dir" "$new_config_file"
|
|
fi
|
|
local ret=$?
|
|
|
|
# Allow simple "make" in the target directory
|
|
local MAKEFILE=$TARGET/${BUILD_NAME}/Makefile
|
|
echo "# autogenerated" > "$MAKEFILE"
|
|
echo "TOP=$ROOT" >> "$MAKEFILE"
|
|
echo "BUILD=$TARGET" >> "$MAKEFILE"
|
|
echo "OBJ=\$(BUILD)/${MAINBOARD}" >> "$MAKEFILE"
|
|
echo "OBJUTIL=\$(BUILD)/sharedutils" >> "$MAKEFILE"
|
|
echo "all:" >> "$MAKEFILE"
|
|
echo " @cp -a config.h config.h.bak" >> "$MAKEFILE"
|
|
echo " @cd \$(TOP); \$(MAKE) oldconfig DOTCONFIG=\$(OBJ)/config.build objutil=\$(OBJUTIL) obj=\$(OBJ)" >> "$MAKEFILE"
|
|
echo " @tail -n+6 config.h > config.new; tail -n+6 config.h.bak > config.old" >> "$MAKEFILE"
|
|
echo " @cmp -s config.new config.old && cp -a config.h.bak config.h || echo \"Config file changed\"" >> "$MAKEFILE"
|
|
echo " @rm config.h.bak config.new config.old" >> "$MAKEFILE"
|
|
echo " @cd \$(TOP); \$(MAKE) DOTCONFIG=\$(OBJ)/config.build objutil=\$(OBJUTIL) obj=\$(OBJ)" >> "$MAKEFILE"
|
|
|
|
return $ret
|
|
}
|
|
|
|
function check_config
|
|
{
|
|
local BUILD_DIR="$1"
|
|
local TEST_TYPE="$2"
|
|
local TEST_STRING="$3"
|
|
|
|
local CONFIG_FILE="$BUILD_DIR/config.build"
|
|
local CONFIG_LOG="$BUILD_DIR/config.log"
|
|
|
|
if ! grep -q "$TEST_STRING" "$CONFIG_FILE"; then
|
|
echo "config file: $CONFIG_FILE has incorrect $TEST_TYPE"
|
|
echo "Error: Expected '$TEST_STRING' in config file." >> "$CONFIG_LOG"
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
function compile_target
|
|
{
|
|
local BUILD_NAME=$1
|
|
|
|
if [ "$quiet" == "false" ]; then echo " Compiling $MAINBOARD image$cpuconfig..."; fi
|
|
|
|
CURR=$( pwd )
|
|
#stime=`perl -e 'print time();' 2>/dev/null || date +%s`
|
|
eval $BUILDPREFIX $MAKE "$verboseopt" DOTCONFIG="${build_dir}/config.build" obj="${build_dir}" objutil="$TARGET/sharedutils" BUILD_TIMELESS=$TIMELESS \
|
|
&> "${build_dir}/make.log" ; \
|
|
MAKE_FAILED=$?
|
|
cp .xcompile "${build_dir}/xcompile.build"
|
|
cd "${build_dir}" || return $?
|
|
|
|
etime=$(perl -e 'print time();' 2>/dev/null || date +%s)
|
|
duration=$(( etime - stime ))
|
|
junit " <testcase classname='board${testclass/#/.}' name='$BUILD_NAME' time='$duration' >"
|
|
|
|
if [ $MAKE_FAILED -eq 0 ]; then
|
|
junit "<system-out>"
|
|
junitfile make.log
|
|
junit "</system-out>"
|
|
printf "ok\n" > compile.status
|
|
printf "%s built successfully. (took %ss)\n" "$BUILD_NAME" "${duration}"
|
|
echo "$BUILD_NAME" >> "$PASSED_BOARDS"
|
|
else
|
|
junit "<failure type='BuildFailed'>"
|
|
junitfile make.log
|
|
junit "</failure>"
|
|
printf "failed\n" > compile.status
|
|
printf "%s build FAILED after %ss!\nLog excerpt:\n" "$BUILD_NAME" "${duration}"
|
|
tail -n $CONTEXT make.log 2> /dev/null || tail -$CONTEXT make.log
|
|
echo "$BUILD_NAME - Log: ${TOP}/${build_dir}/make.log" >> "$FAILED_BOARDS"
|
|
failed=1
|
|
fi
|
|
cd "$CURR" || return $?
|
|
if [ -n "$checksum_file" ]; then
|
|
sha256sum "${build_dir}/coreboot.rom" >> "${checksum_file}_platform"
|
|
sort "${build_dir}/config.h" | grep CONFIG_ > "${build_dir}/config.h.sorted"
|
|
sha256sum "${build_dir}/config.h.sorted" >> "${checksum_file}_config"
|
|
fi
|
|
if [ "$clean_work" = "true" ]; then
|
|
rm -rf "${build_dir}"
|
|
fi
|
|
return $MAKE_FAILED
|
|
}
|
|
|
|
function build_config
|
|
{
|
|
local MAINBOARD=$1
|
|
local build_dir=$2
|
|
local BUILD_NAME=$3
|
|
local config_file=$4
|
|
local board_srcdir
|
|
local ret
|
|
|
|
board_srcdir=$(mainboard_directory "${MAINBOARD}")
|
|
|
|
if [ "$(cat "${build_dir}/compile.status" 2>/dev/null)" = "ok" ] && \
|
|
[ "$buildall" = "false" ]; then
|
|
echo "Skipping $BUILD_NAME; (already successful)"
|
|
return
|
|
fi
|
|
|
|
export HOSTCC='gcc'
|
|
|
|
if [ "$chromeos" = true ] && [ "$(grep -c "^[[:space:]]*select[[:space:]]*MAINBOARD_HAS_CHROMEOS\>" "${ROOT}/src/mainboard/${board_srcdir}/Kconfig")" -eq 0 ]; then
|
|
echo "${BUILD_NAME} doesn't support Chrome OS, skipping."
|
|
return
|
|
fi
|
|
|
|
if [ -f "src/mainboard/${board_srcdir}/abuild.disabled" ]; then
|
|
echo "${BUILD_NAME} disabled:"
|
|
cat "src/mainboard/${board_srcdir}/abuild.disabled"
|
|
return
|
|
fi
|
|
|
|
if [ "$quiet" == "false" ]; then echo "Building $BUILD_NAME"; fi
|
|
mkdir -p "$TARGET/${BUILD_NAME}" "$TARGET/abuild"
|
|
ABSPATH="$(cd "$TARGET/abuild" && pwd)"
|
|
XMLFILE="$ABSPATH/${BUILD_NAME}.xml"
|
|
rm -f "${XMLFILE}"
|
|
|
|
stime=$(perl -e 'print time();' 2>/dev/null || date +%s)
|
|
create_buildenv "$BUILD_NAME" "$build_dir" "$config_file"
|
|
local BUILDENV_CREATED=$?
|
|
|
|
check_config "$build_dir" "mainboard" "CONFIG_BOARD_${MAINBOARD}=y"
|
|
local MAINBOARD_OK=$?
|
|
|
|
check_config "$build_dir" "vendor" "CONFIG_VENDOR_$(mainboard_vendor "${MAINBOARD}")=y"
|
|
local VENDOR_OK=$?
|
|
|
|
if [ $BUILDENV_CREATED -ne 0 ] || [ $MAINBOARD_OK -ne 0 ] || [ $VENDOR_OK -ne 0 ]; then
|
|
junit " <testcase classname='board${testclass/#/.}' name='$BUILD_NAME' >"
|
|
|
|
junit "<failure type='BuildFailed'>"
|
|
junitfile "$build_dir/config.log"
|
|
junit "</failure>"
|
|
printf "failed\n" > compile.status
|
|
printf "%s build configuration FAILED!\nLog excerpt:\n" "$BUILD_NAME"
|
|
tail -n $CONTEXT "$build_dir/config.log" 2> /dev/null || tail -$CONTEXT "$build_dir/config.log"
|
|
|
|
junit "</testcase>"
|
|
echo "$BUILD_NAME - Log: ${TOP}/$build_dir/config.log" >> "$FAILED_BOARDS"
|
|
return
|
|
fi
|
|
|
|
required_arches=$(egrep "^CONFIG_ARCH_(BOOTBLOCK|R.MSTAGE|VERSTAGE)" "$TARGET/${BUILD_NAME}/config.build" | \
|
|
sed "s,^CONFIG_ARCH_[^_]*_\([^=]*\)=.*$,\1," |sort -u |tr 'A-Z\n\r' 'a-z ')
|
|
# shellcheck disable=SC2016,SC2059
|
|
missing_arches=$(printf 'include .xcompile\nall: ; @echo $(foreach arch,'"$required_arches"',$(if $(filter $(arch),$(SUBARCH_SUPPORTED)),,$(arch)))' | make --no-print-directory -f -)
|
|
if [ -n "$missing_arches" ]; then
|
|
printf "skipping %s because we're missing compilers for (%s)\n" "$BUILD_NAME" "$missing_arches"
|
|
return
|
|
fi
|
|
|
|
if [ $BUILDENV_CREATED -eq 0 ] && [ $configureonly -eq 0 ]; then
|
|
BUILDPREFIX=
|
|
if [ "$scanbuild" = "true" ]; then
|
|
scanbuild_out=$TARGET/${BUILD_NAME}-scanbuild
|
|
rm -rf "${scanbuild_out}"
|
|
BUILDPREFIX="scan-build -o ${scanbuild_out}tmp"
|
|
fi
|
|
compile_target "${BUILD_NAME}"
|
|
if [ "$scanbuild" = "true" ]; then
|
|
mv "${scanbuild_out}"tmp/* "${scanbuild_out}"
|
|
rmdir "${scanbuild_out}tmp"
|
|
fi
|
|
fi
|
|
|
|
junit "</testcase>"
|
|
}
|
|
|
|
# One target may build several configs
|
|
function build_target
|
|
{
|
|
local MAINBOARD=$1
|
|
local MAINBOARD_LC
|
|
MAINBOARD_LC=$(echo "$MAINBOARD" | tr '[:upper:]' '[:lower:]')
|
|
|
|
# look for config files in the config directory that match the boardname
|
|
if [ -n "$( find "$configdir" -maxdepth 1 -name "config.${MAINBOARD_LC}*" -print -quit )" ]; then
|
|
for config in "$configdir/config.${MAINBOARD_LC}"*; do
|
|
BUILD_NAME="${config##*/}"
|
|
BUILD_NAME="${BUILD_NAME##config.}"
|
|
BUILD_NAME=$(echo "${BUILD_NAME}" | tr '[:lower:]' '[:upper:]')
|
|
echo "Building config $BUILD_NAME"
|
|
build_dir=$TARGET/${BUILD_NAME}
|
|
build_config "$MAINBOARD" "$build_dir" "$BUILD_NAME" "$config"
|
|
remove_target "$BUILD_NAME"
|
|
|
|
done
|
|
else
|
|
echo "Building board $MAINBOARD (using default config)"
|
|
build_dir=$TARGET/${MAINBOARD}
|
|
|
|
build_config "$MAINBOARD" "$build_dir" "$MAINBOARD"
|
|
remove_target "$MAINBOARD"
|
|
fi
|
|
|
|
}
|
|
|
|
function remove_target
|
|
{
|
|
if [ "$remove" != "true" ]; then
|
|
return
|
|
fi
|
|
|
|
local BUILD_NAME=$1
|
|
|
|
# Save the generated coreboot.rom file of each board.
|
|
if [ -r "$TARGET/${BUILD_NAME}/coreboot.rom" ]; then
|
|
cp "$TARGET/${BUILD_NAME}/coreboot.rom" \
|
|
"${BUILD_NAME}_coreboot.rom"
|
|
fi
|
|
|
|
echo "Removing build dir for $BUILD_NAME..."
|
|
rm -rf "${TARGET:?}/${BUILD_NAME}"
|
|
|
|
return
|
|
}
|
|
|
|
function myhelp
|
|
{
|
|
cat << __END_OF_HELP
|
|
Usage: $0 [options]
|
|
$0 [-V|--version]
|
|
$0 [-h|--help]
|
|
|
|
Options:\n"
|
|
[-a|--all] Build previously succeeded ports as well
|
|
[-B|--blobs] Allow using binary files
|
|
[--checksum <path/basefile>] Store checksums at path/basefile
|
|
[-c|--cpus <numcpus>] Build on <numcpus> at the same time
|
|
[-C|--config] Configure-only mode
|
|
[-d|--dir <dir>] Directory containing config files
|
|
[-J|--junit] Write JUnit formatted xml log file
|
|
[-K|--kconfig <name>] Prepend file to generated Kconfig
|
|
[-l|--loglevel <num>] Set loglevel
|
|
[-L|--clang] Use clang
|
|
[-o|--outdir <path>] Store build results in path
|
|
(defaults to $TARGET)
|
|
[-p|--payloads <dir>] Use payloads in <dir> to build images
|
|
[-P|--prefix <name>] File name prefix in CBFS
|
|
[-q|--quiet] Print fewer messages
|
|
[-r|--remove] Remove output dir after build
|
|
[-R|--root <path>] Absolute path to coreboot sources
|
|
(defaults to $ROOT)
|
|
[--scan-build] Use clang's static analyzer
|
|
[--timeless] Generate timeless builds
|
|
[-t|--target <vendor/board>] Attempt to build target vendor/board only
|
|
[-T|--test] Submit image(s) to automated test system
|
|
[-u|--update] Update existing image
|
|
[-v|--verbose] Print more messages
|
|
[-x|--chromeos] Build with CHROMEOS enabled
|
|
Skip boards without Chrome OS support
|
|
[-X|--xmlfile <name>] Set JUnit XML log file filename
|
|
(defaults to $XMLFILE)
|
|
[-y|--ccache] Use ccache
|
|
[-z|--clean] Remove build results when finished
|
|
|
|
[-V|--version] Print version number and exit
|
|
[-h|--help] Print this help and exit
|
|
|
|
[-s|--silent] obsolete
|
|
__END_OF_HELP
|
|
}
|
|
|
|
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 )
|
|
|
|
# Look if we have getopt. If not, build it.
|
|
export PATH=$PATH:util/abuild
|
|
getopt - > /dev/null 2>/dev/null || gcc -o util/abuild/getopt util/abuild/getopt.c
|
|
|
|
# Save command line for xargs parallelization.
|
|
cmdline=("$@")
|
|
|
|
# parse parameters.. try to find out whether we're running GNU getopt
|
|
getoptbrand="$(getopt -V)"
|
|
|
|
# shellcheck disable=SC2086
|
|
if [ "${getoptbrand:0:6}" == "getopt" ]; then
|
|
# Detected GNU getopt that supports long options.
|
|
args=$(getopt -l version,verbose,quiet,help,all,target:,payloads:,cpus:,silent,junit,config,loglevel:,remove,prefix:,update,scan-build,ccache,blobs,clang,clean,outdir:,chromeos,xmlfile:,kconfig:,dir:,root:,recursive,checksum:,timeless -o Vvqhat:p:c:sJCl:rP:uyBLzo:xX:K:d:R:I -- "$@") || exit 1
|
|
eval set -- $args
|
|
retval=$?
|
|
else
|
|
# Detected non-GNU getopt
|
|
args=$(getopt Vvqhat:p:c:sJCl:rP:uyBLzo:xX:K:d:R:I "$@")
|
|
set -- $args
|
|
retval=$?
|
|
fi
|
|
|
|
if [ $retval != 0 ]; then
|
|
myhelp
|
|
exit 1
|
|
fi
|
|
|
|
chromeos=false
|
|
clean_work=false
|
|
verboseopt='V=0'
|
|
customizing=""
|
|
configoptions=""
|
|
# testclass needs to be undefined if not used for variable expansion to work
|
|
unset testclass
|
|
while true ; do
|
|
case "$1" in
|
|
-J|--junit) shift; mode=junit; rm -f "$XMLFILE" ;;
|
|
-t|--target) shift; target="$1"; shift;;
|
|
-a|--all) shift; buildall=true;;
|
|
-d|--dir) shift; configdir="$1"; shift;;
|
|
-r|--remove) shift; remove=true;;
|
|
-v|--verbose) shift; verbose=true; verboseopt='V=1';;
|
|
-q|--quiet) shift; quiet=true;;
|
|
-V|--version) shift; myversion; exit 0;;
|
|
-h|--help) shift; myversion; myhelp; exit 0;;
|
|
-p|--payloads) shift; payloads="$1"; shift;;
|
|
-R|--root) shift; ROOT="$1"; shift;;
|
|
-c|--cpus) shift
|
|
export MAKEFLAGS="-j $1"
|
|
cpus=$1
|
|
test "$MAKEFLAGS" == "-j max" && export MAKEFLAGS="-j" && cpuconfig=" in parallel"
|
|
test "$1" == "1" && cpuconfig=" on 1 cpu"
|
|
expr "$1" : '-\?[0-9]\+$' > /dev/null && test "0$1" -gt 1 && cpuconfig=" on $1 cpus in parallel"
|
|
shift;;
|
|
# obsolete option
|
|
-s|--silent) shift;;
|
|
--scan-build) shift
|
|
scanbuild=true
|
|
customizing="${customizing}, scan-build"
|
|
;;
|
|
-y|--ccache) shift
|
|
customizing="${customizing}, ccache"
|
|
configoptions="${configoptions}CONFIG_CCACHE=y\n"
|
|
;;
|
|
-C|--config) shift; configureonly=1;;
|
|
-l|--loglevel) shift
|
|
customizing="${customizing}, loglevel $1"
|
|
configoptions="${configoptions}CONFIG_DEFAULT_CONSOLE_LOGLEVEL_$1=y\n"
|
|
configoptions="${configoptions}CONFIG_DEFAULT_CONSOLE_LOGLEVEL=$1\n"
|
|
shift;;
|
|
-u|--update) shift
|
|
customizing="${customizing}, update"
|
|
configoptions="${configoptions}CONFIG_UPDATE_IMAGE=y\n"
|
|
;;
|
|
-P|--prefix) shift
|
|
customizing="${customizing}, cbfs prefix $1"
|
|
configoptions="${configoptions}CONFIG_CBFS_PREFIX=\"$1\""
|
|
shift;;
|
|
-B|--blobs) shift
|
|
customizing="${customizing}, blobs"
|
|
configoptions="${configoptions}CONFIG_USE_BLOBS=y\n"
|
|
;;
|
|
-L|--clang) shift
|
|
customizing="${customizing}, clang"
|
|
configoptions="${configoptions}CONFIG_COMPILER_LLVM_CLANG=y\n# CONFIG_COMPILER_GCC is not set\n"
|
|
;;
|
|
-z|--clean) shift
|
|
customizing="${customizing}, clean"
|
|
clean_work=true
|
|
;;
|
|
-o|--outdir) shift
|
|
TARGET=$1; shift
|
|
;;
|
|
-x|--chromeos) shift
|
|
chromeos=true
|
|
testclass=chromeos
|
|
customizing="${customizing}, chrome os"
|
|
configoptions="${configoptions}CONFIG_CHROMEOS=y\n"
|
|
;;
|
|
-X|--xmlfile) shift; XMLFILE=$1; REAL_XMLFILE=$1; shift;;
|
|
-I|--recursive) shift; recursive=true;;
|
|
-K|--kconfig) shift
|
|
testclass="$(basename "$1" | tr '.' '_' )"
|
|
customizing="${customizing}, $1 config"
|
|
configoptions="$(cat "$1")${configoptions}\n"
|
|
shift;;
|
|
--checksum) shift; checksum_file="$1"; shift;;
|
|
--timeless) shift; TIMELESS=1;;
|
|
--) shift; break;;
|
|
-*) printf "Invalid option '%s'\n\n" "$1"; myhelp; exit 1;;
|
|
*) break;;
|
|
esac
|
|
done
|
|
if [ -n "$1" ]; then
|
|
printf "Invalid option '%s'\n\n" "$1"; myhelp; exit 1;
|
|
fi
|
|
|
|
if [ -z "$TARGET" ] || [ "$TARGET" = "/" ]; then
|
|
echo "Please specify a valid, non-root build directory."
|
|
exit 1
|
|
fi
|
|
|
|
customizing=$(echo "$customizing" | cut -c3-)
|
|
if [ "$customizing" = "" ]; then
|
|
customizing="default configuration"
|
|
fi
|
|
|
|
FAILED_BOARDS="${COREBOOT_BUILD_DIR:-${TOP}/coreboot-builds}/failed_boards"
|
|
PASSED_BOARDS="${COREBOOT_BUILD_DIR:-${TOP}/coreboot-builds}/passing_boards"
|
|
|
|
if [ "$recursive" = "false" ]; then
|
|
rm -f "$FAILED_BOARDS" "$PASSED_BOARDS"
|
|
fi
|
|
|
|
USE_XARGS=0
|
|
if [ "$cpus" != "1" ]; then
|
|
# Limit to 32 parallel builds for now.
|
|
# Thrashing all caches because we run
|
|
# 160 abuilds in parallel is no fun.
|
|
if [ "$cpus" = "max" ]; then
|
|
cpus=32
|
|
fi
|
|
# Test if xargs supports the non-standard -P flag
|
|
# FIXME: disabled until we managed to eliminate all the make(1) quirks
|
|
echo | xargs -P ${cpus:-0} -n 1 echo 2>/dev/null >/dev/null && USE_XARGS=1
|
|
fi
|
|
|
|
if [ "$USE_XARGS" = "0" ]; then
|
|
test "$MAKEFLAGS" == "" && test "$cpus" != "" && export MAKEFLAGS="-j $cpus"
|
|
build_targets()
|
|
{
|
|
local targets=${*-$(get_mainboards)}
|
|
for MAINBOARD in $targets; do
|
|
build_target "${MAINBOARD}"
|
|
done
|
|
}
|
|
else
|
|
build_targets()
|
|
{
|
|
local ABSPATH
|
|
local stime
|
|
local etime
|
|
local num_targets
|
|
local cpus_per_target
|
|
|
|
local targets=${*-$(get_mainboards)}
|
|
# seed shared utils
|
|
TMPCFG=$(mktemp)
|
|
printf "%s" "$configoptions" > "$TMPCFG"
|
|
$MAKE -j "$cpus" DOTCONFIG="$TMPCFG" obj="$TARGET/temp" objutil="$TARGET/sharedutils" allnoconfig
|
|
printf "%s" "$configoptions" >> "$TMPCFG"
|
|
yes "" 2>/dev/null | $MAKE -j "$cpus" DOTCONFIG="$TMPCFG" obj="$TARGET/temp" objutil="$TARGET/sharedutils" oldconfig 2>/dev/null |head > /dev/null
|
|
BUILDPREFIX=
|
|
if [ "$scanbuild" = "true" ]; then
|
|
scanbuild_out=$TARGET/sharedutils-scanbuild
|
|
rm -rf "${scanbuild_out}"
|
|
BUILDPREFIX="scan-build -o ${scanbuild_out}tmp"
|
|
fi
|
|
mkdir -p "$TARGET/abuild"
|
|
ABSPATH="$(cd "$TARGET/abuild" && pwd)"
|
|
local XMLFILE="$ABSPATH/__util.xml"
|
|
rm -f "${XMLFILE}"
|
|
stime=$(perl -e 'print time();' 2>/dev/null || date +%s)
|
|
$BUILDPREFIX $MAKE -j "$cpus" DOTCONFIG="$TMPCFG" obj="$TARGET/temp" objutil="$TARGET/sharedutils" tools > "$TARGET/sharedutils/make.log" 2>&1
|
|
local ret=$?
|
|
etime=$(perl -e 'print time();' 2>/dev/null || date +%s)
|
|
local duration=$(( etime - stime ))
|
|
|
|
junit " <testcase classname='util' name='all' time='$duration' >"
|
|
if [ $ret -eq 0 ]; then
|
|
junit "<system-out>"
|
|
junitfile "$TARGET/sharedutils/make.log"
|
|
junit "</system-out>"
|
|
junit "</testcase>"
|
|
else
|
|
junit "<failure type='BuildFailed'>"
|
|
junitfile "$TARGET/sharedutils/make.log"
|
|
junit "</failure>"
|
|
junit "</testcase>"
|
|
echo "Shared Utilities - Log: $TARGET/sharedutils/make.log" >> "$FAILED_BOARDS"
|
|
return
|
|
fi
|
|
|
|
if [ "$scanbuild" = "true" ]; then
|
|
mv "${scanbuild_out}tmp/"* "${scanbuild_out}"
|
|
rmdir "${scanbuild_out}tmp"
|
|
fi
|
|
rm -rf "$TARGET/temp" "$TMPCFG"
|
|
num_targets=$(wc -w <<<"$targets")
|
|
cpus_per_target=$(((${cpus:-1} + num_targets - 1) / num_targets))
|
|
echo "$targets" | xargs -P ${cpus:-0} -n 1 "$0" "${cmdline[@]}" -I -c "$cpus_per_target" -t
|
|
}
|
|
fi
|
|
|
|
debug "ROOT=$ROOT"
|
|
|
|
junit '<?xml version="1.0" encoding="utf-8"?>'
|
|
junit '<testsuite>'
|
|
|
|
if [ "$target" != "" ]; then
|
|
# build a single board
|
|
MAINBOARD=$(normalize_target "${target}")
|
|
if [ -z "${MAINBOARD}" ]; then
|
|
printf "No such target: %s\n" "$target"
|
|
exit 1
|
|
fi
|
|
build_srcdir="$(mainboard_directory "${MAINBOARD}")"
|
|
if [ "$(echo "${MAINBOARD}" | wc -w)" -gt 1 ]; then
|
|
build_targets "${MAINBOARD}"
|
|
elif [ ! -r "$ROOT/src/mainboard/${build_srcdir}" ]; then
|
|
echo "No such target: ${MAINBOARD}"
|
|
exit 1
|
|
else
|
|
build_target "${MAINBOARD}"
|
|
test "$mode" != "text" && \
|
|
test -f "$TARGET/abuild/${MAINBOARD}.xml" && \
|
|
cat "$TARGET/abuild/${MAINBOARD}.xml" >> "$REAL_XMLFILE"
|
|
XMLFILE=$REAL_XMLFILE
|
|
fi
|
|
else
|
|
build_targets
|
|
rm -f "$REAL_XMLFILE"
|
|
XMLFILE="$REAL_XMLFILE"
|
|
junit '<?xml version="1.0" encoding="utf-8"?>'
|
|
junit '<testsuite>'
|
|
if [ "$mode" != "text" ]; then
|
|
for xmlfile in $TARGET/abuild/*_*.xml; do
|
|
cat "$xmlfile" >> "$REAL_XMLFILE"
|
|
done
|
|
fi
|
|
XMLFILE=$REAL_XMLFILE
|
|
fi
|
|
junit '</testsuite>'
|
|
|
|
if [ "$recursive" = "false" ]; then
|
|
|
|
# Print the list of failed configurations
|
|
if [ -f "$FAILED_BOARDS" ]; then
|
|
printf "%s configuration(s) failed:\n" "$( wc -l < "$FAILED_BOARDS" )"
|
|
cat "$FAILED_BOARDS"
|
|
echo
|
|
else
|
|
printf "All %s tested configurations passed.\n" "$( wc -l < "$PASSED_BOARDS" )"
|
|
fi
|
|
fi
|
|
|
|
exit $failed
|