#! /bin/sh

## Make sure to keep -static-libgcc, -static-libstdc++ and -static-libgfortran
## in DL_LDFLAGS when updating this file.
## Do not add -shared in LDFLAGS (i.e. this file should mimick “mkoctfile
## --link-stand-alone”, see the top of mex/build/configure.ac).
## Also keep BINDIR in DEFAULT_LDFLAGS (for UMFPACK).

# Exit immediately on any error.
set -e

: ${SED="/bin/sed"}

# Get path to the mkoctfile shell script
MKOCTFILE_PATH=$(dirname $(readlink -f "$0"))
OCTAVE_PREFIX="$MKOCTFILE_PATH/octave64/mingw64"

# Get Octave version
current_octave_version=$(grep "^OCTAVE_VERSION" "$MKOCTFILE_PATH/versions.mk")
eval $(echo "$current_octave_version" | tr -d '[:space:]')

DEFAULT_BINDIR="$OCTAVE_PREFIX/bin"
DEFAULT_INCLUDEDIR="$OCTAVE_PREFIX/include"
DEFAULT_LIBDIR="$OCTAVE_PREFIX/lib"
DEFAULT_OCTINCLUDEDIR="$OCTAVE_PREFIX/include/octave-${OCTAVE_VERSION}/octave"
DEFAULT_OCTLIBDIR="$OCTAVE_PREFIX/lib/octave/${OCTAVE_VERSION}"

if [ -n "$OCTAVE_HOME" ]; then
  DEFAULT_BINDIR="`echo $DEFAULT_BINDIR | $SED "s,^$OCTAVE_PREFIX,$OCTAVE_HOME,"`"
  DEFAULT_INCLUDEDIR="`echo $DEFAULT_INCLUDEDIR | $SED "s,^$OCTAVE_PREFIX,$OCTAVE_HOME,"`"
  DEFAULT_LIBDIR="`echo $DEFAULT_LIBDIR | $SED "s,^$OCTAVE_PREFIX,$OCTAVE_HOME,"`"
  DEFAULT_OCTINCLUDEDIR="`echo $DEFAULT_OCTINCLUDEDIR | $SED "s,^$OCTAVE_PREFIX,$OCTAVE_HOME,"`"
  DEFAULT_OCTLIBDIR="`echo $DEFAULT_OCTLIBDIR | $SED "s,^$OCTAVE_PREFIX,$OCTAVE_HOME,"`"
fi

: ${BINDIR=$DEFAULT_BINDIR}
: ${INCLUDEDIR=$DEFAULT_INCLUDEDIR}
: ${LIBDIR=$DEFAULT_LIBDIR}
: ${OCTINCLUDEDIR=$DEFAULT_OCTINCLUDEDIR}
: ${OCTLIBDIR=$DEFAULT_OCTLIBDIR}

DEFAULT_INCFLAGS="-I$OCTINCLUDEDIR/.. -I$OCTINCLUDEDIR"
if [ "$INCLUDEDIR" != /usr/include ]; then
  DEFAULT_INCFLAGS="$DEFAULT_INCFLAGS -I$INCLUDEDIR"
fi

DEFAULT_LDFLAGS="-L$OCTLIBDIR -L$BINDIR"
if [ "$LIBDIR" != /usr/lib ]; then
  DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -L$LIBDIR"
fi

# Default values for these variables are filled in when Octave is
# compiled.

: ${EXEEXT=""}

: ${CPPFLAGS=""}
: ${INCFLAGS=$DEFAULT_INCFLAGS}
: ${F77="x86_64-w64-mingw32-gfortran"}
: ${FFLAGS="-g -O2 -std=legacy"}
: ${FPICFLAG=""}
: ${CC="x86_64-w64-mingw32-gcc"}
: ${CFLAGS="-g -O2"}
: ${CPICFLAG=""}
: ${CXX="x86_64-w64-mingw32-g++"}
: ${CXXFLAGS="-g -O2"}
: ${CXXPICFLAG=""}
: ${XTRA_CFLAGS="-fopenmp"}
: ${XTRA_CXXFLAGS="-fopenmp"}
: ${AR="x86_64-w64-mingw32-ar"}
: ${RANLIB="x86_64-w64-mingw32-ranlib"}

