#!/bin/sh
#
# This script builds the m68k-elf- or arm-elf- toolchain for use
# with uClinux.  It can be used to build for almost any architecture
# without too much change.
#
# Before running you will need to obtain (if you don't have them in this
# directory):
#
#    binutils-2.10.tar.bz2         in current directory (or a gzipped version)
#    binutils-2.10-full.patch      in current directory
#    gcc-2.95.3.tar.bz2            in current directory (or a gzipped version)
#    gcc-2.95.3-full.patch         in current directory
#    gcc-2.95.3-arm-pic.patch      in current directory
#    gcc-2.95.3-arm-pic.patch2     in current directory
#    gcc-2.95.3-arm-mlib.patch     in current directory
#    gcc-2.95.3-sigset.patch       in current directory
#    genromfs-0.5.1.tar.gz         in current directory, romfs.sourceforge.net
#
# You will also need
#
#    a current elf2flt tree from cvs.uclinux.org
#    a current uClibc tree from cvs.uclinux.org
#    a current uClinux kernel (2.0/2.4) from cvs.uclinux.org
#    to change the EDIT section below appropriately
#
# You can link the uClibc and uClinux-2.0.x or uClinux-2.4.x dirs into the
# current directory or change the values below.
#
# This script:
#
# DOES build all the gcc tools/libraries
#
# DOES NOT build target specific versions of libc but provides a mechanism
#          to do this with the "uclibc" argument if that is what you want.
#
# Unless you modify PREFIX below, you will need to be root to run this
# script correctly.
#
# To build everything run "./build-uclinux-tools.sh build 2>&1 | tee errs"
#
# WARNING: it removes all current tools from ${PREFIX},  so back them up
#          first :-)
#
# Copyright (C) 2001-2002 David McCullough <davidm@snapgear.com>
#
#############################################################
#
# our build starts here
#

BASEDIR="`pwd`"

#############################################################
#
# EDIT these to suit your system and source locations
#

MAKE=gmake
ELF2FLT="$BASEDIR/elf2flt"
UCLIBC="$BASEDIR/uClibc"
KERNEL="$BASEDIR/uClinux-2.4.x"
# KERNEL="$BASEDIR/uClinux-2.0.x"

TARGET=m68k-elf
#TARGET=arm-elf
#TARGET=sh-linux

# set your install directory here
# PREFIX=/tmp/tools

#############################################################
#
# mark stage done
#

mark()
{
	echo "STAGE $1 - complete"
	touch "$BASEDIR/STAGE$1"
}

#
# check if stage should be built
#

schk()
{
	echo "--------------------------------------------------------"
	[ -f "$BASEDIR/STAGE$1" ] && echo "STAGE $1 - already built" && return 1
	echo "STAGE $1 - needs building"
	return 0
}

#
# extract most XYZ format files
#

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

#############################################################
#
# clean any previous runs, extract some stuff
#

stage1()
{
	schk 1 || return 0

	rm -rf binutils-2.10
	rm -rf gcc-2.95.3
	rm -rf ${PREFIX}/${TARGET}
	rm -rf ${PREFIX}/lib/gcc-lib/${TARGET}
	rm -rf ${PREFIX}/bin/${TARGET}*
#
#	extract binutils, gcc and anything else we know about
#
	extract binutils-2.10.*
	extract gcc-2.95.3.*
#
#	apply any patches
#
	patch -p0 < gcc-2.95.3-full.patch
    patch -p0 < gcc-2.95.3-arm-pic.patch
    patch -p0 < gcc-2.95.3-arm-pic.patch2
    patch -p0 < gcc-2.95.3-arm-mlib.patch
    patch -p0 < gcc-2.95.3-sigset.patch
	patch -p0 < binutils-2.10-full.patch
	cd $BASEDIR
	mark 1
}

#############################################################
#
# build binutils
#

stage2()
{
	schk 2 || return 0

	rm -rf ${TARGET}-binutils
	mkdir ${TARGET}-binutils
	cd ${TARGET}-binutils
	../binutils-2.10/configure --target=${TARGET} ${PREFIXOPT}
	${MAKE}
	${MAKE} install
	cd $BASEDIR
	mark 2
}

