#! /bin/sh
# Generate files for all apps,
# maybe build all apps,
# and produce a report listing differences from checked in copies.
#
#   Copyright 2012 Free Software Foundation
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING3.  If not see
# <http://www.gnu.org/licenses/>.
#

# NOTE: This script doesn't rm -rf the previous run since it can run
# different tests.  If you want to start fresh, rm -rf tmp-all yourself.
#
# File ./gen-all.rc must exist and must define several env vars.
# It saves us from having to always pass the same long path names as
# parameters.
# The config file lives in "." instead of say "$HOME" so that multiple
# different configs are easily supported.
# Typical contents are:
#
## Paths to src,gcc,rel relative to ${build_dir}.
#SRC_DIR="../../../src"
#GCC_DIR="../../../gcc"
#REL_DIR="../../.."
## Location of mpc (gmp,mpfr taken from /usr/{include,lib}).
#MPC_DIR="$HOME/gnu/rel32/mpc-0.8.1"

set -e
trap "echo ERROR: $(date)" 0

all_args="$@"

if [ ! -f ./gen-all.rc ]
then
    echo "Missing gen-all.rc file." >&2
    exit
fi

source ./gen-all.rc

usage() {
    echo "Usage:"
    echo "  gen-all help"
    echo "  gen-all [options] [todos] [apps]"
    echo "  gen-all all"
    echo ""
    echo "Options:"
    echo "cpus=\"space-separated-list-of-cpus\""
    echo "force    Force cgen files to be regenerated"
    echo ""
    echo "Things-to-do:"
    echo "config   Configure the tree"
    echo "build    Build the tree"
    echo "diffs    Generate diffs from what is checked in"
    echo ""
    echo "Applications:"
    echo "binutils, gcc, newlib, sim, sid, intrinsics"
    echo ""
    echo "Notes:"
    echo "\"all\" can be specified which means \"config, build, and diff everything\""
    echo "Options, todos, and apps may be specified in any order."
    echo ""
    echo "Example:"
    echo "sh gen-all build binutils diffs cpus=m32r"
}

# Parameters to configure.
MPC_CONFIG="--with-mpc=${MPC_DIR}"

# Set up any env vars we need, blech.
export LD_LIBRARY_PATH="${MPC_DIR}/lib"

build_all_target_sys="fr30-elf"

all_cgen_cpus="arm cris fr30 frv ip2k iq2000 lm32 m32c m32r mep mt \
openrisc sh sh64 xc16x xstormy16"

all_sid_cpus="arm m32r mep mt sh xstormy16"

do_force=no

do_config=no
do_build=no
do_diffs=no

do_binutils=no
do_gcc=no
do_newlib=no
do_sim=no
do_sid=no
do_intrinsics=no

cgen_cpus="${all_cgen_cpus}"
sid_cpus="${all_sid_cpus}"

# Parameter processing.

for a in "$@"
do
    case $a in
    help) usage ; trap "" 0 ; exit 0 ;;
    cpus=*) cgen_cpus=${a/cpus=} sid_cpus=${cgen_cpus} ;;
    force) do_force=yes ;;
    config) do_config=yes ;;
    build) do_build=yes ;;
    diffs) do_diffs=yes ;;
    binutils) do_binutils=yes ;;
    gcc) do_gcc=yes ;;
    newlib) do_newlib=yes ;;
    sim) do_sim=yes ;;
    sid) do_sid=yes ;;
    intrinsics) do_intrinsics=yes ;;
    all)
	do_config=yes
	do_build=yes
	do_diffs=yes
	do_binutils=yes
	do_gcc=yes
	do_newlib=yes
	do_sim=yes
	do_sid=yes
	do_intrinsics=yes
	;;
    *) echo "Invalid option: $a" >&2 ; exit 1 ;;
    esac
done

if [ "${do_config}" = "no" -a "${do_build}" = "no" -a "${do_diffs}" = "no" ]
then
    echo "Nothing to do." >&2
    exit 1
fi

for c in ${cgen_cpus}
do
    if echo " ${all_cgen_cpus} " | grep -q " ${c} "
    then
	: ok
    else
	echo "Invalid cgen cpu ${c}" >&2
	exit 1
    fi
done
if [ "${do_sid}" = "yes" ]
then
    for c in ${sid_cpus}
    do
	if echo " ${all_sid_cpus} " | grep -q " ${c} "
	then
	    : ok
	else
	    echo "Invalid sid cpu ${c}" >&2
	    exit 1
	fi
    done
fi

# Utility functions.

