#!/bin/sh

# This is my script for building a complete MinGW cross-compiler toolchain
# that runs under Linux to produce executables that run under Windows.  It
# probably works (or can easily be adapted to work) under any unix system.
#
# It is based in large part on Sam Lantinga's script, which in turn was
# based partly on Ray Kelm's script, which in turn was built on
# Mo Dejong's script for doing the same, but with some added fixes.
#
# NOTE: If you choose a destination directory for the installation (set
# in the macro PREFIX) for which you do not have write access, you will
# need to run this script with root (or equivalent) privileges.
#
#
# Updated by Igor Mikolic-Torreira <igormt@alumni.caltech.edu>
# Updated by Adam Kropelin <adam@kroptech.com>



#-----------------------------------------------------
#
# BEGIN USER SETTINGS
#
# You need to review and adjust the macros that follow
#
#-----------------------------------------------------


# Directory where cross-tools directory will be placed
TOPDIR=../../..
# Cross tools directory name under TOPDIR
CROSSTOOLS=cross-tools
# What flavor of GCC cross-compiler are we building? under CROSSTOOLS
TARGET=mingw32

cwd=`pwd`
cd ${TOPDIR}
# Make TOPDIR absolute 
TOPDIR=`pwd`
BUILDDIR=${TOPDIR}/${CROSSTOOLS}

cd ${cwd}

# Where does the cross-compiler go?
# This should be the directory into which your cross-compiler
# will be installed.  Remember that if you set this to a directory
# that only root has write access to, you will need to run this
# script as root.

PREFIX=${BUILDDIR}/${TARGET}
mkdir -p ${BUILDDIR}
mkdir -p ${BUILDDIR}/${TARGET}

echo "Building cross tools in ${BUILDDIR} ..."
echo " "

# Purge anything and everything already in the $PREFIX
#(also known as the destination or installation) directory?
# Set to "Y" to purge, any other value omits the purge step.

PURGE_DIR="Y"


# Set the following to the files from the current MinGW release
# (or whichever MinGW release you wish to build and install)
# You need to set both the URL they will be downloaded from
# and the exact name of the individual component files.

MINGW_URL="http://heanet.dl.sourceforge.net/sourceforge/mingw"
MINGW_ARCHIVE="mingwrt-3.20-mingw32-dev.tar.gz"
MINGW_DLL_ARCHIVE="mingwrt-3.20-mingw32-dll.tar.gz"
W32API_ARCHIVE="w32api-3.17-2-mingw32-dev.tar.lzma"

# GCC_CORE is required; the other components are optional.
# Set any you don't want to "".  You need binutils,
# mingw runtime and w32api; do not ever set those to "".
GNU_URL="ftp://ftp.gnu.org/gnu"
GCC_VER="4.2.4"
BINUTILS_VER="2.23.1"

BINUTILS_URL="$GNU_URL/binutils"
BINUTILS_ARCHIVE="binutils-$BINUTILS_VER.tar.bz2"

GCC_URL="$GNU_URL/gcc/gcc-$GCC_VER"
GCC_CORE_ARCHIVE="gcc-core-$GCC_VER.tar.bz2"
GCC_GPP_ARCHIVE="gcc-g++-$GCC_VER.tar.bz2"
GCC_G77_ARCHIVE=""
GCC_OBJC_ARCHIVE=""
GCC_JAVA_ARCHIVE=""
GCC_ADA_ARCHIVE=""
GCC_PATCH=""

# These are the files from the SDL website
# These are optional, set them to "" if you don't want them)

SDL_URL="http://www.libsdl.org/extras/win32/common"

OPENGL_ARCHIVE=""
DIRECTX_ARCHIVE=""


# These are the files from NSIS at sf.net
NSIS_URL="http://heanet.dl.sourceforge.net/sourceforge/nsis"
NSIS_ARCHIVE=nsis-2.46-src.tar.bz2

