#!/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.10.1 gcc-2.95.3 linux-2.4.3 glibc-2.2.2
# glibc-linuxthreads-2.2.2 newlib-1.9.0
#
#
# 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.
#


#DEFAULT_TARDIR=~/tars
DEFAULT_TARDIR=~/projects/handheld/crosstools/tars
#DEFAULT_PREFIX=/opt/billgatliff/H-i686-pc-linux-gnu
DEFAULT_PREFIX=~/projects/handheld/crosstools

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"
MY_BUILD_LIST="all kernel_cfg binutils gcc1st newlib glibc gcc2nd gdb kernel"


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 ] ; 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

    PS3="Please select what to build: "
    select MY_BUILD in ${MY_BUILD_LIST};
	do echo; break; done


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

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


###

#
# 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.11.2
BINUTILSDISTO=binutils-2.14
#GCCDISTO=gcc-2.95.3
GCCDISTO=gcc-3.3.1
#LINUXDISTO=linux-2.4.3
LINUXDISTO=linux-2.4.19
#add a symlink to cvs:ed kernel manual /home/zingo/projects/handheld/linux/linux

#GLIBCDISTO=glibc-2.2.2
GLIBCDISTO=glibc-2.3.2
#GLIBCTHREADSDISTO=glibc-linuxthreads-2.2.2
GLIBCTHREADSDISTO=glibc-linuxthreads-2.3.2
#NEWLIBDISTO=newlib-1.9.0
NEWLIBDISTO=newlib-1.11.0
GDBDISTO=insight+dejagnu-6.0.0.90_20031018

# 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=${PATH}:${PREFIX}/bin


# 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 $MY_BUILD in 

    # these targets use kernel
    all | kernel_cfg )

    case $TARGET in

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

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

    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
#	    make ARCH=$ARCH menuconfig
	    make ARCH=$ARCH 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
    	cd ..

    	;;

    esac
		;;
    * )
    echo Dont config kernel and copy headers

esac



#
# build binutils
#

case $MY_BUILD in 

    # these targets use glibc
    all | binutils)

		echo
		echo Building binutils.

		gunzip -c ${TARDIR}/${BINUTILSDISTO}.tar.gz | tar $TARFLAGS - 
		mkdir build-binutils; cd build-binutils
		../${BINUTILSDISTO}/configure --target=$TARGET --prefix=$PREFIX  2>&1 | tee configure.log
		make all install 2>&1 | tee make.log
		cd ..


		;;
    * )
    echo Dont build binutils


esac





# 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
#

case $MY_BUILD in 

    all | gcc1st)

		echo
		echo Building gcc-core.

		gunzip -c ${TARDIR}/${GCCDISTO}.tar.gz | tar $TARFLAGS - 
		mv ${GCCDISTO} ${GCCDISTO}-core
		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 --disable-threads

    		../${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
    		;;
		esac

		# with that done, now we can make and install gcc-core
		make all-gcc install-gcc 2>&1 | tee make.log
		cd ..
		;;
    * )
    echo Dont build gcc1st

esac


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



#
# build glibc or newlib, as appropriate
#
case $MY_BUILD in 

    all | newlib | glibc)

		case $TARGET in 

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

		    echo
		    echo Building glibc and linuxthreads.

		    gunzip -c ${TARDIR}/${GLIBCDISTO}.tar.gz | tar $TARFLAGS - 
		    cd ${GLIBCDISTO}
		    gunzip -c ${TARDIR}/${GLIBCTHREADSDISTO}.tar.gz | tar $TARFLAGS - 
( cat << GLIBC_PATCH_END1 
--- ./sysdeps/unix/sysv/linux/arm/sysdep.h.orig	2003-02-20 12:22:10.000000000 -0800
+++ ./sysdeps/unix/sysv/linux/arm/sysdep.h	2003-08-04 19:06:17.000000000 -0700
@@ -158,7 +158,7 @@
        asm volatile ("swi	%1	@ syscall " #name	\\
 		     : "=r" (_a1)				\\
 		     : "i" (SYS_ify(name)) ASM_ARGS_##nr	\\
-		     : "a1", "memory");				\\
+		     : "memory");				\\
        _sys_result = _a1;					\\
      }								\\
      (int) _sys_result; })
