#! /bin/sh


set -o pipefail


# globals generated at runtime, do not modify...
declare XT_PREFIX=''
declare XT_TARGET=''
declare XT_TMP_DIR=''
declare XT_TMP_CTR=0
declare XT_ROOT_DIR=''
declare XT_NO_BOOTSTRAP=''
declare XT_NO_HEADER=''
declare XT_BINUTILS_SRC_DIR=''
declare XT_GCC_SRC_DIR=''
declare XT_LIBC_SRC_DIR=''
declare XT_EXTRAS_SRC_DIR=''
declare XT_KERN_SRC_DIR=''


trap "rm -rf $XT_TMP_DIR; exit 0" INT TERM KILL


xt_error()
  {
   echo "$1" 1>&2
  }

xt_action()
  {
   local key="$1" msg="$2"
   shift 2
   echo "$msg"
   echo "`date '+%Y-%m-%d %H:%M:%S %Z'` : START : $key : $msg" \
     >> "$XT_ROOT_DIR/logs/main.log"
   eval "$@" >> "$XT_ROOT_DIR/logs/$key.log" 2>&1
   local status=$? st_msg='OK'
   test $status = 0 || st_msg='FAILED'
   echo "`date '+%Y-%m-%d %H:%M:%S %Z'` : STOP : $key : [$st_msg]" >> \
     "$XT_ROOT_DIR/logs/main.log"
   return $status
  }

xt_show_help()
  {
   cat <<EOF
crosstool builder.

Usage: $0 {-b|--binutils} BINUTILS {-g|--gcc} GCC {-l|--libc} LIBC {-p|--prefix} PREFIX {-t|--target} TARGET [-n]

OPTIONS:
  -b, --binutils      binutils source.
  -g, --gcc           gcc source.
  -k, --kernel        kernel source.
  -l, --libc          glibc source.
  -e, --extras        glibc ports source.
  -p, --prefix        Installation prefix directory. Must be writable/creatable.
  -t, --target        Cross compiler target.
  -n, --nobootstrap   Do not build bootstrap gcc.
  -x, --noheader      Do not build libc headers.
  -h, --help          Displays this message.
EOF
  }

xt_build_init()
  {
   # parse command-line...
   local options=`getopt -o b:l:g:e:k:p:t:nxh \
     --long binutils:,libc:,gcc:,extras:,kernel:,prefix:,target:,nobootstrap,noheader,help \
     -n "$0" -- "$@"`
   test $? = 0 || return 1

   local binutils_src='' gcc_src='' kern_src='' libc_src='' extras_src='' \
     prefix='' target=''
   eval set -- $options
   while test x"$1" != 'x--' ; do
     case "$1" in
       '-b' | '--binutils' ) binutils_src="$2" ; shift ;;
       '-l' | '--libc' )     libc_src="$2" ; shift ;;
       '-e' | '--extras' )   extras_src="$2" ; shift ;;
       '-g' | '--gcc' )      gcc_src="$2" ; shift ;;
       '-k' | '--kernel' )   kern_src="$2" ; shift ;;
       '-p' | '--prefix' )   prefix="$2" ; shift ;;
       '-t' | '--target' )   target="$2" ; shift ;;
       '-n' | '--nobootstrap' ) XT_NO_BOOTSTRAP=1 ;;
       '-x' | '--noheader' ) XT_NO_HEADER=1 ;;
       '-h' | '--help' )  xt_show_help ; exit 0 ;;
     esac
     shift
   done

   test x"$target" = 'x' && \
     xt_error 'No target given.' && return 1
   test x"${prefix:0:1}" != x'/' && \
     xt_error "$prefix must be an absolute directory." && return 1

   XT_ROOT_DIR=`pwd`
   XT_TARGET="$target"
   XT_PREFIX="$prefix"

   # create temp dirs, log and the prefix...
   XT_TMP_DIR=`mktemp -d` || return $?
   rm -rf "$XT_ROOT_DIR/logs" >& /dev/null
   mkdir -p $XT_TMP_DIR/{build,ctr,src,stg} "$XT_ROOT_DIR/logs" $prefix || \
     return $?

   # download/extract source...
   local i='' status=0
   for i in "$binutils_src" "$gcc_src" "$libc_src" "$kern_src" "$extras_src" ; do
     test x"$i" = 'x' && continue # skip blanks
     if test -d "$i" ; then # symlink if it is a directory
       test x"${i:0:1}" = 'x/' || i="`pwd`/$i"
       ln -s "$i" "$XT_TMP_DIR/src/${i##*/}"
     else  # url or file
       local tar_opt=''
       case "$i" in
         *.gz | *.tgz ) tar_opt='-xz' ;;
         *.bz2 | *.tbz2 ) tar_opt='-xj' ;;
         *.tar ) tar_opt='-x' ;;
       esac
       test x"$tar_opt" = 'x' && \
         xt_error "Unknown archive type: $i" && return 1

       case "$i" in
         http://* | ftp://* )
           xt_action 'download' "Downloading $i." \
             "wget -O - \"$i\" | tar -C \"$XT_TMP_DIR/src\" $tar_opt" ;;
         * )
           xt_action 'download' "Extracting $i." \
             "tar -C \"$XT_TMP_DIR/src\" $tar_opt -f \"$i\"" ;;
       esac
       test $? = 0 || return 1
     fi
   done

   # set our global variables with the extracted source directories...
   set -- $XT_TMP_DIR/src/binutils-*
   test -d "$1" && XT_BINUTILS_SRC_DIR="$1"
   set -- $XT_TMP_DIR/src/gcc-*
   test -d "$1" && XT_GCC_SRC_DIR="$1"
   set -- $XT_TMP_DIR/src/linux-*
   test -d "$1" && XT_KERN_SRC_DIR="$1"
   # if extras is given, move it...
   set -- $XT_TMP_DIR/src/glibc-ports-*
   test -d "$1" && mv "$1" "$XT_TMP_DIR/ports"
   set -- $XT_TMP_DIR/src/glibc-*
   test -d "$1" && XT_LIBC_SRC_DIR="$1"
   test -d "$XT_TMP_DIR/ports" && mv "$XT_TMP_DIR/ports" "$XT_LIBC_SRC_DIR"

   return 0
  }