#-----------------------------------------------------
#
# END USER SETTINGS
#
# The remainder of the script should not neet any edits
#
#-----------------------------------------------------



# Make sure these are initialized as we want them

GCC_CORE=""
BINUTILS=""
GCC_LANGS="c"


# Set our build directory and where our sources will go

if [ "x$BUILDDIR" = "x" ]; then
        # Default to the current directory
        BUILDDIR=$(pwd)
fi
SRCDIR="$BUILDDIR/source"


# Need install directory first on the path so gcc can find binutils

PATH="$PREFIX/bin:$PATH"



#-----------------------------------------------------
#
# Functions that do most of the work
#
#-----------------------------------------------------


function download_files
{
        # Download a file from a given url, only if it is not present
        mkdir -p "$SRCDIR"

        # Make sure wget is installed
        if test "x`which wget`" = "x" ; then
                echo "You need to install wget."
                exit 1
        fi

        download_file "$GCC_CORE_ARCHIVE" "$GCC_URL"
        if [ "x$GCC_GPP_ARCHIVE" != "x" ]; then
                download_file "$GCC_GPP_ARCHIVE" "$GCC_URL"
        fi
        if [ "x$GCC_G77_ARCHIVE" != "x" ]; then
                download_file "$GCC_G77_ARCHIVE" "$GCC_URL"
        fi
        if [ "x$GCC_OBJC_ARCHIVE" != "x" ]; then
                download_file "$GCC_OBJC_ARCHIVE" "$GCC_URL"
        fi
        if [ "x$GCC_JAVA_ARCHIVE" != "x" ]; then
                download_file "$GCC_JAVA_ARCHIVE" "$GCC_URL"
        fi
        if [ "x$GCC_ADA_ARCHIVE" != "x" ]; then
                download_file "$GCC_ADA_ARCHIVE" "$GCC_URL"
        fi

        download_file "$BINUTILS_ARCHIVE" "$BINUTILS_URL"
        download_file "$MINGW_ARCHIVE" "$MINGW_URL"
        download_file "$MINGW_DLL_ARCHIVE" "$MINGW_URL"
        download_file "$W32API_ARCHIVE" "$MINGW_URL"

        if [ "x$OPENGL_ARCHIVE" != "x" ]; then
                download_file "$OPENGL_ARCHIVE" "$SDL_URL"
        fi
        if [ "x$DIRECTX_ARCHIVE" != "x" ]; then
                download_file "$DIRECTX_ARCHIVE" "$SDL_URL"
        fi
}


function download_file
{
        cd "$SRCDIR"
        if test ! -f $1 ; then
                echo "Downloading $1"
                wget "$2/$1"
                if test ! -f $1 ; then
                        echo "Could not download $1"
                        exit 1
                fi
        else
                echo "Found $1 in the srcdir $SRCDIR"
        fi
        cd "$BUILDDIR"
}


function purge_existing_install
{
        echo "Purging the existing files in $PREFIX"
        if cd "$PREFIX"; then
                rm -rf *
        fi
        cd "$BUILDDIR"
}


function install_libs
{
        echo "Installing cross libs and includes"
        mkdir -p "$PREFIX/$TARGET"
        cd "$PREFIX/$TARGET"

        tar -xzf "$SRCDIR/$MINGW_ARCHIVE"
        tar -xzf "$SRCDIR/$MINGW_DLL_ARCHIVE"
        lzma -dc "$SRCDIR/$W32API_ARCHIVE" | tar -x

        if [ "x$OPENGL_ARCHIVE" != "x" ]; then
                tar -xzf "$SRCDIR/$OPENGL_ARCHIVE"
        fi

        if [ "x$DIRECTX_ARCHIVE" != "x" ]; then
                tar -xzf "$SRCDIR/$DIRECTX_ARCHIVE"
        fi

        cd "$BUILDDIR"
}


