#!/bin/sh

# Silly shorthand, used for source reorganization
src="src/arch"

more=0

syntax() {
  echo ''
  echo 'Usage: build <target> <version> <options> [charmc-options ...]'
  echo ''
  echo '<targets>: converse charm++ LIBS AMPI FEM bluegene pose jade msa'
  echo '<targets>: doc ps-doc pdf-doc html-doc'
  if test $more = 1
  then
  echo ''
  echo '  charm++         compile Charm++ core only'
  echo '  AMPI            compile Adaptive MPI on top of Charm++'
  echo '  FEM             compile FEM framework'
  echo '  LIBS            compile additional parallel libraries with Charm++ core'
  echo '  bluegene        build additional BigSim libraries'
  echo '  pose            build POSE parallel discrete event simulator'
  echo '  jade            build Jade compiler (auto-builds charm++, msa)'
  echo '  msa             build Multiphase Shared Arrays(MSA) library'
  echo ''
  fi
  echo '<versions>: ' 
  ( cd $src ; ls -1 | egrep -v '(^CVS)|(^shmem$)|(^mpi$)|(^sim$)|(^net$)|(^elan$)|(^util$)|(^common$)|(^uth$)|(^conv-mach-fix.sh$)|(^win32$)|(^paragon$)|(^vmi$)|(^lapi$)|(^template$)' | pr -3 -t )
  echo ''
  echo '<options>: compiler and platform specific options'
  echo 'cc cc64 cxx kcc pgcc acc icc ecc gcc3 mpcc pathscale'
  echo 'help smp gm tcp vmi scyld clustermatic bluegene ooc syncft papi'
  echo 'pthreads lam'
  echo '--incdir --libdir --basedir --no-build-shared -j'
  if test $more = 1
  then
  echo ''
  echo 'For platform specific options, use help option:'
  echo '  help		  platform specific help, e.g. ./build charm++ net-linux help'
  echo ''
  echo 'Choose a compiler (only one option is allowed from this section):'
  echo '  cc, cc64        For Sun WorkShop C++ 32/64 bit compilers'
  echo '  cxx             DIGITAL C++ compiler (DEC Alpha)'
  echo '  kcc             KAI C++ compiler'
  echo "  pgcc            Portland Group's C++ compiler"
  echo '  acc             HP aCC compiler'
  echo '  icc             Intel C/C++ compiler for Linux IA32'
  echo '  ecc             Intel C/C++ compiler for Linux IA64'
  echo '  gcc3            use gcc3 - GNU GCC/G++ version 3'
  echo '  mpcc            SUN Solaris C++ compiler for MPI'
  echo '  pathscale       use pathscale compiler suite'
  echo ''
  echo 'Choose a fortran compile (only one option is allowed from this section):'
  echo '  g95             G95 at http://ww.g95.org'
  echo '  absoft          Absoft fortran compiler'
  echo "  pgf90           Portland Group\'s Fortran compiler"
  echo '  ifc             Intel Fortran compiler (older versions)'
  echo '  ifort           Intel Fortran compiler (newer versions)'
  echo ''
  echo 'Platform specific options (choose multiple if apply):'
  echo '  lam             Use LAM MPI'
  echo '  smp             support for SMP, multithreaded charm on each node'
  echo '  mpt             use SGI Message Passing Toolkit (only for mpi version)'
  echo '  gm              use Myrinet for communication'
  echo '  tcp             use TCP sockets for communication (ony for net version)'
  echo "  vmi             use NCSA's VMI for communication (only for mpi version)"
  echo '  scyld           compile for Scyld Beowulf cluster based on bproc'
  echo '  clustermatic    compile for Clustermatic (support version 3 and 4) '
  echo '  pthreads        compile with pthreads Converse threads'
  echo ''
  echo 'Advanced options:'
  echo '  bluegene	  compile for BigSim (Blue Gene) simulator'
  echo '  ooc		  compile with out of core support'
  echo '  syncft	  compile with Charm++ fault tolerance support'
  echo '  papi            compile with PAPI performance counter support (if any)'
  echo ''
  echo "Charm++ dynamic libraries:"
  echo "  --build-shared     build Charm++ dynamic libraries (.so) (default)"
  echo "  --no-build-shared  don't build Charm++'s shared libraries"
  echo ''
  echo 'Miscellaneous options:'
  echo '  --incdir=DIR	  specify additional include path for compiler'
  echo '  --libdir=DIR	  specify additional lib path for compiler'
  echo '  --basedir=DIR	  shortcut for the above two - DIR/include and DIR/lib'
  echo '  -j[N]           parallel make, N is the number of paralle make jobs'
  echo "  --with-romio    build AMPI with ROMIO library"
  fi
  echo ''
  echo '<charmc-options>: normal compiler options e.g. -g -O -save -verbose'
  if test $more = 1
  then
  echo ''
  echo 'Examples:'
  echo "1. display all supported options for net-linux using 'help':"
  echo '  ./build charm++ net-linux help'
  echo '2. compile Charm++ on Linux with optimizations:'
  echo '  ./build charm++ net-linux -O -DCMK_OPTIMIZE'
  echo '3. compile Charm++ for Linux clustermatic Beowulf cluster with Intel compiler:'
  echo '  ./build charm++ net-linux clustermatic icc -O'
  echo '4. compile Charm++ for IA64 Linux cluster with MPICH-GM:'
  echo '  ./build charm++ mpi-linux-ia64 gm -O'
  echo '5. compile Charm++ for Windows with VC++ (Cygwin required):'
  echo '  ./build charm++ net-win32 -O'
  echo '6. compile on IBM SP with MPI using parallel gmake, 4 jobs simultaneously:'
  echo '  MAKE=gmake  ./build charm++ mpi-sp -j4 -O            # sh'
  echo '  setenv MAKE gmake;  ./build charm++ mpi-sp -j4 -O    # csh'
  echo '7. compile Charm++ with MPI that is installed at /usr/local/mpich:'
  echo '  ./build charm++ mpi-linux --incdir /usr/local/mpich/include --libdir /usr/local/mpich/lib -O'
  echo '   or in short,'
  echo '  ./build charm++ mpi-linux --basedir /usr/local/mpich -O'
  echo ''
  echo 'Note: This script:'
  echo ' 1. Creates directories <version> and <version>/tmp';
  echo ' 2. Copies src/scripts/Makefile into <version>/tmp';
  echo ' 3. Does a "make <target> <version> OPTS=<charmc-options>" in <version>/tmp.'
  echo "That's all build does.  The rest is handled by the Makefile."
  echo ''
  echo 'You should register your copy of Charm++ with us by sending email'
  echo 'to tms@charm.cs.uiuc.edu containing the message "subscribe charm-users"'
  echo 'This will allow us to notify you of new releases of Charm++.'
  echo ''
  echo 'Thank you for using Charm++, please send questions or comments to '
  echo 'Parallel Programming Lab at University of Illinois at Urbana-Champaign'
  echo '(email: ppl@cs.uiuc.edu).'

  else
  echo ''
  echo "To get more detailed help, run ./build --help"
  fi
}