xt_build_uninit()
  {
   rm -rf "$XT_TMP_DIR" >& /dev/null
  }

xt_build_binutils()
  {
   rm -rf "$XT_TMP_DIR/build" && mkdir -p "$XT_TMP_DIR/build" && \
     cd "$XT_TMP_DIR/build"
   test $? = 0 || return 1
   test x"$XT_BINUTILS_SRC_DIR" = 'x' && return 0 # skip binutils if no src

   xt_action 'binutils_configure' 'Configuring binutils.' \
     "\"$XT_BINUTILS_SRC_DIR/configure\" --prefix=\"$XT_PREFIX\" \
     --target=\"$XT_TARGET\" --disable-nls" && \
     xt_action 'binutils_make' 'Compiling binutils.' make && \
     xt_action 'binutils_install' 'Installing binutils.' 'make install'

   return $?
  }

xt_build_bootstrap_gcc()
  {
   rm -rf "$XT_TMP_DIR/build" && mkdir -p "$XT_TMP_DIR/build" && \
     cd "$XT_TMP_DIR/build"
   test $? = 0 || return 1

   test x"$XT_NO_BOOTSTRAP" != 'x' && return 0 # skip if not required

   xt_action 'bootgcc_configure' 'Configuring bootstrap gcc.' \
     "\"$XT_GCC_SRC_DIR/configure\" \
     --prefix=\"$XT_PREFIX\" --target=\"$XT_TARGET\" \
     --disable-shared --disable-threads --enable-languages=c \
     --with-newlib --without-headers" && \
     xt_action 'bootgcc_make' 'Compiling bootstrap gcc.' 'make all-gcc' && \
     xt_action 'bootgcc_install' 'Installing bootstrap gcc.' \
     'make install-gcc'

   return $?
  }

xt_build_libc_headers()
  {
   rm -rf "$XT_TMP_DIR/build" && mkdir -p "$XT_TMP_DIR/build" && \
     cd "$XT_TMP_DIR/build"
   test $? = 0 || return 1

   test x"$XT_LIBC_SRC_DIR" = 'x' && return 0
   test x"$XT_NO_HEADER" != 'x' && return 0 # skip if noheader specified

   # generate some cache values to prevent misautodetection...
   echo "libc_cv_forced_unwind=yes" > config.cache
   echo "libc_cv_c_cleanup=yes" >> config.cache
   case "$XT_TARGET" in # special cases
     ppc* | powerpc* ) echo "libc_cv_ppc_machine=yes" >> config.cache ;;
     arm* ) echo "libc_cv_arm_tls=yes"  >> config.cache
   esac

   # configure and build libc...
   xt_action 'libchdr_configure' 'Configuring libc headers.' \
     "\"$XT_LIBC_SRC_DIR/configure\" --prefix=\"$XT_PREFIX/$XT_TARGET\" \
     --host=\"$XT_TARGET\" --with-headers=\"$XT_PREFIX/$XT_TARGET/include\" \
     --cache-file=config.cache" && \
     xt_action 'libchdr_install' 'Installing libc headers.' \
     'make install-headers'

   return $?
  }