function extract_binutils
{
        cd "$SRCDIR"
        BINUTILS="binutils-$BINUTILS_VER"
        rm -rf "$BINUTILS"
        echo "Extracting binutils"
        tar -xjf "$SRCDIR/$BINUTILS_ARCHIVE"
        cd "$BUILDDIR"
}


function configure_binutils
{
        cd "$BUILDDIR"
        rm -rf "binutils-$TARGET"
        mkdir "binutils-$TARGET"
        cd "binutils-$TARGET"
        echo "Configuring binutils"
        "$SRCDIR/$BINUTILS/configure" --prefix="$PREFIX" --target=$TARGET --disable-nls \
                --with-gcc --with-gnu-as --with-gnu-ld --disable-shared &> configure.log
        cd "$BUILDDIR"
}


function build_binutils
{
        cd "$BUILDDIR/binutils-$TARGET"
        echo "Building binutils"
        make CFLAGS="-O2 -fno-exceptions" LDFLAGS="-s" &> make.log
        if test $? -ne 0; then
                echo "make of binutils failed - log available: binutils-$TARGET/make.log"
                exit 1
        fi
        cd "$BUILDDIR"
}


function install_binutils
{
        cd "$BUILDDIR/binutils-$TARGET"
        echo "Installing binutils"
        make install &> make-install.log
        if test $? -ne 0; then
                echo "install of binutils failed - log available: binutils-$TARGET/make-install.log"
                exit 1
        fi
        cd "$BUILDDIR"
}


function extract_gcc
{
        cd "$SRCDIR"
        GCC="gcc-$GCC_VER"
        rm -rf "$GCC"
        echo "====== GCC ${GCC} ========="
        echo "Extracting gcc"
        tar -xjf "$SRCDIR/$GCC_CORE_ARCHIVE"
        if [ "x$GCC_GPP_ARCHIVE" != "x" ]; then
                GCC_LANGS=${GCC_LANGS}",c++"
                tar -xjf "$SRCDIR/$GCC_GPP_ARCHIVE"
        fi
        if [ "x$GCC_G77_ARCHIVE" != "x" ]; then
                GCC_LANGS=${GCC_LANGS}",f77"
                tar -xjf "$SRCDIR/$GCC_G77_ARCHIVE"
        fi
        if [ "x$GCC_OBJC_ARCHIVE" != "x" ]; then
                GCC_LANGS=${GCC_LANGS}",objc"
                tar -xjf "$SRCDIR/$GCC_OBJC_ARCHIVE"
        fi
        if [ "x$GCC_JAVA_ARCHIVE" != "x" ]; then
                GCC_LANGS=${GCC_LANGS}",java"
                tar -xjf "$SRCDIR/$GCC_JAVA_ARCHIVE"
        fi
        if [ "x$GCC_ADA_ARCHIVE" != "x" ]; then
                GCC_LANGS=${GCC_LANGS}",ada"
                tar -xjf "$SRCDIR/$GCC_ADA_ARCHIVE"
        fi
        cd "$BUILDDIR"
}


function patch_gcc
{
        if [ "$GCC_PATCH" != "" ]; then
                echo "Patching gcc"
                cd "$SRCDIR/$GCC"
                patch -p1 < "$SRCDIR/$GCC_PATCH"
                cd "$BUILDDIR"
        fi
}


function configure_gcc
{
        cd "$BUILDDIR"
        rm -rf "gcc-$TARGET"
        mkdir "gcc-$TARGET"
        cd "gcc-$TARGET"
        echo "Configuring gcc"
        "$SRCDIR/$GCC/configure" -v \
                --prefix="$PREFIX" --target=$TARGET \
                --with-headers="$PREFIX/$TARGET/include" \
                --with-gcc --with-gnu-ld --with-gnu-as \
                --enable-threads --disable-nls --enable-languages=$GCC_LANGS \
                --disable-win32-registry --disable-shared --enable-sjlj-exceptions --enable-libgcj \
                --disable-java-awt --without-x --enable-java-gc=boehm --disable-libgcj-debug \
                --enable-interpreter --enable-hash-synchronization --enable-libstdcxx-debug \
                &> configure.log
        cd "$BUILDDIR"
}


