#!/bin/bash
#
# build-crossgcc.sh
#
# Copyright (c) 2001 by Bill Gatliff, bgat@billgatliff.com All rights
# reserved.  This script is provided under the terms of the GPL.
#
# $Id: build-crossgcc.sh,v 1.14 2002/03/21 03:03:32 bgat Exp $
#
# This script automates the tool build process for arm-linux,
# powerpc-linux, and other crosscompilers.  Over time, it will be
# extended for lots of other configurations as well.
#
# To use this script, first download copies of the binutils, gcc,
# glibc and your Linux kernel tarballs into a single directory, say,
# ~/tars.  See the declarations of LINUXDISTO, GCCDISTO, etc. below to
# know what versions of the files you need, or change them as
# appropriate.
#
# This script has been tested with the following versions:
#
# binutils-2.14.90 gcc-3.3.2 linux-2.4.21 glibc-2.3.2
# glibc-linuxthreads-2.3.2
#
#
# For the moment, you're on your own if you use different versions,
# although I would be interested in hearing both success and failure
# stories.
#
# Above all, THINK.  Avoid just sending me an "it didn't work" email.
#
# You will need about 1GB of disk space to build a *-linux cross
# toolchain, and about 500MB for a non *-linux one.
#
# The first line in this script should point to your "bash"
# executable.  usually, just !/bin/sh will do it; sometimes
# (especially if you're running GNU tools on a non-GNU host, like
# solaris8), you need to set it to something like
# !/usr/local/bin/bash.
#
# Some targets need a preconfigured kernel tree (as opposed to just a
# raw one).  If the target you select falls into this category, then
# this script will dump you over to menuconfig, or manually configure
# a kernel itself at the appropriate time.  If you end up in
# menuconfig, simply focus on the System Type configuration, because
# that's all we're interested in.
#
# <aside>
#
# When you do finally build your kernel (the script doesn't do this
# for you), you'll either have to hack the top-level Linux Makefile,
# or you'll need to do something like this:
#
# make ARCH=arm CROSS_COMPILE=arm-linux-
#
# If you're running a target-specific Linux kernel, this may already
# have been done for you.
#
# </aside>
#
# RUN THIS SCRIPT IN ITS OWN DIRECTORY.  It makes lots of
# subdirectories, and isn't very smart about not clobbering something
# useful that may be in its way.
#
# DO NOT RUN THIS SCRIPT AS ROOT, because if you do and something goes
# wrong (a bug in the script, or an incorrect PREFIX definition), then
# you can really hose things up on your workstation.  Instead, as root
# simply create a directory like /opt, chmod 777 it, and then return
# to non-root and aim PREFIX over to the new directory. At least then
# if the script really runs wild, you won't clobber important system
# stuff.
#
# Sample invocations:
#
#     build-crossgcc.sh
#
# You can also pre-specify the information this script needs, like this:
#
#     TARDIR=~/tars PREFIX=/home/me TARGET=arm-linux \
#          build-crossgcc.sh 2>&1 | tee build.log
#
# TARDIR is the location of the tarballs, PREFIX is the installation
# location, and TARGET is the type of toolchain you want.
#
# For questions, comments or improvements see the crossgcc mailing
# list at http://sources.redhat.com/ml/crossgcc, or contact the
# author.
#
# TODO: error handling.  If a step fails, we currently blindly continue.
#       idea: test for the existence of the build products after each step.
# TODO: add capability to use a preexisting linux kernel source tree.
#

set -ex

CURRDIR=$(/bin/pwd)
DEFAULT_TARDIR=${CURRDIR}/source
DEFAULT_PREFIX=/usr/local
DEFAULT_PATCHDIR=${CURRDIR}/patch

REVISION="$Id: build-crossgcc.sh,v 1.14 2002/03/21 03:03:32 bgat Exp $"
TARGET_LIST="arm-elf arm-linux h8300-coff h8300-hitachi-hms m68k-coff m68k-elf powerpc-linux powerpc-eabi sh-elf sh-hms"


echo
echo Linux crosscompiler building script,
echo revision $REVISION
echo


