#!/bin/bash

# Build cross binutils for ARM.
# by Stuart Winter <mozes@slackware.com>
#
# References:
# http://www.cygwin.com/ml/crossgcc/2006-12/msg00075.html
# 
# The purpose of this is to build enough of a toolchain that I can use
# distcc to a fast x86 host from my native ARM build hosts.
# This script does not build an entire cross toolchain and the result
# in /opt/arm is pretty messy (although could easily be tidied).
# 
# On your x86 host you can do:
# 
# PATH=/opt/arm/bin /usr/bin/distccd --daemon --allow 0/0 -j20
#
# For the original work I did, check out this:
# ftp://ftp.armedslack.org/loft/oldsource/OLD_CROSS_COMPILE/ARM-compiling-bits-bobs
####################################################################################
# Notes#
########
# 1. This script is supposed to be run:
#    [ ]  on an x86 running Slackware
#    [ ]  from inside armedslack-current/source/x-toolchain
####################################################################################

# Automatically determine architecture for build & packaging:
case "$( uname -m )" in
  i?86) export LOCALARCH=i486 ;;
  *)    export LOCALARCH=$( uname -m ) ;;
esac
echo "Local architecture: $LOCALARCH"

# Versions of packages:
#BINUTILSVER=2.17.50.0.17
# gcc 4.2 doesn't build without binutils 2.18, at least for me.
BINUTILSVER=2.18*
GCCVER=4.2.4
LINUXVER=2.6.24.7
GLIBCVER=2.7

# Installation location
INSTLOC=/opt/arm
rm -rf $INSTLOC
mkdir -p $INSTLOC

CWD=$PWD

# Temp build locations:
TMP=/tmp/xbuild
rm -rf $TMP
mkdir -p $TMP

# Create some framework:
mkdir -p $INSTLOC/lib
mkdir -p $INSTLOC/usr/lib
mkdir -p $INSTLOC/include

################## Functions ##############################################
# Functions:
#
# Take a patch and work apply it at the level it needs.
#
# Functions:
function apply_patch () {
 patchfile=$1
 # Most patches should not require more levels than this:
 success=0
 for (( pl=0 ; pl<=5 ; pl++ )) ; do
   echo "Patch : $patchfile , trying patch level $pl"
     patch --fuzz=20 -t --dry-run -p$pl < $patchfile > /dev/null 2>&1 && success=1 && break
   done
 if [ $success = 1 ]; then
    echo "Patch: $patchfile will apply at level $pl"
    patch --fuzz=20 --verbose -p$pl < $patchfile
    return 0
  else
    echo "Patch: $patchfile failed to apply at levels 0-5"
    return 1
 fi
}


################## Extract ARM Linux Kernel headers #######################
cd $TMP
tar xf $CWD/sources/linux-$LINUXVER.tar.bz2
cd linux*
cp -f $CWD/../k/configs/config-versatile-linux-2.6 .config
make ARCH=arm oldconfig
make ARCH=arm include/asm include/linux/version.h include/asm-arm/.arch
cp -fa include/asm-generic/ $INSTLOC/include/
cp -fa include/linux/ $INSTLOC/include/
cp -fa include/asm-arm $INSTLOC/include/asm

################## Build binutils #########################################

# Extract source:
cd $TMP
#tar xvvf $CWD/sources/binutils-$BINUTILSVER.tar.bz2
tar xvvf $CWD/sources/binutils*orig*gz
cd binutils*
zcat $CWD/sources/binutils*diff* | patch -p1