: ${DEPEND_FLAGS="-M"}
: ${DEPEND_EXTRA_SED_PATTERN=""}

: ${DL_LD="x86_64-w64-mingw32-g++"}
: ${DL_LDFLAGS="-shared -static-libgcc -static-libstdc++ -static-libgfortran"}

: ${RLD_FLAG=""}
: ${RDYNAMIC_FLAG=""}
: ${LIBOCTAVE=-loctave}
: ${LIBOCTINTERP=-loctinterp}
: ${READLINE_LIBS=-lreadline}
: ${LAPACK_LIBS="-llapack"}
: ${BLAS_LIBS="-lblas -lxerbla"}
: ${FFTW3_LDFLAGS=""}
: ${FFTW3_LIBS="-lfftw3"}
: ${FFTW3F_LDFLAGS=""}
: ${FFTW3F_LIBS="-lfftw3f"}
: ${LIBS="-lpsapi -lgdi32 -lm"}
: ${FLIBS="-lm -lgfortran -lmingw32 -lmoldname -lmingwex -lmsvcrt -lquadmath -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32"}
: ${LD_CXX="x86_64-w64-mingw32-g++"}
: ${LDFLAGS=$DEFAULT_LDFLAGS}
: ${LD_STATIC_FLAG=""}
: ${LFLAGS=$DEFAULT_LDFLAGS}
: ${F77_INTEGER_8_FLAG=""}

: ${ALL_FFLAGS="$FFLAGS $F77_INTEGER_8_FLAG"}

: ${ALL_CFLAGS="$INCFLAGS $XTRA_CFLAGS $CFLAGS"}

: ${ALL_CXXFLAGS="$INCFLAGS $XTRA_CXXFLAGS $CXXFLAGS"}

: ${ALL_LDFLAGS="$LD_STATIC_FLAG $CPICFLAG $LDFLAGS"}

: ${OCTAVE_LIBS="$LIBOCTINTERP $LIBOCTAVE $SPECIAL_MATH_LIB"}

# Local variables.

FFTW_LIBS="$FFTW3_LDFLAGS $FFTW3_LIBS $FFTW3F_LDFLAGS $FFTW3F_LIBS"

usage_msg="usage: mkoctfile [options] file ..."

version_msg="mkoctfile, version $OCTAVE_VERSION"

cfiles=
ccfiles=
f77files=
objfiles=
libfiles=
octfiles=
octfile=
outputfile=
incflags=
defs=
ldflags=
dbg=:
pass_on_options=
strip=false
no_oct_file_strip_on_this_platform=false
link=true
link_stand_alone=false
output_ext=".oct"
depend=false
compile=true

if [ $# -eq 0 ]; then
  echo $usage_msg 1>&2
  exit 1
fi

if [ $# -eq 1 ]; then
  case "$1" in
    -v | -version | --version)
      echo $version_msg 1>&2
      exit 0
    ;;
  esac
fi

while [ $# -gt 0 ]; do
  file=
  case "$1" in
    *.c)
      file=$1
      cfiles="$cfiles $file"
    ;;
    *.cc | *.C | *.cpp)
      file=$1
      ccfiles="$ccfiles $file"
    ;;
    *.f | *.F | *.f90 | *.F90)
      file=$1
      f77files="$f77files $file"
    ;;
    *.o)
      file=$1
      objfiles="$objfiles $file"
    ;;
    *.a)
      file=$1
      libfiles="$libfiles $file"
    ;;
    -d | -debug | --debug | -v | -verbose | --verbose)
      dbg=echo
    ;;
    -h | -\? | -help | --help)
      echo $usage_msg 1>&2
      cat << EOF

