#!/bin/sh
#=========================================================================
# Script to compile and link EPOS applications
#
# Auth: Guto (adapted from mpicc)
#=========================================================================

#=========================================================================
# CUSTOMIZABLE DEFINITIONS
#=========================================================================
TMP=/tmp

ANALYZER=eposanl
ANL_FLGS="-u"
ANL_COMP_FLGS="-DANALYZE"

CONFIGURATOR=eposcfg

COMP_FLGS=
COMP_HDRS="$EPOS/include"

C_COMPILER=gcc3
C_COMP_FLGS=
C_COMP_HDRS=
C_LINK_FLGS=
C_LINK_OBJS=
C_LINK_LIBS=

CPP_COMPILER=g++3
CPP_COMP_FLGS="-fno-exceptions -fno-rtti"
CPP_COMP_HDRS=
CPP_LINK_FLGS=
CPP_LINK_OBJS=
CPP_LINK_LIBS=

F77_COMPILER=g77
F77_COMP_FLGS=
F77_COMP_HDRS=
F77_LINK_FLGS=
F77_LINK_OBJS=
F77_LINK_LIBS="f2c"

NATIVE_LINKER=ld
NATIVE_LINK_FLGS="-L$EPOS/lib -L`gcc -print-file-name=` -Bstatic -n -Ttext 0x0 -Tdata 0x00400000"
NATIVE_LINK_OBJS="$EPOS/lib/start.o"
NATIVE_LINK_LIBS="dummyc++ epos gcc c gcc"

GUEST_LINKER=g++3
GUEST_LINK_FLGS="-L$EPOS/lib"
GUEST_LINK_OBJS="$EPOS/lib/init_guest.o $EPOS/lib/system.o"
GUEST_LINK_LIBS="guest epos system system_data gcc pthread stdc++ c gcc"

#=========================================================================
# VARIABLES
#=========================================================================
do_exec=eval
do_echo=:
need_link=1
need_compile=0
need_trace=0
need_analyze=0
only_analyze=0
os_is_library=0
os_is_kernel=0
os_is_guest=0
language=C
getting_output_file=0
has_dash_c=0
my_name=`basename $0`
status=0

