#!/bin/bash
#
# @brief Build a GNU cross compiler targetting ARM Cortex M3 processor
# 
# Builds a bare-metal cross GNU toolchain targetting the ARM Cortex-M3
# microprocessor in EABI mode and using the newlib embedded C library.
#
# @note This deletes and overwrites /opt/sidebranch (or $TOOLCHAIN_PATH).
# 
# @version 2010-06-18
# @author Leon Woestenberg <leon@sidebranch.com>
#
# @note GPL license
#
# @note Known hack: This script overrides newlib's autoconf 2.59 version
# dependency to 2.61.
#
# @note This script was tested on an OS X 10.5.8 x86 host.
#
# @note You need to pre-install some Ubuntu packages on your host:
# sudo apt-get install flex bison autoconf texinfo libgmp3-dev libmpfr-dev 
#
# @note For GDB you need to pre-install some extra Ubuntu packages:
# sudo apt-get install libncurses5-dev 

set -e

CORTEX_TOPDIR=`pwd`

DOWNLOAD_DIR=${CORTEX_TOPDIR}/downloads

TOOLCHAIN_PATH=/opt/sidebranch

TOOLCHAIN_TARGET=arm-sidebranch-eabi

AC_VER="2.64"
GCC_VER="4.5.0"
GMP_VER="5.0.1"
MPFR_VER="2.4.2"
MPC_VER="0.8.2"
BIN_VER="2.20.1"
NEWLIB_VER="1.18.0"
GDB_VER="7.1"

# check if the return code is 0, if not exit.
# used throughout the script to bail out on failure.
#
function stop_on_error {
  if [ ! $? -eq 0 ]; then
    exit 1
  fi
}

mkdir -p ${TOOLCHAIN_PATH}
touch ${TOOLCHAIN_PATH}/need_write_access_here
if [ ! $? -eq 0 ]; then
  echo "Need ${TOOLCHAIN_PATH} directory with write access."
  exit 1
fi
rm -f ${TOOLCHAIN_PATH}/need_write_access_here