xt_build_kernel_headers()
  {
   rm -rf "$XT_TMP_DIR/build" && mkdir -p "$XT_TMP_DIR/build" && \
     cd "$XT_TMP_DIR/build"
   test $? = 0 || return 1

   test x"$XT_KERN_SRC_DIR" = 'x' && return 0

   # configure and install kernel headers...
   set -- ${XT_TARGET//\-/ }
   local kern_arch="$1" # extract the CPU type from the target
   # clean kernel sources...
   make -C "$XT_KERN_SRC_DIR" ARCH="$kern_arch" mrproper >& /dev/null
   xt_action 'kern_configure' 'Configuring kernel headers.' \
     "make -C \"$XT_KERN_SRC_DIR\" ARCH=\"$kern_arch\" headers_check" && \
     xt_action 'kern_install' 'Installing kernel headers.' \
     "make -C \"$XT_KERN_SRC_DIR\" ARCH=\"$kern_arch\" \
     INSTALL_HDR_PATH=\"$XT_PREFIX/$XT_TARGET\" headers_install"

   return $?
  }

xt_build_libc()
  {
   rm -rf "$XT_TMP_DIR/build" && mkdir -p "$XT_TMP_DIR/build" && \
     cd "$XT_TMP_DIR/build"
   test $? = 0 || return 1

   test x"$XT_LIBC_SRC_DIR" = 'x' && return 0

   # generate some cache values to prevent misautodetection...
   echo "libc_cv_forced_unwind=yes" > config.cache
   echo "libc_cv_c_cleanup=yes" >> config.cache
   case "$XT_TARGET" in # special cases
     ppc* | powerpc* ) echo "libc_cv_ppc_machine=yes" >> config.cache ;;
     arm* ) echo "libc_cv_arm_tls=yes"  >> config.cache
   esac

   # patch libc...
   wget -O - 'http://svn.cross-lfs.org/svn/repos/cross-lfs/trunk/patches/glibc-2.6.1-libgcc_eh-1.patch' | \
     patch -Np1 -d "$XT_LIBC_SRC_DIR"
   wget -O - 'http://svn.cross-lfs.org/svn/repos/cross-lfs/branches/clfs-sysroot/patches/glibc-2.6.1-RTLD_SINGLE_THREAD_P-1.patch' | \
     patch -Np1 -d "$XT_LIBC_SRC_DIR"

   # configure and build libc...
   xt_action 'libc_configure' 'Configuring libc.' \
     "\"$XT_LIBC_SRC_DIR/configure\" --prefix=\"$XT_PREFIX/$XT_TARGET\" \
     --host=\"$XT_TARGET\" --enable-addons --enable-kernel=2.4 \
     --disable-profile --without-gd --with-__thread --with-elf \
     --without-cvs --with-headers=\"$XT_PREFIX/$XT_TARGET/include\" \
     --with-tls --disable-sanity-checks --cache-file=config.cache" && \
     xt_action 'libc_make' 'Compiling libc.' make && \
     xt_action 'libc_install' 'Installing libc.' 'make install'

   return $?
  }

xt_build_gcc()
  {
   rm -rf "$XT_TMP_DIR/build" && mkdir -p "$XT_TMP_DIR/build" && \
     cd "$XT_TMP_DIR/build"
   test $? = 0 || return 1

   xt_action 'gcc_configure' 'Configuring gcc.' \
     "\"$XT_GCC_SRC_DIR/configure\" \
     --prefix=\"$XT_PREFIX\" --target=\"$XT_TARGET\" \
     --enable-languages=c,c++ --enable-c-mbchar --enable-threads \
     --enable-shared --enable-__cxa_atexit" && \
     xt_action 'gcc_make' 'Compiling gcc.' make && \
     xt_action 'gcc_install' 'Installing gcc.' 'make install-no-fixedincludes'

   return $?
  }


unset CPPFLAGS CFLAGS CXXFLAGS LDFLAGS ASFLAGS
xt_build_init $@ && \
  export PATH="$XT_PREFIX/bin:$PATH" && \
  xt_build_binutils && \
  xt_build_kernel_headers && \
  xt_build_libc_headers && \
  xt_build_bootstrap_gcc && \
  xt_build_libc && \
  xt_build_gcc
declare st=$?
xt_build_uninit
exit $st