function build_gcc
{
        cd "$BUILDDIR/gcc-$TARGET"
        echo "Building gcc"
        make CFLAGS="-O2" CXXFLAGS="-O2" GCJFLAGS="-O2" LDFLAGS="-s" DEBUG_FLAGS="-g0" &> make.log
        if test $? -ne 0; then
                echo "make of gcc failed - log available: gcc-$TARGET/make.log"
                exit 1
        fi
        if [ "x$GCC_ADA" != "x" ]; then
                cd gcc
                make "CFLAGS=-O2" "LDFLAGS=-s" gnatlib_and_tools &> make-gnatlib.log
                if test $? -ne 0; then
                        echo "make of gnatlib and tools failed - log available: gcc-$TARGET/make-gnatlib.log"
                        exit 1
                fi
        fi
        cd "$BUILDDIR"
}


function install_gcc
{
        cd "$BUILDDIR/gcc-$TARGET"
        echo "Installing gcc"
        make install &> make-install.log
        if test $? -ne 0; then
                echo "install of gcc failed - log available: gcc-$TARGET/make-install.log"
                exit 1
        fi
        cd "$BUILDDIR"
}


function do_nsis
{
	echo Checking for SCons
	scons --version > /dev/null 2>&1
	if [ $? -ne 0 ]; then
		echo Native SCons not found.
		echo It is required for building NSIS.
		echo Skipping NSIS.
	else
		echo Downloading NSIS
		download_file "$NSIS_ARCHIVE" "$NSIS_URL"
	        cd "$BUILDDIR"
	        NSIS=`tar -tjf "$SRCDIR/$NSIS_ARCHIVE" | head -n 1`
	        echo "====== NSIS ${NSIS} ========="
	        echo "Extracting NSIS"
		tar xjf "$SRCDIR/$NSIS_ARCHIVE"
		echo Building and Installing NSIS
        	cd "$NSIS"
		scons PREFIX=$PREFIX install &> scons.log
  	      	if test $? -ne 0; then
			echo "make of nsis failed - log available: $NSIS/scons.log"
			exit 1
    		fi
	fi
}

function final_tweaks
{
        echo "Finalizing installation"

        # remove gcc build headers
        rm -rf "$PREFIX/$TARGET/sys-include"

        # Add extra binary links
        if [ ! -f "$PREFIX/$TARGET/bin/objdump" ]; then
                ln "$PREFIX/bin/$TARGET-objdump" "$PREFIX/$TARGET/bin/objdump"
        fi

        # make cc and c++ symlinks to gcc and g++
        if [ ! -f "$PREFIX/$TARGET/bin/g++" ]; then
                ln "$PREFIX/bin/$TARGET-g++" "$PREFIX/$TARGET/bin/g++"
        fi
        if [ ! -f "$PREFIX/$TARGET/bin/cc" ]; then
                ln -s "gcc" "$PREFIX/$TARGET/bin/cc"
        fi
        if [ ! -f "$PREFIX/$TARGET/bin/c++" ]; then
                ln -s "g++" "$PREFIX/$TARGET/bin/c++"
        fi

        # strip all the binaries
        ls "$PREFIX"/bin/* "$PREFIX/$TARGET"/bin/* | egrep -v '.dll$' | egrep -v 'gccbug$' |
        while read file; do
                strip "$file"
        done

        echo "Installation complete!"
}



#
# Main part of the script
#

download_files

if [ "x$PURGE_DIR" = "xY" ]; then
        purge_existing_install
fi

install_libs

extract_binutils
configure_binutils
build_binutils
install_binutils

extract_gcc
patch_gcc
configure_gcc
build_gcc
install_gcc

do_nsis

final_tweaks


#
# End
#