printOption() {
  for prefix in cc conv-mach
  do
    str="Supported compilers:"
    [ "$prefix" = "conv-mach" ] && str="Supported options:"
    opts=""
    for dir in $OPT_DIRS
    do
#         echo "Checking for $prefix in $dir"
          files=`cd $dir; ls $prefix-*.h 2>/dev/null`
          opts="$opts "`echo $files | sed 's/'$prefix'-\([^.]*\).h/\1/g'`
    done 
    tmp=.tmp.$$
    rm -f $tmp; touch $tmp
    for o in $opts
    do
      echo $o >> $tmp
    done
    opts=`sort $tmp | uniq`
    rm -f $tmp
    echo $str $opts
  done
  exit 1
}

CheckDir() {
  for d in $*
  do
    if test ! -d $d
    then
      echo Error: cannot find $d!
      exit 1
    fi
  done
}

TestIfCompiler() {
  for dir in $OPT_DIRS
  do
    [ -f $dir/cc-$1.sh ] && return 1
  done  
  return 0
}

TestIfOption() {
  for dir in $OPT_DIRS
  do
    [ -f $dir/conv-mach-$1.h ] && return 1 
  done
  
  echo "Error> option: $1 is not supported in this version!"; 
  printOption
}


# start

MAKEOPTS=""
OPTS=""
BOPTS=""
MORE=""
COMPILER=""
BASEDIR=
LIBDIR=
INCDIR=
ARCH=
BUILD_SHARED=
WITH_ROMIO=

