#!/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 IDL TSM SM PVM bluegene'
  echo '<targets>: doc ps-doc pdf-doc html-doc'
  echo '<versions>: ' 
  ( cd $src ; ls -1 | egrep -v '(^CVS)|(^shmem$)|(^mpi$)|(^sim$)|(^net$)|(^elan$)|(^util$)|(^common$)|(^uth$)|(^conv-mach-fix.sh$)|(^win32$)|(^paragon$)' | pr -3 -t )
  echo ''
  echo '<options>: help cc cc64 cxx kcc pgcc acc icc ecc gcc3 mpcc smp gm tcp vmi scyld opteron bluegene --incdir --libdir --basedir --no-shared'
  if test $more = 1
  then
  echo ''
  echo 'Not all these options are supported by one version, use version based help:'
  echo '  help		version based help message, 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		to use gcc3 - GNU GCC/G++ version 3'
  echo '  mpcc		SUN Solaris C++ compiler for MPI'
  echo ''
  echo 'Platform specific options (choose multiple):'
  echo '  opteron	compile for AMD Opteron'
  echo '  smp		support for SMP, multithreaded charm on each node'
  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"
  echo '  scyld		compile for Scyld Beowulf cluster'
  echo ''
  echo 'Advanced options:'
  echo '  bluegene	compile for BigSim (Blue Gene) simulator'
  echo '  occ		compile with out of core support'
  echo ''
  echo 'Miscellaneous options:'
  echo '  --incdir=DIR	specify additional include path for compilers'
  echo '  --libdir=DIR	specify additional lib path for compilers'
  echo '  --basedir=DIR	specify additional path at once - DIR/include and DIR/lib'
  echo "  --no-shared	disable the compilation for Charm++'s shared libraries"
  fi
  echo ''
  echo '<charmc-options>: normal compiler options e.g. -g -O -save -verbose'
  echo 'Note: This script:'
  echo ' 1. Creates directories <version> and <version>/tmp';
#  echo ' 2. Copies src/Common/scripts/Makefile into <version>/tmp';
  echo ' 2. Does a "make <target> <version> OPTS=<charmc-options>" in <version>/tmp.'
#  echo "That's all build does.  The rest is handled by the Makefile."
  [ $more = 0 ] && echo "To get more detailed help, run ./build --help"
}

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 
    echo $str $opts
  done
  exit 1
}

CheckDir() {
  for dir in $*
  do
    if test ! -d $dir
    then
      echo Error: cannot find $1!
      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="-build-shared"

[ "$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; CheckDir $1/include $1/lib
          	LIBDIR="$LIBDIR -L$1/lib";
          	INCDIR="$INCDIR -I$1/include"; shift
 	  	;;
    	    --basedir=*)
                basedir=`echo $1 | awk -F= '{print $2}'`
		CheckDir $basedir/include $basedir/lib
          	LIBDIR="$LIBDIR -L$basedir/lib";
          	INCDIR="$INCDIR -I$basedir/include"; shift
 	  	;;
    	    "--libdir")
          	shift; CheckDir $1
          	LIBDIR="$LIBDIR -L$1"; shift
 	  	;;
    	    --libdir=*)
                libdir=`echo $1 | awk -F= '{print $2}'`
		CheckDir $libdir
          	LIBDIR="$LIBDIR -L$libdir"; shift
 	  	;;
    	    "--incdir")
          	shift; CheckDir $1
          	INCDIR="$INCDIR -I$1"; shift
 	  	;;
    	    --incdir=*)
                incdir=`echo $1 | awk -F= '{print $2}'`
		CheckDir $incdir
          	INCDIR="$INCDIR -I$incdir"; shift
 	  	;;
	    --no-shared)
		BUILD_SHARED=""; 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

[ -f $src/$BASEVERSION/conv-mach.h ] || syntax

#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

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
  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 -f $newdir
    fi
		$VERSION/tmp/system_ln $VERSION/$newdir $newdir
	done
fi

$VERSION/tmp/system_ln "../../src/scripts/Makefile" $VERSION/tmp/Makefile

ConvUsr="$VERSION/tmp/conv-mach-pre.sh"
echo "Generating $ConvUsr"
echo > $ConvUsr
test -n "$LIBDIR" && echo "CMK_LIBDIR=\"$LIBDIR\"" >> $ConvUsr
test -n "$INCDIR" && echo "CMK_INCDIR=\"$INCDIR\"" >> $ConvUsr
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


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" \
	     "pgms/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
