#!/bin/sh
#
# configure [ <options> ]

# usage
#
# Prints usage.
#
usage()
{
	cat << EOF

Usage: $0 <options>
options:
  --bootstrap <haikuporter> <HaikuPorts cross repo> <HaikuPorts repo>
                              Prepare for a bootstrap build. No pre-built
                              packages will be used, instead they will be built
                              from the sources (in several phases).
                              <haikuporter> is the path to the haikuporter tool
                              suitable for the host platform.
                              <HaikuPorts cross repo> is the path to a checked
                              out HaikuPorts cross-compilation repository.
                              <HaikuPorts repo> is the path to a checked out
                              HaikuPorts repository.
  --build-cross-tools <arch> [ <build tools dir> ]
                              Assume cross compilation. <build tools dir>
                              defines the location of the build tools sources.
                              They will be compiled and placed in the output
                              directory under "cross-tools". The HAIKU_* tools
                              variables will be set accordingly.
                              <arch> specifies the target architecture, either
                              "x86_gcc2", "x86", "x86_64", "ppc", "m68k", "arm",
                              or "mipsel".
                              This option and --cross-tools-prefix can be
                              specified multiple times. The first cross tools
                              specify the primary tools, the subsequent ones the
                              secondary tools (for "hybrid" images).
                              For the first --build-cross-tools the
                              <build tools dir> argument must be specified and
                              for the subsequent ones it must be omitted.
  --cross-tools-prefix <prefix>
                              Assume cross compilation. <prefix> should be a
                              path to the directory where the cross
                              compilation tools are located, plus the platform
                              prefix, e.g. "/path/to/tools/i586-pc-haiku-".
                              This overrides the HAIKU_* tool variables.
  --distro-compatibility <level>
                              The distribution's level of compatibility with
                              the official Haiku distribution. The generated
                              files will contain the respective trademarks
                              accordingly.
                              official -- the official Haiku distribution.
                              compatible -- a Haiku Compatible (tm) distro.
                              default -- any other distro (default value).
  --enable-multiuser          Enable experimental multiuser support.
  --help                      Prints out this help.
  --host-only                 Configure for building tools for the build host
                              only. Haiku cannot be built when configured like
                              this.
  --include-gpl-addons        Include GPL licensed add-ons.
  --include-patented-code     Enable code that is known to implemented patented
                              ideas and techniques. If this option is not
                              specified, the resulting distribution may still
                              implement patented ideas and techniques. This
                              option only disables code that is currently known
                              to be problematic.
  --include-sources           Includes the source code of projects that require
                              either an offer of source code or a copy of the
                              patched sources. This is preferable when
                              distributing on physical mediums.
  --include-3rdparty          Include 3rdparty/ in the build system.
  -j<n>                       Only relevant for --build-cross-tools and
                              --build-cross-tools-gcc4. Is passed on to the
                              make building the build tools.
  --remote-user <username>    Use given username when logging into 
                              git.haiku-os.org (via ssh).
  --target=TARGET             Select build target platform.
                              [default=${TARGET_PLATFORM}]
                              valid targets=r5,bone,dano,haiku
  --target-arch <arch>        Haiku only: Specify the target architecture to
                              build for. Must be one of the architectures of the
                              host system. The installed build tools for that
                              architecture will be used.
                              This option can be specified multiple times. The
                              first occurrence specifies the primary
                              architecture of the Haiku to build, subsequent
                              ones the secondary architectures.
  --update                    re-runs last configure invocation [must be given
                              as first option!]
  --use-gcc-pipe              Build with GCC option -pipe. Speeds up the build
                              process, but uses more memory.
  --use-gcc-graphite          Build with GCC Graphite engine for loop
                              optimizations. Only for gcc 4.
  --use-32bit                 Use -m32 flag on 64bit host gcc compiler.
  --use-xattr                 Use Linux xattr respectively *BSD extattr support
                              for BeOS attribute emulation. Warning: Make sure
                              your file system supports sufficient attribute
                              sizes (4 KB per file for all attributes won't
                              suffice).
  --use-xattr-ref             Use the generic BeOS attribute emulation, but use
                              Linux xattr respectively *BSD extattr support to
                              make it more robust (i.e. attribute mix-ups become
                              less likely).

environment variables:
  HAIKU_AR_x86_gcc2           The static library archiver for x86_gcc2.
                              Defaults to "ar".
  HAIKU_CC_x86_gcc2           The x86_gcc2 compiler. Defaults to "gcc".
  HAIKU_LD_x86_gcc2           The x86_gcc2 linker. Defaults to "ld".
  HAIKU_OBJCOPY_x86_gcc2      The x86_gcc2 objcopy to be used. Defaults to
                              "objcopy".
  HAIKU_RANLIB_x86_gcc2       The static library indexer for x86_gcc2. Defaults
                              to "ranlib".
  HAIKU_STRIP_x86_gcc2        The x86_gcc2 strip command. Defaults to "strip".
  HAIKU_YASM                  The yasm assembler (x86 only).
  HAIKU_CPPFLAGS_<arch>       The preprocessor flags for target architecture
                              <arch>. Defaults to "".
  HAIKU_CCFLAGS_<arch>        The C flags for target architecture <arch>.
                              Defaults to "".
  HAIKU_CXXFLAGS_<arch>       The C++ flags for target architecture <arch>.
                              Defaults to "".
  HAIKU_LDFLAGS_<arch>        The linker flags for target architecture <arch>.
                              Defaults to "".
  HAIKU_ARFLAGS_<arch>        The flags passed to HAIKU_AR for target
                              architecture <arch> for archiving. Defaults to
                              "cru".
  HAIKU_UNARFLAGS_<arch>      The flags passed to HAIKU_AR for target
                              architecture <arch> for unarchiving. Defaults to
                              "x".

Non-default output directories:
  By default all objects, build configuration, and other related files are
  stored in /path/to/haiku_source/generated.  To store objects in a non-default
  location, run "../../relative/path/to/haiku_source/configure <options>" from
  within your non-default location.  "jam [ options ] targets" can then be run
  directly inside your non-default location.  Another option is to invoke "jam
  [ options ] targets" from within haiku_source.  This can be accomplished by
  either "export HAIKU_OUTPUT_DIR=your non-default location" before invoking
  jam or by creating a symlink of haiku_source/generated pointing to your
  non-default location and running jam.


EOF
}

