#!/bin/sh
# hmake - make for Haskell programs
# Original Author (in tcsh): Thomas Hallgren, hallgren@cs.chalmers.se
# hacked by Niklas Röjemo, rojemo@cs.chalmers.se
# Current Author (in sh): (c) 1998-2002 Malcolm.Wallace@cs.york.ac.uk 

INSTALLVER="3.06 (2002-08-09)"
SCRIPTDIR=${SCRIPTDIR-/usr/local/bin}
MACHINE=${MACHINE-"`$SCRIPTDIR/harch`"}
HMAKEDIR=${HMAKEDIR-/usr/local/lib/hmake}
TMP=${TMP-/tmp}
export HMAKEDIR		# to find location of global hmakerc file.

MKPROG=${MKPROG-$HMAKEDIR/$MACHINE/MkProg}	# the real `hmake' program
OLDER=${OLDER-$HMAKEDIR/$MACHINE/Older}		# a helper program

if [ ! -d $HMAKEDIR/$MACHINE ]
then
  echo "`basename $0` is not installed/configured for $MACHINE."
  echo "  See your system administrator, or install it yourself from"
  echo "  http://www.cs.york.ac.uk/fp/hmake/"
  exit 1
fi

# We need a working `which' command: CYGWIN at least doesn't have it,
#    and other installed `which's may have undesirable behaviour.
#if which which >/dev/null 2>&1  && ( which which | grep -v Warning >/dev/null)
#then echo -n "" ;
#else
  which () {
    ( for path in `echo \":$PATH\" | sed -e 's/:/\" \"/g'`
      do
        thefile=`echo $path | tr -d "\""`/$1
        if [ -f "$thefile" -a -x "$thefile" ]
        then echo $thefile
             exit 0
        fi
      done; exit 1 )
  }
#fi

## Fix an absolute Cygwin path to an absolute native Windows path.
## (Also copes with options like -I/path etc.)
## This routine is only strictly required when the MkProg executable
## was built with GHC/mingw32.
#if echo $MACHINE | grep -y CYGWIN >/dev/null
#then filepath() { case $1 in
#                    -?/*) echo `cygpath -w $1` | tr '\\' '/';;
#                    /*)   echo `cygpath -w $1` | tr '\\' '/';;
#                    *)    echo $1;;
#                  esac; }
#else filepath() { echo $1; }
#fi

BUILTBY=ghc
# USINGRTS decides how run-time system options should be passed to MkProg
# itself (***Note: NOT to the compiler called by hmake).  Possible values
# are:   rts       enclosed between +RTS -RTS
#        minus     first on commandline, trailed by -
# If you compiled hmake with ghc or nhc13/98, USINGRTS should be rts.
# If you compiled hmake with hbc or xtc,      USINGRTS should be minus.
case $BUILTBY in
  ghc|nhc*) USINGRTS=rts;;
  hbc|xtc) USINGRTS=minus;;
  gcc)     USINGRTS=rts; BUILTBY=nhc98 ;;
esac


# Now let's get started.

exec="sh -e"
modules=""
flags=""	# compiler + hmake flags
hmflags=""	# hmake flags only
hcflags=""	# compiler flags only
ctflags=""	# protected compiler flags
rtflags=""	# protected compiler run-time flags
hmrtflags=""	# hmake run-time flags
	# 'portable Hat' flags (passed to hat-trans by MkProg)
importflags=""  # -I, -i and -P flags (directories for Haskell imports)
bigIflags=""	# -I flags for cpp includes
cppflags=""	# -D (and -U ?) flags for cpp
TPROF=0
TRACE=0


# Also assume compiler/linker flags from the environment
#    HFLAGS, LDFLAGS
# 'portable Hat' flags (passed to hat-trans by MkProg)
#    HATFLAGS

while [ "$1" != "" ]
do
  case $1 in
    --version) echo "$0: $INSTALLVER"
               exit 0;;

    # Flags to hmake itself
    -clean)        hmflags=$hmflags" $1" ;;
    -realclean)    hmflags=$hmflags" $1" ;;
    -keepPrelude)  hmflags=$hmflags" $1" ;;
    -watch)        hmflags=$hmflags" $1" ;;
    -hat)          hmflags=$hmflags" $1" ;;
    -n)  hmflags=$hmflags" -q"; exec="cat" ;;
    -q)  hmflags=$hmflags" $1" ;;
    -N*) hmflags=$hmflags" $1" ;;
    -g)  hmflags=$hmflags" $1"; exec=cat ;;
    -gd) hmflags=$hmflags" $1"; exec=cat ;;
    -M*) hmflags=$hmflags" $1"; exec=cat ;;