for i in debian/patches/*.dpatch ; do
  apply_patch $i || exit 1
done


# Configure:
./configure \
   --prefix=$INSTLOC \
   --with-sysroot=$INSTLOC \
   --enable-shared \
   --disable-nls \
   --host=$LOCALARCH-slackware-linux \
   --build=$LOCALARCH-slackware-linux \
   --target=arm-slackware-linux || exit 1

# Build:
make -j4 || failmake
# Install into /opt:
make install

# Our binutils stuff is in here now:
export PATH=$PATH:/opt/arm/bin/:/opt/arm/arm-slackware-linux/bin/

################## Build glibc headers ###########################################

cd $TMP
tar xvvf $CWD/sources/glibc_${GLIBCVER}*.orig.tar.gz
cd glibc*
tar xvvf glibc-$GLIBCVER*ds*.tar.bz2
cd glibc-$GLIBCVER
tar xvvf ../glibc-libidn-*.tar.bz2
mv glibc-libidn-* libidn || exit 1
tar xvvf ../glibc-linuxthreads-*.tar.bz2
tar xvvf ../glibc-ports-*.tar.bz2
mv glibc-ports-* ports || exit 1
zcat $CWD/sources/glibc_${GLIBCVER}-*.diff.gz | patch -p1 || exit 1
# Apply the Debian patches based on the information in the 'series' file.
egrep -v "^#|^$" debian/patches/series | awk '{print $1}' | while read patchfile ; do
   if [ -s "debian/patches/$patchfile" ]; then
      # Most patches should not require more levels than this:
      success=0
      for (( pl=0 ; pl<=5 ; pl++ )) ; do
          echo "Patch : $patchfile , trying patch level $pl"
          patch -N --fuzz=20 -t --dry-run -p$pl < debian/patches/$patchfile > /dev/null 2>&1 && success=1 && break
      done
      if [ $success = 1 ]; then
         echo "Patch: $patchfile will apply at level $pl"
         patch -N --fuzz=20 --verbose -p$pl < debian/patches/$patchfile
       else
        echo "Patch: $patchfile failed to apply"
      fi
   fi
done

mkdir build.dir
cd build.dir
../configure \
   --prefix=/opt/arm \
   --without-cvs \
   --disable-sanity-checks \
   --enable-add-ons=libidn,nptl,ports \
   --with-tls \
   --with-headers=/opt/arm/include/ \
   --enable-hacker-mode \
   --host=$LOCALARCH-slackware-linux \
   --build=$LOCALARCH-slackware-linux \
   --target=arm-slackware-linux || exit 1

make CFLAGS=-DBOOTSTRAP_GCC sysdeps/gnu/errlist.c || exit 1
mkdir -p stdio-common
touch stdio-common/errlist-compat.c
make -j4 cross-compiling=yes install_root=$INSTLOC prefix="" CFLAGS=-DBOOTSTRAP_GCC install-headers || exit 1

mkdir -p $INSTLOC/include/gnu
touch $INSTLOC/include/gnu/stubs.h
#cp -vfa bits/stdio_lim.h $INSTLOC/bits/stdio_TARGET_PREFIX
cp -vfa bits/stdio_lim.h $INSTLOC/include/bits/

################## Build gcc ##############################################

# Extract source:
cd $TMP
tar xvvf $CWD/sources/gcc-$GCCVER.tar.bz2
cd gcc-*

# Apply patches:
# No includes:
zcat $CWD/gcc-no_fixincludes.diff.gz | patch -p1 || exit 1
#
# Unpack Debian patches:
zcat $CWD/sources/gcc*diff.gz | patch -p1 || exit 1
# Apply ARM patches:
  apply_patch debian/patches/arm-pragma-pack.dpatch || exit 1
  apply_patch debian/patches/arm-pr30486.dpatch     || exit 1
  apply_patch debian/patches/arm-unbreak-eabi-armv4t.dpatch || exit 1
  # Already applied upstream:
  #  apply_patch debian/patches/arm-pr28516.dpatch || exit 1
  # apply_patch debian/patches/gdc-arm-unwind_ptr.dpatch || exit 1
  # apply_patch debian/patches/libjava-armel-ldflags.dpatch || exit 1

# Apply Gentoo patches:
#tar xvvf $CWD/sources/gcc-4.2.3-patches-1.0.tar.bz2
#for i in patch/*.patch ; do
#  apply_patch $i
#done

mkdir gcc.build
cd gcc.build

# -fstack-protector on gcc 4.2.3 causes segfaults on ARM
# so it's best to disable it since many newer packages check for 
# this option and enable if supported.
STACKPROT="--disable-libssp"

# Configure:
../configure $STACKPROT \
      --prefix=/opt/arm \
      --disable-multilib \
      --with-newlib \
      --with-local-prefix=$INSTLOC \
      --enable-threads=no \
      --enable-symvers=gnu \
      --enable-__cxa_atexit \
      --disable-shared \
      --without-headers \
      --disable-nls \
      --enable-languages=c,c++,fortran,objc \
      --disable-checking \
      --verbose \
      --host=$LOCALARCH-slackware-linux \
      --build=$LOCALARCH-slackware-linux \
      --target=arm-slackware-linux || exit 1 

# Build:
make -j4 all-gcc || exit 1
make install-gcc || exit 1

# Make symlinks:
cd $INSTLOC/bin
for i in * ; do
  ln -vfs $i $( echo $i | sed s'?arm-slackware-linux-??' )
done
ln -vfs gcc cc