--- ./stdio-common/sscanf.c.orig	2003-08-04 19:27:34.000000000 -0700
+++ ./stdio-common/sscanf.c	2003-08-04 19:27:59.000000000 -0700
@@ -27,9 +27,7 @@
 /* Read formatted input from S, according to the format string FORMAT.  */
 /* VARARGS2 */
 int
-sscanf (s, format)
-     const char *s;
-     const char *format;
+sscanf (const char *s, const char *format, ...)
 {
   va_list arg;
   int done;
--- ./linuxthreads/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h.orig	2003-08-04 20:14:05.000000000 -0700
+++ ./linuxthreads/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h	2003-08-04 20:14:33.000000000 -0700
@@ -34,7 +34,7 @@
 # define PSEUDO(name, syscall_name, args)				\\
   .section ".text";							\\
     PSEUDO_PROLOGUE;							\\
-  ENTRY (name)								\\
+  ENTRY (name);								\\
     SINGLE_THREAD_P_INT;						\\
     bne .Lpseudo_cancel;						\\
     DO_CALL (syscall_name, args);					\\
GLIBC_PATCH_END1
) | patch -p1 || exit 1
		    cd ..
		    mkdir build-glibc; cd build-glibc
		    CC=${TARGET}-gcc AR=${TARGET}-ar RANLIB=${TARGET}-ranlib \
			../${GLIBCDISTO}/configure --host=$TARGET --prefix=${PREFIX}/${TARGET} \
			--enable-add-ons=linuxthreads --with-headers=${PREFIX}/${TARGET}/include \
			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
		cd ..

		;;
    * )
    echo Dont build newlib

esac


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


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


case $MY_BUILD in 

    all | gcc2nd)
    echo
    echo Building gcc.

    gunzip -c ${TARDIR}/${GCCDISTO}.tar.gz | tar $TARFLAGS - 
    mkdir build-gcc; cd build-gcc
    ../${GCCDISTO}/configure --target=$TARGET --prefix=$PREFIX --with-headers=~/projects/handheld/crosstools/arm-elf/arm-elf/include \
        --enable-languages=c,c++ --with-local-prefix=${PREFIX}/${TARGET} \
        2>&1 | tee configure.log


    case $TARGET in

        powerpc-eabi)

        # powerpc-eabi doesn't come with a "default" build target, so to
        # the configuration process, the compiler looks broken because it
        # won't link to produce executables (because it doesn't know what
        # linker command file to use).  To fix that, we just specify a
        # build target.  This doesn't affect anything other than it lets
        # the configuration steps that happen internal to the build
        # process know that the compiler indeed works.

        make all install 2>&1 | tee make.log
        make CFLAGS="-myellowknife -O" all 2>&1 | tee -a make.log
        make install 2>&1 | tee -a make.log

        ;;


        *)

        # everyone else can use the standard procedure

        make all install 2>&1 | tee make.log

        ;;
    esac

 		;;
    * )
    echo Dont build gcc2nd

esac


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


case $MY_BUILD in 

    all | gdb)

		echo Building gdb.

  	if [ -f ${TARDIR}/${GDBDISTO}.tar.gz ]; then
				gunzip -c ${TARDIR}/${GDBDISTO}.tar.gz | tar $TARFLAGS - 
		fi

		if [ -f ${TARDIR}/${GDBDISTO}.tar.bz2 ]; then
				bunzip2 -c ${TARDIR}/${GDBDISTO}.tar.bz2 | tar $TARFLAGS -
		fi


		mkdir build-gdb; cd build-gdb
		../${GDBDISTO}/configure --target=$TARGET --prefix=$PREFIX 2>&1 | tee configure.log

		make all install info install-info 2>&1 | tee make.log
		cd ..
 		;;
    * )
    echo Dont build gdb

esac


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


case $MY_BUILD in 

    all | kernel)

		echo Building kernel: ${LINUXDISTO}
		PATH=$PATH:${PREFIX}/${TARGET}/bin
		echo $PATH
		cd ${LINUXDISTO}
		make dep 2>&1 | tee make.log
		make zImage 2>&1 | tee make.log
		make modules 2>&1 | tee make.log
		cd ..
 		;;
    * )
    echo Dont build gdb

esac