#   -f)  shift; configfile=$1; hmflags=$hmflags" -f`filepath $1`" ;;
#   -d)  shift; objdir=$1;     hmflags=$hmflags" -d`filepath $1`" ;;
#   -d*) objdir=`echo $1 | cut -c3-`; hmflags=$hmflags" `filepath $1`" ;;
    -f)  shift; configfile=$1; hmflags=$hmflags" -f$1" ;;
    -d)  shift; objdir=$1;     hmflags=$hmflags" -d$1" ;;
    -d*) objdir=`echo $1 | cut -c3-`; hmflags=$hmflags" $1" ;;
    -hbc)   COMP=hbc ;;
    -ghc)   COMP=ghc ;;
    -nhc98) COMP=nhc98 ;;
    -nhc13) COMP=nhc13 ;;
    -HC=*)  COMP=`echo $1 | cut -c5-` ;;
    -hc=*)  COMP=`echo $1 | cut -c5-` ;;
    -HC)    shift ; COMP=$1 ;;
    -hc)    shift ; COMP=$1 ;;

    # Run-time flags to hmake itself
    +RTS) shift
          while [ "$1" != "-RTS" ]
          do hmrtflags=$hmrtflags" $1"
             shift
          done ;;

    # Run-time flags to the compiler
    -H*)  rtflags=$rtflags" $1" ;;	# heapsize:  ghc, hbc, nhc98
    -h*)  rtflags=$rtflags" $1" ;;	# heapsize:            nhc98
    -A*)  rtflags=$rtflags" $1" ;;	# stacksize:      hbc
    -V*)  rtflags=$rtflags" $1" ;;	# stacksize:           nhc98
    -K*)  rtflags=$rtflags" $1" ;;	# stacksize: ghc       nhc98
    -B*)  rtflags=$rtflags" $1" ;;	# GC stats:       hbc, nhc98
    -S*)  rtflags=$rtflags" $1" ;;	# GC stats:       hbc
   #-gc*) rtflags=$rtflags" $1" ;;	# GC flags:       hbc?

    # Protected compiler flags
    +CTS) shift
          while [ "$1" != "-CTS" ]
          do ctflags=$ctflags" $1"
             shift
          done ;;

    # Cpp + import flags - need to translate later, based on haskell compiler
#   -P*) importflags=$importflags" `filepath $1`" ;;
#   -I*) importflags=$importflags" `filepath $1`";
#          bigIflags=$bigIflags" `filepath $1`" ;;
#   -i*) importflags=$importflags" `filepath $1`" ;;
    -P*) importflags=$importflags" $1" ;;
    -I*) importflags=$importflags" $1";
           bigIflags=$bigIflags" $1" ;;
    -i*) importflags=$importflags" $1" ;;
    -D*) cppflags=$cppflags" $1"; ;;
  # -U*) cppflags=$cppflags" $1"; ;;

    # Link flags
    -L*) LDFLAGS=$LDFLAGS" $1" ;;
    -l*) LDFLAGS=$LDFLAGS" $1" ;;

    # tracing and profiling flags - mainly nhc98, some hat-trans
    -T) hcflags=$hcflags" $1";
        hmflags=$hmflags" -hi-suffix=T.hi -o-suffix=T.o";
        TRACE=1 ;;
    -p) hcflags=$hcflags" $1";
        hmflags=$hmflags" -o-suffix=p.o" ;;
    -t|-z) hcflags=$hcflags" $1";
           hmflags=$hmflags" -o-suffix=z.o";
           TPROF=1 ;;
    -C) hcflags=$hcflags" $1";
        hmflags=$hmflags" -o-suffix=hc" ;;
    -trusted) HATFLAGS=$HATFLAGS" $1" ;;
    -prelude) HATFLAGS=$HATFLAGS" $1";
              hcflags=$hcflags" $1" ;;

    # package flags - ghc or nhc98
    -package-name) hcflags=$hcflags" $1 $2";
                   shift ;;
    -package|-syslib) hcflags=$hcflags" $1 $2";
                      hmflags=$hmflags" -package=$2";
                      shift ;;

    # Any other compiler flags
    -*) hcflags=$hcflags" $1" ;;

    # Objects and archives for linking
    *.o)   LDFLAGS=$LDFLAGS" $1" ;;
    *.a)   LDFLAGS=$LDFLAGS" $1" ;;

    # Anything else must be a module name
    *) modules=$modules" $1" ;;

  esac
  shift
done

# Fix o-suffix when time profiling _and_ tracing
if test $TPROF -eq 1 -a $TRACE -eq 1	# relies on src/hmake/Argv.hs
then hmflags=$hmflags" -o-suffix=Tz.o"	# using only the last o-suffix
fi

