#! /bin/sh

# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ┃ Local checking for INTEL_IFC.                                              ┃
# ┃                                                                            ┃
# ┃ É. Canot -- IPR/CNRS -- 20 Nov 2024                                        ┃
# ┃                                                                            ┃
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

# What could be changed by you (builder, installer and user) below:
#   on line 51-52:   f90_comp  [ifort or ifx]
#   on line 338-339: c_comp    [icc   or icx]
#   on line 397-398: cxx_comp  [icpc  or icpx]

# A warning is emitted if the MKL library (which replaces Blas/Lapack) is
# not used, because errors and seg. faults have been encountered when
# using the Reference version (Netlib) of Blas/Lapack.

#==============================================================================

PID=$$

TMP_CHECK_FORT_COMP=/tmp/local_check_INTEL_IFC_$PID.out
TMP_COMP_VERSION=/tmp/local_check_INTEL_COMP_$PID.ver

abort() {
  $COLOR_ERROR
  echo
  echo "  *** aborting ***"
  echo
  if test $# = 0; then
    echo "  (if you think that this is a bug, mail to: Edouard.Canot@univ-rennes.fr)"
  fi
  $COLOR_NORMAL
  echo
  exit 2
}

# -- check that the current script is called by the MUESLI 'configure'
if test "$KDUGPSJRVZ" != "1"; then
  echo
  echo "  $0 must be called only by configure!"
  abort "bad call"
fi

# -- check Fortran compilers ---------------------------------------------------

# which executable
echo -n $ECHO_OPT "\n  Checking for INTEL Fortran compiler... "
if test "$f90_comp" = ""; then
#  f90_comp=ifort
  f90_comp=ifx
fi
PROG=`which $f90_comp 2>/dev/null`
if test $? = 0; then
  echo $PROG
else
  echo "not found"
  echo
  $COLOR_ERROR
  echo "  ERROR: $f90_comp cannot be launched!"
  echo "    -> please verify your PATH variable."
  $COLOR_NORMAL
  abort
fi

# validity of ifort (warning, ifort send his infos to stderr)
echo -n $ECHO_OPT "  Checking for INTEL Fortran compiler version... \t "
$f90_comp -V > /dev/null 2> $TMP_COMP_VERSION
LINE=`cat $TMP_COMP_VERSION | head -n 1`
if test -n "`echo $LINE | grep Intel`"; then
  # extracting version number
  IFS=" "
  set `echo $LINE`
  while test $1 != "Version"; do
    shift
  done
  VERSION_IFC=$2
  echo $VERSION_IFC
  FAMILY_IFC=`echo $VERSION_IFC | cut -d'.' -f1`
  if test $FAMILY_IFC != "13" && \
     test $FAMILY_IFC != "14" && \
     test $FAMILY_IFC != "15" && \
     test $FAMILY_IFC != "16" && \
     test $FAMILY_IFC != "17" && \
     test $FAMILY_IFC != "18" && \
     test $FAMILY_IFC != "19" && \
     test $FAMILY_IFC != "2021" && \
     test $FAMILY_IFC != "2022" && \
     test $FAMILY_IFC != "2023" && \
     test $FAMILY_IFC != "2024" && \
     test $FAMILY_IFC != "2025"; then
    echo
    $COLOR_ERROR
    echo "  Warning: version of the INTEL Fortran compiler must be ranged in [13-19] or [2021-2025]!"
    $COLOR_NORMAL
    abort
  fi
else
  echo "not found"
  echo
  $COLOR_ERROR
  echo "  ERROR: it seems that $f90_comp is not the INTEL Fortran compiler!"
  echo "    -> please consider installing INTEL compiler suite, or"
  echo "       choose another appropriate compiler directory."
  echo "       [the other is GNU_GFC]"
  $COLOR_NORMAL
  abort
fi

# check that compiler works: (i) compilation
echo -n $ECHO_OPT "  Does `basename $f90_comp` compile a simple program? \t "
cat > test.f90 <<EOF
program test
   integer :: i = 0
   print *, "i = ", i
end program
EOF
$f90_comp -c test.f90 > /dev/null 2>&1
if test $? != 0; then
  echo
  $COLOR_ERROR
  echo "  ERROR: $f90_comp cannot compile a simple program!"
  echo "    -> please consider using another compiler,"
  echo "       [the other is GNU_GFC]"
  echo "       or at least reinstall INTEL_IFC."
  $COLOR_NORMAL
  rm -f test.*
  abort