# only prompt if we're missing information
if [ x${PREFIX} = x ] || [ x${TARGET} = x ] || [ x${TARDIR} = x ] || [ x${PATCHDIR} = x ] ; then


    PS3="Please select a target: "
    select TARGET in ${TARGET_LIST};
	do echo; break; done

    PREFIX=${DEFAULT_PREFIX}/${TARGET}
    echo "Install the tools where?"
    read -p "[${PREFIX}]: "
    if [ x${REPLY} != x ]; then PREFIX=$REPLY; fi
    echo

    echo "Tarballs are where?"
    TARDIR=${DEFAULT_TARDIR}
    read -p "[${TARDIR}]: "
    if [ x${REPLY} != x ]; then TARDIR=${REPLY}; fi
    echo

    echo "Patches are where?"
    PATCHDIR=${DEFAULT_PATCHDIR}
    read -p "[${PATCHDIR}]: "
    if [ x${REPLY} != x ]; then TARDIR=${REPLY}; fi

fi

# test that we have write permissions to the install dir
mkdir -p ${PREFIX}/${TARGET}
touch ${PREFIX}/${TARGET}/test-if-write
if [ ! -f ${PREFIX}/${TARGET}/test-if-write ]; then
    echo "You don't appear to have write permissions to ${PREFIX}/${TARGET}."
    echo "You must fix that before continuing."
    exit
fi
rm -rf ${PREFIX}/${TARGET}/test-if-write

echo
echo Building for:
echo "    --target=$TARGET"
echo "    --prefix=$PREFIX"
echo "    tarballs are at $TARDIR"
echo "    patches are at $PATCHDIR"

###

#
# Tweak these for the versions you will use.  Their names must
# correspond to the base names of the tarballs they come from,
# i.e. if you define BINUTILSDISTO=my-binutils, then there should
# be a file my-binutils.tar.gz in $TARDIR.
#
BINUTILSDISTO=binutils-2.14.90.0.7
GCCDISTO=gcc-3.3.2
LINUXDISTO=linux-2.4.21
GLIBCDISTO=glibc-2.3.2
GLIBCTHREADSDISTO=glibc-linuxthreads-2.3.2
NEWLIBDISTO=newlib-1.11.0

# optionally, you can take out the 'v' here to quiet things down a bit.
#TARFLAGS=xvf
TARFLAGS=xf


###
#
# Don't modify anything below here, unless you're fixing bugs.
#


# make sure the build product's binaries are in the search path

export PATH=${PREFIX}/bin:$PATH


# map TARGET to Linux equivalent, if applicable
case $TARGET in
    powerpc-linux) ARCH=ppc ;;
    arm-linux)  ARCH=arm ;;
esac



#
# get Linux headers, if we need them
#
case $TARGET in

    powerpc-linux | arm-linux)
    
	echo
	echo Configuring and installing linux headers. 

        if [ -d ${LINUXDISTO} ]; then rm -rf ${LINUXDISTO}; fi

	gunzip -c ${TARDIR}/${LINUXDISTO}.tar.gz | tar $TARFLAGS - 
	;;

esac


#
# some headers need tweaking before use, so tweak and install
#
case $TARGET in

    powerpc-linux)

	# we don't need to do anything funky with the kernel first,
	# so just grab the parts we need, and go
	cd ${LINUXDISTO}
	make ARCH=${ARCH} symlinks include/linux/version.h

	mkdir -p ${PREFIX}/${TARGET}/include
	cp -r include/linux ${PREFIX}/${TARGET}/include/linux
	cp -r include/asm-${ARCH} ${PREFIX}/${TARGET}/include/asm
	cd ..

	;;

    arm-linux)

	# we need target-specific and platform-specific headers, so
        # that we can build the right libgcc2 and glibc.

	echo "This target requires configured kernel headers."
	echo "(actually, it just needs ARM processor and platform selections---"
	echo "the rest you can do later, after the tools are built)"
	#read -p "Press ENTER to run menuconfig."

	# don't try to combine these two, the dependencies in the makefile
	# cause symlinks to get run before menuconfig, which is wrong here
        # TODO: this is currently broken.

	cd ${LINUXDISTO}
	bzip2 -dc ${PATCHDIR}/patch-2.4.21-rmk1.bz2 | patch -p1
	gzip -dc ${PATCHDIR}/diff-2.4.21-rmk1-pxa1.gz | patch -p1
	gzip -dc ${PATCHDIR}/diff-2.4.21-rmk1-pxa1-intc3.gz | patch -p1
	make mainstone_config
	make oldconfig
	make ARCH=${ARCH} symlinks include/linux/version.h

	mkdir -p ${PREFIX}/${TARGET}/include
	cp -r include/linux ${PREFIX}/${TARGET}/include
	cp -r include/asm-${ARCH} ${PREFIX}/${TARGET}/include/asm
	cp -r include/asm-generic ${PREFIX}/${TARGET}/include/asm-generic
	cd ..

	;;

esac


