#!/usr/bin/env bash

# (C) 2007, Robert Bradshaw, William Hart, William Stein, Michael Abshoff
# (C) 2011, William Hart
# (C) 2012, William Hart, Jean-Pierre Flori, Thomas DuBuisson

PREFIX="/usr/local"
MPIR_DIR="/usr/local"
MPFR_DIR="/usr/local"
NTL_DIR="/usr/local"
WANT_NTL=0
SHARED=1
STATIC=1
REENTRANT=0
BUILD=
ABI=

usage()
{
   echo "Usage: ./configure <options> <args>"
   echo "   where <options> may be"
   echo "     -h display usage information"
   echo "   where <args> may be:"
   echo "     --with-mpir=<path> Specify location of MPIR"
   echo "     --with-mpfr=<path> Specify location of MPFR"
   echo "     --with-ntl=<path>  Specify location of NTL and build NTL interface"
   echo "     --build=arch-os    Specify architecture/OS combination rather than use values from uname -m/-s"
   echo "     --prefix=<path>    Specify path to installation location"
   echo "     --disable-shared   Do not build a shared library"
   echo "     --disable-static   Do not build a static library"
   echo "     --reentrant        Build fully reentrant version of library"
   echo "     --single           Faster non-reentrant version of library (default)"
   echo "     CC=<name>          Use the C compiler with the given name"
   echo "     AR=<name>          Use the AR library builder with the given name"
   echo "     CFLAGS=<flags>     Pass the given flags to the compiler"
   echo "     ABI=[32|64]        Tell the compiler to use given ABI"
}

while [ "$1" != "" ]; do
   PARAM=`echo $1 | awk -F= '{print $1}'`
   VALUE=`echo $1 | awk -F= '{print $2}'`
   case $PARAM in
      -h) usage
         exit 0
         ;;
      --with-mpir)
         MPIR_DIR=$VALUE
         ;;
      --with-mpfr)
         MPFR_DIR=$VALUE
         ;;
      --with-ntl)
         NTL_DIR=$VALUE
         WANT_NTL=1
         ;;
      --build)
         BUILD=$VALUE
         ;;
      --prefix)
         PREFIX=$VALUE
         ;;
      --disable-shared)
         SHARED=0
         ;;
      --disable-static)
         STATIC=0
         ;;
      --reentrant)
         REENTRANT=1
         ;;
      --single)
         REENTRANT=0
         ;;
      AR)
         AR=$VALUE
         ;;
      CC)
         CC=$VALUE
         ;;
      CFLAGS)
         CFLAGS=$VALUE
         ;;
      ABI)
         ABI=$VALUE
         ;;
      *) usage
         exit 1
         ;;
   esac
   shift
done

#find dependencies

if [ -d "${MPIR_DIR}/lib" ]; then
   MPIR_LIB_DIR="${MPIR_DIR}/lib"
   MPIR_INCLUDE_DIR="${MPIR_DIR}/include"
elif [ -d "${MPIR_DIR}/lib64" ]; then
   MPIR_LIB_DIR="${MPIR_DIR}/lib64"
   MPIR_INCLUDE_DIR="${MPIR_DIR}/include"
elif [ -d "${MPIR_DIR}/.libs" ]; then
   MPIR_LIB_DIR="${MPIR_DIR}/.libs"
   MPIR_INCLUDE_DIR="${MPIR_DIR}"
else
   echo "Invalid MPIR directory"
   exit 1
fi

if [ -d "${MPFR_DIR}/lib" ]; then
   MPFR_LIB_DIR="${MPFR_DIR}/lib"
   MPFR_INCLUDE_DIR="${MPFR_DIR}/include"
elif [ -d "${MPFR_DIR}/lib64" ]; then
   MPFR_LIB_DIR="${MPFR_DIR}/lib64"
   MPFR_INCLUDE_DIR="${MPFR_DIR}/include"
elif [ -d "${MPFR_DIR}/.libs" ]; then
   MPFR_LIB_DIR="${MPFR_DIR}/.libs"
   MPFR_INCLUDE_DIR="${MPFR_DIR}"
elif [ -d "${MPFR_DIR}/src/.libs" ]; then
   MPFR_LIB_DIR="${MPFR_DIR}/src/.libs"
   MPFR_INCLUDE_DIR="${MPFR_DIR}/src"
else
   echo "Invalid MPFR directory"
   exit 1
fi

if [ -d "${NTL_DIR}/lib" ]; then
   NTL_LIB_DIR="${NTL_DIR}/lib"
   NTL_INCLUDE_DIR="${NTL_DIR}/include"
elif [ -d "${NTL_DIR}/lib64" ]; then
   NTL_LIB_DIR="${NTL_DIR}/lib64"
   NTL_INCLUDE_DIR="${NTL_DIR}/include"
