#! /bin/sh
#
# Script to compile and link MPI programs
# We'd like to just add a few libraries to the link line and an include
# directory to the compile line, but some systems that MPICH supports make
# that difficult because the compiler and the linker are different programs.
# Thus, this code tries to figure out which options go where, at least for
# things that are different between compile and link steps.
#
# New Organization:
# To better support a range of compilers and library formats, the compilation
# scripts can now read a configuration file describing the compiler (defaults
# are provided in the script for the default case, i.e., same as MPICH was 
# built with.  This file is mpicc-<compilername>.conf.  For example, a
# typical installation might have mpicc-cc.conf and mpicc-gcc.conf, for the 
# vendor compiler and gcc, respectively.  These are selected by either setting
# the environment variable CC, or using the -config name switch.
#
DoLink=1
DoCompile=0
show_compile=0
show_link=0
MPILOG=
CCFLAGS=" -no-cpp-precomp -DUSE_STDARG  -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STDARG_H=1 -DUSE_STDARG=1 -DMALLOC_RET_VOID=1"
Show=eval
allargs=
compileargs=
linkargs=
linkobjs=
gettinglinkarg=0
HasDashC=0
UsesPmpi=0
verbose=0
#
# Directory locations: Fixed for any MPI implementation
prefix=/usr/local/mpich
exec_prefix=${prefix}
sysconfdir=${exec_prefix}/etc
includedir=/usr/local/mpich/include
libdir=/usr/local/mpich/lib
#
#
# Default compiler configuration.  A configuration file may override any
# of these (including the location of the MPI library), but must do so
# consistently with the MPICH library chosen.  By including the library
# and include paths here, we can use the same mpicc for a range of 
# libraries and compilers, including ones for 32 and 64 bit systems.
CCCBASE="c++"
CCLINKERBASE="c++"
LDFLAGSBASE=""
USER_CFLAGS="-no-cpp-precomp -DUSE_STDARG  -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STDARG_H=1 -DUSE_STDARG=1 -DMALLOC_RET_VOID=1"
ROMIO_TCFLAGS=""
ROMIO_LFLAGS=""
BASE_LIB_LIST="   "
LIB_PATH="-L${libdir} "
MPILIBNAME="mpich"
MPIVERSION="1.2.3 of : 2002/01/23 21:03:59"
FLIBNAME="mpich"
# F77_IN_C_LIBS are the libraries needed to link with the Fortran routines
# referenced from MPI_Init.  With any luck, this will usually be empty
F77_IN_C_LIBS=""
hasMPE=yes
#
MPI_WITH_PMPI="no"
proflib=-lp${MPILIBNAME}
proflibfullname=${libdir}/libp${MPILIBNAME}.a
# Shared library support (probably does not work yet with CC)
SHAREDKIND="ignore"
SHARED_LIB_SEARCH_PATH_LEADER=''
SHARED_LIB_LOCALDIR=""
sharedlibdir=/usr/local/mpich/lib/shared
#
# Override the compilers using environment variables
CCLINKER="${MPICH_CCLINKER-$CCLINKERBASE}"
#
# C++ variables
cpplib=-l${MPILIBNAME}++
cpplibfullname=${libdir}/lib${MPILIBNAME}++.a
cppproflib=-lp${MPILIBNAME}++
cppproflibfulname=${libdir}/libp${MPILIBNAME}++.a
CXXFLAGS="-I${includedir}/mpi2c++"
LDFLAGS=""
CCC="${MPICH_CCC-$CCCBASE}"
CCLINKER="${MPICH_CCLINKER-$CCLINKERBASE}"

if [ -n "$MPICH_CCC" ] ; then
    CCC="$MPICH_CCC"
    CCCname=`echo $CCC | sed 's/ /-/g'`
    if [ -s $sysconfdir/mpiCC-$CCCname.conf ] ; then
        . $sysconfdir/mpiCC-$CCCname.conf
    fi
else
    CCC="$CCCBASE"
fi
UseSharedLib=${MPICH_USE_SHLIB-no}

if [ -z "c++" -o -z "c++" ] ; then
    echo "No C++ compiler and linker specified when MPICH configured."
    exit 1