if [ ! -f .binutils ]; then
rm -rf ${TOOLCHAIN_PATH}/*
fi

if [ ! -d ${DOWNLOAD_DIR} ]; then
mkdir ${DOWNLOAD_DIR}
fi

cd ${DOWNLOAD_DIR}
if [ ! -f ${DOWNLOAD_DIR}/autoconf-${AC_VER}.tar.bz2 ]; then
  wget http://ftp.gnu.org/gnu/autoconf/autoconf-${AC_VER}.tar.bz2
fi
if [ ! -f ${DOWNLOAD_DIR}/binutils-${BIN_VER}.tar.bz2 ]; then
  wget http://ftp.gnu.org/gnu/binutils/binutils-${BIN_VER}.tar.bz2 || \
  wget http://www.kernel.org/pub/linux/devel/binutils/binutils-${BIN_VER}.tar.bz2
fi
if [ ! -f ${DOWNLOAD_DIR}/gcc-${GCC_VER}.tar.bz2 ]; then
  wget http://ftp.gnu.org/pub/gnu/gcc/gcc-${GCC_VER}/gcc-${GCC_VER}.tar.bz2
fi
if [ ! -f ${DOWNLOAD_DIR}/gmp-${GMP_VER}.tar.bz2 ]; then
  wget http://ftp.sunet.se/pub/gnu/gmp/gmp-${GMP_VER}.tar.bz2
fi
if [ ! -f ${DOWNLOAD_DIR}/mpfr-${MPFR_VER}.tar.bz2 ]; then
  wget http://www.mpfr.org/mpfr-${MPFR_VER}/mpfr-${MPFR_VER}.tar.bz2
fi
if [ ! -f ${DOWNLOAD_DIR}/mpc-${MPC_VER}.tar.gz ]; then
  wget http://www.multiprecision.org/mpc/download/mpc-${MPC_VER}.tar.gz
fi
if [ ! -f ${DOWNLOAD_DIR}/gdb-${GDB_VER}.tar.bz2 ]; then
  wget http://ftp.gnu.org/pub/gnu/gdb/gdb-${GDB_VER}.tar.bz2
fi
if [ ! -f ${DOWNLOAD_DIR}/newlib-${NEWLIB_VER}.tar.gz ]; then
  wget ftp://sources.redhat.com/pub/newlib/newlib-${NEWLIB_VER}.tar.gz
fi

cd ${CORTEX_TOPDIR}
if [ ! -f .autoconf ]; then
rm -rf native
mkdir native
rm -rf autoconf-${AC_VER}
tar xjf ${DOWNLOAD_DIR}/autoconf-${AC_VER}.tar.bz2
cd autoconf-${AC_VER}
mkdir build
cd build
../configure --prefix=${CORTEX_TOPDIR}/native
make -j3 all 2>&1 | tee make.log
stop_on_error
make install 2>&1 | tee install.log
stop_on_error
cd $CORTEX_TOPDIR
touch .autoconf
fi

export PATH=${CORTEX_TOPDIR}/native/bin:$PATH

cd ${CORTEX_TOPDIR}
if [ ! -f .binutils ]; then
rm -rf binutils-${BIN_VER}
tar xjf ${DOWNLOAD_DIR}/binutils-${BIN_VER}.tar.bz2
cd binutils-${BIN_VER}
mkdir build
cd build
../configure --target=${TOOLCHAIN_TARGET} --prefix=${TOOLCHAIN_PATH} \
--enable-interwork --disable-multilib --with-gnu-as --with-gnu-ld --disable-nls \
2>&1 | tee configure.log
stop_on_error
make -j3 all 2>&1 | tee make.log
stop_on_error
make install 2>&1 | tee install.log
stop_on_error
cd $CORTEX_TOPDIR
touch .binutils
fi

cd ${CORTEX_TOPDIR}
if [ -f .gmp ]; then
rm -rf gmp-${GMP_VER}
tar xjf ${DOWNLOAD_DIR}/gmp-${GMP_VER}.tar.bz2
cd gmp-${GMP_VER}
mkdir build
cd build
#--disable-shared --enable-static \
../configure --prefix=${CORTEX_TOPDIR}/native \ 
--disable-nls 2>&1 | tee configure.log
stop_on_error
make -j3 all 2>&1 | tee make.log
stop_on_error
make install 2>&1 | tee install.log
stop_on_error
cd $CORTEX_TOPDIR
touch .gmp
fi

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

cd ${CORTEX_TOPDIR}
if [ ! -f .gcc ]; then
rm -rf gcc-${GCC_VER}
tar xjf ${DOWNLOAD_DIR}/gcc-${GCC_VER}.tar.bz2
cd gcc-${GCC_VER}

#sed 's@  [m4_define([_GCC_AUTOCONF_VERSION], [2.64])])@  [m4_define([_GCC_AUTOCONF_VERSION], [2.65])])@' \
#  config/override.m4 >/tmp/override.m4
#exit
#mv /tmp/override.m4 config/

tar xjf ${DOWNLOAD_DIR}/gmp-${GMP_VER}.tar.bz2
tar xjf ${DOWNLOAD_DIR}/mpfr-${MPFR_VER}.tar.bz2
tar xzf ${DOWNLOAD_DIR}/mpc-${MPC_VER}.tar.gz
ln -snf gmp-${GMP_VER} gmp
ln -snf mpfr-${MPFR_VER} mpfr
ln -snf mpc-${MPC_VER} mpc

#sed 's@AC_PREREQ.*@AC_PREREQ(2.61)@' configure.ac >/tmp/configure.ac
#mv /tmp/configure.ac .

#cd libstdc++-v3
# uncomment AC_LIBTOOL_DLOPEN
# (Linux sed)
#sed -e 's@^AC_LIBTOOL_DLOPEN.*@# AC_LIBTOOL_DLOPEN@' -i configure.ac
# the Mac OS X way (BSD sed)
#sed 's@^AC_LIBTOOL_DLOPEN.*@# AC_LIBTOOL_DLOPEN@' configure.ac >/tmp/configure.ac
#mv /tmp/configure.ac .
#autoconf
#cd ..

mkdir build
cd build
../configure --target=${TOOLCHAIN_TARGET} --prefix=${TOOLCHAIN_PATH} \
--disable-nls --disable-threads \
--with-cpu=cortex-m3 --with-mode=thumb \
--enable-interwork --disable-multilib \
--enable-languages="c,c++" --with-newlib --without-headers \
--disable-shared --with-gnu-as --with-gnu-ld \
2>&1 | tee configure.log
stop_on_error
make -j3 all-gcc 2>&1 | tee make.log
stop_on_error
make install-gcc 2>&1 | tee install.log
stop_on_error
cd ${TOOLCHAIN_PATH}/bin
# hack: newlib argz build wants arm-*-{eabi|elf}-cc, not arm-*-{eabi|elf}-gcc,
# so create a soft link from -cc to -gcc
ln -snf ${TOOLCHAIN_TARGET}-gcc ${TOOLCHAIN_TARGET}-cc
cd ${CORTEX_TOPDIR}
touch .gcc
fi

cd ${CORTEX_TOPDIR}
if [ ! -f .newlib ]; then
rm -rf newlib newlib-${NEWLIB_VER}

# Either this:
tar xzf ${DOWNLOAD_DIR}/newlib-${NEWLIB_VER}.tar.gz
cd newlib-${NEWLIB_VER}

# ...or this:
#mkdir newlib
#cd newlib
#echo "--- use password: anoncvs"
#cvs -z 9 -d :pserver:anoncvs@sources.redhat.com:/cvs/src login
#cvs -z 9 -d :pserver:anoncvs@sources.redhat.com:/cvs/src co newlib
#cd src

# hack: allow autoconf version 2.61 instead of 2.59
# Linux sed:
#sed -e 's@\(.*_GCC_AUTOCONF_VERSION.*\)2.59\(.*\)@\12.61\2@' -i config/override.m4
# Mac OS X sed:
#
#sed 's@\(.*_GCC_AUTOCONF_VERSION.*\)2.59\(.*\)@\12.64\2@' config/override.m4 > /tmp/override.m4
#mv /tmp/override.m4 config/override.m4
#autoconf

mkdir build
cd build
# note: this needs arm-*-{eabi|elf}-cc to exist or link to arm-*-{eabi|elf}-gcc
../configure --target=${TOOLCHAIN_TARGET} --prefix=${TOOLCHAIN_PATH} \
--enable-interwork --disable-nls \
--disable-newlib-supplied-syscalls --with-gnu-ld --with-gnu-as --disable-shared \
2>&1 | tee configure.log
stop_on_error

#make -j3 CFLAGS_FOR_TARGET="-ffunction-sections -fdata-sections -DPREFER_SIZE_OVER_SPEED -D__OPTIMIZE_SIZE__ -Os -fomit-frame-pointer -mcpu=cortex-m3 -mthumb -D__thumb2__ -D__BUFSIZ__=256" \
#CCASFLAGS="-mcpu=cortex-m3 -mthumb -D__thumb2__" \
make -j3 CFLAGS_FOR_TARGET="-ffunction-sections -fdata-sections -DPREFER_SIZE_OVER_SPEED -D__OPTIMIZE_SIZE__ -Os -fomit-frame-pointer -D__BUFSIZ__=256" \
2>&1 | tee make.log
stop_on_error
make install 2>&1 | tee install.log
stop_on_error
cd ${CORTEX_TOPDIR}
touch .newlib
fi

cd ${CORTEX_TOPDIR}
if [ ! -f .gcc-full ]; then
cd gcc-${GCC_VER}/build
#make -j3 CFLAGS="-mcpu=cortex-m3 -mthumb" all 2>&1 | tee make-full.log
make -j3 all 2>&1 | tee make-full.log
make install 2>&1 | tee install-full.log
cd ${CORTEX_TOPDIR}
touch .gcc-full
fi

cd ${CORTEX_TOPDIR}
if [ ! -f .gdb ]; then
rm -rf gdb-${GDB_VER}
tar xjf ${DOWNLOAD_DIR}/gdb-${GDB_VER}.tar.bz2
cd gdb-${GDB_VER}
mkdir build
cd build
../configure --target=${TOOLCHAIN_TARGET} --prefix=${TOOLCHAIN_PATH} \
--with-libexpat \
--disable-nls --disable-threads \
2>&1 | tee configure.log
stop_on_error
make -j3 2>&1 | tee make.log
stop_on_error
make install 2>&1 | tee install.log
stop_on_error
cd ${CORTEX_TOPDIR}
touch .gdb
fi