fi
echo "yes"
rm -f test.*

# check that compiler works: (ii) linking
echo -n $ECHO_OPT "  Does `basename $f90_comp` link a simple program? \t "
cat > test.f90 <<EOF
program test
   integer :: i = 0
   print *, "i = ", i
end program
EOF
$f90_comp -c test.f90 > /dev/null 2>&1
$f90_comp -o test.out test.o > /dev/null 2>&1
if test $? != 0; then
  echo
  $COLOR_ERROR
  echo "  ERROR: $f90_comp cannot link a simple program!"
  echo "    -> please consider using another compiler,"
  echo "       [the other is GNU_GFC]"
  echo "       or at least reinstall INTEL_IFC."
  $COLOR_NORMAL
  rm -f test.*
  abort
fi
echo "yes"
rm -f test.*

# check that compiler treats default integers as 32bits
echo -n $ECHO_OPT "  Is default integer type 32 bits? \t "
cat > test.f90 <<EOF
module test
   implicit none
   interface sub
      module procedure sub_int4
      module procedure sub_int8
   end interface
contains
   subroutine sub_int4( i )
      integer :: i
   end subroutine
   subroutine sub_int8( i )
      integer*8 :: i
   end subroutine
end module
EOF
$f90_comp -c test.f90 > /dev/null 2>&1
if test $? != 0; then
  echo
  $COLOR_ERROR
  echo "  ERROR: $f90_comp treats default integers as 64bit numbers!"
  echo "         default integers must be 32 bits."
  echo "    -> please consider using another compiler."
  echo "       [the other is GNU_GFC]"
  $COLOR_NORMAL
  rm -f test.*
  abort
fi
echo "yes"
rm -f test.*

# a further check concerns the compatibility of BLAS/LAPACK;
echo $ECHO_OPT "\n  Testing a simple LAPACK program:"
cat > lapack_test.f90 <<EOF
program test

   implicit none

   integer :: i, j, info, ipiv(5)
   double precision :: mat(5,5), mat_inv(5,5), work(5), prod(5,5)

   call random_number( mat )
   mat(:,:) = 0.1d0*mat(:,:)
   do i = 1, 5
      mat(i,i) = 1.0d0
   end do

   mat_inv(:,:) = mat(:,:)

   ! LU factorization
   call dgetrf( 5, 5, mat_inv, 5, ipiv, info )

   if( info /= 0 ) then
      print "(I0)", info
      stop
   end if

   ! matrix inversion
   call dgetri( 5, mat_inv, 5, ipiv, work, 5, info )

   if( info /= 0 ) then
      print "(I0)", info
      stop
   end if

   ! check inverse
   prod(:,:) = matmul(mat,mat_inv)
   do i = 1, 5
      do j = 1, 5
         if( j == i ) then
            ! value should be closed to 1
            if( abs(prod(i,j)-1.0d0) > 1.0d-12 ) then
               print "('1')"
               stop
            end if
         else
            ! value should be closed to 0
            if( abs(prod(i,j)) > 1.0d-12 ) then
               print "('1')"
               stop
            end if
         end if
      end do
   end do

   print "('0')"

end program
EOF

echo -n $ECHO_OPT "\t\t   compiling... \t "
cmd="$f90_comp -c lapack_test.f90"
$cmd > /dev/null 2> $TMP_CHECK_FORT_COMP
if test $? = 0; then
  echo "done"
else
  echo "failed"
  echo
  $COLOR_ERROR
  echo "  ERROR: $f90_comp cannot compile a simple LAPACK program!"
  echo "         output is:"
  $COLOR_GRAY
  echo "$cmd > /dev/null"
  cat $TMP_CHECK_FORT_COMP
  rm -f $TMP_CHECK_FORT_COMP
  $COLOR_ERROR
  echo "    -> please fix the problem."
  $COLOR_NORMAL
  rm -f lapack_test.f90
  abort
fi

if test -z "$blas_lapack_vendor_flag"; then
  # added -lpthread because OpenBLAS is multithreaded
  link_cmd="$f90_comp $ld_opt -o lapack_test lapack_test.o -L$lapack_path -llapack -L$blas_path -lblas $add_lib -lpthread"
  blas_lapack_warning=1
else # MKL has been selected
  link_cmd="$f90_comp -o lapack_test lapack_test.o -qmkl $add_lib"
  blas_lapack_warning=0
fi