#=========================================================================
# ARGUMENT PARSING
#=========================================================================
for arg in "$@" ; do
    if [ $getting_output_file = 1 ] ; then
	getting_output_file=0
	output_file="$arg"
	continue
    fi
    case "$arg" in 
    -c)
	all_args="$all_args $arg"
	compile_flgs="$compile_flgs $arg"
	need_link=0
	need_compile=1
	has_dash_c=1
	;;
    -E)
	all_args="$all_args $arg"
	compile_flgs="$compile_flgs $arg"
	need_link=0
	has_dash_c=1
	need_compile=1
	;;
    -S)
	all_args="$all_args $arg"
	compile_flgs="$compile_flgs $arg"
	need_link=0
	has_dash_c=1
	need_compile=1
	;;
    -o)
	all_args="$all_args $arg"
	getting_output_file=1
	;;
    -l*)
	libs="$libs $arg"
	link_args="$link_args $arg"
	all_args="$all_args $arg"
	;;
    --analyze)
	need_analyze=1
	only_analyze=1
	need_link=0
	need_compile=0
	;;
    --guest)
	os_is_guest=1
	;;
    --lib)
	if [ $epos_is_kernel = 1 ] ; then
	    echo "--lib and --kernel cannot be used together!"
	    exit -1
	else
   	    os_is_library=1
	fi
	;;
    --kernel)
	if [ $os_is_library = 1 ] ; then
	    echo "--lib and --kernel cannot be used together!"
	    exit -1
	else
	    os_is_kernel=1
	fi
	;;
    --trace)
	need_trace=1
	;;
    --echo)
	do_echo=echo
	;;
    --show)
	do_echo=echo
	do_exec=:
	;;
    --help)
	echo "This is a script to compile and/or link EPOS programs"
	echo "written in C, C++ or Fortran."
	echo
	echo "In addition to your compiler options, the following is supported"
	echo "  --analyze analyze application requirements"
	echo "  --lib     EPOS is a library"
	echo "  --kernel  EPOS is a kernel"
	echo "  --guest   EPOS is guest at Linux"
	echo "  --trace   instruct EPOS to generate traces"
	echo "  --show    show commands without issuing them"
	echo "  --help    print this help"
	echo "  --echo    show what this script is doing"
	echo
	echo "This script should be used just like your usual compiler, e.g.:"
	echo "   $my_name -c foo.cc"
	echo "   $my_name -o foo foo.o"
	echo "   $my_name -c -O -Llibrary_path -Iheader_path -o foo foo.c"
	exit 1
	;;
    *\"*) 
	all_args="$all_args `echo $arg | sed 's/\"/\\\"/g'`"
	compile_flgs="$compile_flgs `echo $arg | sed 's/\"/\\\"/g'`"
	link_flgs="$link_flgs `echo $arg | sed 's/\"/\\\"/g'`"
	;;
    *)
	all_args="$all_args $arg"
	if [ -s "$arg" ] ; then
	    ext=`expr "$arg" : '.*\(\..*\)'`
	    if [ "$ext" = ".c" ] ; then
		language="C"
	        need_compile=1
	        input_file="$arg"
		key_file="`basename $arg $ext`.key"
	        link_objs="$link_objs `basename $arg $ext`.o"
	    elif [ "$ext" = ".f" ] ; then
		language="F77"
	        need_compile=1
	        input_file="$arg"
		key_file="`basename $arg $ext`.key"
	        link_objs="$link_objs `basename $arg $ext`.o"
	    elif [ "$ext" = ".C" -o "$ext" = ".cpp" -o "$ext" = ".cc" ] ; then
		language="CPP"
	        need_compile=1
	        input_file="$arg"
		key_file="`basename $arg $ext`.key"
	        link_objs="$link_objs `basename $arg $ext`.o"
	    elif [ "$ext" = ".o" ] ; then
		if [ $need_compile = 1 ] ; then
	            compile_args="$compile_args $arg"
                else
	            need_link=1
	            link_objs="$link_objs $arg"
                fi
	    else
	        compile_args="$compile_args $arg"
	        link_args="$link_args $arg"
	    fi
	else
            compile_flgs="$compile_flgs $arg"
	    link_flgs="$link_flgs $arg"
	fi
	;;
    esac
done

#=========================================================================
# COMMAND ISSUING
#=========================================================================
if [ "$language" = "F77" ] ; then
    compiler=$F77_COMPILER
    compile_flgs="$compile_flgs $F77_COMP_FLGS"
    for hdr in $F77_COMP_HDRS ; do
	compile_flgs="$compile_flgs -I$hdr"
    done
    link_flgs="$link_flgs $F77_LINK_FLGS"
    link_objs="$F77_LINK_OBJS $link_objs"
    for lib in $F77_LINK_LIBS ; do
	link_libs="$link_libs -l$lib"
    done
elif [ "$language" = "CPP" ] ; then
    compiler=$CPP_COMPILER
    compile_flgs="$compile_flgs $CPP_COMP_FLGS"
    for hdr in $CPP_COMP_HDRS ; do
	compile_flgs="$compile_flgs -I$hdr"
    done
    link_flgs="$link_flgs $CPP_LINK_FLGS"
    link_objs="$CPP_LINK_OBJS $link_objs"
    for lib in $CPP_LINK_LIBS ; do
	link_libs="$link_libs -l$lib"
    done
else
    compiler=$C_COMPILER
    compile_flgs="$compile_flgs $C_COMP_FLGS"
    for hdr in $C_COMP_HDRS ; do
	compile_flgs="$compile_flgs -I$hdr"
    done
    link_flgs="$link_flgs $C_LINK_FLGS"
    link_objs="$C_LINK_OBJS $link_objs"
    for lib in $C_LINK_LIBS ; do
	link_libs="$link_libs -l$lib"
    done