config_src () {
    target_sys=$1
    prefix=$2

    extra_config_args=""
    if [ "${target_sys}" = "${build_all_target_sys}" ]
    then
	extra_config_args="${extra_config_args} --enable-targets=all"
    fi

    if [ -f Makefile ]
    then
	true # already configured
    elif [ "${do_config}" = "yes" ]
    then
	echo "Configuring: $(date)"
	../${SRC_DIR}/configure \
	    --prefix=${prefix} \
	    --build=${build_sys} \
	    --host=${host_sys} \
	    --target=${target_sys} \
	    --enable-shared \
	    --enable-cgen-maint \
	    --enable-languages=c \
	    ${extra_config_args}
    fi
}

config_gcc () {
    target_sys=$1
    prefix=$2

    extra_config_args=""

    if [ -f Makefile ]
    then
	true # already configured
    elif [ "${do_config}" = "yes" ]
    then
	echo "Configuring: $(date)"
	../${GCC_DIR}/configure \
	    --prefix=${prefix} \
	    --build=${build_sys} \
	    --host=${host_sys} \
	    --target=${target_sys} \
	    --enable-languages=c \
	    ${MPC_CONFIG} \
	    ${extra_config_args}
    fi
}

build_binutils () {
    target_sys=$1
    prefix=$2
    PATH=${prefix}/bin:$PATH

    if [ "${do_force}" = "yes" ]
    then
	touch ${SRC_DIR}/cgen/opcodes.scm
    fi

    echo "Building ${target_sys} binutils, $(date)"
    mkdir -p tmp-src-${target_sys}
    (
	set -e
	cd tmp-src-${target_sys}

	config_src ${target_sys} ${prefix}

	if [ "${do_build}" = "yes" ]
	then
	    echo "Building: $(date)"
	    if [ ! -f Makefile ]
	    then
		echo "Tree hasn't been configured."
		exit 1
	    fi
	    make -j3 all-binutils all-gas all-ld
	    make -j1 install-binutils install-gas install-ld
	    echo "Build done: $(date)"
	fi
    )
    if [ $? != 0 ] ; then exit 1 ; fi 
}

build_gcc () {
    target_sys=$1
    prefix=$2
    PATH=${prefix}/bin:$PATH

    echo "Building ${target_sys} gcc, $(date)"
    mkdir -p tmp-gcc-${target_sys}
    (
	set -e
	cd tmp-gcc-${target_sys}

	config_gcc ${target_sys} ${prefix}

	if [ "${do_build}" = "yes" ]
	then
	    echo "Building: $(date)"
	    if [ ! -f Makefile ]
	    then
		echo "Tree hasn't been configured."
		exit 1
	    fi
	    make -j3 all-gcc
	    make -j1 install-gcc
	    # FIXME: The toplevel makefile doesn't find ${target}-gcc,
	    # it sets CC_FOR_TARGET to ${target}-cc.
	    rm -f ${prefix}/bin/${target_sys}-cc
	    ln -s ${target_sys}-gcc ${prefix}/bin/${target_sys}-cc
	    echo "Build done: $(date)"
	fi
    )
    if [ $? != 0 ] ; then exit 1 ; fi 
}

build_newlib () {
    target_sys=$1
    prefix=$2
    PATH=${prefix}/bin:$PATH

    echo "Building ${target_sys} newlib, $(date)"
    mkdir -p tmp-src-${target_sys}
    (
	set -e
	cd tmp-src-${target_sys}

	config_src ${target_sys} ${prefix}

	if [ "${do_build}" = "yes" ]
	then
	    echo "Building: $(date)"
	    if [ ! -f Makefile ]
	    then
		echo "Tree hasn't been configured."
		exit 1
	    fi
	    make -j3 all-target-newlib all-target-libgloss
	    make -j1 install-target-newlib install-target-libgloss
	    echo "Build done: $(date)"
	fi
    )
    if [ $? != 0 ] ; then exit 1 ; fi 
}

build_sim () {
    target_sys=$1
    prefix=$2
    PATH=${prefix}/bin:$PATH

    if [ "${do_force}" = "yes" ]
    then
	touch ${SRC_DIR}/cgen/sim.scm
    fi

    echo "Building ${cpu} sim, $(date)"
    mkdir -p tmp-src-${target_sys}
    (
	set -e
	cd tmp-src-${target_sys}

	config_src ${target_sys} ${prefix}

	if [ "${do_build}" = "yes" ]
	then
	    echo "Building: $(date)"
	    if [ ! -f Makefile ]
	    then
		echo "Tree hasn't been configured."
		exit 1
	    fi
	    make -j3 all-sim all-gdb
	    make -j1 install-sim install-gdb
	    echo "Build done: $(date)"
	fi
    )
    if [ $? != 0 ] ; then exit 1 ; fi 
}