echo -n $ECHO_OPT "\t\t   linking... \t\t "
$link_cmd > /dev/null 2> $TMP_CHECK_FORT_COMP
if test $? = 0; then
  echo "done"
else
  echo "failed"
  echo
  $COLOR_ERROR
  echo "  ERROR: $f90_comp cannot link. Output is:"
  $COLOR_GRAY
  echo "$link_cmd > /dev/null"
  cat $TMP_CHECK_FORT_COMP
  rm -f $TMP_CHECK_FORT_COMP
  $COLOR_ERROR
  echo "    -> please consider choosing correct BLAS/LAPACK paths, or using"
  echo "       an appropriate '--addlib' argument. Was MKL correctly selected?"
  $COLOR_NORMAL
  rm -f lapack_test.o
  abort
fi
echo -n $ECHO_OPT "\t\t   executing... \t "
RES=`./lapack_test 2> $TMP_CHECK_FORT_COMP`
if test "$RES" = "0"; then
  echo "done"
else
  echo "failed"
  echo
  $COLOR_ERROR
  echo "  ERROR: simple LAPACK program gives incorrect result!"
  if test -s $TMP_CHECK_FORT_COMP; then
    echo "         Output is:"
    cat $TMP_CHECK_FORT_COMP
    rm -f $TMP_CHECK_FORT_COMP
  fi
  echo "    -> please consider using an appropriate '--ldopt' argument."
  echo
  echo "  For your information, 'ldd lapack_test' returns:"
  ldd ./lapack_test
  $COLOR_NORMAL
  rm -f lapack_test.*
  abort
fi

rm -f lapack_test.* lapack_test

if test "$blas_lapack_warning" = "1"; then
  $COLOR_WARNING
  echo
  echo "  ......................................................................."
  echo "    WARNING: You are currently using the Reference Blas/Lapack library."
  echo "             You must be warned that some errors or seg. faults could"
  echo "             be obtained."
  echo "             -> The use of the MKL library (which includes the whole"
  echo "                Blas/Lapack library) is strongly recommended!"
  echo "  ......................................................................."
  $COLOR_NORMAL
fi

# -- check C compilers ---------------------------------------------------------

# which executable
echo -n $ECHO_OPT "\n  Checking for C compiler... \t\t "
if test "$c_comp" = ""; then
#  c_comp=icc
  c_comp=icx
fi
PROG=`which $c_comp 2>/dev/null`
if test $? = 0; then
  echo $PROG
else
  echo "not found"
  echo
  $COLOR_ERROR
  echo "  ERROR: $c_comp cannot be launched!"
  echo "    -> please verify your PATH variable."
  $COLOR_NORMAL
  abort
fi

# for icx only, version should be the same as the version of ifx
c_comp_base=`basename $c_comp`
if test $c_comp_base = "icx"; then
  echo -n $ECHO_OPT "  Checking for icx version... \t\t "
  $c_comp -V 2> $TMP_COMP_VERSION
  LINE=`cat $TMP_COMP_VERSION | head -n 1`
  if test -n "`echo $LINE | grep Intel`"; then
    # extracting version number
    IFS=" "
    set `echo $LINE`
    while test $1 != "Version"; do
      shift
    done
    VERSION_ICC=$2
    echo $VERSION_ICC
    if test $VERSION_ICC != $VERSION_IFC; then
      echo
      $COLOR_WARNING
      echo "  Warning: version of icx should be the same as version of ifort"
      echo "  -> try at your own risks."
      $COLOR_NORMAL
    fi
  else
    echo "not found"
    echo
    $COLOR_WARNING
    echo "  Warning: it seems that $c_comp is not the INTEL C compiler!"
    echo "  -> try at your own risks."
    $COLOR_NORMAL
  fi
else
  echo
  $COLOR_WARNING
  echo "  Warning: it seems that $c_comp is not the INTEL C compiler!"
  echo "  -> try at your own risks."
  $COLOR_NORMAL
fi

# -- check C++ compilers -------------------------------------------------------

# which executable
echo -n $ECHO_OPT "\n  Checking for C++ compiler... \t\t "
if test "$cxx_comp" = ""; then
#  cxx_comp=icpc
  cxx_comp=icpx
fi
PROG=`which $cxx_comp 2>/dev/null`
if test $? = 0; then
  echo $PROG
else
  echo "not found"
  echo
  $COLOR_ERROR
  echo "  ERROR: $cxx_comp cannot be launched!"
  echo "    -> please verify your PATH variable."
  $COLOR_NORMAL
  abort