#############################################################
#
# common uClibc Config substitutions
#

fix_uclibc_config()
{
	sed "s?^[ 	]*KERNEL_SOURCE[ 	]*=.*\$?KERNEL_SOURCE=${KERNEL}?" |
		if [ "${NOMMU}" ]; then
			sed -e "s?^[ 	]*HAS_MMU[ 	]*=.*\$?HAS_MMU=false?" \
				-e "s?^[ 	]*HAVE_SHARED[ 	]*=.*\$?HAVE_SHARED=false?" \
				-e "s?^[ 	]*BUILD_UCLIBC_LDSO[ 	]*=.*\$?BUILD_UCLIBC_LDSO=false?" \
				-e "s?^[ 	]*DOPIC[ 	]*=.*\$?DOPIC=${1:-false}?"
		else
			cat
		fi
}

#############################################################
#
# hack the env up for gcc build
#

stage3()
{
	schk 3 || return 0

	#
	# fix up the uClibc auto gen files
	#
	cd ${UCLIBC}/.
	fix_uclibc_config < extra/Configs/Config.${_CPU} > Config
	rm -f ${KERNEL}/include/asm
	ln -s ${KERNEL}/include/asm-${_CPU}${NOMMU} ${KERNEL}/include/asm
	${MAKE} uClibc_config.h CROSS="${TARGET}-"
	chmod 644 uClibc_config.h

	rm -rf ${PREFIX}/${TARGET}/sys-include
	rm -f ${UCLIBC}/include/asm
	cp -r ${UCLIBC}/include ${PREFIX}/${TARGET}/sys-include
	rm -rf ${PREFIX}/${TARGET}/sys-include/asm
	rm -rf ${PREFIX}/${TARGET}/sys-include/bits
	cp -r ${UCLIBC}/libc/sysdeps/linux/${_CPU}/bits \
					${PREFIX}/${TARGET}/sys-include/.
	cp uClibc_config.h ${PREFIX}/${TARGET}/sys-include/bits/.
	rm -rf ${PREFIX}/${TARGET}/sys-include/linux
	cp -r ${KERNEL}/include/linux ${PREFIX}/${TARGET}/sys-include/linux
	touch ${PREFIX}/${TARGET}/sys-include/linux/autoconf.h
	cp -r ${KERNEL}/include/asm-${_CPU}${NOMMU} \
					${PREFIX}/${TARGET}/sys-include/.

	# 2.4 headers also need this (may not be there for some archs)
	cp -r ${KERNEL}/include/asm-${_CPU} ${PREFIX}/${TARGET}/sys-include/.  ||\
			true

	ln -s ${PREFIX}/${TARGET}/sys-include/asm-${_CPU}${NOMMU} \
					${PREFIX}/${TARGET}/sys-include/asm
	
	case ${TARGET} in
	arm*)
		ln -s ${PREFIX}/${TARGET}/sys-include/asm-${_CPU}${NOMMU}/proc-armv \
						${PREFIX}/${TARGET}/sys-include/asm/proc
		;;
	esac

	#
	# clean out any CVS files,  don't fail on this one
	#
	set +e
	find ${PREFIX}/${TARGET}/sys-include -name CVS | xargs rm -rf
	set -e

	mkdir -p ${PREFIX}/lib/gcc-lib || true
	chmod 755 ${PREFIX}/lib/gcc-lib

	cd $BASEDIR
	mark 3
}

#############################################################
#
# first pass,  just the C compiler so we can build uClibc
#

stage4()
{
	schk 4 || return 0

	rm -rf ${TARGET}-gcc
	mkdir ${TARGET}-gcc
	cd ${TARGET}-gcc
	../gcc-2.95.3/configure --enable-languages=c --target=${TARGET} ${PREFIXOPT}
	${MAKE}
	${MAKE} install

	cd $BASEDIR
	mark 4
}

#############################################################
#
# build uCLibc with first pass compiler
#