build_sid () {
    target_sys=$1
    prefix=$2
    PATH=${prefix}/bin:$PATH

    if [ "${do_force}" = "yes" ]
    then
	touch ${SRC_DIR}/cgen/sid.scm
    fi

    echo "Building ${cpu} sid, $(date)"
    mkdir -p tmp-src-${target_sys}
    (
	set -e
	cd tmp-src-${target_sys}

	config_src ${target_sys} ${prefix}

	if [ "${do_build}" = "yes" ]
	then
	    echo "Building: $(date)"
	    if [ ! -f Makefile ]
	    then
		echo "Tree hasn't been configured."
		exit 1
	    fi
	    # SID doesn't support --enable-cgen-maint, sigh.
	    if [ ! -f sid/component/cgen-cpu/Makefile ]
	    then
		make -j3 configure-sid
	    fi
	    (cd sid/component/cgen-cpu && make cgen-all)
	    if [ $? != 0 ] ; then exit 1 ; fi
	    make -j3 all-sid
	    make -j1 install-sid
	    echo "Build done: $(date)"
	fi
    )
    if [ $? != 0 ] ; then exit 1 ; fi 
}

build_intrinsics () {
    if [ "${do_build}" = "yes" ]
    then
	echo "Building intrinsics: $(date)"
	(cd ${SRC_DIR}/cgen && sh ./gen-all-intrinsics ${build_dir}/${GCC_DIR})
	if [ $? != 0 ] ; then exit 1 ; fi
	echo "Build done: $(date)"
    fi
}

build_diffs () {
    # NOTE: cvs will return with a non-zero exit code if there are diffs.
    if [ "${do_binutils}" = "yes" ]
    then
	(cd ${SRC_DIR}/opcodes && cvs diff -du >${build_dir}/opcodes.diffs)
    fi
    if [ "${do_sim}" = "yes" ]
    then
	(cd ${SRC_DIR}/sim && cvs diff -du >${build_dir}/sim.diffs)
    fi
    if [ "${do_sid}" = "yes" ]
    then
	(cd ${SRC_DIR}/sid/component/cgen-cpu && cvs diff -du >${build_dir}/sid.diffs)
    fi
    if [ "${do_intrinsics}" = "yes" ]
    then
	(cd ${GCC_DIR}/gcc/config/mep && svn diff -x -u >${build_dir}/gcc.diffs)
    fi
}

# And we're off.

echo "Starting gen-all: $(date)"
# Print the command line to make it easier to review old builds.
echo "Options: ${all_args}"

mkdir -p tmp-all
cd tmp-all
build_dir=$(pwd)

# We can't call config.guess until we've cd'd into the build_dir because
# SRC_DIR, if relative, is relative to build_dir.
build_sys=$(sh ${SRC_DIR}/config.guess)
host_sys=${build_sys}

for cpu in ${cgen_cpus}
do
    # FIXME: arm-eabi is preferred over arm-elf
    target_sys=${cpu}-elf
    prefix=$(cd ${REL_DIR} && pwd -P)/rel-${target_sys}
    [ $? != 0 ] && { echo "Error setting prefix" >&2 ; exit 1 ; }
    mkdir -p ${prefix}

    if [ "${do_binutils}" = "yes" ]
    then
	build_binutils ${target_sys} ${prefix}
    fi

    if [ "${do_sim}" = "yes" ]
    then
	build_sim ${target_sys} ${prefix}
    fi

    if [ "${do_gcc}" = "yes" ]
    then
	# GCC doesn't support some cpus that cgen supports.
	case ${target_sys} in
	ip2k-*) ;;
	mt-*) ;;
	openrisc-* | or32-*) ;;
	xc16x-*) ;;
	*) build_gcc ${target_sys} ${prefix} ;;
	esac
    fi

    if [ "${do_newlib}" = "yes" ]
    then
	# Newlib doesn't support some cpus that cgen supports.
	# We also can't build newlib if we don't have gcc.
	case ${target_sys} in
	ip2k-*) ;;
	mt-*) ;;
	openrisc-* | or32-*) ;;
	xc16x-*) ;;
	*) build_newlib ${target_sys} ${prefix} ;;
	esac
    fi
done

for cpu in ${sid_cpus}
do
    # FIXME: arm-eabi is preferred over arm-elf
    target_sys=${cpu}-elf
    prefix=$(cd ${REL_DIR} && pwd -P)/rel-${target_sys}
    [ $? != 0 ] && { echo "Error setting prefix" >&2 ; exit 1 ; }
    mkdir -p ${prefix}

    if [ "${do_sid}" = "yes" ]
    then
	build_sid ${target_sys} ${prefix}
    fi
done

if [ "${do_intrinsics}" = "yes" ]
then
    build_intrinsics ${target_sys} ${prefix}
fi

if [ "${do_diffs}" = "yes" ]
then
    build_diffs ${target_sys} ${prefix}
fi

echo "Ending gen-all: $(date)"
trap "" 0