fi

# for icpx only, version should be the same as the version of ifort
cxx_comp_base=`basename $cxx_comp`
if test $cxx_comp_base = "icpx"; then
  echo -n $ECHO_OPT "  Checking icpx version... \t\t "
  $cxx_comp -V 2> $TMP_COMP_VERSION
  LINE=`cat $TMP_COMP_VERSION | head -n 1`
  if test -n "`echo $LINE | grep Intel`"; then
    # extracting version number
    IFS=" "
    set `echo $LINE`
    while test $1 != "Version"; do
      shift
    done
    VERSION_ICPC=$2
    echo $VERSION_ICPC
    if test $VERSION_ICPC != $VERSION_IFC; then
      echo
      $COLOR_WARNING
      echo "  Warning: version of icpx should be the same as version of ifx"
      echo "  -> try at your own risks."
      $COLOR_NORMAL
    fi
  else
    echo "not found"
    echo
    $COLOR_WARNING
    echo "  Warning: it seems that $cxx_comp is not the INTEL C++ compiler!"
    echo "  -> try at your own risks."
    $COLOR_NORMAL
  fi
else
  echo
  $COLOR_WARNING
  echo "  Warning: it seems that $cxx_comp is not the INTEL C++ compiler!"
  echo "  -> try at your own risks."
  $COLOR_NORMAL
fi

rm -f $TMP_COMP_VERSION

# check that C and C++ compilers are of the same version
if test "$VERSION_ICC" != "" && test "$VERSION_ICPC" != ""; then
  if test $VERSION_ICC != $VERSION_ICPC; then
    echo
    $COLOR_WARNING
    echo "  Warning: the C and C++ compilers should be of the same version!"
    echo "  -> try at your own risks."
    $COLOR_NORMAL
  fi
fi

# testing mixed-language link
echo -n $ECHO_OPT "\n  Testing a C++/Fortran program... \t "
cat > ml_test_sub.cpp <<EOF
#include <math.h>

extern "C" {
void sub_(double *x) {
  double pi = 3.14159265358979;
  *x = sin(pi);
}
}
EOF
cmd="$cxx_comp -c ml_test_sub.cpp"
$cmd > /dev/null 2> $TMP_CHECK_FORT_COMP
if test $? != 0; then
  $COLOR_ERROR
  echo "  ERROR: $cxx_comp cannot compile a small C++ test function!"
  echo "         output is:"
  $COLOR_GRAY
  echo "$cmd > /dev/null"
  $COLOR_NORMAL
  cat $TMP_CHECK_FORT_COMP
  rm -f $TMP_CHECK_FORT_COMP
  rm -f ml_test*
  abort
fi

cat > ml_test.f90 <<EOF
program ml_test
  double precision :: d
  call sub(d)
  if( abs(d) < 1.0d-14 ) then
    print "('0')"
  else
    print "('1')"
  endif
end
EOF
$f90_comp -c ml_test.f90 > /dev/null 2>&1
if test "$libstdcxx_path" = ""; then
  LIBSTDCXX="-lstdc++"
else
  LIBSTDCXX="-L$libstdcxx_path -lstdc++"
fi
cmd="$f90_comp $ld_opt -o ml_test ml_test.o ml_test_sub.o $LIBSTDCXX"
$cmd > /dev/null 2> $TMP_CHECK_FORT_COMP
if test $? != 0; then
  echo "failed"
  echo
  $COLOR_ERROR
  echo "  ERROR: $f90_comp cannot link a mixed-language program!"
  echo "         output is:"
  $COLOR_GRAY
  echo "$cmd > /dev/null"
  cat $TMP_CHECK_FORT_COMP
  rm -f $TMP_CHECK_FORT_COMP
  $COLOR_ERROR
  echo "    -> please consider choosing correct LIBSTDC++ paths."
  $COLOR_NORMAL
  rm -f ml_test*
  abort
fi
RES=`./ml_test`
if test $RES != 0; then
  echo "failed"
  echo
  $COLOR_ERROR
  echo "  ERROR: mixed-language program gives incorrect result!"
  echo "    -> please fix the problem."
  $COLOR_NORMAL
  rm -f ml_test*
  abort
fi
echo "done"
rm -f ml_test*

rm -f $TMP_CHECK_FORT_COMP

# -- check TERMCAP -------------------------------------------------------------