Options:

  -h, -?, --help          Print this message.

  -IDIR                   Add -IDIR to compile commands.

  -idirafter DIR          Add -idirafter DIR to compile commands.

  -DDEF                   Add -DDEF to compile commands.

  -lLIB                   Add -lLIB to link command.

  -LDIR                   Add -LDIR to link command.

  -RDIR                   Add -RDIR to link command.

  -g                      Enable debugging option for all compilers.

  -pthread                Add -pthread to link command.

  -W...                   Pass flags to the compiler such as -Wa,OPTION.

  -Wl,...                 Pass flags to the linker such as -Wl,-rpath=...

  -M, --depend            Generate dependency files (.d) for C and C++
                          source files.

  -c, --compile           Compile, but do not link.

  --link-stand-alone      Link a stand-alone executable file.

  -s, --strip             Strip output file.

  --mex                   Create a MEX file.  
                          Set the default output extension to ".mex".

  -o FILE, --output FILE  Output file name.  Default extension is .oct
                          (or .mex if --mex is specified) unless linking
                          a stand-alone executable.

  -p VAR, --print VAR     Print configuration variable VAR.  Recognized
                          variables are:

                            ALL_CFLAGS                FFTW3F_LDFLAGS
                            ALL_CXXFLAGS              FFTW3F_LIBS
                            ALL_FFLAGS                FLIBS
                            ALL_LDFLAGS               FPICFLAG
                            BLAS_LIBS                 INCFLAGS
                            CC                        LAPACK_LIBS
                            CFLAGS                    LDFLAGS
                            CPICFLAG                  LD_CXX
                            CPPFLAGS                  LD_STATIC_FLAG
                            CXX                       LFLAGS
                            CXXFLAGS                  LIBCRUFT
                            CXXPICFLAG                LIBOCTAVE
                            DEPEND_EXTRA_SED_PATTERN  LIBOCTINTERP
                            DEPEND_FLAGS              LIBS
                            DL_LD                     OCTAVE_LIBS
                            DL_LDFLAGS                RDYNAMIC_FLAG
                            EXEEXT                    READLINE_LIBS
                            F77                       RLD_FLAG
                            F77_INTEGER_8_FLAG        SED
                            FFLAGS                    XTRA_CFLAGS
                            FFTW3_LDFLAGS             XTRA_CXXFLAGS
                            FFTW3_LIBS

  -v, --verbose           Echo commands as they are executed.

  FILE                    Compile or link FILE.  Recognized file types are:

                            .c    C source
                            .cc   C++ source
                            .C    C++ source
                            .cpp  C++ source
                            .f    Fortran source (fixed form)
                            .F    Fortran source (fixed form)
                            .f90  Fortran source (free form)
                            .F90  Fortran source (free form)
                            .o    object file
                            .a    library file

EOF
      exit 0
    ;;
    -I*)
      incflags="$incflags $1"
    ;;
    -idirafter)
      shift
      if [ $# -gt 0 ]; then
        incflags="$incflags -idirafter $1"
      else
        echo "mkoctfile: include directory name missing" 1>&2
      fi
    ;;
    -D*)
      defs="$defs $1"
    ;;
    -[lLR]* | -Wl,*)
      ldflags="$ldflags $1"
    ;;
    -pthread)
      ldflags="$ldflags $1"
    ;;
    -M | -depend | --depend)
      depend=true
      compile=false
    ;;
    -o | -ouput | --output)
      shift
      if [ $# -gt 0 ]; then
        outputfile="$1"
      else
        echo "mkoctfile: output file name missing" 1>&2
      fi
    ;;
    -p | -print | --print)
      shift
      if [ $# -gt 0 ]; then
        eval echo \${$1}
        exit 0
      else
        echo "mkoctfile: --print requires argument" 1>&2
        exit 1
      fi
    ;;
    -s | -strip | --strip)
      if $no_oct_file_strip_on_this_platform; then
        echo "mkoctfile: stripping disabled on this platform" 1>&2
      else
        strip=true
      fi
    ;;
    -c | -compile | --compile)
      link=false
    ;;
    -g)
      ALL_CFLAGS="$ALL_CFLAGS -g"
      ALL_CXXFLAGS="$ALL_CXXFLAGS -g"
      ALL_FFLAGS="$ALL_FFLAGS -g"
    ;;
    -link-stand-alone | --link-stand-alone)
      link_stand_alone=true
    ;;
    -mex | --mex)
      incflags="$incflags -I."
      output_ext=".mex"
    ;;
    -W*)
      pass_on_options="$pass_on_options $1"
    ;;
    *)
      echo "mkoctfile: unrecognized argument $1" 1>&2
      exit 1
    ;;
  esac
  if [ -n "$file" ]; then
    if [ -z "$octfile" ]; then
      octfile="$file"
    fi
  fi
  shift