# Throw an error if there is nothing specified to compile.
if [ "$modules" = "" ]
then
  echo 'Usage: hmake [compiler] [options] (module|program)* [object...]'
  echo '       compiler     choose -ghc, -hbc, -nhc98, or -hc=comp'
  echo '       --version    show version information and quit'
  echo '       -q           quiet (do not echo commands)'
  echo '       -n           noexec (echo but do not execute commands)'
  echo '       -g           show graph of dependencies (implies noexec)'
  echo '       -M           show Makefile format dependencies'
  echo '       -Md          show Makefile format dependencies, wrt -d option'
  echo '       -dobjdir     use objdir for object files'
  echo '       -clean       just remove all relevant .o files'
  echo '       -realclean   just remove all relevant .o and .hi files'
  echo '       -*           other options are passed through to the compiler'
  echo '       module       modules (.hs, .lhs, .gc) are compiled'
  echo '       program      programs are compiled and linked'
  echo '       object       objects (.o, .a) are linked into a program only'
  exit 1
fi

# Ensure we know the default compiler to use if none was specified, by
# checking (in this order)
#   (1) a specified config file,
#   (2) the user's personal config file
#   (3) the system-wide config file
#
if [ -z "$COMP" ]
then
  if [ -f "$configfile" ]
  then COMP=`grep defaultCompiler $configfile | cut -d'"' -f2`
  else
    if [ -f $HOME/.hmakerc/$MACHINE ]
    then COMP=`grep defaultCompiler $HOME/.hmakerc/$MACHINE |cut -d'"' -f2`
    else
      if [ -f $HMAKEDIR/$MACHINE/hmakerc ]
      then COMP=`grep defaultCompiler $HMAKEDIR/$MACHINE/hmakerc |cut -d'"' -f2`
      else COMP=$BUILTBY	# a desparate fallback position
      fi
    fi
  fi
fi

# This variable should be null - do not change it.
OD=
# Define the characteristics of each known compiler.
compilerstyle () {
  case `basename $1` in
    hbc)   RTSOPTIONSTYLE=minus
           CTSOPTIONSTYLE=none
           IMPORTOPTIONSTYLE=minusi
           export LMLDIR HBCDIR
           ;;
    nhc98) RTSOPTIONSTYLE=rts
           CTSOPTIONSTYLE=cts
           IMPORTOPTIONSTYLE=minusP
           OD="-od"
           ;;
    ghc*)  RTSOPTIONSTYLE=none
           CTSOPTIONSTYLE=none
           IMPORTOPTIONSTYLE=minusi
           ;;
    *)     ;;
  esac
}

# Select the right compiler-specific style in which to pass various options.
compilerstyle $COMP
case $RTSOPTIONSTYLE in
  rts)     if [ "$rtflags" != "" ]
           then rtflags=" +RTS$rtflags -RTS"
           fi ;;
  minus)   rtflags="$rtflags -" ;;
  none)    ;;
esac
case $CTSOPTIONSTYLE in
  cts)     if [ "$ctflags" != "" ]
           then ctflags=" +CTS$ctflags -CTS"
           fi ;;
esac
case $OD in
  -od) if [ "$objdir" != "" ]
       then #hcflags=$hcflags" -d $objdir"
            hmflags="$hmflags $OD"
       fi ;;
esac
case $USINGRTS in
  minus) hmrtflags="$hmrtflags -" ;;
  rts)   hmrtflags="+RTS $hmrtflags -RTS" ;;
esac
	# Note: cppflags are given only to hmake, not to the compiler,
	#       because they are only needed if cpp is called, so to
	#       reduce screen clutter, hmake controls their addition
case $IMPORTOPTIONSTYLE in
  minusi) hmflags="$hmflags $cppflags $importflags"
          hcflags="$hcflags $bigIflags `echo \"$importflags\" | sed 's/ -[PI]/ -i/g'`"
          ;;
  minusP) hmflags="$hmflags $cppflags $importflags"
          hcflags="$hcflags `echo \"$importflags\" | sed 's/ -i/ -I/g'`"
          ;;
esac

# Get ready to build...
HFLAGS="$rtflags$ctflags$hcflags$flags $HFLAGS"

export HC HFLAGS OLDER LDFLAGS	# MkProg expects these variables to be set.
export HATFLAGS			# ditto
export MACHINE			# nhc98 script is faster if this is set.

# Here we go...
#$MKPROG -hc=`filepath $COMP` $hmrtflags $hmflags $flags $modules >$TMP/hmake$$
$MKPROG -hc=$COMP $hmrtflags $hmflags $flags $modules >$TMP/hmake$$
CODE=$?
case $CODE in
  0) cat $TMP/hmake$$ | $exec
     CODE=$?
     rm $TMP/hmake$$
     exit $CODE ;;
  *) rm $TMP/hmake$$
     echo >&2 "Stop - hmake dependency error."
     exit $CODE ;;
esac
