#!/bin/bash
# BEGIN_ICS_COPYRIGHT8 ****************************************
#
# Copyright (c) 2015-2020, Intel Corporation
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#     * Redistributions of source code must retain the above copyright notice,
#       this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#     * Neither the name of Intel Corporation nor the names of its contributors
#       may be used to endorse or promote products derived from this software
#       without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# END_ICS_COPYRIGHT8   ****************************************
##
## runmake
## -----------
## Perform a full build
## This is used by the weeklybuild script to provide product specific
## build operations for product's whose build is more complex
## than simply a "make stage prepfiles"
## When this is invoked, the current directory will be the TL_DIR for a
## full checkout of the product to be built
##
## Usage:
##	runmake [-B 'build_config'] [-n]
##			or
##	runmake -r [-B 'build_config'] [-iCRP] [-n]
##
## Arguments:
##	-f options_file - deprecated, see -B
##	-B build_config	release types to build, (debug/release). default is release
##	-V os_version	- deprecated, N/A
##	-r		rerun the build in place without doing a new checkout/tag
##	-i		allow incremental builds by building in-place before package rpm
##	-R		skip building rpm, just leave in-place files
##	-C		don't clobber prior to the rerun
##	-P		skip building and packaging IntelEth-Tests
##	-O		deprecated, N/A
##	-n		No build.  Useful for checking build machine
##	-T PROJ_FILE_DIR - deprecated, PROJ_FILE_DIR always set to OpenIb_Host
##
## In addition, the following environment variables are expected to be set:
##	RELEASE_TAG, BRANCH_TAG, BUILD_TARGET, PRODUCT, RELEASE_HOME, BUILD_CONFIG 
##	The target command is expected to have already been run to set up the
##	environment for the specified target
##
##	re-run can be used for 2 situations:
##	1. re-run a failed build to correct incorrect weeklybuild arguments
##		or other non-source code related problems (out of disk space)
##	2. re-run a build for a different BUILD_TARGET_OS_VERSION while using the same
##		source code image/tag
##	If the source code needs to be corrected, a full weeklybuild should be run
##	after the correction such that the code is properly tagged.
##
## For developer builds (such as via dobuildall), the following combinations
## of the -r, -i, -C and -R options are useful
##	-r  - existing typical mode for developer builds
##			- clobbers any existing built files
##			- creates a src.rpm
##			- builds in rpmbuild tree
##			- creates a resulting binary rpm
##			- IntelEth-Tests built in a tests_build area
##	-r -C - for opa FF & mpi_apps, behaves same as -r above except skips clobber
##			- IntelEth-Tests tree is not cleaned, so will do incremental build
##	-r -i [-C] - incremental build mode for developer builds
##			- clobbers any existing built files (unless -C specified)
##			- builds code in place in source tree
##			- src rpm contains pre-built code
##			- rpmbuild ends up using pre-built code, creates binary rpm
##			- IntelEth-Tests built in a tests_build area using
##				pre-built code from FF and previous tests build
##			After this build, the developer may do incremental sub-tree builds
##			using . setenv and then running make in the subtree
##			For subtree builds in tests_build, also export PROJ_FILE_DIR=.
##	-r -i [-C] -R - incremental build mode for developer builds with no rpms
##			- same as -r -i [-C] except no rpms are created
##	none of these options - typical production build
##			- expects a fresh un-built checkout of code tree
##			- creates a src.rpm
##			- builds in rpmbuild tree
##			- creates a resulting binary rpm
##			- IntelEth-Tests built in a tests_build area
##	if developer does not need an updated build of IntelEth-Tests, the -P option
##	may be used to further speed up the build
##
## Recommended developer sequence of builds when debugging new code
## -r -i -C -R - performs the fastest full build possible, generates no rpms
##			It is recommended to omit the -C option on 1st build so the tree
##			is clobbered to be sure you start fresh.
##			iterate on this and code changes until the basic build works
##			and syntax errors and warnings are all resolved
##			For unit tests only needing a few binaries, they can also be
##			directly tested.
##			If IntelEth-Tests is not needed also use -P option
##			after initial attempt, if compile errors are limited to a subtree:
##				create a new bash shell, use . setenv and then
##				iterate on make in the subtree and code changes until compiles
## -r -i -C - performs a build to generate rpms
##			install the rpms and continue testing
##			if focused on a few executables:
##				create a new bash shell, use . setenv and then
##				iterate on make in the subtree and code changes and test of
##				the individual binary until works properly
## -r		- perform a full build and generate rpms
##			install the rpms, confirm clean build, proper install and function
##
##	Since weeklybuild and target commands always set BUILD_CONFIG, this
##	script ignores BUILD_CONFIG.  As such the BuildOptions file
##	or the -B argument completely control BUILD_CONFIG for this product.