done

if $link_stand_alone; then
  if [ -n "$outputfile" ]; then
    output_option="-o $outputfile"
  fi
else
  if [ -n "$outputfile" ]; then
    octfile="$outputfile"
    case "$octfile" in
      *$output_ext)
      ;;
      *)
        octfile="$octfile$output_ext"
      ;;
    esac
  else
    octfile=`basename $octfile`
    octfile=`echo $octfile | $SED 's,\.[^.]*$,,'`$output_ext
  fi
fi

# Generate dependency files for C and C++ files.

if $depend; then
  if [ -n "$cfiles" ]; then
    for f in $cfiles; do
      b=`echo $f | $SED 's,\.c$,,'`
      d=$b.d
      cmd="rm -f $d"
      $dbg $cmd
      eval $cmd
      cmd="$CC $DEPEND_FLAGS $CPPFLAGS $ALL_CFLAGS $incflags $def $f | $SED $DEPEND_EXTRA_SED_PATTERN -e 's,^[^:]*/\(.*\.o\):,\1:,' -e 's,$b\.o,pic/& & $d,g' > $d-t && mv $d-t $d"
      $dbg $cmd
      eval $cmd
    done
  fi

  if [ -n "$ccfiles" ]; then
    for f in $ccfiles; do
      case $f in
        *.cc)
          b=`echo $f | $SED 's,\.cc$,,'`
        ;;
        *.C)
          b=`echo $f | $SED 's,\.C$,,'`
        ;;
        *.cpp)
          b=`echo $f | $SED 's,\.cpp$,,'`
        ;;
      esac
      d=$b.d
      cmd="rm -f $d"
      $dbg $cmd
      eval $cmd
      cmd="$CXX $DEPEND_FLAGS $CPPFLAGS $ALL_CXXFLAGS $incflags $defs $f | $SED $DEPEND_EXTRA_SED_PATTERN -e 's,^[^:]*/\(.*\.o\):,\1:,' -e 's,$b\.o,pic/& & $d,g' > $d-t && mv $d-t $d"
      $dbg $cmd
      eval $cmd
    done
  fi
  # If generating dependencies, that's all we do.
  exit 0
fi

# Compile Fortran, C, and C++ files.  Add the name of each object file
# that is produced to the overall list of object files.

if [ -n "$f77files" ]; then
  for f in $f77files; do
    case $f in
      *.f)
        b=`echo $f | $SED 's,.*/,,; s,\.f$,,'`
      ;;
      *.F)
        b=`echo $f | $SED 's,.*/,,; s,\.F$,,'`
      ;;
      *.f90)
        b=`echo $f | $SED 's,.*/,,; s,\.f90$,,'`
      ;;
      *.F90)
        b=`echo $f | $SED 's,.*/,,; s,\.F90$,,'`
      ;;
    esac
    if [ -n "$F77" ]; then
      if [ -n "$outputfile" ]; then
        if $link; then
          o=$b.o
        else
          o=$outputfile
        fi
      else
        o=$b.o
      fi
      objfiles="$objfiles $o"
      cmd="$F77 -c $FPICFLAG $ALL_FFLAGS $incflags $defs $pass_on_options $f -o $o"
      $dbg $cmd
      eval $cmd
    else
      echo "mkoctfile: no way to compile Fortran file $f" 1>&2
    fi
  done