fi
for arg in "$@" ; do
#    echo procssing arg $arg
    # Special processing for -o name
    if [ $gettinglinkarg = 1 ] ; then
	linkargs="$linkargs $arg"
	outputfilename="$arg"
	gettinglinkarg=0
	continue
    fi
    case "$arg" in 
	-c)
	# If -c is NOT specified, then we need to perform a link step.
	allargs="$allargs $arg"
	compileargs="$compileargs $arg"
        # If -o was set, then we need to move the output file option
        # to the compile line (note that this is non-standard, and should
        # not be used in portable codes)
        if [ $DoLink = 1 -a -n "$outputfilename" ] ; then
	    compileargs="$compileargs -o $outputfilename"
        fi
	DoLink=0
	HasDashC=1
	;;
        -o)
	# Need to link
	allargs="$allargs $arg"
        if [ $HasDashC = 1 ] ; then
            # Some BUT NOT ALL compilers support -o with -c.  Allow
            # the user to make use of the feature, IF IT EXISTS.
            compileargs="$compileargs $arg"	
        else
	    linkargs="$linkargs $arg"
	    # Still need to add the target of the -o
	    gettinglinkarg=1
	    DoLink=1
        fi
	;;
	-E|-M)
	# For compilers that support -E as a way to get at the C preprocessor
	# Also, for compilers that support -M for creating dependencies
	allargs="$allargs $arg"
	compileargs="$compileargs $arg"
	HasDashC=1
	DoLink=0
	;;

	-mpilog)
	if [ $UsesPmpi = 1 ] ; then
	    echo "Only one of -mpilog, -mpitrace, or -mpianim may be used."
	    exit 1
	else
	    UsesPmpi=1
        fi
	if [ "$hasMPE" = "yes" ] ; then
		MPILOG="-llmpe -lmpe"
	else
	    echo "-mpilog requires the MPE libraries"
	fi
	;;
	-mpitrace)
	if [ $UsesPmpi = 1 ] ; then
	    echo "Only one of -mpilog, -mpitrace, or -mpianim may be used."
	    exit 1
	else
	    UsesPmpi=1
        fi
	if [ "$hasMPE" = "yes" ] ; then
   	    MPILOG="-ltmpe -lmpe"
	else
	    echo "-mpitrace requires the MPE libraries"
	fi
	;;
	-mpianim)
	if [ $UsesPmpi = 1 ] ; then
	    echo "Only one of -mpilog, -mpitrace, or -mpianim may be used."
	    exit 1
	else
	    UsesPmpi=1
        fi
	if [ "$hasMPE" = "yes" ] ; then
	    MPILOG="-lampe -lmpe"
	else
	    echo "-mpianim requires the MPE libraries"
	fi
	;;
	-echo)
	set -x
	;;
	-show)
	Show=echo
	;;
	-config=*)
	CCname=`echo A$arg | sed -e 's/A-config=//g'`
        if [ -s $sysconfdir/mpiCC-$CCname.conf ] ; then
	    . $sysconfdir/mpiCC-$CCname.conf 
	else
	    echo "Configuration file mpiCC-$CCname.conf not found"
	fi
	;;
	-CC=*)
	CCC=`echo A$arg | sed -e 's/A-CC=//g'`
	CCLINKER="$CCC"
	;;
	-compile_info)
	show_compile=1
	DoLink=0
	Show=echo
	;;
	-link_info)
	show_link=1
	Show=echo
	;;
	-v)
	verbose=1
	echo "mpiCC for $MPIVERSION"
	compileargs="$compileargs -v"
	linkargs="$linkargs -v"
	;;
	-l*)
	# This SHOULD be the -l<lib> argument.  Only for the linker
	linkargs="$linkargs $arg"
	allargs="$allargs $arg"
	;;
	-help)
	echo "This is a program to compile or link C++ MPI programs"
	echo "In addition, the following special options are supported"
	echo "    -mpilog    - Build version that generate MPE log files"
	echo "    -mpitrace  - Build version that generates traces"
	echo "    -mpianim   - Build version that generates real-time"
	echo "                 animation"
	echo "    -CC=pgm    - Change the program to use to compile and link"
        echo "                 MPI programs.  WARNING! The program that you"
        echo "                 choose MUST be compatible with the MPICH "
        echo "                 libraries.  If you have trouble, you should"
        echo "                 reconfigure and rebuild MPICH, selecting"
        echo "                 this compiler."
	echo "    -show      - Show the commands that would be used without"
	echo "                 runnning them"
	echo "    -compile_info - Show how to compile a program"
	echo "    -link_info - Show how to link a program"
	echo "    -help      - Give this help"
	echo "    -echo      - Show exactly what this program is doing."
	echo "                 This option should normally not be used."
	echo "This should be used just like the usual C++ compiler"
	echo "For example,"
	echo "   $0 -c foo.C "
	echo "and"
	echo "   $0 -o foo foo.o"
	echo "Combining compilation and linking in a single command"
	echo "   $0 -o foo foo.C"
	echo "may not work on some systems, and is not recommended."
	exit 1
	;;
	# Unrecognized args.  Because we do an eval, we need to
	# carefully quote any args that contain quotes.
        *\"*) 
	qarg="'"$arg"'"
	allargs="$allargs $qarg"
	compileargs="$compileargs $qarg"
	linkargs="$linkargs $qarg"
	;;
        *\'*) 
	qarg='\"'"$arg"'\"'
	allargs="$allargs $qarg"
	compileargs="$compileargs $qarg"
	linkargs="$linkargs $qarg"
	;;
        *) allargs="$allargs $arg"
	if [ -s "$arg" ] ; then
	    ext=`expr "$arg" : '.*\(\..*\)'`
	    if [ "$ext" = ".C" -o "$ext" = ".cxx" -o "$ext" = ".cpp" -o \
		 "$ext" = ".cc" -o "$ext" = ".c" -o "$ext" = ".CC" ] ; then
	        DoCompile=1
	        compileargs="$compileargs $arg"
	        fname=`basename $arg $ext`
	        linkobjs="$linkobjs $fname.o"
	    elif [ "$ext" = ".o" ] ; then
		if [ $HasDashC = 1 ] ; then
	            compileargs="$compileargs $arg"
                else
	            DoLink=1
	            linkobjs="$linkobjs $arg"
                fi
	    else
	        compileargs="$compileargs $arg"
	        linkargs="$linkargs $arg"
	    fi
	else
            compileargs="$compileargs $arg"
	    linkargs="$linkargs $arg"
	fi
	;;
    esac