. $ICSBIN/funcs.sh

# A given release will be targeted for a specific version of ofed
# however we allow build.config to override if needed
export OFED_STACK_PREFIX=${OFED_STACK_PREFIX:-/usr}

# typically exported by build.config
export BUILD_WITH_STACK=${BUILD_WITH_STACK:-OPENIB}

Usage()
{
	# include "ERROR" in message so weeklybuild catches it in error log
	echo "ERROR: runmake failed" >&2
	echo "Usage: runmake [-B 'build_config'] [-n]" >&2
	echo "            OR" >&2
	echo "       runmake -r [-B 'build_config'] [-iCRP] [-n]" >&2
	exit 2
}

build_config=
rerun=n
Cflag=n
nflag=n
inplace=n
rpm=y
buildtests=y
while getopts f:B:V:riRPCOnT: param
do
	case $param in
	V)	echo "Deprecated -V os_versions ignored." >&2 ;;
	f)
		echo "Deprecated -f options_file ignored." >&2 ;;
	r)
		rerun=y;;
	B)
		build_config="$OPTARG";;
	i)
		inplace=y;;
	R)
		rpm=n;;
	C)
		Cflag=y;;
	n)
		nflag=y;;
	P)
		buildtests=n;;
	O)
		echo "Deprecated -O ignored." >&2 ;;
	T)
		echo "Deprecated -T PROJ_FILE_DIR ignored." >&2 ;;
	?)
		Usage
	esac
done
shift $(($OPTIND -1))