stage5()
{
	schk 5 || return 0

	cd ${UCLIBC}/.
	fix_uclibc_config < extra/Configs/Config.${_CPU} > Config
	rm -f ${KERNEL}/include/asm
	ln -s ${KERNEL}/include/asm-${_CPU}${NOMMU} ${KERNEL}/include/asm
	${MAKE} clean CROSS="${TARGET}-"
	${MAKE} CROSS="${TARGET}-"

	cd $BASEDIR
	mark 5
}

#############################################################
#
# second pass,  build everything,  all compilers of use :-)
#

stage6()
{
	schk 6 || return 0

	#
	# We need these files for the configure parts of this stage
	#
	cp ${UCLIBC}/lib/libc.a ${PREFIX}/${TARGET}/lib/.
	cp ${UCLIBC}/lib/crt0.o ${PREFIX}/${TARGET}/lib/.

	rm -rf ${TARGET}-gcc
	mkdir ${TARGET}-gcc
	cd ${TARGET}-gcc

	case "${TARGET}" in
	arm-*) ar rv ${PREFIX}/${TARGET}/lib/libg.a ;; # create if not there
	esac

	case "${TARGET}" in
	sh-*)
		../gcc-2.95.3/configure --enable-languages=c --target=${TARGET} \
				--enable-multilib ${PREFIXOPT}
		${MAKE} LIBS=-lc
		${MAKE} install
		;;
	*)
		../gcc-2.95.3/configure --enable-languages=c,c++ --target=${TARGET} \
				--enable-multilib ${PREFIXOPT}
		${MAKE} LIBS=-lc

		#
		# Make sure the multilib directories exist, the ARM install misses
		# these for some reason
		#
		for lib in libio libiostream libstdc++
		do
			find ${TARGET} -name $lib.a -print | while read file
			do
				MLIB=`expr $file : "${TARGET}\(.*\)"`
				MLIB=`expr $MLIB : "\(.*\)/[^/]*/$lib.a"`
				if [ ! -d "${PREFIX}/lib/gcc-lib/${TARGET}/2.95.3/$MLIB" ]
				then
					echo "Fixing ${PREFIX}/lib/gcc-lib/${TARGET}/2.95.3/$MLIB"
					mkdir -p "${PREFIX}/lib/gcc-lib/${TARGET}/2.95.3/$MLIB"
					chmod 755 "${PREFIX}/lib/gcc-lib/${TARGET}/2.95.3/$MLIB"
				fi
			done || exit 1
		done || exit 1

		${MAKE} install
		#
		# for some reason "make install" doesn't install all the multilib
		# libraries in the right place.  We have to do this ourselves.
		# the directories should exist, so failing if they don't is ok
		#
		for lib in libio libiostream
		do
			echo "Manual install of $lib.a ..."
			find ${TARGET} -name $lib.a -print | while read file
			do
				MLIB=`expr $file : "${TARGET}\(.*\)"`
				MLIB=`expr $MLIB : "\(.*\)/[^/]*/$lib.a"`
				echo "  $MLIB/$lib.a"
				cp $file ${PREFIX}/${TARGET}/lib/$MLIB/$lib.a || exit 1
			done || exit 1
		done || exit 1
		;;
	esac

	#
	# Don't leave these around as they will not work for all targets
	# If you want uClibc-multilib,  build that later
	#
	rm -f ${PREFIX}/${TARGET}/lib/libc.a
	rm -f ${PREFIX}/${TARGET}/lib/crt0.o

	cd $BASEDIR
	mark 6
}

#############################################################
#
# build genromfs
#

stage7()
{
	schk 7 || return 0
	rm -rf genromfs-0.5.1
	extract genromfs-0.5.1*
	cd genromfs-0.5.1
	${MAKE}
	cp genromfs ${PREFIX}/bin/.
	chmod 755 ${PREFIX}/bin/genromfs

	cd $BASEDIR
	mark 7
}

#############################################################
#
# build elf2flt
#