done
#
status=0
if [ $DoCompile = 1 -o $show_compile = 1 ] ; then 
    if [ $HasDashC != 1 ] ; then
        compileargs="-c $compileargs"
    fi
    # note the use of HAVE_MPI_CPP to cause the mpi++.h file to be 
    # included from mpi.h
    $Show $CCC $CCFLAGS  -I$includedir -DHAVE_MPI_CPP $CXXFLAGS $compileargs

    status=$?
    if [ $status != 0 ] ; then 
	exit $status
    fi
fi
if [ $DoLink = 1 -o $show_link = 1 ] ; then
    # If no LDFLAGS defined, use the ones that MPICH was built with
    if [ -z "$LDFLAGS" ] ; then
        LDFLAGS="$LDFLAGSBASE"
    fi
    # Figure out the library list.  Because we want to support both a single
    # mpi library containing both C and Fortran interfaces, as well as 
    # a library that allows multiple Fortran interfaces, we may need different
    # library link lines.  With a unified C/Fortran library, we just
    # use -l${MPILIBNAME}.  With separate Fortran libraries, we need
    # -l<fortranwrapperlib> -l${MPILIBNAME} -l<fortransuplib>
    # We also handle the profiling library here, which may not be needed
    # for those systems that support weak symbols.
    if [ "${MPILIBNAME}" = "${FLIBNAME}" -o -z "${FLIBNAME}" ] ; then
        mpilibs="-l${MPILIBNAME}"
    else
        mpilibs="-l${FLIBNAME} -l${MPILIBNAME} -l${FLIBNAME}fsup"
    fi
    # If the profiling library doesn't exist, or MPICH_NO_PROF environment
    # variable is set, skip the profiling library.
    if [ -n "$MPICH_NO_PROF" -o ! -s "$proflibfullname" ] ; then
        proflib=""
    fi
    #
    # Some programs need the profiling library, so add it if it exists
    # The C++ libraries use only a single library name
    if [ -s "$cppproflibfulname" ] ; then
        cpplib="${cppproflib}"
    elif [ ! -s "$cpplibfullname" ] ; then
        cpplib=""
    fi
    # IRIX complains if we include a library twice.  In the case of a
    # library using weak symbols, we don't need the proflib.  Just
    # in case we do, there is an enviroment variable that
    # can be used to override this test.
    if [ "${MPI_WITH_PMPI}" = "yes" -a "$MPICH_INCLUDE_PROFLIB" != yes ] ; then
        proflib=""
    fi
    # If proflib is non-empty, then add it
    if [ -n "$proflib" ] ; then
        mpilibs="$proflib $mpilibs $proflib"
    fi
    # If the C++ library doesn't exist, skip it
    # This may be needed because the C++ build wants to build executables
    # before the libraries are built.
    # 
    # This also assumes that any libraries needed by the C linker to handle
    # any Fortran dependencies are also needed by the C++ linker.
    # This is true when using the PGI compilers and specifying pgf90 as the
    # Fortran compiler (not just as the f90 compiler)
    $Show $CCLINKER $CCFLAGS $LDFLAGS $ROMIO_LFLAGS $LIB_PATH $linkobjs $linkargs $LDFLAGS $cpplib $MPILOG $mpilibs $BASE_LIB_LIST $F77_IN_C_LIBS
    status=$?
fi
exit $status
