bc1cb38ce1
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>
926 lines
28 KiB
Bash
Executable file
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
|