[ "$1" = '--help' -o "$1" = '-h' ] && more=1 && syntax | more && exit 1
[ $# -lt 2 ] && syntax && exit 1
PROGRAM=$1
shift
VERSION=$1; BASEVERSION=$1; ARCH=`echo $1 | sed -e 's@-.*@@'`
shift

OPT_DIRS="$src/$BASEVERSION $src/$ARCH $src/common"

while [ ! $# -eq 0 ]
do
  case "$1" in
    	    "--basedir")
          	shift; 
  		for dir in $1
  		do
		  CheckDir $dir/include $dir/lib
          	  LIBDIR="$LIBDIR -L$dir/lib";
          	  INCDIR="$INCDIR -I$dir/include"
		done
          	shift
 	  	;;
    	    --basedir=*)
                basedir=`echo $1 | awk -F= '{print $2}'`
  		for dir in $basedir
  		do
		  CheckDir $dir/include $dir/lib
          	  LIBDIR="$LIBDIR -L$dir/lib";
          	  INCDIR="$INCDIR -I$dir/include"
		done
          	shift
 	  	;;
    	    "--libdir")
          	shift; CheckDir $1
  		for dir in $1
  		do
          	  LIBDIR="$LIBDIR -L$dir"; 
		done
                shift
 	  	;;
    	    --libdir=*)
                libdir=`echo $1 | awk -F= '{print $2}'`
		CheckDir $libdir
  		for dir in $libdir
  		do
          	  LIBDIR="$LIBDIR -L$dir"; 
		done
          	shift
 	  	;;
    	    "--incdir")
          	shift; CheckDir $1
  		for dir in $1
  		do
          	  INCDIR="$INCDIR -I$dir"; 
		done
          	shift
 	  	;;
    	    --incdir=*)
                incdir=`echo $1 | awk -F= '{print $2}'`
		CheckDir $incdir
  		for dir in $incdir
  		do
          	  INCDIR="$INCDIR -I$dir"; 
		done
          	shift
 	  	;;
	    --no-build-shared|-nobs|--no-shared)
		BUILD_SHARED="-nobs"; shift
		;;
	    --with-romio)
		WITH_ROMIO="true"; shift
		;;
	    --build-shared|-bs)
		# obsolete, do nothing
		shift
		;;
	    -j*)
                PMAKENUM=`echo $1 | awk -Fj '{print $2}'`
		MAKEOPTS="$MAKEOPTS -j $PMAKENUM"
		shift;
		;;
    -*) 
# We hit a real compiler option (like -g, or -Dfoo),
# so just copy over all remaining options
          while [ ! $# -eq 0 ]
          do
            OPTS="$OPTS $1"; shift
          done
	  ;;
    "help")
	printOption
	;;
    *)
# This has to be a build-time option (like "smp", "gcc3", or "kcc")
        TestIfCompiler $1
        if [ $? -eq 1 ] 
        then
# It specifies a compiler:
          if [ ! -z "$COMPILER" ] 
          then
              echo "Error> Tried to specify two compilers: $COMPILER and $1"
              printOption
          fi
          COMPILER=$1
        else
# It specifies some other option:
          TestIfOption $1
          BOPTS="$BOPTS $1"
        fi
        shift
	;;
  esac
done

[ "x$VERSION" = "x" ] && syntax && exit 1

if [ -z "$MAKE" ] 
then
  # prefer gmake
  MAKE=`which gmake 2>/dev/null`
  [ -z "$MAKE" -o ! -x "$MAKE" ] && MAKE='make'
fi

if [ ! -f $src/$BASEVERSION/conv-mach.h ] 
then
  echo "Error> build can not find arch: $BASEVERSION!" 
  exit 1
fi

#generate VERSION name combining all the build-time options.
if [ -n "$BOPTS" -o -n "$COMPILER" ]
then
  echo "Selected Compiler: $COMPILER"
  echo "Selected Options: $BOPTS"
  SORTED=`echo $BOPTS | awk  '{ for (i = 1; i <= NF; ++i) print $i }' | sort`
  BOPTS_WITHCOMPILER=`echo $SORTED $COMPILER`
  for i in $BOPTS_WITHCOMPILER
  do
    VERSION=$VERSION-$i
  done
fi

[ -d $VERSION ] || echo "Creating dir: $VERSION" 
[ -d $VERSION ] || mkdir $VERSION
[ -d $VERSION/tmp ] || echo "Creating dir: $VERSION/tmp" 
[ -d $VERSION/tmp ] || mkdir $VERSION/tmp

echo "Copying src/scripts/Makefile to $VERSION/tmp"
rm -f $VERSION/tmp/Makefile
rm -f $VERSION/tmp/Make.depends
rm -f $VERSION/tmp/Make.lb
rm -f $VERSION/tmp/Make.machine


