#!/bin/sh
#
# x86_64-linux-toolchain.sh  -- build an x86_64-linux cross toolchain
#
# (C) Copyright 2013-2014,  Greg Ungerer <gerg@uclinux.org>
#

ARCH=x86_64
TARGET=x86_64-linux
PREFIX=/usr/local
PREFIX_TARGET=${PREFIX}/${TARGET}

BINUTILS_VERSION=2.23.2
GCC_VERSION=4.8.3
UCLIBC_VERSION=0.9.33.2
GDB_VERSION=7.6
LINUX_VERSION=3.10

###########################################################################

extract()
{
	for i in "$@"
	do
		echo "Extracting $i..."
		case "$i" in
		*.tar.gz|*.tgz)   tar xzf "$i" ;;
		*.tar.bz2|*.tbz2) tar xjf "$i" ;;
		*.tar.xz|*.txz)   tar xJf "$i" ;;
		*.tar)            tar xf  "$i" ;;
		*)                echo "Unknown file format $i" >&2
		                  return 1 ;;
		esac
	done
	return 0
}

build_binutils()
{
	cd ${ROOTDIR}
	echo "BUILD: binutils-${BINUTILS_VERSION}"

	extract binutils-${BINUTILS_VERSION}.tar.*
	cd binutils-${BINUTILS_VERSION}

	patch -p1 < ../binutils-2.23.2-texinfo.patch || exit 1

	mkdir ${TARGET}
	cd ${TARGET}

	# when multilibing configure with lib32 as well...
	#../configure --target=${TARGET} --with-lib-path=${PREFIX_TARGET}/lib:${PREFIX_TARGET}/lib/32
	../configure --target=${TARGET}
	make || exit 1
	make install || exit 1

	return 0
}


build_linux_headers()
{
	cd ${ROOTDIR}
	echo "BUILD: linux-${LINUX_VERSION} headers"

	extract linux-${LINUX_VERSION}.tar.*
	cd linux-${LINUX_VERSION}

	patch -p1 < ../linux-3.10-netlink.patch || exit 1

	make ARCH=${ARCH} defconfig || exit 1
	make ARCH=${ARCH} headers_install || exit 1
	cp -a usr/include ${PREFIX_TARGET}/
	return 0
}

build_package()
{
	PACKAGE=$1
	VERSION=$2

	cd ${ROOTDIR}
	echo "BUILD: ${PACKAGE}-${VERSION}"

	extract ${PACKAGE}-${VERSION}.tar.*
	cd ${PACKAGE}-${VERSION}
	./configure || exit 1
	make || exit 1
	make install || exit 1

	return 0
}

build_gcc()
{
	PASS=$1
	CFGOPTS=""

	cd ${ROOTDIR}
	echo "BUILD: gcc-${GCC_VERSION} (pass ${PASS})"

	if [ "${PASS}" = 1 ] ; then
		CFGOPTS="--enable-newlib \
			--disable-threads \
			--disable-shared \
			--disable-libmudflap \
			--disable-libssp \
			--disable-multilib \
			--enable-languages=c"
	else
		CFGOPTS="--disable-multilib \
			--enable-languages=c,c++"
	fi

	extract gcc-${GCC_VERSION}.tar.*
	mv gcc-${GCC_VERSION} gcc-${GCC_VERSION}.pass-${PASS}
	cd gcc-${GCC_VERSION}.pass-${PASS}

	chmod +x contrib/download_prerequisites
	contrib/download_prerequisites || exit 1

	mkdir ${TARGET}
	cd ${TARGET}

	../configure --target=${TARGET} \
		--with-system-zlib \
		${CFGOPTS} \
		--prefix=${PREFIX} || exit 1
	make || [ $PASS -eq 1 ] || exit 1
	make install || [ $PASS -eq 1 ] || exit 1

	return 0
}

fix_uclibc_headers()
{
	#
	# sysnum.h is a generated header, and uClibc doesn't correctly
	# generate a multilib capable one for i386 and x86_64. We use the
	# 2 original ones to create a multilib clean one.
	#
	HEADER=${PREFIX_TARGET}/include/bits/sysnum.h
	HEADER64=${ROOTDIR}/uClibc-${UCLIBC_VERSION}./include/bits/sysnum.h
	HEADER32=${ROOTDIR}/uClibc-${UCLIBC_VERSION}.i386/include/bits/sysnum.h

	head -n +9 ${HEADER64} > ${HEADER}
	echo -e "#if defined __x86_64__\n" >> ${HEADER}
	tail -n +10 ${HEADER64} | head -n -2 >> ${HEADER}
	echo -e "\n#else\n" >> ${HEADER}
	tail -n +10 ${HEADER32} | head -n -2 >> ${HEADER}
	echo -e "\n#endif\n\n#endif" >> ${HEADER}
}

