#!/bin/bash
#
# edk2-build.sh: evolution of uefi-build.sh for edk2-platforms
#
unset MAKEFLAGS # BaseTools not safe to build parallel, prevent env overrides
TOOLS_DIR="`dirname $0`"
TOOLS_DIR="`readlink -f \"$TOOLS_DIR\"`"
export TOOLS_DIR
. "$TOOLS_DIR"/common-functions
PLATFORM_CONFIG="-c $TOOLS_DIR/edk2-platforms.config"
ARCH=
VERBOSE=0 # Override with -v
ATF_DIR=
TOS_DIR=
TOOLCHAIN="gcc" # Override with -T
WORKSPACE=
EDK2_DIR=
PLATFORMS_DIR=
NON_OSI_DIR=
IMPORT_OPENSSL=TRUE
OPENSSL_CONFIGURED=FALSE
# Number of threads to use for build
export NUM_THREADS=$((`getconf _NPROCESSORS_ONLN` + `getconf _NPROCESSORS_ONLN`))
function do_build
{
PLATFORM_ARCH=`echo $board | cut -s -d: -f2`
if [ -n "$PLATFORM_ARCH" ]; then
board=`echo $board | cut -d: -f1`
else
PLATFORM_ARCH="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o arch`"
fi
PLATFORM_NAME="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o longname` ($PLATFORM_ARCH)"
if [ -z "$PLATFORM_ARCH" ]; then
echo "Unknown target architecture - aborting!" >&2
return 1
fi
PLATFORM_PREBUILD_CMDS="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o prebuild_cmds`"
PLATFORM_BUILDFLAGS="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o buildflags`"
PLATFORM_BUILDFLAGS="$PLATFORM_BUILDFLAGS ${EXTRA_OPTIONS[@]}"
PLATFORM_BUILDCMD="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o buildcmd`"
PLATFORM_DSC="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o dsc`"
PLATFORM_PACKAGES_PATH=""
COMPONENT_INF="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o inf`"
TEMP_PACKAGES_PATH="$GLOBAL_PACKAGES_PATH:`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o packages_path`"
IFS=:
for path in "$TEMP_PACKAGES_PATH"; do
case "$path" in
/*)
PLATFORM_PACKAGES_PATH="$PLATFORM_PACKAGES_PATH:$path"
;;
*)
PLATFORM_PACKAGES_PATH="$PLATFORM_PACKAGES_PATH:$PWD/$path"
;;
esac
done
unset IFS
if [ $VERBOSE -eq 1 ]; then
echo "Setting build parallellism to $NUM_THREADS processes"
echo "PLATFORM_NAME=$PLATFORM_NAME"
echo "PLATFORM_PREBUILD_CMDS=$PLATFORM_PREBUILD_CMDS"
echo "PLATFORM_BUILDFLAGS=$PLATFORM_BUILDFLAGS"
echo "PLATFORM_BUILDCMD=$PLATFORM_BUILDCMD"
echo "PLATFORM_DSC=$PLATFORM_DSC"
echo "PLATFORM_ARCH=$PLATFORM_ARCH"
echo "PLATFORM_PACKAGES_PATH=$PLATFORM_PACKAGES_PATH"
fi
set_cross_compile
CROSS_COMPILE="$TEMP_CROSS_COMPILE"
echo "Building $PLATFORM_NAME - $PLATFORM_ARCH"
echo "CROSS_COMPILE=\"$TEMP_CROSS_COMPILE\""
echo "$board"_BUILDFLAGS="'$PLATFORM_BUILDFLAGS'"
if [ "$TARGETS" == "" ]; then
TARGETS=( RELEASE )
fi
case $TOOLCHAIN in
"gcc")
PLATFORM_TOOLCHAIN=`get_gcc_version "$CROSS_COMPILE"gcc`
;;
"clang")
PLATFORM_TOOLCHAIN=`get_clang_version clang`
;;
*)
# Use command-line specified profile directly
PLATFORM_TOOLCHAIN=$TOOLCHAIN
;;
esac
echo "PLATFORM_TOOLCHAIN is ${PLATFORM_TOOLCHAIN}"
export ${PLATFORM_TOOLCHAIN}_${PLATFORM_ARCH}_PREFIX=$CROSS_COMPILE
echo "Toolchain prefix: ${PLATFORM_TOOLCHAIN}_${PLATFORM_ARCH}_PREFIX=$CROSS_COMPILE"
export PACKAGES_PATH="$PLATFORM_PACKAGES_PATH"
for target in "${TARGETS[@]}" ; do
if [ X"$PLATFORM_PREBUILD_CMDS" != X"" ]; then
echo "Run pre-build commands:"
if [ $VERBOSE -eq 1 ]; then
echo " ${PLATFORM_PREBUILD_CMDS}"
fi
eval ${PLATFORM_PREBUILD_CMDS}
fi
if [ -n "$COMPONENT_INF" ]; then
# Build a standalone component
if [ $VERBOSE -eq 1 ]; then
echo "build -n $NUM_THREADS -a \"$PLATFORM_ARCH\" -t ${PLATFORM_TOOLCHAIN} -p \"$PLATFORM_DSC\"" \
"-m \"$COMPONENT_INF\" -b "$target" ${PLATFORM_BUILDFLAGS}"
fi
build -n $NUM_THREADS -a "$PLATFORM_ARCH" -t ${PLATFORM_TOOLCHAIN} -p "$PLATFORM_DSC" \
-m "$COMPONENT_INF" -b "$target" ${PLATFORM_BUILDFLAGS}
else
# Build a platform
if [ $VERBOSE -eq 1 ]; then
echo "build -n $NUM_THREADS -a \"$PLATFORM_ARCH\" -t ${PLATFORM_TOOLCHAIN} -p \"$PLATFORM_DSC\"" \
"-b "$target" ${PLATFORM_BUILDFLAGS}"
fi
build -n $NUM_THREADS -a "$PLATFORM_ARCH" -t ${PLATFORM_TOOLCHAIN} -p "$PLATFORM_DSC" \
-b "$target" ${PLATFORM_BUILDFLAGS}
fi
RESULT=$?
if [ $RESULT -eq 0 ]; then
if [ X"$TOS_DIR" != X"" ]; then
pushd $TOS_DIR >/dev/null
if [ $VERBOSE -eq 1 ]; then
echo "$TOOLS_DIR/tos-build.sh -e "$EDK2_DIR" -t "$target"_${PLATFORM_TOOLCHAIN} $board"
fi
$TOOLS_DIR/tos-build.sh -e "$EDK2_DIR" -t "$target"_${PLATFORM_TOOLCHAIN} $board
RESULT=$?
popd >/dev/null
fi
fi
if [ $RESULT -eq 0 ]; then
if [ X"$ATF_DIR" != X"" ]; then
pushd $ATF_DIR >/dev/null
if [ $VERBOSE -eq 1 ]; then
echo "$TOOLS_DIR/atf-build.sh -e "$EDK2_DIR" -t "$target"_${PLATFORM_TOOLCHAIN} $board"
fi
$TOOLS_DIR/atf-build.sh -e "$EDK2_DIR" -t "$target"_${PLATFORM_TOOLCHAIN} $board
RESULT=$?
popd >/dev/null
fi
fi
result_log $RESULT "$PLATFORM_NAME $target"
done
unset PACKAGES_PATH
}
function configure_paths
{
WORKSPACE="$PWD"
# Check to see if we are in a UEFI repository
# refuse to continue if we aren't
if [ ! -d "$EDK2_DIR"/BaseTools ]
then
if [ -d "$PWD"/edk2/BaseTools ]; then
EDK2_DIR="$PWD"/edk2
else
echo "ERROR: can't locate the edk2 directory" >&2
echo " please specify -e/--edk2-dir" >&2
exit 1
fi
fi
GLOBAL_PACKAGES_PATH="$EDK2_DIR"
# locate edk2-platforms
if [ -z "$PLATFORMS_DIR" -a -d "$PWD"/edk2-platforms ]; then
PLATFORMS_DIR="$PWD"/edk2-platforms
fi
if [ -n "$PLATFORMS_DIR" ]; then
GLOBAL_PACKAGES_PATH="$GLOBAL_PACKAGES_PATH:$PLATFORMS_DIR"
fi
# locate edk2-non-osi
if [ -z "$NON_OSI_DIR" -a -d "$PWD"/edk2-non-osi ]; then
NON_OSI_DIR="$PWD"/edk2-non-osi
fi
if [ -n "$NON_OSI_DIR" ]; then
GLOBAL_PACKAGES_PATH="$GLOBAL_PACKAGES_PATH:$NON_OSI_DIR"
fi
# locate arm-trusted-firmware
if [ -z "$ATF_DIR" -a -d "$PWD"/arm-trusted-firmware ]; then
ATF_DIR="$PWD"/arm-trusted-firmware
fi
export WORKSPACE
}
function prepare_build
{
get_build_arch
export ARCH=$BUILD_ARCH
export ARCH
cd $EDK2_DIR
PACKAGES_PATH=$GLOBAL_PACKAGES_PATH . edksetup.sh --reconfig
if [ $? -ne 0 ]; then
echo "Sourcing edksetup.sh failed!" >&2
exit 1
fi
if [ $VERBOSE -eq 1 ]; then
echo "Building BaseTools"
fi
make -C BaseTools
RET=$?
cd -
if [ $RET -ne 0 ]; then
echo " !!! BaseTools failed to build !!! " >&2
exit 1
fi
if [ "$IMPORT_OPENSSL" = "TRUE" ]; then
cd $EDK2_DIR
import_openssl
if [ $? -ne 0 ]; then
echo "Importing OpenSSL failed - aborting!" >&2
echo " specify --no-openssl to attempt build anyway." >&2
exit 1
fi
cd $WORKSPACE
fi
}
function usage
{
echo "usage:"
echo -n "uefi-build.sh [-b DEBUG | RELEASE] [ all "
for board in "${boards[@]}" ; do
echo -n "| $board "
done
echo "]"
printf "%8s\tbuild %s\n" "all" "all supported platforms"
for board in "${boards[@]}" ; do
PLATFORM_NAME="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG -p $board get -o longname`"
printf "%8s\tbuild %s\n" "$board" "${PLATFORM_NAME}"
done
}
#
# Since we do a command line validation on whether specified platforms exist or
# not, do a first pass of command line to see if there is an explicit config
# file there to read valid platforms from.
#
commandline=( "$@" )
i=0
for arg;
do
if [ $arg == "-c" ]; then
FILE_ARG=${commandline[i + 1]}
if [ ! -f "$FILE_ARG" ]; then
echo "ERROR: configuration file '$FILE_ARG' not found" >&2
exit 1
fi
case "$FILE_ARG" in
/*)
PLATFORM_CONFIG="-c $FILE_ARG"
;;
*)
PLATFORM_CONFIG="-c `readlink -f \"$FILE_ARG\"`"
;;
esac
echo "Platform config file: '$FILE_ARG'"
fi
i=$(($i + 1))
done
export PLATFORM_CONFIG
builds=()
boards=()
boardlist="`$TOOLS_DIR/parse-platforms.py $PLATFORM_CONFIG shortlist`"
for board in $boardlist; do
boards=(${boards[@]} $board)
done
NUM_TARGETS=0
while [ "$1" != "" ]; do
case $1 in
-1) # Disable build parallellism
NUM_THREADS=1
;;
-a | --arm-tf-dir)
shift
ATF_DIR="`readlink -f $1`"
;;
-c) # Already parsed above - skip this + option
shift
;;
-b | --build-target)
shift
echo "Adding Build target: $1"
TARGETS=(${TARGETS[@]} $1)
;;
-D) # Pass through as -D option to 'build'
shift
echo "Adding Macro: -D $1"
EXTRA_OPTIONS=(${EXTRA_OPTIONS[@]} "-D" $1)
;;
-e | --edk2-dir)
shift
export EDK2_DIR="`readlink -f $1`"
;;
-h | --help)
usage
exit
;;
--no-openssl)
IMPORT_OPENSSL=FALSE
;;
-n | --non-osi-dir)
shift
NON_OSI_DIR="`readlink -f $1`"
;;
-p | --platforms-dir)
shift
PLATFORMS_DIR="`readlink -f $1`"
;;
-s | --tos-dir)
shift
export TOS_DIR="`readlink -f $1`"
;;
-T) # Set specific toolchain tag, or clang/gcc for autoselection
shift
echo "Setting toolchain tag to '$1'"
TOOLCHAIN="$1"
;;
-v)
VERBOSE=1
;;
all) # Add all targets in configuration file to list
builds=(${boards[@]})
NUM_TARGETS=$(($NUM_TARGETS + 1))
;;
*) # Try to match target in configuration file, add to list
MATCH=0
for board in "${boards[@]}" ; do
if [ "`echo $1 | cut -d: -f1`" == $board ]; then
MATCH=1
builds=(${builds[@]} "$1")
break
fi
done
if [ $MATCH -eq 0 ]; then
echo "unknown arg $1"
usage
exit 1
fi
NUM_TARGETS=$(($NUM_TARGETS + 1))
;;
esac
shift
done
if [ $NUM_TARGETS -le 0 ]; then
echo "No targets specified - exiting!" >&2
exit 0
fi
export VERBOSE
configure_paths
prepare_build
if [[ "${EXTRA_OPTIONS[@]}" != *"FIRMWARE_VER"* ]]; then
if test -d .git && head=`git rev-parse --verify --short HEAD 2>/dev/null`; then
FIRMWARE_VER=`git rev-parse --short HEAD`
if ! git diff-index --quiet HEAD --; then
FIRMWARE_VER="${FIRMWARE_VER}-dirty"
fi
EXTRA_OPTIONS=( ${EXTRA_OPTIONS[@]} "-D" FIRMWARE_VER=$FIRMWARE_VER )
if [ $VERBOSE -eq 1 ]; then
echo "FIRMWARE_VER=$FIRMWARE_VER"
echo "EXTRA_OPTIONS=$EXTRA_OPTIONS"
fi
fi
fi
for board in "${builds[@]}" ; do
do_build
done
result_print