elif [ "$WANT_NTL" = "0" ]; then
   NTL_DIR="/usr"
   if [ -d "${NTL_DIR}/lib" ]; then
      NTL_LIB_DIR="${NTL_DIR}/lib"
   else
      NTL_LIB_DIR="${NTL_DIR}/lib64"
   fi
   NTL_INCLUDE_DIR="${NTL_DIR}/include"
else
   echo "Invalid NTL directory"
   exit 1
fi

#configure extra libraries

if [ "$WANT_NTL" = "1" ]; then
    EXTRA_LIBS="$EXTRA_LIBS -lntl"
fi

#handle reentrant flag

if [ "$REENTRANT" = "1" ]; then
   cp fmpz/link/fmpz_reentrant.c fmpz/fmpz.c
   cp fmpz-conversions-reentrant.in fmpz-conversions.h
else
   cp fmpz/link/fmpz_single.c fmpz/fmpz.c
   cp fmpz-conversions-single.in fmpz-conversions.h
fi

# Architecture handler

KERNEL=`uname`

if [ -z $BUILD ]; then
   ARCH=`uname -m`

   if [ "$(uname | cut -d_ -f1)" = "MINGW32" ]; then
      OS="MINGW32"
   elif [ "$(uname | cut -d_ -f1)" = "MINGW64" ]; then
      OS="MINGW64"
   elif [ "$(uname | cut -d_ -f1)" = "CYGWIN" ]; then
      OS="CYGWIN"
   else
      OS=`uname -s`
   fi
else
   ARCH=`echo "$BUILD" | cut -d- -f1`
   OS=`echo "$BUILD" | cut -d- -f2`
fi

case $ARCH in
   x86_64 | amd64)
      MACHINE="x86_64";;
   x86 | i*86 | pc)
      MACHINE="x86";;
   ia64)
      MACHINE="ia64";;
   sparc | sun4*)
      MACHINE="sparc";;
   sparc64)
      MACHINE="sparc64";;
   ppc | powerpc | [P|p]ower*)
      MACHINE="ppc";;
   ppc64 | powerpc64)
      MACHINE="ppc64";;
   *)
      MACHINE="unknown";;
esac

#ABI flag
if [ "$ABI" = "32" ]; then
   ABI_FLAG="-m32"
   case $MACHINE in
      x86_64)
         MACHINE="x86";;
      sparc64)
         MACHINE="sparc";;
      ppc64)
         MACHINE="ppc";;
      *)
         ;;
   esac
elif [ "$ABI" = "64" ]; then
   ABI_FLAG="-m64"
   if [ "$MACHINE" = "sparc" ]; then
      MACHINE="sparc64"
   fi
fi

echo "Configuring...${MACHINE}-${OS}"

#name for FLINT shared library

if [ -z "$FLINT_LIB" ]; then
   case $OS in
      Darwin)
         case $MACHINE in
            *64)
               FLINT_LIB="libflint.dylib64";;
            *)
               FLINT_LIB="libflint.dylib";;
         esac;;
      CYGWIN | MINGW*)
         FLINT_LIB="libflint.dll";;
      *)
         FLINT_LIB="libflint.so";;
   esac
fi

# don't build both shared and static lib on MinGW and Cygwin

case $OS in
   CYGWIN | MINGW*)
      if [ "$STATIC" = "1" ]; then
         SHARED=0
      fi
      ;;
   *)
      ;;
esac

#select fft_tuning parameters

case $MACHINE in
   x86_64 | ia64 | sparc64 | ppc64)
      cp fft_tuning64.in fft_tuning.h;;
   *)
      cp fft_tuning32.in fft_tuning.h;;
esac

#various tuning parameters

if [ -z "$FLINT_TUNE" ]; then
   if [ "$KERNEL" = "Linux" -a "$ARCH" = "x86_64" ]; then
      FLINT_TUNE="-funroll-loops"
   elif [ "$KERNEL" = "Darwin" -a "$ARCH" = "ppc" ]; then
      FLINT_TUNE=" -funroll-loops"
   elif [ "`uname -p`" = "powerpc" ]; then
      FLINT_TUNE="-m64 -mcpu=970 -mtune=970 -mpowerpc64 -falign-loops=16 -falign-functions=16 -falign-labels=16 -falign-jumps=16"
   elif [ "$ARCH" = "ia64" ]; then
      # -funroll-loops crashes the build on itanium under GCC-4.2.1, as reported by
      # Kate Minola.
      FLINT_TUNE=""
   else
      FLINT_TUNE="-funroll-loops"
   fi
fi

# defaults for CC and CXX

if [ -z "$CC" ]; then
   CC=gcc
fi

if [ -z "$CXX" ]; then
   CXX=g++
fi

# Test for popcnt flag and set needed CFLAGS