fi

if [ -n "$cfiles" ]; then
  for f in $cfiles; do
    if [ -n  "$CC" ]; then
      b=`echo $f | $SED 's,.*/,,; s,\.c$,,'`
      if [ -n "$outputfile" ]; then
        if $link; then
          o=$b.o
        else
          o=$outputfile
        fi
      else
        o=$b.o
      fi
      objfiles="$objfiles $o"
      cmd="$CC -c $CPPFLAGS $CPICFLAG $ALL_CFLAGS $pass_on_options $incflags $defs $f -o $o"
      $dbg $cmd
      eval $cmd
    else
      echo "mkoctfile: no way to compile C++ file $f" 1>&2
    fi
  done
fi

if [ -n "$ccfiles" ]; then
  for f in $ccfiles; do
    if [ -n "$CXX" ]; then
      case $f in
        *.cc)
          b=`echo $f | $SED 's,.*/,,; s,\.cc$,,'`
        ;;
        *.C)
          b=`echo $f | $SED 's,.*/,,; s,\.C$,,'`
        ;;
        *.cpp)
          b=`echo $f | $SED 's,.*/,,; s,\.cpp$,,'`
        ;;
      esac
      if [ -n "$outputfile" ]; then
        if $link; then
          o=$b.o
        else
          o=$outputfile
        fi
      else
        o=$b.o
      fi
      objfiles="$objfiles $o"
      cmd="$CXX -c $CPPFLAGS $CXXPICFLAG $ALL_CXXFLAGS $pass_on_options $incflags $defs $f -o $o"
      $dbg $cmd
      eval $cmd
    else
      echo "mkoctfile: no way to compile C++ file $f" 1>&2
    fi
  done
fi

## Uncomment the following group of lines if you get `Text file busy'
## errors from ld.  This may happen if the .oct file is currently
## running while you are trying to recompile it.  We try moving first,
## since on some systems (HP-UX, maybe others) it is possible to
## rename running programs but not remove them.

## if [ -f "$octfile" ]; then
##   cmd="mv $octfile $octfile.bak"
##   $dbg $cmd
##   eval $cmd
##   cmd="rm -f $octfile.bak"
##   $dbg $cmd
##   eval $cmd
## fi

# Link all the object files.

if $link && [ -n "$objfiles" ]; then
  if $link_stand_alone; then
    if [ -n "$LD_CXX" ]; then
      cmd="$LD_CXX $CPPFLAGS $ALL_CXXFLAGS $RDYNAMIC_FLAG $ALL_LDFLAGS $pass_on_options $output_option $objfiles $libfiles $ldflags $LFLAGS $RLD_FLAG $OCTAVE_LIBS $LAPACK_LIBS $BLAS_LIBS $FFTW_LIBS $READLINE_LIBS $LIBS $FLIBS"
      $dbg $cmd
      eval $cmd
    else
      echo "mkoctfile: no way to link stand-alone executable file" 1>&2
      exit 1
    fi
  else
    LINK_DEPS="$LFLAGS $OCTAVE_LIBS $LDFLAGS $LAPACK_LIBS $BLAS_LIBS $FFTW_LIBS $LIBS $FLIBS"
    cmd="$DL_LD $DL_LDFLAGS $pass_on_options -o $octfile $objfiles $libfiles $ldflags $LINK_DEPS"
    $dbg $cmd
    eval $cmd
  fi

# Maybe strip it.

  if $strip; then
    cmd="strip $octfile"
    $dbg $cmd
    eval $cmd
  fi
fi

exit 0