if [ $# != 0 ]
then
		Usage
fi

if [ -z "$RELEASE_TAG" ]
then
	export RELEASE_TAG=`patch_engineer_version|cut -d"." -f1`
	echo "Defaulting RELEASE_TAG to $RELEASE_TAG"
	# engineers will always forget this flag, since clobber is fast
	# default to a rerun which will clobber first unless -C specified
	rerun=y
fi

# these are special cases
if [ "$SUBPRODUCT" = "TESTS" ]
then
	# build the IntelEth-IntTests (aka HostTests) for use by validation and
	# DST testing
	# This builds so quick there is no need for incremental builds nor packaging
	# options like -r -i -C and -R
	# simply always clobber any old packaging and start fresh
	settl
	PRODUCT_DIR=$PWD
	cd $TL_DIR
	dir=release.$PRODUCT.$SUBPRODUCT
	rm -rf $dir
	mkdir $dir
	cp -R HostTestCases $dir/HostTests
	cp -R Makerules MakeTemplates MakeTools TestTools TestOnly CodeTemplates $dir/HostTests
	( cd $dir; tar cvfz IntelEth-IntTests.$RELEASE_TAG.tgz --exclude CVS --exclude '*.bak' HostTests; [ $? = 0 ] || echo "ERROR: tar command failed" )
	echo "$TL_DIR/$dir/IntelEth-IntTests.$RELEASE_TAG.tgz" > $PRODUCT_DIR/packaged_files
	# this should not be distributed, so create an empty dist_files
	> $PRODUCT_DIR/dist_files
	exit $?
elif [ "$SUBPRODUCT" = "GPL" -o "$SUBPRODUCT" = "SRC" \
		-o "$SUBPRODUCT" = "MCLX" -o "$SUBPRODUCT" = "OPEN12200" ]
then
	echo "ERROR: $SUBPRODUCT build no longer supported for OPENIB_HOST" >&2
	exit 1
fi
# other values of SUBPRODUCT are ignored in the compilation, however can set
# the destination directory in the Integration and System_Test areas, so we
# allow them, but do nothing special with them

resetct
resetbsp
if [ "$BUILD_TARGET_TOOLCHAIN" == "INTEL" ]
then
	target $BUILD_TARGET_TOOLCHAIN
else
	target $BUILD_TARGET
fi

# the kernel rev is not important.  We simply use the kernel rev
# of the running kernel.  While BUILD_TARGET_OS_VERSION is needed by Makerules
# it will have no impact on what is actually built
export BUILD_TARGET_OS_VERSION=${BUILD_TARGET_OS_VERSION:-`uname -r`}
setver $BUILD_TARGET_OS_VENDOR $BUILD_TARGET_OS_VERSION

export PROJ_FILE_DIR=OpenIb_Host
echo "Using PROJ_FILE_DIR=$PROJ_FILE_DIR"

if [ -z "$build_config" ]
then
	# default to release build
	export BUILD_CONFIG=release
elif [ "$build_config" != debug -a "$build_config" != release ]
then
	Usage
else
	export BUILD_CONFIG="$build_config"
fi

echo "---------------------------------------"
# Import OPA Build feature settings.
export OPA_FEATURE_SET=${OPA_FEATURE_SET:-$(cat $TL_DIR/$PROJ_FILE_DIR/DEFAULT_OPA_FEATURE_SET)}
FEATURE_SETTINGS_FILE=opa_feature_settings.${PRODUCT}.$BUILD_CONFIG
$TL_DIR/OpaBuildFeatureToggles/opa_build_import_feature_settings.sh
if [ -e ./$FEATURE_SETTINGS_FILE ]; then
	. ./$FEATURE_SETTINGS_FILE
else
	echo "$0: ERROR: OPA BUILD - $FEATURE_SETTINGS_FILE not found" >&2
	exit 1
fi
showenv
echo "---------------------------------------"

# To run thew klocwork scans using klocwork_analyze script, it requires OPA_FEATURE_SET and BUILD_TARGET_OS_ID
# Copying the required variables to $TL_DIR/$PRODUCT_DIRNAME/klocwork.env
if [ "$KW_ENABLE" = "yes" ]; then
	echo "export OPA_FEATURE_SET=${OPA_FEATURE_SET}" >> $TL_DIR/$PRODUCT_DIRNAME/klocwork.env
	echo "export BUILD_TARGET_OS_ID=${BUILD_TARGET_OS_ID}" >> $TL_DIR/$PRODUCT_DIRNAME/klocwork.env
fi

echo "build for: $BUILD_TARGET"
echo "Stack to build for: $BUILD_WITH_STACK "

if [ "$nflag" = "y" ]
then
	exit 0
fi

if [ "$BUILD_TARGET_OS" = "VXWORKS" ]
then
	echo "ERROR: Wrong runmake file"
	exit 1
fi

# Define BUILD_TUPLE here as shell vars, not env vars.
# It is echoed into build.env so values used at packaging time can be
# used when software is rebuilt from package.
# BUILD_TUPLE can still be overridden, both during packaging
# and later during building, either from package or in-place.
BUILD_TUPLE="${BUILD_TUPLE:-${PRODUCT}.${BUILD_CONFIG}.${OPA_FEATURE_SET}}"
export BUILT_SUFFIX=.${BUILD_TUPLE}

MODULEVERSION=`$TL_DIR/MakeTools/format_releasetag.sh $RELEASE_TAG`
RPMVERSION=`$TL_DIR/MakeTools/format_releasetag.sh -f rpm $RELEASE_TAG`
RPM_VER=`echo $RPMVERSION|cut -d"-" -f1`
RPM_REL=`echo $RPMVERSION-999|cut -d"-" -f2`
export MKRPM_VER=$RPM_VER
export MKRPM_REL=$RPM_REL`rpm --eval %{?dist}`

# even if building rpms, clobber to cleanup any previous in-place builds
# so they don't end up inside the src.rpm when not wanted
# clean up from prior build when rebuilding
if [ "$rerun" = y -a "$Cflag" != y ]
then
	# force full rebuild
	# Clobber is really only necessary if we have ever built inplace
	# but to be safe we always clobber just in case an aborted inplace
	# build has previously occurred.
	#if [ -e $TL_DIR/builtinplace.$PRODUCT.$BUILD_CONFIG \
	#	-o  -e $TL_DIR/builtinclude.$PRODUCT.$BUILD_CONFIG \
	#	-o  -e $TL_DIR/builtlibs.$PRODUCT.$BUILD_CONFIG \
	#	-o  -e $TL_DIR/builtbin.$PRODUCT.$BUILD_CONFIG ]
	#then
		export REMOVE_DEPENDS=yes
		make clobber clobber_stage clobber_release
		(cd $TL_DIR/CommonInstall; make clobber_pl_files)
		rm -f $TL_DIR/builtinplace$BUILT_SUFFIX
	#fi
fi

rm -rf $TL_DIR/$PROJ_FILE_DIR/packaged_files $TL_DIR/$PROJ_FILE_DIR/dist_files $TL_DIR/Fd/buildFeatureDefs

# make sure buildFeatureDefs is in place for the build
make $TL_DIR/Fd/buildFeatureDefs || exit 1

# make sure detailed_topology.xlsx is in place for the build
(if [ "$OPA_FEATURE_SET" = "opa110a0" -o "$OPA_FEATURE_SET" = "opa11a21" ]; then OPA_FEATURE_SET=opa11;fi;cd $TL_DIR/IbaTools/ethxlattopology; make detailed_topology.xlsx) || exit 1

# make sure files from BaseFiles are in place
while read comp fn
do
	if ! echo $comp | grep FF > /dev/null
	then
		continue
	fi
	dir=$(dirname $fn)
	bn=$(basename $fn)
	(cd $TL_DIR/$dir;make $bn) || exit 1
done < $TL_DIR/Fd/BaseFiles

# make sure CommonInstall files are in place
#(cd $TL_DIR/CommonInstall; make clobber_pl_files ff_files)

args=
if [ "$inplace" = y ]
then
	# Do not use unifdef for inplace build
	export USE_UNIFDEF="no"
	echo > $TL_DIR/builtinplace$BUILT_SUFFIX
	./rpm_runmake -r -C -B $BUILD_CONFIG
	args="-r -C"	# we pre-built, so skip clobber in rpmbuild
fi

if [ "$rpm" = y ]
then
	USE_UNIFDEF=${USE_UNIFDEF:-"yes"}
	set -x

	# Pass env variables to rpmbuild. In integration build,
	# most of the rpmbuild environment variables remains the same except
	# a few (like TL_DIR). However, when the SRPM is built on another
	# different machine, the environment variables may be totally
	# different. In that case, we may want to pass (hardcode) some
	# environment variables.
	echo "# Adjust the environment variables if necessary" > build.env
	echo "export PRODUCT=${PRODUCT}" >> build.env
	echo "export RELEASE_TAG=${RELEASE_TAG}" >> build.env
	echo "export BUILD_CONFIG=\${BUILD_CONFIG:-\"${BUILD_CONFIG}\"}" >> build.env
	echo "export BUILD_WITH_STACK=${BUILD_WITH_STACK}" >> build.env
	echo "export LDENVFS=${LDENVFS}" >> build.env
	echo "export BUILD_TUPLE=\${BUILD_TUPLE:-\"${BUILD_TUPLE}\"}" >> build.env

	FILES_TO_TAR=
	# if in-place build left builtbin, builtinclude and builtlibs, pick them up
	# to accelerate incremental builds
	for i in builtbin builtinclude builtlibs builtinplace
	do
		if [ -e $TL_DIR/${i}${BUILT_SUFFIX} ]
		then
			FILES_TO_TAR="$FILES_TO_TAR ${i}${BUILT_SUFFIX}"
		fi
	done

	FILES_TO_TAR="$FILES_TO_TAR -T tar_manifest"
	MPIAPPS_FILES_TO_TAR="-T mpiapps_tar_manifest"
	./update_eth_spec.sh "${RPM_VER}" "${RPM_REL}"
	./update_eth_tools_debian.sh "${RPM_VER}" "${RPM_REL}"
	./update_mpi_spec.sh "${RPM_VER}" "${RPM_REL}"
	./update_mpi_apps_debian.sh "${RPM_VER}" "${RPM_REL}" "${TL_DIR}/MpiApps"

	OUTPUT_DIR="${TL_DIR}/host_tools_sources"
	mkdir -p ${OUTPUT_DIR}
	ETH_TOOLS_TAR="${OUTPUT_DIR}/eth-fast-fabric-${RPM_VER}.tar.gz"
	MPI_APPS_TAR="${OUTPUT_DIR}/eth-mpi-apps.tgz"

	# Create source tar ball. Update licenses if needed.
	$TL_DIR/MakeTools/make_src_tar.sh \
		"${RELEASE_TYPE}" \
		"${TL_DIR}" \
		"${USE_UNIFDEF}" \
		"${ETH_TOOLS_TAR}" \
		"${FILES_TO_TAR}" \
		" -X tar_excludes " \
		" --transform=s,$PROJ_FILE_DIR/debian,debian," \
	|| exit 1
	# Do same for MpiApps
	$TL_DIR/MakeTools/make_src_tar.sh \
		"${RELEASE_TYPE}" \
		"${TL_DIR}" \
		"${USE_UNIFDEF}" \
		"${MPI_APPS_TAR}" \
		"${MPIAPPS_FILES_TO_TAR}" \
		"" \
		" --transform=s,MpiApps/debian,debian," \
	|| exit 1

	./build_packages.sh "${RPM_VER}" "${RPM_REL}" "$args"

	make final_package
	echo "$TL_DIR/$PROJ_FILE_DIR/$FEATURE_SETTINGS_FILE" >> packaged_files
fi

if [ "$buildtests" = y ]
then
	echo "Building IntelEth-Tests $build_config for allkernels for $BUILD_TARGET_OS $BUILD_TARGET ..."
	echo "==============================================================================="
	./build_tests.sh $args
	echo "Done IntelEth-Tests $BUILD_TARGET_OS $BUILD_TARGET allkernels $(date)"
	echo "==============================================================================="
fi
exit 0