#
# build binutils
#
echo 
#read -p "Press ENTER to build binutils..."
echo Building binutils...

if [ -d ${BINUTILSDISTO} ]; then rm -rf ${BINUTILSDISTO}; fi
gunzip -c ${TARDIR}/${BINUTILSDISTO}.tar.gz | tar $TARFLAGS - 
cd ${BINUTILSDISTO}; patch -p1 <${PATCHDIR}/binutils.patch; cd ..

if [ -d build-binutils ]; then rm -rf build-binutils; fi
mkdir build-binutils; cd build-binutils
../${BINUTILSDISTO}/configure --target=$TARGET --prefix=$PREFIX --disable-nls 2>&1 | tee configure.log
make all install 2>&1 | tee make.log
cd ..

# test to see if this step passed
if [ ! -f ${PREFIX}/bin/${TARGET}-ld ]; then
    echo Build failed during binutils && exit 1
fi


#
# build gcc-core
#

echo
#read -p "Press ENTER to build gcc-core..."
echo Building gcc-core...

if [ -d ${GCCDISTO} ]; then rm -rf ${GCCDISTO}; fi
gunzip -c ${TARDIR}/${GCCDISTO}.tar.gz | tar $TARFLAGS - 
if [ -d ${GCCDISTO}-core ]; then rm -rf ${GCCDISTO}-core; fi
mv ${GCCDISTO} ${GCCDISTO}-core
cd ${GCCDISTO}-core; patch -p1 <${PATCHDIR}/gcc-base.patch; cd ..

if [ -d build-gcc-core ]; then rm -rf build-gcc-core; fi
mkdir build-gcc-core; cd build-gcc-core

case $TARGET in

    arm-elf | h8300-coff | h8300-hitachi-hms | m68k-coff | m68k-elf | powerpc-eabi | powerpc-linux | sh-elf | sh-hms )

    # for these targets, gcc's libgcc2 assumes the presence of some
    # header files that we won't have until after glibc or newlib are
    # built.  When we throw in --without-headers --without-newlib, the
    # configure process throws in a:
    #
    # TARGET_LIBGCC2_CFLAGS=-Dinhibit_libc
    #
    # in the makefiles, to cut out pieces of libgcc code that need
    # target-specific header files.
    #
    # the result is a compiler that *almost* works, that should only
    # be used to build libraries and target-specific header files.
    # After we we do that, we build a full-up gcc crosscompiler.

    # first, configure

    ../${GCCDISTO}-core/configure --target=$TARGET --prefix=$PREFIX \
	--enable-languages=c --with-local-prefix=${PREFIX}/${TARGET} \
	--without-headers --with-newlib --disable-shared \
	2>&1 | tee configure.log

    ;;


    arm-linux)

    # like the above, only we have to modify gcc/config/arm/t-linux,
    # for reasons I can't entirely explain right now.  One would
    # *think* that the procedure above for powerpc-eabi et al would be
    # fine...

    # we add -D__gthr_posix_h and -Dinhibit_libc to
    # TARGET_LIBGCC2_CFLAGS, so that libgcc2 will be built without
    # needing "gthr" (gnu pthreads).

#    mv ../${GCCDISTO}-core/gcc/config/arm/t-linux \
#	../${GCCDISTO}-core/gcc/config/arm/t-linux-original
#    sed "s/TARGET_LIBGCC2_CFLAGS =/TARGET_LIBGCC2_CFLAGS = -D__gthr_posix_h -Dinhibit_libc/" \
#	< ../${GCCDISTO}-core/gcc/config/arm/t-linux-original \
#	> ../${GCCDISTO}-core/gcc/config/arm/t-linux

    # now configure

    ../${GCCDISTO}-core/configure --target=$TARGET --prefix=$PREFIX \
	--with-local-prefix=${PREFIX}/${TARGET} \
	--host=i686-host_pc-linux-gnu \
	--disable-shared --disable-threads \
	--with-cpu=xscale --with-inhibit-libc \
	--enable-languages=c --without-headers --with-newlib \
	--without-fp --disable-nls \
	2>&1 | tee configure.log
    ;;


esac

# with that done, now we can make and install gcc-core
# make all-gcc install-gcc 2>&1 | tee make.log
make 2>&1 | tee make.log
make install 2>&1 | tee makeinstall.log
cd ..


# test to see if this step passed
if [ ! -f ${PREFIX}/bin/${TARGET}-gcc ]; then
    echo Build failed during gcc-core && exit 1
fi



#
# build glibc or newlib, as appropriate
#
echo
#read -p "Press ENTER to build glibc or newlib..."
echo Building glibc or newlib...