build_uclibc()
{
	MULTILIB=$1
	LIBDIR=""
	CFLAGS=""

	MULTILIB_ARCH=${ARCH}
	if [ "${MULTILIB}" = "fix" ] ; then
		fix_uclibc_headers
		return 0
	fi
	if [ "${MULTILIB}" = "i386" ] ; then
		MULTILIB_ARCH=i386
		LIBDIR="/32"
		CFLAGS="-m32"
	fi

	cd ${ROOTDIR}
	echo "BUILD: uClibc-${UCLIBC_VERSION} (type ${MULTILIB})"

	extract uClibc-${UCLIBC_VERSION}.tar.*
	mv uClibc-${UCLIBC_VERSION} uClibc-${UCLIBC_VERSION}.${MULTILIB}
	cd uClibc-${UCLIBC_VERSION}.${MULTILIB}

	make ARCH=${MULTILIB_ARCH} defconfig || exit 1

	KHDR=`echo ${PREFIX_TARGET}/include | sed -e 's/\//\\\\\//g'`
	PDIR=`echo ${PREFIX_TARGET} | sed -e 's/\//\\\\\//g'`
	DDIR=`echo ${PREFIX_TARGET}/usr/ | sed -e 's/\//\\\\\//g'`
	LDIR=`echo lib${LIBDIR} | sed -e 's/\//\\\\\//g'`

	cat .config | \
	sed -e "s/^KERNEL_HEADERS.*$/KERNEL_HEADERS=\"${KHDR}\"/" | \
	sed -e "s/^RUNTIME_PREFIX.*$/RUNTIME_PREFIX=\"${PDIR}\"/" | \
	sed -e "s/^DEVEL_PREFIX.*$/DEVEL_PREFIX=\"${PDIR}\"/" | \
	sed -e "s/^MULTILIB_DIR.*$/MULTILIB_DIR=\"${LDIR}\"/" | \
	sed -e "s/^DEVEL_PREFIX.*$/DEVEL_PREFIX=\"${PDIR}\"/" | \
	sed -e "s/^CROSS_COMPILER_PREFIX.*$/CROSS_COMPILER_PREFIX=\"${TARGET}-\"/" | \
	sed -e "s/^UCLIBC_EXTRA_CFLAGS.*$/UCLIBC_EXTRA_CFLAGS=\"${CFLAGS}\"/" | \
	sed -e "s/^HAS_NO_THREADS.*$/# HAS_NO_THREADS is not set/" | \
	sed -e "s/^# UCLIBC_HAS_THREADS_NATIVE.*$/UCLIBC_HAS_THREADS_NATIVE=y/" | \
	sed -e "/PTHREADS_DEBUG_SUPPORT/d" | \
	sed -e "/UCLIBC_SUSV4_LEGACY/d" | \
	sed -e "/UCLIBC_SUSV3_LEGACY/d" | \
	sed -e "/UCLIBC_SUSV3_LEGACY_MACROS/d" | \
	sed -e "/DO_C99_MATH/d" | \
	sed -e "/UCLIBC_HAS_LONG_DOUBLE_MATH/d" | \
	sed -e "/UCLIBC_HAS_FENV/d" | \
	sed -e "/UCLIBC_HAS_WCHAR/d" | \
	sed -e "/UCLIBC_HAS_IPV6/d" | \
	sed -e "/UCLIBC_HAS_RPC/d" | \
	sed -e "/UCLIBC_HAS_FULL_RPC/d" | \
	sed -e "/UCLIBC_HAS_REENTRANT_RPC/d" | \
	sed -e "/UCLIBC_HAS_RESOLVER_SUPPORT/d" | \
	sed -e "/UCLIBC_HAS_LIBRESOLV_STUB/d" | \
	sed -e "/UCLIBC_HAS_LIBNSL_STUB/d" | \
	cat > /tmp/config
	echo PTHREADS_DEBUG_SUPPORT=n >> /tmp/config
	echo UCLIBC_SUSV3_LEGACY=y >> /tmp/config
	echo UCLIBC_SUSV3_LEGACY_MACROS=y >> /tmp/config
	echo UCLIBC_SUSV4_LEGACY=y >> /tmp/config
	echo DO_C99_MATH=y >> /tmp/config
	echo UCLIBC_HAS_LONG_DOUBLE_MATH=y >> /tmp/config
	echo UCLIBC_HAS_FENV=y >> /tmp/config
	echo UCLIBC_HAS_WCHAR=y >> /tmp/config
	echo UCLIBC_HAS_IPV6=y >> /tmp/config
	echo UCLIBC_HAS_RPC=y >> /tmp/config
	echo UCLIBC_HAS_FULL_RPC=y >> /tmp/config
	echo UCLIBC_HAS_RESOLVER_SUPPORT=y >> /tmp/config
	echo UCLIBC_HAS_LIBRESOLV_STUB=y >> /tmp/config
	echo UCLIBC_HAS_LIBNSL_STUB=y >> /tmp/config
	echo "# UCLIBC_HAS_REENTRANT_RPC is not set" >> /tmp/config
	echo "# UCLIBC_HAS_FTW is not set" >> /tmp/config

	cp /tmp/config .config

	make ARCH=${ARCH} oldconfig

	if [ "${MULTILIB}" = headers ] ; then
		make install_headers || exit 1
		return 0
	fi

	make || exit 1
	make install || exit 1

	return 0
}