stage8()
{
	schk 8 || return 0


	cd ${ELF2FLT}
	./configure --with-libbfd=${BASEDIR}/${TARGET}-binutils/bfd/libbfd.a \
		--with-libiberty=${BASEDIR}/${TARGET}-binutils/libiberty/libiberty.a \
		--with-bfd-include-dir=${BASEDIR}/${TARGET}-binutils/bfd \
		--target=${TARGET} ${PREFIXOPT}
	${MAKE}
	${MAKE} install

	cd $BASEDIR
	mark 8
}

#############################################################
#
# build multilib versions of uCLibc for a fuller install
#

build_uclibc_mlib()
{
	# set -x
	cd ${UCLIBC}/.

	case "${_CPU}" in
	m68k*) ALL_BUILDS="-Wa,--bitwise-or -D__linux__=1" ;;
	*)     ALL_BUILDS="-D__linux__=1" ;;
	esac

	ALL_BUILDS="${ALL_BUILDS} -I${KERNEL}/include"

	(
		echo ". $ALL_BUILDS"
		case "${_CPU}" in
		m68k*)
			echo "msoft-float       false $ALL_BUILDS -msoft-float"
			echo "m5200             false $ALL_BUILDS -m5200 -Wa,-m5200"
			echo "m5200/msep-data   true  $ALL_BUILDS -m5200 -Wa,-m5200 -msep-data"
			echo "m5307             false $ALL_BUILDS -m5307 -Wa,-m5307"
			echo "m5307/msep-data   true  $ALL_BUILDS -m5307 -Wa,-m5307 -msep-data"
			echo "m68000            false $ALL_BUILDS -m68000"
			echo "m68000/msep-data  true  $ALL_BUILDS -m68000 -msep-data"
			echo "mcpu32            false $ALL_BUILDS -mcpu32"
			echo "mcpu32/msep-data  true  $ALL_BUILDS -mcpu32 -msep-data"
			;;
		arm*)
			echo "fpic                           true $ALL_BUILDS -fpic"
			echo "mapcs-26                       false $ALL_BUILDS -mapcs-26"
			echo "fpic/mapcs-26                  true $ALL_BUILDS -fpic -mapcs-26"
			echo "fpic/mapcs-26/msingle-pic-base true $ALL_BUILDS -fpic -mapcs-26 -msingle-pic-base"
			echo "mbig-endian/fpic                           true $ALL_BUILDS -fpic -mbig-endian"
			echo "mbig-endian/mapcs-26                       false $ALL_BUILDS -mapcs-26 -mbig-endian"
			echo "mbig-endian/fpic/mapcs-26                  true $ALL_BUILDS -fpic -mapcs-26 -mbig-endian"
			echo "mbig-endian/fpic/mapcs-26/msingle-pic-base true $ALL_BUILDS -fpic -mapcs-26 -msingle-pic-base -mbig-endian"
			;;
		sh*)
			# don't know what is needed here yet
			;;
		esac
	) | while read mlibdir pic cflags
	do
		fix_uclibc_config $pic < extra/Configs/Config.${_CPU} |
		    sed -e "s?^[ 	]*ARCH_CFLAGS[ 	]*=.*?ARCH_CFLAGS=${cflags}?g" \
					> Config
		${MAKE} clean CROSS="${TARGET}-"
		${MAKE} CROSS="${TARGET}-"

		cp lib/crt0.o ${PREFIX}/${TARGET}/lib/$mlibdir/crt0.o || exit 1
		cp lib/libc.a ${PREFIX}/${TARGET}/lib/$mlibdir/libc.a || exit 1
		cp lib/libcrypt.a ${PREFIX}/${TARGET}/lib/$mlibdir/libcrypt.a || exit 1
		cp lib/libm.a ${PREFIX}/${TARGET}/lib/$mlibdir/libm.a || exit 1
		cp lib/libresolv.a ${PREFIX}/${TARGET}/lib/$mlibdir/libresolv.a || \
				exit 1
		cp lib/libutil.a ${PREFIX}/${TARGET}/lib/$mlibdir/libutil.a || exit 1

		chmod 644 ${PREFIX}/${TARGET}/lib/$mlibdir/libc.a || exit 1
		chmod 644 ${PREFIX}/${TARGET}/lib/$mlibdir/crt0.o || exit 1
	done

	cd $BASEDIR
}