NEED_TERMCAP='"no"'
# check only if READLINE is ok
if test "$READLINE_INC" = "1"; then
  echo -n $ECHO_OPT "\n  Is termcap needed... \t\t\t "
  cat > readline_test.c <<EOF
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>

int main() {

  char *line, *prompt;
  line = readline(prompt);
  where_history();
  clear_history();
}
EOF
  $c_comp -c readline_test.c > /dev/null 2>&1
  if test $? != 0; then
    echo "failed"
    $COLOR_ERROR
    echo "  Internal error: compilation of readline_test.c failed!"
    echo "    -> please report this bug to Edouard.Canot@univ-rennes.fr"
    $COLOR_NORMAL
    abort "bug"
  fi
  $c_comp -o readline_test readline_test.o -lreadline > /dev/null 2>&1
  if test $? != 0; then
    NEED_TERMCAP='"yes"'
  fi
  echo $NEED_TERMCAP

  if test $NEED_TERMCAP = '"yes"'; then
    # it seems that -ltermcap is needed... let's go further...
    echo -n $ECHO_OPT "  Checking for termcap library... \t "
    if test $HW = "x86_64"; then
      search_path="/usr/lib64"
    else
      search_path="/usr/lib"
    fi
    TERMCAP_LIB=0
    LIB=`ls $search_path/libtermcap.* 2>/dev/null`
    if test $? = 0; then
      LIB=`ls $search_path/libtermcap.* 2>/dev/null | head -n 1`
      TERMCAP_LIB=1
      echo $LIB
    else
      echo "not found"
    fi

    if test $TERMCAP_LIB = 0; then
      echo
      $COLOR_WARNING
      echo "  Warning: you don't have the termcap library!"
      echo "  -> command line editing (including history) will not be available,"
      echo "     therefore, please consider installing 'termcap'."
      $COLOR_NORMAL
    fi

    echo -n $ECHO_OPT "  Checking if termcap solves the link... "
    $c_comp -o readline_test readline_test.o -lreadline -ltermcap > /dev/null 2>&1
    if test $? = 0; then
      echo '"yes"'
    else
      echo '"no"'
      echo
      $COLOR_WARNING
      echo "  Warning: it seems that termcap is needed for linking,"
      echo "           but adding '-ltermcap' fails to link a small test program!"
      echo "  -> command line editing (including history) will not be available."
      $COLOR_NORMAL
    fi
  fi
  rm -f readline_test readline_test.*
fi

# -- check for need of -lrt ----------------------------------------------------

echo -n $ECHO_OPT "\n  Does link need '-lrt'? \t\t "
cat > test_clock_gettime.c <<EOF
#include <time.h>
void main() {
   struct timespec t;
   clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t);
}
EOF
$c_comp -o test_clock_gettime test_clock_gettime.c > /dev/null 2>&1
if test $? = 0; then
  echo '"no"'
  NEED_LRT='"no"'
else
  echo '"yes"'
  NEED_LRT='"yes"'
fi
rm -f test_clock_gettime*

# -- substitution in Makefile.config.in ----------------------------------------
cat ../config/Makefile.config.in \
    | sed -e "s+@NEED_TERMCAP@+$NEED_TERMCAP+" \
    | sed -e "s=@LIBSTDC++@=$LIBSTDCXX=" \
    | sed -e "s+@NEED_LRT@+$NEED_LRT+" \
    > Makefile.config.tmp

# -- substitution in fontconfig/fonts.conf.in ----------------------------------
if echo "$PWD" | grep -q "|" ;then
  echo
  $COLOR_ERROR
  echo "  ERROR: your MUESLI source path cannot contain the '|' character!"
  echo
  $COLOR_NORMAL
  exit 1
fi
cat ../src/fgl/mfplot/fontconfig/fonts.conf.in \
    | sed -e "s+@FONTS_DIR@+$PWD/fgl/mfplot+" \
    > fgl/mfplot/fontconfig/fonts.conf

# -- adding some stuff only for INTEL ------------------------------------------
echo $ECHO_OPT "#-- special for INTEL ----------------------------------------------------------\n" >> Makefile.config.tmp
echo $ECHO_OPT "F90_COMP = $f90_comp\n" >> Makefile.config.tmp
echo $ECHO_OPT "C_COMP = $c_comp\n" >> Makefile.config.tmp
echo $ECHO_OPT "CXX_COMP = $cxx_comp\n" >> Makefile.config.tmp

exit 0