build_gdb()
{
	cd ${ROOTDIR}
	echo "BUILD: gdb-${GDB_VERSION}"

	extract gdb-${GDB_VERSION}.tar.*
	cd gdb-${GDB_VERSION}

	mkdir ${TARGET}
	cd ${TARGET}

	../configure --target=${TARGET} || exit 1
	make || exit 1
	make install || exit 1

	return 0
}

build_tarball()
{
	DATE=`date +%Y%m%d`
	PACKAGE="${TARGET}-tools-${DATE}.tar.gz"

	echo "BUILD: packaging ${PACKAGE}"

	cd /
	strip ${PREFIX_TARGET}/bin/* 2> /dev/null || true
	strip ${PREFIX}/bin/${TARGET}-* 2> /dev/null || true
	strip ${PREFIX}/libexec/gcc/${TARGET}/${GCC_VERSION}/* 2> /dev/null || true
	tar cvzf ${ROOTDIR}/${PACKAGE} \
		${PREFIX_TARGET} \
		${PREFIX}/lib/gcc/${TARGET}/${GCC_VERSION} \
		${PREFIX}/libexec/gcc/${TARGET}/${GCC_VERSION} \
		${PREFIX}/bin/${TARGET}-*

	return 0
}

build_clean()
{
	echo "BUILD: cleaning up..."

	rm -rf gcc-${GCC_VERSION}.pass*
	rm -rf binutils-${BINUTILS_VERSION}
	rm -rf uClibc-${UCLIBC_VERSION}.headers
	rm -rf uClibc-${UCLIBC_VERSION}.i386
	rm -rf uClibc-${UCLIBC_VERSION}.
	rm -rf gdb-${GDB_VERSION}
	rm -rf linux-${LINUX_VERSION}
	rm -rf ${TARGET}-tools-*

	rm -rf ${PREFIX_TARGET}
	rm -rf ${PREFIX}/bin/${TARGET}-[a-zA-Z]*
	rm -rf ${PREFIX}/lib/gcc/${TARGET}/${GCC_VERSION}
	rm -rf ${PREFIX}/libexec/gcc/${TARGET}/${GCC_VERSION}

	return 0
}

###########################################################################

ROOTDIR=`pwd`

if [ "$1" = clean ] ; then
	build_clean
	exit 0
fi
if [ "$1" = package ] ; then
	build_tarball
	exit $?
fi
if [ "$1" ] ; then
	build_$1 $2 $3 $4 $5 $6 $7 $8 $9
	exit $?
fi

echo "BUILD: target=${TARGET}"

# If anything fails we want the build to stop
set -e

mkdir -p ${PREFIX_TARGET}
chmod 777 ${PREFIX_TARGET}

build_binutils
build_linux_headers
build_uclibc headers
build_gcc 1
#build_uclibc i386
build_uclibc
#build_uclibc fix
build_gcc 2
build_gdb
build_tarball

exit 0