# assertparam
#
# Checks whether at least one parameter is left.
#
assertparam()
{
	if [ $2 -lt 2 ]; then
		echo $0: \`$1\': Parameter expected.
		exit 1
	fi
}

# assertparams
#
# Checks whether at least a certain number of parameters is left.
#
assertparams()
{
	if [ $3 -le $2 ]; then
		echo $0: \`$1\': Not enough parameters.
		exit 1
	fi
}

# absolute_path
#
# returns the absolute path of a given path.
#
absolute_path()
{
	if [ "x$1" != "x${1#/}" ]; then
		echo "$1"
	else
		echo "`pwd`/$1"
	fi
}

# real_path
#
# returns the realpath of a symbolic link.
#
real_path()
{
	perl -MCwd=realpath -e'print realpath($ARGV[0]), "\n"' "$1"
}

# standard_gcc_settings
#
# Sets the variables for a GCC platform.
#
standard_gcc_settings()
{
	local gcc=$1

	if which greadlink > /dev/null 2>&1; then
		readlink="greadlink -e"
	elif which realpath > /dev/null 2>&1; then
		readlink=realpath
	elif readlink -e / > /dev/null 2>&1; then
		readlink="readlink -e"
	else
		readlink=real_path
	fi

	# PLATFORM_LINKLIBS
	local gcclib=`$gcc -print-libgcc-file-name`
	local gccdir=`dirname ${gcclib}`

	local gccRawVersion=`$gcc -dumpversion`
	local gccMachine=`$gcc -dumpmachine`

	local libgcc=${gccdir}/libgcc.a

	# determine architecture from machine triple
	case $gccMachine in
		arm-*)		targetCpu=arm;;
		i?86-*)		targetCpu=x86;;
		m68k-*)		targetCpu=m68k;;
		mipsel-*)	targetCpu=mipsel;;
		powerpc-*)	targetCpu=ppc;;
		x86_64-*)	targetCpu=x86_64;;
		*)
			echo "Unsupported gcc target machine: $gccMachine" >&2
			exit 1
			;;
	esac

	local targetArch=$targetCpu
	local staticLibStdCxx
	local sharedLibStdCxx
	local staticLibSupCxx
	local sharedLibSupCxx
	local kernelLibgcc
	local cxxHeaders

	case $gccRawVersion in
		4.*)
			# for gcc 4 we use the libstdc++ and libsupc++ that come with the
			# compiler
			staticLibStdCxx=`$gcc -print-file-name=libstdc++.a`
			sharedLibStdCxx=`$gcc -print-file-name=libstdc++.so`
			staticLibSupCxx=`$gcc -print-file-name=libsupc++.a`
			sharedLibSupCxx=`$gcc -print-file-name=libsupc++.so`

			# If the architecture has separate runtime libraries for the
			# kernel, use them.
			kernelLibgcc=`$gcc -print-file-name=libgcc-kernel.a`
			if [ $kernelLibgcc = libgcc-kernel.a ]; then
				kernelLibgcc=$libgcc
			fi
			kernelLibSupCxx=`$gcc -print-file-name=libsupc++-kernel.a`
			if [ $kernelLibSupCxx = libsupc++-kernel.a ]; then
				kernelLibSupCxx=$staticLibSupCxx
			fi

			local headersBase=$gccdir/../../../..
			local headers=$headersBase/$gccMachine/include/c++/$gccRawVersion
			if [ ! -d $headers ]; then
				headers=$headersBase/include/c++/$gccRawVersion
			fi

			cxxHeaders=$headers
			for d in $gccMachine backward ext; do
				# Note: We need the line break, otherwise the line might become
				# too long for jam (512 bytes max).
				cxxHeaders="$cxxHeaders $headers/$d"
			done

			# Unset the HAIKU_{SHARED,STATIC}_LIB{STD,SUP}CXX variables, if the
			# compiler didn't give us actual file names. Otherwise resolve
			# symlinks to avoid problems when copying the libraries to the
			# image.

			if [ $staticLibStdCxx = libstdc++.a ]; then
				staticLibStdCxx=
			else
				staticLibStdCxx=`$readlink $staticLibStdCxx`
			fi

			if [ $sharedLibStdCxx = libstdc++.so ]; then
				sharedLibStdCxx=
			else
				sharedLibStdCxx=`$readlink $sharedLibStdCxx`
			fi

			if [ $staticLibSupCxx = libsupc++.a ]; then
				staticLibSupCxx=
			else
				staticLibSupCxx=`$readlink $staticLibSupCxx`
			fi

			if [ $sharedLibSupCxx = libsupc++.so ]; then
				sharedLibSupCxx=
			else
				sharedLibSupCxx=`$readlink $sharedLibSupCxx`
			fi
			;;
		2.9*)
			# check for correct (most up-to-date) legacy compiler and complain
			# if an older one is installed
			if [ $gccRawVersion != $haikuRequiredLegacyGCCVersion ]; then
				echo "GCC version $haikuRequiredLegacyGCCVersion is required!";
				echo "Please download it from www.haiku-os.org...";
				exit 1;
			fi

			kernelLibgcc=$libgcc
			kernelLibSupCxx=
			targetArch=x86_gcc2
			;;
	esac

	local bootLibgcc
	local bootLibSupCxx
	local bootCxxHeaders
	case $gccMachine in
		x86_64-*)
			# Boot loader is 32-bit, need the 32-bit libs and c++ config
			bootLibgcc=`$gcc -m32 -print-libgcc-file-name`
			bootLibSupCxx=`$gcc -m32 -print-file-name=libsupc++.a`

			local headersBase=$gccdir/../../../..
			local headers=$headersBase/$gccMachine/include/c++/$gccRawVersion
			if [ ! -d $headers ]; then
				headers=$headersBase/include/c++/$gccRawVersion
			fi
			bootCxxHeaders="$headers/$gccMachine/32"
			;;
		*)
			bootLibgcc=$libgcc
			bootLibSupCxx=$staticLibSupCxx
			;;
	esac

	# determine whether graphite loop optimization should/can be used
	local useGraphite=`get_variable HAIKU_USE_GCC_GRAPHITE_$targetCpu`
	if [ -z "$useGraphite" ]; then
		useGraphite=$useGccGraphiteDefault
	fi

	if [ "$useGraphite" != 0 ]; then
		UNUSED=`echo "int main() {}" | $gcc -xc -c -floop-block - 2>&1`
		if [ $? != 0 ]; then
			echo "GCC Graphite loop optimizations cannot be used on $targetArch"
			useGraphite=0
		fi
	fi

	set_variable HAIKU_CPU_$targetArch $targetCpu

	get_build_tool_path CC_$targetArch "$gcc"
	set_variable HAIKU_GCC_RAW_VERSION_$targetArch $gccRawVersion
	set_variable HAIKU_GCC_MACHINE_$targetArch $gccMachine
	set_variable HAIKU_GCC_LIB_DIR_$targetArch $gccdir
	set_variable HAIKU_GCC_LIBGCC_$targetArch $libgcc
	set_variable HAIKU_GCC_GLUE_CODE_$targetArch "crtbegin.o crtend.o"
	set_variable HAIKU_GCC_HEADERS_DIR_$targetArch \
		"${gccdir}/include ${gccdir}/include-fixed"
	set_variable HAIKU_STATIC_LIBSTDCXX_$targetArch "$staticLibStdCxx"
	set_variable HAIKU_SHARED_LIBSTDCXX_$targetArch "$sharedLibStdCxx"
	set_variable HAIKU_STATIC_LIBSUPCXX_$targetArch "$staticLibSupCxx"
	set_variable HAIKU_SHARED_LIBSUPCXX_$targetArch "$sharedLibSupCxx"
	set_variable HAIKU_KERNEL_LIBSUPCXX_$targetArch "$kernelLibSupCxx"
	set_variable HAIKU_BOOT_LIBSUPCXX_$targetArch "$bootLibSupCxx"
	set_variable HAIKU_KERNEL_LIBGCC_$targetArch $kernelLibgcc
	set_variable HAIKU_CXX_HEADERS_DIR_$targetArch "$cxxHeaders"
	set_variable HAIKU_BOOT_LIBGCC_$targetArch $bootLibgcc
	set_variable HAIKU_BOOT_CXX_HEADERS_DIR_$targetArch "$bootCxxHeaders"
	set_variable HAIKU_USE_GCC_GRAPHITE_$targetArch $useGraphite

	standard_gcc_settings_targetArch=$targetArch
}

# set_variable
#
# Set the value of a variable.
#
set_variable()
{
	eval "$1=\"$2\""
}

# get_variable
#
# Echo the value of a variable.
#
get_variable()
{
	eval "echo \${$1}"
}

# set_default_value
#
# Set the value for a variable, if no value is set yet.
#
set_default_value()
{
	eval "$1=\${$1-$2}"
}

# get_build_tool_path
#
# Gets a usable absolute path of a build tool.
#
get_build_tool_path()
{
	local var="HAIKU_$1"
	local path=$2

	if [ -f "$path" ]; then
		# get absolute path
		local oldPwd="`pwd`"
		cd "`dirname "$path"`"
		path="`pwd`/`basename "$path"`"
		cd $oldPwd
	else
		which "$path" > /dev/null 2>&1 || {
			echo "Build tool \"$path\" not found." >&2
			exit 1
		}
	fi

	eval "$var=$path"
}

is_in_list()
{
	local element
	for element in $2; do
		if [ "$1" = "$element" ]; then
			return 0
		fi
	done
	return 1
}

# get cwd and the source directory
currentDir=`pwd`
cd `dirname "$0"`
sourceDir=`pwd`
cd "$currentDir"

# backup the passed arguments
configureArgs="$@"

# internal default parameter values
#
platform=`uname`
platformMachine=`uname  -m`
targetArchs=
buildCrossTools=
buildCrossToolsScript="$sourceDir/build/scripts/build_cross_tools"
buildCrossToolsJobs=
useGccGraphiteDefault=0
unknownArchIndex=1
haikuTargetArchs=

# exported (BuildSetup) default parameter values
#
HOST_GCC_RAW_VERSION=`gcc -dumpversion`
HOST_GCC_MACHINE=`gcc -dumpmachine`
HAIKU_INCLUDE_GPL_ADDONS=0
HAIKU_INCLUDE_PATENTED_CODE=0
HAIKU_INCLUDE_SOURCES=0
HAIKU_INCLUDE_3RDPARTY=0
HAIKU_ENABLE_MULTIUSER=0
HAIKU_DISTRO_COMPATIBILITY=default
TARGET_PLATFORM=haiku
HAIKU_USE_GCC_PIPE=0
HAIKU_HOST_USE_32BIT=0
HAIKU_HOST_USE_XATTR=0
HAIKU_HOST_USE_XATTR_REF=0
HAIKU_HOST_BUILD_ONLY=0
HOST_EXTENDED_REGEX_SED="sed -r"
HOST_GCC_LD=`gcc -print-prog-name=ld`
HOST_GCC_OBJCOPY=`gcc -print-prog-name=objcopy`
SFDISK_BINARY=sfdisk
HOST_SFDISK=$SFDISK_BINARY
HOST_SHA256=
HOST_HAIKU_PORTER=
HAIKU_PORTS=
HAIKU_PORTS_CROSS=

HAIKU_PACKAGING_ARCHS=

set_default_value HAIKU_YASM		yasm

if sha256sum < /dev/null > /dev/null 2>&1; then
	HOST_SHA256=sha256sum
elif sha256 < /dev/null > /dev/null 2>&1; then
	HOST_SHA256="sha256 -q"
elif shasum < /dev/null > /dev/null 2>&1; then
	HOST_SHA256="shasum -a 256"
else
	echo "Error: Neither sha256sum nor sha256 seem to be available!" >&2
	exit 1
fi

haikuRequiredLegacyGCCVersion="2.95.3-haiku-2013_08_15"
export haikuRequiredLegacyGCCVersion
	# version of legacy gcc required to build haiku
supportedTargetArchs="
	arm
	m68k
	mipsel
	ppc
	x86
	x86_64
	x86_gcc2
	"

# determine output directory
if [ "$currentDir" = "$sourceDir" ]; then
	outputDir=$currentDir/generated
else
	outputDir=$currentDir
fi
buildOutputDir="$outputDir/build"
HAIKU_BUILD_ATTRIBUTES_DIR="$outputDir/attributes"
buildConfigFile="$buildOutputDir/BuildConfig"

# check for update request
if [ "$1" = "--update" ]; then
	if ! [ -e "$buildConfigFile" ]; then
		echo $0 --update: \'$buildConfigFile\' not found - updating not possible.
		exit 1
	fi
	if ! type perl >/dev/null 2>&1; then
		echo $0 --update: \'perl\' not found - updating not possible.
		exit 1
	fi
	# convert BuildConfig from jam format to shell format and evaluate it
	shellConfigFile="${buildConfigFile}.shell"
	perl "$sourceDir/build/scripts/convert_build_config_to_shell_format.pl" \
		<"$buildConfigFile" >"$shellConfigFile"
	. "$shellConfigFile"
	rm "$shellConfigFile"
	shift
fi

# parse parameters
#
while [ $# -gt 0 ] ; do
	case "$1" in
		--bootstrap)
			assertparams "$1" 3 $#
			HOST_HAIKU_PORTER="`absolute_path $2`"
			HAIKU_PORTS_CROSS="`absolute_path $3`"
			HAIKU_PORTS="`absolute_path $4`"
			shift 4
			;;
		--build-cross-tools)
			if [ -z "$buildCrossTools" ]; then
				assertparams "$1" 2 $#
				targetArch=$2
				buildCrossTools=$3
				shift 3
			else
				assertparam "$1" $#
				targetArch=$2
				shift 2
			fi
			case "$targetArch" in
				x86_gcc2)	targetMachine=i586-pc-haiku;;
				x86)		targetMachine=i586-pc-haiku;;
				x86_64)		targetMachine=x86_64-unknown-haiku;;
				ppc)		targetMachine=powerpc-apple-haiku;;
				m68k)		targetMachine=m68k-unknown-haiku;;
				arm)		targetMachine=arm-unknown-haiku;;
				mipsel)		targetMachine=mipsel-unknown-haiku;;
				*)
					echo "Unsupported target architecture: $2" >&2
					exit 1
					;;
			esac
			set_variable buildCrossToolsMachine_$targetArch $targetMachine
			targetArchs="$targetArchs $targetArch"
			HAIKU_PACKAGING_ARCHS=
			;;
		--cross-tools-prefix)
			assertparam "$1" $#
			targetArch=unknown${unknownArchIndex}
			set_variable crossToolsPrefix_$targetArch "$2"
			targetArchs="$targetArchs $targetArch"
			HAIKU_PACKAGING_ARCHS=
			unknownArchIndex=$(($unknownArchIndex + 1))
			shift 2
			;;
		--distro-compatibility)
			assertparam "$1" $#
			HAIKU_DISTRO_COMPATIBILITY=$2
			case "$HAIKU_DISTRO_COMPATIBILITY" in
				official)	;;
				compatible)	;;
				default)	;;
				*)			echo "Invalid distro compatibility" \
								"level: $HAIKU_DISTRO_COMPATIBILITY"
							exit 1;;
			esac
			shift 2
			;;
		--enable-multiuser)	HAIKU_ENABLE_MULTIUSER=1; shift 1;;
		--help | -h)	usage; exit 0;;
		--host-only)	HAIKU_HOST_BUILD_ONLY=1; shift 1;;
		--include-gpl-addons)	HAIKU_INCLUDE_GPL_ADDONS=1; shift 1;;
		--include-patented-code)	HAIKU_INCLUDE_PATENTED_CODE=1; shift 1;;
		--include-sources)	HAIKU_INCLUDE_SOURCES=1; shift 1;;
		--include-3rdparty)	HAIKU_INCLUDE_3RDPARTY=1; shift 1;;
        -j*)				buildCrossToolsJobs="$1"; shift 1;;
		--target=*)     TARGET_PLATFORM=`echo $1 | cut -d'=' -f2-`; shift 1;;
		--target-arch)
			assertparam "$1" $#
			targetArch=$2
			shift 2
			if [ ! "$platform" = Haiku ]; then
				echo "--target-arch can only be specified on Haiku." >&2
				exit 1
			fi
			is_in_list "$targetArch" "$supportedTargetArchs" || (
				echo "Unsupported target architecture: \"$targetArch\"" >&2
				exit 1
			)
			haikuTargetArchs="$haikuTargetArchs $targetArch"
			;;
		--use-gcc-pipe)	HAIKU_USE_GCC_PIPE=1; shift 1;;
		--use-gcc-graphite)	useGccGraphiteDefault=1; shift 1;;
		--use-32bit)	HAIKU_HOST_USE_32BIT=1; shift 1;;
		--use-xattr)	HAIKU_HOST_USE_XATTR=1; shift 1;;
		--use-xattr-ref)	HAIKU_HOST_USE_XATTR_REF=1; shift 1;;
		*)				echo Invalid argument: \`$1\'; exit 1;;
	esac
done

# detect the build platform
case "${platform}" in
	Darwin)	HOST_PLATFORM=darwin ;;
	FreeBSD)	HOST_PLATFORM=freebsd
				SFDISK_BINARY=sfdisk-linux
				if [ "$HAIKU_HOST_USE_32BIT" = 1 ] ; then
					echo Unsupported platform: FreeBSD ${platformMachine}
					exit 1
				fi	;;
	Haiku)	HOST_PLATFORM=haiku_host ;;
	Linux)	HOST_PLATFORM=linux ;;
	OpenBSD) HOST_PLATFORM=openbsd ;;
	SunOS)	HOST_PLATFORM=sunos ;;
	CYGWIN_NT-*) HOST_PLATFORM=cygwin ;;
	*)		echo Unsupported platform: ${platform}
			exit 1 ;;
esac

# check common locations for sfdisk
for sfdiskDir in /sbin /usr/sbin /usr/local/sbin ; do
	if [ -e ${sfdiskDir}/${SFDISK_BINARY} ]; then
		HOST_SFDISK=${sfdiskDir}/${SFDISK_BINARY}
	fi
done

# check for case-sensitive filesystem
mkdir haikuCaseTest 2>/dev/null
mkdir haikucasetest 2>/dev/null
caseInsensitive=$?
rmdir haikuCaseTest haikucasetest 2>/dev/null
if [ $caseInsensitive != 0 ]; then
	echo "You need a case-sensitive file-system to build Haiku."
	if [ $HOST_PLATFORM = "darwin" ]; then
		echo "You can create a case-sensitive disk image using Disk Utility and use"
		echo "it to store the Haiku sources on."
	fi
	exit 1
fi

# determine how to invoke sed with extended regexp support for non-GNU sed
if [ $HOST_PLATFORM = "darwin" ]; then
	HOST_EXTENDED_REGEX_SED="sed -E"
fi

# create output directory
mkdir -p "$buildOutputDir" || exit 1

if [ "$HAIKU_HOST_BUILD_ONLY" = 1 ]; then
	invalidCommand=$sourceDir/build/scripts/host_build_only
	HAIKU_AR=$invalidCommand
	HAIKU_CC=$invalidCommand
	HAIKU_LD=$invalidCommand
	HAIKU_OBJCOPY=$invalidCommand
	HAIKU_RANLIB=$invalidCommand
	HAIKU_ELFEDIT=$invalidCommand
	HAIKU_YASM=$invalidCommand
	HAIKU_STRIP=$invalidCommand
else
	if [ -n "$HAIKU_PACKAGING_ARCHS" ]; then
		targetArchs="$HAIKU_PACKAGING_ARCHS"
	fi
	HAIKU_PACKAGING_ARCHS=

	# On Haiku determine target architectures and tools automatically.
	if [ -z "$targetArchs" ]; then
		if [ $HOST_PLATFORM != haiku_host ]; then
			echo "Please specify the build tools to use or build (via" \
				"--cross-tools-prefix or --build-cross-tools) or specify a" \
				"host-only build (--host-only)." >&2
			exit 1
		fi

		# determine primary architecture
		targetArch=`package list -i /system/packages/haiku-*.hpkg \
			| sed '/^\s*architecture:/!d; s,^\s*architecture:\s*,,'`
		is_in_list "$targetArch" "$supportedTargetArchs" || (
			echo "Unsupported target architecture: \"$targetArch\"" >&2
			exit 1
		)
		targetArchs=$targetArch

		set_default_value HAIKU_AR_$targetArch			ar
		set_default_value HAIKU_CC_$targetArch			gcc
		set_default_value HAIKU_LD_$targetArch			ld
		set_default_value HAIKU_OBJCOPY_$targetArch		objcopy
		set_default_value HAIKU_RANLIB_$targetArch		ranlib
		set_default_value HAIKU_ELFEDIT_$targetArch		elfedit
		set_default_value HAIKU_STRIP_$targetArch		strip

		# determine secondary architectures
		for targetArch in $supportedTargetArchs; do
			if [ -e /system/packages/haiku_$targetArch-*.hpkg ]; then
				targetArchs="$targetArchs $targetArch"
				set_default_value HAIKU_AR_$targetArch		ar-$targetArch
				set_default_value HAIKU_CC_$targetArch		gcc-$targetArch
				set_default_value HAIKU_LD_$targetArch		ld-$targetArch
				set_default_value HAIKU_OBJCOPY_$targetArch	objcopy-$targetArch
				set_default_value HAIKU_RANLIB_$targetArch	ranlib-$targetArch
				set_default_value HAIKU_ELFEDIT_$targetArch	elfedit-$targetArch
				set_default_value HAIKU_STRIP_$targetArch	strip-$targetArch
			fi
		done

		# The target architectures might have been specified explicitly.
		if [ -n "$haikuTargetArchs" ]; then
			for targetArch in $haikuTargetArchs; do
				is_in_list "$targetArch" "$targetArchs" || (
					echo "Unsupported target architecture: \"$targetArch\"." \
						"Only native architectures of the host platform can" \
						"be specified." >&2
					exit 1
				)
			done
			targetArchs="$haikuTargetArchs"
		fi
	fi

	isPrimaryArch=1
	for targetArch in $targetArchs; do
		# Note: targetArch is "unknown<n>" at this point, if a cross-tools
		# prefix was specified. The standard_gcc_settings call below will get
		# the actual architecture.

		crossToolsPrefix=`get_variable crossToolsPrefix_$targetArch`

		# build cross tools from sources
		if [ -n "$buildCrossTools" -a -z "$crossToolsPrefix" ]; then
			crossToolsDir="$outputDir/cross-tools-$targetArch"
			targetMachine=`get_variable buildCrossToolsMachine_$targetArch`
			script="$buildCrossToolsScript"
			scriptArgs=
			if [ $targetArch != x86_gcc2 ]; then
				script="${script}_gcc4"
				scriptArgs="$targetMachine"
				set_default_value HAIKU_USE_GCC_GRAPHITE_$targetArch	\
					$useGccGraphiteDefault
			fi
			secondaryArch=
			if [ -z "$isPrimaryArch" ]; then
				secondaryArch=$targetArch
			fi

			case $HOST_PLATFORM in
				freebsd|openbsd)	MAKE=gmake;;
				*)					MAKE=make;;
			esac

			MAKE=$MAKE \
			SECONDARY_ARCH=$secondaryArch \
			HAIKU_USE_GCC_GRAPHITE=`get_variable \
				HAIKU_USE_GCC_GRAPHITE_$targetArch` \
			"$script" $scriptArgs "$sourceDir" "$buildCrossTools" \
				"$crossToolsDir" $buildCrossToolsJobs || exit 1
			crossToolsPrefix="$crossToolsDir/bin/${targetMachine}-"
		fi

		# prepare gcc settings and get the actual target architecture
		gcc="${crossToolsPrefix}gcc"
		if [ -z "${crossToolsPrefix}" ]; then
			gcc=`get_variable HAIKU_CC_$targetArch`
		fi
		standard_gcc_settings "$gcc"
		targetArch=$standard_gcc_settings_targetArch

		# set default values for flags
		set_default_value HAIKU_CPPFLAGS_$targetArch	""
		set_default_value HAIKU_CCFLAGS_$targetArch		""
		set_default_value HAIKU_CXXFLAGS_$targetArch	""
		set_default_value HAIKU_LDFLAGS_$targetArch		""
		set_default_value HAIKU_ARFLAGS_$targetArch		cru
		set_default_value HAIKU_UNARFLAGS_$targetArch	x

		# Override the cross tools variables, if the tools were built or a
		# prefix was specified.
		if [ -n "$crossToolsPrefix" ]; then
			get_build_tool_path AR_$targetArch ${crossToolsPrefix}ar
			get_build_tool_path LD_$targetArch ${crossToolsPrefix}ld
			get_build_tool_path OBJCOPY_$targetArch ${crossToolsPrefix}objcopy
			get_build_tool_path RANLIB_$targetArch ${crossToolsPrefix}ranlib
			get_build_tool_path STRIP_$targetArch ${crossToolsPrefix}strip

			case `get_variable HAIKU_GCC_RAW_VERSION_$targetArch` in
				4.*)
					get_build_tool_path ELFEDIT_$targetArch \
						${crossToolsPrefix}elfedit
				;;
			esac
		fi

		# Get the libgcc objects. We couldn't do that in standard_gcc_settings,
		# since we need "ar", which may be set later.
		ar=`get_variable HAIKU_AR_$targetArch`
		libgcc=`get_variable HAIKU_GCC_LIBGCC_$targetArch`
		set_variable HAIKU_GCC_LIBGCC_OBJECTS_$targetArch \
			"`$ar t $libgcc | grep -v eabi.o`"
			# Note: We filter out eabi.o. It's present in gcc's libgcc for PPC
			# and neither needed nor wanted.

		# check whether the Haiku compiler really targets Haiku
		targetMachine=`get_variable HAIKU_GCC_MACHINE_$targetArch`
		case "$targetMachine" in
			*-*-haiku)	;;
			*)
				echo The compiler specified as Haiku target compiler is not a \
				valid Haiku cross-compiler. Please see ReadMe.cross-compile. >&2
				echo compiler: $HAIKU_CC
				echo compiler is configured for target: $targetMachine
				exit 1 ;;
		esac

		HAIKU_PACKAGING_ARCHS="$HAIKU_PACKAGING_ARCHS $targetArch"
		isPrimaryArch=
	done
fi

# Generate BuildConfig
cat << EOF > "$buildConfigFile"
# BuildConfig
# Note: This file has been automatically generated by configure with the
# following arguments:
# ${configureArgs}

TARGET_PLATFORM 			?= "${TARGET_PLATFORM}" ;
HOST_PLATFORM				?= "${HOST_PLATFORM}" ;

HAIKU_INCLUDE_GPL_ADDONS			?= "${HAIKU_INCLUDE_GPL_ADDONS}" ;
HAIKU_INCLUDE_PATENTED_CODE			?= "${HAIKU_INCLUDE_PATENTED_CODE}" ;
HAIKU_INCLUDE_SOURCES				?= "${HAIKU_INCLUDE_SOURCES}" ;
HAIKU_INCLUDE_3RDPARTY				?= "${HAIKU_INCLUDE_3RDPARTY}" ;
HAIKU_ENABLE_MULTIUSER				?= "${HAIKU_ENABLE_MULTIUSER}" ;
HAIKU_DISTRO_COMPATIBILITY			?= "${HAIKU_DISTRO_COMPATIBILITY}" ;
HAIKU_USE_GCC_PIPE					?= "${HAIKU_USE_GCC_PIPE}" ;
HAIKU_HOST_USE_32BIT				?= "${HAIKU_HOST_USE_32BIT}" ;
HAIKU_HOST_USE_XATTR				?= "${HAIKU_HOST_USE_XATTR}" ;
HAIKU_HOST_USE_XATTR_REF			?= "${HAIKU_HOST_USE_XATTR_REF}" ;
HAIKU_HOST_BUILD_ONLY				?= "${HAIKU_HOST_BUILD_ONLY}" ;

HAIKU_PACKAGING_ARCHS		?= ${HAIKU_PACKAGING_ARCHS} ;

HAIKU_BUILD_ATTRIBUTES_DIR	?= ${HAIKU_BUILD_ATTRIBUTES_DIR} ;

HAIKU_YASM					?= ${HAIKU_YASM} ;

HOST_EXTENDED_REGEX_SED		?= ${HOST_EXTENDED_REGEX_SED} ;
HOST_GCC_RAW_VERSION		?= ${HOST_GCC_RAW_VERSION} ;
HOST_GCC_MACHINE			?= ${HOST_GCC_MACHINE} ;
HOST_LD						?= ${HOST_GCC_LD} ;
HOST_OBJCOPY				?= ${HOST_GCC_OBJCOPY} ;
HOST_SFDISK					?= ${HOST_SFDISK} ;
HOST_SHA256					?= ${HOST_SHA256} ;

HOST_HAIKU_PORTER			?= ${HOST_HAIKU_PORTER} ;
HAIKU_PORTS					?= ${HAIKU_PORTS} ;
HAIKU_PORTS_CROSS			?= ${HAIKU_PORTS_CROSS} ;

EOF

for targetArch in $HAIKU_PACKAGING_ARCHS; do
	variables="
		HAIKU_GCC_RAW_VERSION		HAIKU_GCC_RAW_VERSION
		HAIKU_GCC_MACHINE			HAIKU_GCC_MACHINE
		HAIKU_GCC_LIB_DIR			HAIKU_GCC_LIB_DIR
		HAIKU_GCC_LIBGCC			HAIKU_GCC_LIBGCC
		HAIKU_CPU					HAIKU_CPU
		HAIKU_STATIC_LIBSTDC++		HAIKU_STATIC_LIBSTDCXX
		HAIKU_SHARED_LIBSTDC++		HAIKU_SHARED_LIBSTDCXX
		HAIKU_STATIC_LIBSUPC++		HAIKU_STATIC_LIBSUPCXX
		HAIKU_SHARED_LIBSUPC++		HAIKU_SHARED_LIBSUPCXX
		HAIKU_KERNEL_LIBGCC			HAIKU_KERNEL_LIBGCC
		HAIKU_KERNEL_LIBSUPC++		HAIKU_KERNEL_LIBSUPCXX
		HAIKU_BOOT_LIBGCC			HAIKU_BOOT_LIBGCC
		HAIKU_BOOT_LIBSUPC++		HAIKU_BOOT_LIBSUPCXX
		HAIKU_AR					HAIKU_AR
		HAIKU_CC					HAIKU_CC
		HAIKU_LD					HAIKU_LD
		HAIKU_OBJCOPY				HAIKU_OBJCOPY
		HAIKU_RANLIB				HAIKU_RANLIB
		HAIKU_ELFEDIT				HAIKU_ELFEDIT
		HAIKU_STRIP					HAIKU_STRIP
		HAIKU_CPPFLAGS				HAIKU_CPPFLAGS
		HAIKU_CCFLAGS				HAIKU_CCFLAGS
		HAIKU_C++FLAGS				HAIKU_CXXFLAGS
		HAIKU_LDFLAGS				HAIKU_LDFLAGS
		HAIKU_ARFLAGS				HAIKU_ARFLAGS
		HAIKU_UNARFLAGS				HAIKU_UNARFLAGS
		HAIKU_USE_GCC_GRAPHITE		HAIKU_USE_GCC_GRAPHITE
		"
	set -- $variables
	while [ $# -ge 2 ]; do
		value=`get_variable ${2}_$targetArch`
		echo "${1}_${targetArch} ?= $value ;" >> "$buildConfigFile"
		shift 2
	done

	# For variables that may have long values, distribute them over multiple
	# lines so that jam doesn't hit the maximum line length.
	variables="
		HAIKU_GCC_HEADERS_DIR		HAIKU_GCC_HEADERS_DIR
		HAIKU_C++_HEADERS_DIR		HAIKU_CXX_HEADERS_DIR
		HAIKU_BOOT_C++_HEADERS_DIR	HAIKU_BOOT_CXX_HEADERS_DIR
		HAIKU_GCC_LIBGCC_OBJECTS	HAIKU_GCC_LIBGCC_OBJECTS
		"
	set -- $variables
	while [ $# -ge 2 ]; do
		echo "${1}_${targetArch} ?= " >> "$buildConfigFile"
		get_variable ${2}_$targetArch | xargs -n 1 echo "   " \
			>> "$buildConfigFile"
		echo "    ;" >> "$buildConfigFile"
		shift 2
	done
done


# Generate a boot strap Jamfile in the output directory.

cat << EOF > $outputDir/Jamfile
# automatically generated Jamfile

HAIKU_TOP			= ${sourceDir} ;
HAIKU_OUTPUT_DIR	= ${outputDir} ;

include [ FDirName \$(HAIKU_TOP) Jamfile ] ;

EOF