case $TARGET in 

    # these targets use glibc
    arm-linux | powerpc-linux)

    echo
    echo Building glibc and linuxthreads...

    if [ -d ${GLIBCDISTO} ]; then rm -rf ${GLIBCDISTO}; fi
    gunzip -c ${TARDIR}/${GLIBCDISTO}.tar.gz | tar $TARFLAGS - 
    cd ${GLIBCDISTO}
    gunzip -c ${TARDIR}/${GLIBCTHREADSDISTO}.tar.gz | tar $TARFLAGS - 
    patch -p1 <${PATCHDIR}/glibc-2.3.2.patch
    patch -p1 <${PATCHDIR}/glibc-vfp.patch
    patch -p1 <${PATCHDIR}/glibc-2.3.2-memxxx-strxxx.patch
    cd ..

    if [ -d build-glibc ]; then rm -rf build-glibc; fi
    mkdir build-glibc; cd build-glibc

    CC="${TARGET}-gcc -finline-limit=10000" AR="${TARGET}-ar" \
    LD="${TARGET}-ld" CFLAGS="-O" \
    ../${GLIBCDISTO}/configure --prefix=/usr \
    --host=${TARGET} \
    --build=i686-pc-linux-gnu --with-headers=${PREFIX}/${TARGET}/include \
    --without-__thread --enable-add-ons=linuxthreads --enable-shared \
    --without-tls --without-fp --without-gd \
    --disable-profile --disable-debug --disable-sanity-checks \
    --with-cpu=xscale \
    2>&1 | tee configure.log ;;


    # these targets use newlib
    arm-elf | h8300-coff | h8300-hitachi-hms | m68k-coff | m68k-elf | powerpc-eabi | sh-elf | sh-hms)

    echo
    echo Building newlib...

    gunzip -c ${TARDIR}/${NEWLIBDISTO}.tar.gz | tar $TARFLAGS - 
    mkdir build-newlib; cd build-newlib
    ../${NEWLIBDISTO}/configure --target=$TARGET --prefix=$PREFIX \
	2>&1 | tee configure.log

esac


#make all install info install-info 2>&1 | tee make.log
make 2>&1 | tee make.log
make install install_root=${PREFIX}/${TARGET} prefix="" 2>&1 | tee makeinstall.log

cd ..

# test to see if this step passed
 if [ ! -f ${PREFIX}/${TARGET}/lib/libc.a ]; then
    echo Building libc failed && exit 1
 fi


# hack the libs 
# read -p "hack the lib for compiling rootfs"
# echo hack the libs

for file in libc.so libpthread.so libgcc_s.so; do
	if test -f ${PREFIX}/${TARGET}/lib/$file && test ! -h ${PREFIX}/${TARGET}/lib/$file; then
	  mv ${PREFIX}/${TARGET}/lib/$file ${PREFIX}/${TARGET}/lib/${file}_orig
	  sed 's,/lib/,,g;/BUG in libc.scripts.output-format.sed/d'< ${PREFIX}/${TARGET}/lib/${file}_orig > ${PREFIX}/${TARGET}/lib/$file
	fi
done



#
# finally, build a full-up gcc c/c++ compiler
#

echo
#read -p "Build full-up gcc..."
echo building full-up gcc...

if [ -d ${GCCDISTO} ]; then rm -rf ${GCCDISTO}; fi
gunzip -c ${TARDIR}/${GCCDISTO}.tar.gz | tar $TARFLAGS -
cd ${GCCDISTO}; patch -p1 <${PATCHDIR}/gcc-base.patch; cd ..
if [ -d build-gcc ]; then rm -rf build-gcc; fi
mkdir build-gcc; cd build-gcc

   ../${GCCDISTO}/configure --target=${TARGET} --prefix=${PREFIX} \
	--enable-languages=c,c++ --with-local-prefix=${PREFIX}/${TARGET} \
	--with-cpu=xscale \
	--with-headers=${PREFIX}/${TARGET}/include \
	--host=i686-host_pc-linux-gnu --disable-nls \
	--enable-threads=posix --enable-symvers=gnu --enable-__cxa_atexit \
	--enable-shared --enable-c99 --enable-long-long --without-fp \
	2>&1 | tee configure.log


case $TARGET in
	powerpc-eabi)
	;;

	*)
	make all install 2>&1 | tee make.log
	;;
esac

if [ ! -f ${PREFIX}/bin/${TARGET}-gcc ]; then 
	echo Build failed during gcc && exit 1
fi