mkdir -p build
rm -f build/test-popcnt > /dev/null 2>&1
MSG="Testing __builtin_popcountl..."
([ -x /bin/echo ] && /bin/echo -n $MSG) || echo $MSG
echo "int main(int argc, char ** argv) {return __builtin_popcountl(argc) == 100;}" > build/test-popcnt.c
$CC build/test-popcnt.c -o ./build/test-popcnt > /dev/null 2>&1
if [ $? -eq 0 ]; then
   echo "yes"
   CONFIG_POPCNT_INTRINSICS="#define POPCNT_INTRINSICS"

   if [ "$MACHINE" = "x86_64" ]; then
      MSG="Testing native popcount..."
      ([ -x /bin/echo ] && /bin/echo -n $MSG) || echo $MSG
      touch build/test-popcnt.c
      rm build/test-popcnt
      $CC -mpopcnt build/test-popcnt.c -o ./build/test-popcnt > /dev/null 2>&1
      build/test-popcnt > /dev/null 2>&1
      if [ $? -eq 0 ]; then
         echo "yes"
         POPCNT_FLAG="-mpopcnt"
      else
         echo "no"
      fi
      rm -f build/test-popcnt{,.c}
   fi
else
   rm -f build/test-popcnt.c
   echo "no"
fi

#defaults for CFLAGS, CC and CXX

if [ -z "$CFLAGS" ]; then
   CFLAGS="-O2 -g -ansi -pedantic -Wall $POPCNT_FLAG $ABI_FLAG"
fi

#add tuning parameters to CFLAGS

CFLAGS="$CFLAGS $FLINT_TUNE"

#PIC flag

if [ -z $PICFLAG ]; then
   case $OS in
      CYGWIN | MINGW*)
         ;;
      *)
         PICFLAG="-fPIC";;
   esac
fi

#write out config.h

echo "/* This file is autogenerated by ./configure -- do not edit! */" > config.h
echo $CONFIG_POPCNT_INTRINSICS >> config.h

#write out Makefile

echo "# This file is autogenerated by ./configure -- do not edit!" > Makefile
echo "" >> Makefile
echo "SHELL := /usr/bin/env bash" >> Makefile
echo "" >> Makefile
echo "FLINT_STATIC=$STATIC" >> Makefile
echo "FLINT_SHARED=$SHARED" >> Makefile
echo "WANT_NTL=$WANT_NTL" >> Makefile
echo "EXTRA_LIBS=$EXTRA_LIBS" >> Makefile
echo "FLINT_MPIR_LIB_DIR=$MPIR_LIB_DIR" >> Makefile
echo "FLINT_MPIR_INCLUDE_DIR=$MPIR_INCLUDE_DIR" >> Makefile
echo "FLINT_MPFR_LIB_DIR=$MPFR_LIB_DIR" >> Makefile
echo "FLINT_MPFR_INCLUDE_DIR=$MPFR_INCLUDE_DIR" >> Makefile
echo "FLINT_NTL_LIB_DIR=$NTL_LIB_DIR" >> Makefile
echo "FLINT_NTL_INCLUDE_DIR=$NTL_INCLUDE_DIR" >> Makefile
echo "" >> Makefile
echo "FLINT_LIB=$FLINT_LIB" >> Makefile
echo "CC=$CC" >> Makefile
echo "CXX=$CXX" >> Makefile
echo "CFLAGS=$CFLAGS" >> Makefile
echo "ABI_FLAG=$ABI_FLAG" >> Makefile
echo "PICFLAG=$PICFLAG" >> Makefile
echo "PREFIX=$PREFIX" >> Makefile
case $OS in
   MINGW*)
      echo "PATH+=:\${CURDIR}:\${FLINT_MPFR_LIB_DIR}:\${FLINT_MPIR_LIB_DIR}:\${FLINT_NTL_LIB_DIR}" >> Makefile;;
   Darwin)
      echo "DYLD_LIBRARY_PATH+=:\${CURDIR}:\${FLINT_MPFR_LIB_DIR}:\${FLINT_MPIR_LIB_DIR}:\${FLINT_NTL_LIB_DIR}" >> Makefile;;
   sparc)
      echo "LD_LIBRARY_PATH32+=:\${CURDIR}:\${FLINT_MPFR_LIB_DIR}:\${FLINT_MPIR_LIB_DIR}:\${FLINT_NTL_LIB_DIR}" >> Makefile;;
   sparc64)
      echo "LD_LIBRARY_PATH64+=:\${CURDIR}:\${FLINT_MPFR_LIB_DIR}:\${FLINT_MPIR_LIB_DIR}:\${FLINT_NTL_LIB_DIR}" >> Makefile;;
   *)
      echo "LD_LIBRARY_PATH+=:\${CURDIR}:\${FLINT_MPFR_LIB_DIR}:\${FLINT_MPIR_LIB_DIR}:\${FLINT_NTL_LIB_DIR}" >> Makefile;;
esac
echo "" >> Makefile

cat Makefile.in >> Makefile

