coreboot-kgpe-d16/util/abuild/abuild
Julius Werner bc1cb38ce1 Add qc_blobs repository
This patch adds a separate blobs repository for Qualcomm blobs,
analogous to the existing AMD blobs. Qualcomm's binary licenses allow
files to be redistributed and used by anyone, but they explicitly
require the user to agree to the license terms when just *downloading*
the binary (even if they're not using them to build any firmware). Some
community members do not like to have to agree to licenses for files
they're not actually using, so we are keeping these files separate from
the main blobs repository and adding an extra Kconfig to make sure the
user is aware of and must explicitly agree to this before downloading
these files.

Signed-off-by: Julius Werner <jwerner@chromium.org>
Change-Id: I247746c1b633343064c9f32ef1556000475d6c4a
Reviewed-on: https://review.coreboot.org/c/coreboot/+/42548
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
2020-06-30 08:57:03 +00:00

926 lines
28 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# coreboot autobuild
#
# This script builds coreboot images for all available targets.
#
# 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
# Exit with a non-zero errorlevel on failure
exitcode=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
{
# TODO: Change 'targets' variable to an array
local targets
local VARIANT_UC
VARIANT_UC=$(echo "${variant}" | tr '[:lower:]' '[:upper:]')
targets=$(get_mainboards "$1")
if [ -n "$targets" ]; then
# shellcheck disable=SC2086
targets="$(grep "${VARIANT_UC}\$" <<< ${targets})"
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_ELF is not set"
} >> "${config_file}"
elif [ "$PAYLOAD" != "/dev/null" ]; then
{
echo "# CONFIG_PAYLOAD_NONE is not set"
echo "CONFIG_PAYLOAD_ELF=y"
echo "CONFIG_PAYLOAD_FILE=\"$PAYLOAD\""
} >> "${config_file}"
fi
# Disable all other payload config options
{
echo "# CONFIG_PAYLOAD_SEABIOS 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_LINUXBOOT is not set"
echo "# CONFIG_PAYLOAD_UBOOT is not set"
echo "# CONFIG_PAYLOAD_TIANOCORE is not set"
echo "# CONFIG_PXE is not set"
echo "# CONFIG_BUILD_IPXE is not set"
echo "# CONFIG_MEMTEST_SECONDARY_PAYLOAD is not set"
echo "# CONFIG_COREINFO_SECONDARY_PAYLOAD is not set"
echo "# CONFIG_NVRAMCUI_SECONDARY_PAYLOAD is not set"
echo "# CONFIG_TINT_SECONDARY_PAYLOAD is not set"
} >> "${config_file}"
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 "${ROOT}/.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
if [ "$clean_work" = "true" ]; then
echo "$BUILD_NAME" >> "$FAILED_BOARDS"
else
echo "$BUILD_NAME - Log: ${build_dir}/make.log" >> "$FAILED_BOARDS"
fi
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
if [ "$clean_objs" = "true" ]; then
find ${build_dir} \! \( -name coreboot.rom -o -name config.h -o -name config.build -o -name make.log \) -type f -exec rm {} +
find ${build_dir} -type d -exec rmdir -p {} + 2>/dev/null
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
local required_arches
required_arches=$(grep -E "^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 ')
missing_arches="$($MAKE --no-print-directory -f - \
REQUIRED_ARCHES="$required_arches" <<'EOF'
include .xcompile
.PHONY: missing_arches
missing_arches:
$(if $(XCOMPILE_COMPLETE),,$(error .xcompile is invalid.))
@echo $(foreach arch,$(REQUIRED_ARCHES),$(if $(filter $(arch),$(SUBARCH_SUPPORTED)),,$(arch)))
EOF
)"
# shellcheck disable=SC2181
if [[ $? -ne 0 ]]; then
echo "Calculating missing_arches failed" >&2
exit 1
fi
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 ${SCANBUILD_ARGS} -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
fi
echo "Building board $MAINBOARD (using default config)"
build_dir=$TARGET/${MAINBOARD}
build_config "$MAINBOARD" "$build_dir" "$MAINBOARD"
remove_target "$MAINBOARD"
}
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
[-A|--any-toolchain] Use any toolchain
[-b|--board-variant <name>] Build specific board variant under the
given target.
[-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
[-e|--exitcode] Exit with a non-zero errorlevel on failure
[-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
[-Z|--clean-somewhat] Remove build but keep coreboot.rom + config
[-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:,board-variant:,payloads:,cpus:,silent,junit,config,loglevel:,remove,prefix:,update,scan-build,ccache,blobs,clang,any-toolchain,clean,clean-somewhat,outdir:,chromeos,xmlfile:,kconfig:,dir:,root:,recursive,checksum:,timeless,exitcode,asserts -o Vvqhat:b:p:c:sJCl:rP:uyBLAzZo:xX:K:d:R:Ie -- "$@") || exit 1
eval set -- $args
retval=$?
else
# Detected non-GNU getopt
args=$(getopt Vvqhat:b:p:c:sJCl:rP:uyBLAZzo:xX:K:d:R:Ie "$@")
set -- $args
retval=$?
fi
if [ $retval != 0 ]; then
myhelp
exit 1
fi
chromeos=false
clean_work=false
clean_objs=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;;
-b|--board-variant) shift; variant="$1"; shift;;
-a|--all) shift; buildall=true;;
-d|--dir) shift; configdir="$1"; shift;;
-e|--exitcode) shift; exitcode=1;;
-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"; MAKE="$MAKE -C $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"
SCANBUILD_ARGS=${SCANBUILD_ARGS:-'-k'}
configoptions="${configoptions}CONFIG_FATAL_ASSERTS=y\n"
;;
--asserts) shift
configoptions="${configoptions}CONFIG_FATAL_ASSERTS=y\n"
;;
-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_AMD_BLOBS=y\nCONFIG_USE_QC_BLOBS=y\nCONFIG_ADD_FSP_BINARIES=y\n"
;;
-A|--any-toolchain) shift
customizing="${customizing}, any-toolchain"
configoptions="${configoptions}CONFIG_ANY_TOOLCHAIN=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
;;
-Z|--clean-somewhat) shift
customizing="${customizing}, clean-somewhat"
clean_objs=true
;;
-o|--outdir) shift
TARGET=$1; shift
;;
-x|--chromeos) shift
chromeos=true
testclass=chromeos
customizing="${customizing}, chrome os"
configoptions="${configoptions}CONFIG_CHROMEOS=y\nCONFIG_VBOOT_MEASURED_BOOT=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
if ! mkdir -p "$TARGET"; then
echo "Unable to create build directory"
exit 1
fi
$MAKE -C"${ROOT}" .xcompile || exit 1
customizing=$(echo "$customizing" | cut -c3-)
if [ "$customizing" = "" ]; then
customizing="default configuration"
fi
FAILED_BOARDS="$(realpath ${TARGET}/failed_boards)"
PASSED_BOARDS="$(realpath ${TARGET}/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
git submodule update --checkout --init
if [ "$USE_XARGS" = "0" ]; then
test "$MAKEFLAGS" == "" && test "$cpus" != "" && export MAKEFLAGS="-j $cpus"
export MAKEFLAGS="$MAKEFLAGS UPDATED_SUBMODULES=1" # no need to re-download
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
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" "${target}"
if [ -n "${variant}" ]; then
printf ", variant: %s" "${variant}"
fi
printf "\n"
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
if [ "$exitcode" != "0" ]; then
failed=1
fi
else
printf "All %s tested configurations passed.\n" "$( wc -l < "$PASSED_BOARDS" )"
fi
fi
exit $failed