#############################################################
#
# tar up everthing we have built
#

build_tar_file()
{
	# set -x
	cd /

	#
	# strip the binaries,  make sure we don't strip the libraries (some
	# platforms allow this :-(
	#
	strip ${PREFIX}/bin/genromfs > /dev/null 2>&1 || true
	strip ${PREFIX}/bin/${TARGET}-* > /dev/null 2>&1 || true
	strip ${PREFIX}/${TARGET}/bin/* > /dev/null 2>&1 || true
	strip ${PREFIX}/lib/gcc-lib/${TARGET}/2.95.3/*[!a] > /dev/null 2>&1 || true

	#
	# tar it all up
	#
	tar cvzf $BASEDIR/${TARGET}-tools-`date +%Y%m%d`.tar.gz \
		.${PREFIX}/${TARGET} \
		.${PREFIX}/lib/gcc-lib/${TARGET} \
		.${PREFIX}/include/g++-3 \
		.${PREFIX}/bin/${TARGET}-* \
		.${PREFIX}/bin/genromfs \
		.${PREFIX}/bin/elf2flt \
		.${PREFIX}/bin/flthdr

	cd $BASEDIR
}

#############################################################
#
# cleanup
#

clean_all()
{
	echo "Cleaning everything up..."

	rm -f $BASEDIR/STAGE*
	rm -rf binutils-2.10
	rm -rf gcc-2.95.3
	rm -rf genromfs-0.5.1
	rm -rf elf2flt-20020208
	rm -rf ${TARGET}-gcc
	rm -rf ${TARGET}-binutils
}

#############################################################
#
# main - put everything together in order.
#
# Some setup
#

case ${TARGET} in
m68k*) _CPU=m68k; NOMMU=nommu ;;
arm*)  _CPU=arm;  NOMMU=nommu ;;
sh*)   _CPU=sh;   NOMMU=      ;;
esac

#
# if not defined use the GNU tools default of /usr/local
#
if [ -z "${PREFIX}" ]
then
	PREFIX=/usr/local
else
	PREFIXOPT="--prefix=${PREFIX}"
fi

#
# first check some args
#

case "$1" in
build)
	rm -f $BASEDIR/STAGE*
	;;
continue)
	# do nothing here
	;;
uclibc)
	build_uclibc_mlib
	exit 0
	;;
tar)
	build_tar_file
	exit 0
	;;
clean)
	clean_all
	exit 0
	;;
*)
	echo "usage: $0 (build|continue|clean)" >&2
	echo ""
	echo "       build    = build everything from scratch."
	echo "       continue = continue building from last error."
	echo "       uclibc   = build multilib versions of uClibc (if wanted)."
	echo "       tar      = build for distribution of binaries."
	echo "       clean    = clean all temporary files etc."
	exit 1
	;;
esac

#
# You have to root for this one
#

if [ "${PREFIXOPT}" ]
then
	if [ ! -w "${PREFIX}" ]
	then
		echo "Bad,  ${PREFIX} is not writable !"
		exit 1
	fi
else
	if id | grep root > /dev/null
	then
		echo "Good, you are root :-)"
	else
		echo "Bad,  you are not root."
		exit 1
	fi
fi

if [ ! -f ${KERNEL}/include/linux/version.h -o \
		! -f ${KERNEL}/include/linux/autoconf.h ]; then
	echo "Your kernel is not configured, cannot continue." >&2
	echo "The following files do not exist:"
	echo
	echo "    ${KERNEL}/include/linux/version.h"
	echo "    ${KERNEL}/include/linux/autoconf.h"
	echo
	echo "These are need by the build.  You should do the following:"
	echo
	echo "    cd ${KERNEL}"
	echo "    make ARCH=${_CPU}${NOMMU} oldconfig"
	echo "    make dep"
	echo
	echo "You should then be able to continue."
	exit 1
fi

# set -x	# debug script
set -e		# if anything fails, stop

stage1
stage2
stage3
stage4
stage5
stage6
stage7
stage8

echo "--------------------------------------------------------"
echo "Build successful !"
echo "--------------------------------------------------------"

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