fi

compile_flgs="$compile_flgs $COMP_FLGS"
for hdr in $COMP_HDRS ; do
    compile_flgs="$compile_flgs -I$hdr"
done

if [ $os_is_guest = 1 ] ; then
    linker=$GUEST_LINKER
    link_flgs="$link_flgs $GUEST_LINK_FLGS"
    link_objs="$GUEST_LINK_OBJS $link_objs"
    for lib in $GUEST_LINK_LIBS ; do
	link_libs="$link_libs -l$lib"
    done
else
    linker=$NATIVE_LINKER
    link_flgs="$link_flgs $NATIVE_LINK_FLGS"
    link_objs="$NATIVE_LINK_OBJS $link_objs"
    for lib in $NATIVE_LINK_LIBS ; do
	link_libs="$link_libs -l$lib"
    done
    if [ $os_is_kernel = 1 ] ; then
	link_libs="$link_libs -lstub"
    else
	link_flgs="$link_flgs -R$EPOS/img/system"
    fi
fi

if [ $need_compile = 1 -a ! -f "$key_file" ] ; then
    need_analyze=1
fi

if [ $need_analyze = 1 ] ; then
    analyze_flgs=$compile_flgs

    if [ $has_dash_c = 0 ] ; then
	analyze_flgs="-c $analyze_flgs"
    fi
    tmp_file="$TMP/epos`date +%Y%m%d%H%M%S`"
    analyze_flgs="$analyze_flgs $ANL_COMP_FLGS"
    analyze_flgs="$analyze_flgs -o $tmp_file.o"
    $do_echo $compiler $analyze_flgs $analyze_args $input_file
    $do_exec $compiler $analyze_flgs $analyze_args $input_file
    status=$?
    if [ $status != 0 ] ; then
	$do_echo rm -f "$tmp_file.*"
	$do_exec rm -f "$tmp_file.*"
	exit $status
    fi

    $do_echo $ANALYZER $ANL_FLAGS "$tmp_file.o" -o "$tmp_file.anl"
    $do_exec $ANALYZER $ANL_FLAGS "$tmp_file.o" -o "$tmp_file.anl"
    status=$?
    if [ $status != 0 ] ; then
	$do_echo rm -f "$tmp_file.*"
	$do_exec rm -f "$tmp_file.*"
	exit $status
    fi

    $do_echo $CONFIGURATOR "$tmp_file.anl" -o $key_file
    $do_exec $CONFIGURATOR "$tmp_file.anl" -o $key_file

    status=$?
    $do_echo rm -f "$tmp_file.*"
    $do_exec rm -f "$tmp_file.*"

    if [ $only_analyze = 1 ] ; then
	exit $status
    fi
fi

if [ $need_compile = 1 ] ; then
    if [ $has_dash_c = 0 ] ; then
	compile_flgs="-c $compile_flgs"
    fi
    if [ $has_dash_c = 1 -a -n "$output_file" ] ; then
	compile_flgs="$compile_flgs -o $output_file"
    fi
    compile_flgs="$compile_flgs -DCONFIG_KEYS=\\\"$PWD/$key_file\\\""
    $do_echo $compiler $compile_flgs $compile_args $input_file
    $do_exec $compiler $compile_flgs $compile_args $input_file
    status=$?
    if [ $status != 0 ] ; then 
	exit $status
    fi
fi

if [ $need_link = 1 ] ; then
    if [ -n "$output_file" ] ; then
	link_flgs="$link_flgs -o $output_file"
    fi
    $do_echo $linker $link_flgs $link_args $link_objs $link_libs
    $do_exec $linker $link_flgs $link_args $link_objs $link_libs
    status=$?
fi

exit $status