# Create the bin, lib, include, etc. links:
if [ "x_`echo $VERSION | awk -F- '{print $2}'`" = "x_win32" ]
then
#Win32 version needs special compilers and *copied* (not linked)
# source files.
	echo "Copying compilers for win32 into cygwin /bin directory"
	cp $src/win32/unix2nt* /bin
	cp $src/win32/system_ln $VERSION/tmp
	cp $src/win32/unistd.h $VERSION/tmp
	cp $src/win32/createlink.exe /bin
  chmod +x $VERSION/tmp/system_ln
else
	cat > $VERSION/tmp/system_ln <<EOF
#!/bin/sh
ln -f -s \$@
EOF
  chmod +x $VERSION/tmp/system_ln
  for newdir in `echo bin lib lib_so include tmp`
  do
    echo "Soft-linking over $newdir"
    if [ -r $newdir ]
    then
      rm -fr $newdir || exit 1
    fi
    $VERSION/tmp/system_ln $VERSION/$newdir $newdir
  done
  rm -f VERSION
  $VERSION/tmp/system_ln $VERSION/include/VERSION VERSION
fi

$VERSION/tmp/system_ln "../../src/scripts/Make.depends" $VERSION/tmp/Make.depends
$VERSION/tmp/system_ln "../../src/ck-ldb/Make.lb" $VERSION/tmp/Make.lb
$VERSION/tmp/system_ln "../../src/scripts/Makefile" $VERSION/tmp/Makefile
touch $VERSION/tmp/Makefile.machine

ConvUsr="$VERSION/tmp/conv-mach-pre.sh"
echo "Generating $ConvUsr"
echo > $ConvUsr
if test -n "$LIBDIR" 
then
  echo 'USER_OPTS_LD="$USER_OPTS_LD '$LIBDIR'"' >> $ConvUsr
  echo 'USER_OPTS_LDXX="$USER_OPTS_LDXX '$LIBDIR'"' >> $ConvUsr
fi
if test -n "$INCDIR" 
then
  echo 'USER_OPTS_CC="$USER_OPTS_CC '$INCDIR'"' >> $ConvUsr
  echo 'USER_OPTS_CXX="$USER_OPTS_CXX '$INCDIR'"' >> $ConvUsr
fi
chmod +x $ConvUsr

# Create conv-mach-opt headers with special build-time options
ConvHeader="$VERSION/tmp/conv-mach-opt.h"
ConvSh="$VERSION/tmp/conv-mach-opt.sh"
if [ ! -f $ConvSh -o ! -f $ConvHeader ]
then
  echo "Generating $ConvHeader, conv-mach-opt.sh"
  echo '/* Build-time options header, automatically generated by charm/build*/'> $ConvHeader
  echo '# Built-time options header, automatically generated by charm/build'> $ConvSh
  echo '[ -z "$CHARMINC" ] && CHARMINC="."' >> $ConvSh
fi
if test -n "$COMPILER"
then
      i="$COMPILER"
      echo '#include "'cc-$i.h'"' >> $ConvHeader
      echo '. $CHARMINC/'"cc-$i.sh" >> $ConvSh
fi
if test -n "$BOPTS"
then
    for i in $BOPTS
    do
      echo '#include "'conv-mach-$i.h'"' >> $ConvHeader
      echo '. $CHARMINC/'"conv-mach-$i.sh" >> $ConvSh
    done
fi

if test  -n "$BUILD_SHARED" 
then
    echo "CMK_NO_BUILD_SHARED=true" >> $ConvSh
fi

if test  -n "$WITH_ROMIO" 
then
    echo "CMK_AMPI_WITH_ROMIO=\"true\"" >> $ConvSh
fi

echo $BASEVERSION > $VERSION/tmp/.vdir

echo "Performing '$MAKE $MAKEOPTS $PROGRAM OPTS="$OPTS"' in $VERSION/tmp"
cd $VERSION/tmp 
$MAKE $MAKEOPTS $PROGRAM OPTS="$OPTS $BUILD_SHARED"

MAKEEXIT=$?
if [ $MAKEEXIT -eq 0 ]
then
	echo "-------------------------------------------------"
	echo "$PROGRAM built successfully."
	echo "Next, try out a sample program like" \
	     "tests/charm++/simplearrayhello"
else
	echo "-------------------------------------------------"
	echo "Charm++ NOT BUILT. Either cd into $VERSION/tmp and try"
	echo "to resolve the problems yourself, visit"
	echo "    http://charm.cs.uiuc.edu/"
	echo "for more information. Otherwise, email the developers at ppl@cs.uiuc.edu"
	exit $MAKEEXIT
fi
