#! /bin/sh

# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ┃ Local checking for GNU_GFC.                                                ┃
# ┃                                                                            ┃
# ┃ É. Canot -- IPR/CNRS -- 29 Apr 2025                                        ┃
# ┃                                                                            ┃
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

PID=$$

TMP_CHECK_FORT_COMP=/tmp/local_check_GNU_GFC_$PID.out

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
}

read_gcc_version() {
  COMP=$1
  found_version=0
  IFS=""
  set `$COMP -v 2>&1`
  IFS="
"
  for LINE in $*; do
    if test -n "`echo $LINE | grep "gcc version "`"; then
      found_version=1
      break
    fi
  done
  IFS=" "
  if test $found_version = "1"; then
    set `echo $LINE`
    echo $3
  else
    echo "read_gcc_version failed"
  fi
}

# -- 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 gfortran compiler... \t\t "
if test "$f90_comp" = ""; then
  f90_comp=gfortran
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, or the name of your compiler."
  $COLOR_NORMAL
  abort
fi

# validity of gfortran
echo -n $ECHO_OPT "  Checking for gfortran version... \t\t "
set `read_gcc_version $f90_comp`
if test $? = 0; then
  VERSION_GFC=$1
  echo $VERSION_GFC
  GCC_FAMILY_MAJOR=`echo $VERSION_GFC | cut -d'.' -f1`
  GCC_FAMILY_MINOR=`echo $VERSION_GFC | cut -d'.' -f2`
  CONDENSED_FAMILY_GFC=$GCC_FAMILY_MAJOR$GCC_FAMILY_MINOR
  if test $CONDENSED_FAMILY_GFC -lt 49; then
    echo
    $COLOR_ERROR
    echo "  ERROR: version of gfortran must be greater than 4.9!"
    $COLOR_NORMAL
    abort
  fi
  if test $CONDENSED_FAMILY_GFC -gt 159; then
    echo
    $COLOR_WARNING
    echo "  Warning: this version of gfortran has not been yet tested!"
    echo "           (it seems greater than 15.9)"
    echo "  -> Don't know if the library can be built... Try at your own risk."
    echo
    $COLOR_NORMAL
  fi
else
  echo "not found"
  echo
  $COLOR_ERROR
  echo "  ERROR: it seems that $f90_comp is not the GNU gfortran compiler!"
  echo "    -> please consider installing GNU-GCC compiler suite, or"
  echo "       choose another appropriate compiler directory."
  echo "       [the other is INTEL_IFC]"
  $COLOR_NORMAL
  abort
fi

# check that compiler works: (i) compilation
echo -n $ECHO_OPT "  Can $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 INTEL_IFC]"
  echo "       or at least reinstall GNU_GCC."
  $COLOR_NORMAL
  rm -f test.*
  abort
fi
echo "yes"
rm -f test.*

# check that compiler works: (ii) linking
echo -n $ECHO_OPT "  Can $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 "       [other are INTEL_IFC]"
  echo "       or at least reinstall GNU_GCC."
  $COLOR_NORMAL
  rm -f test.*
  abort
fi
echo "yes"
rm -f test.*

# check that compiler can compile a simple module
echo -n $ECHO_OPT "  Can $f90_comp compile a simple module? \t "
cat > test.f90 <<EOF
module test
contains
end module
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 module!"
  echo "    -> please consider using another compiler,"
  echo "       [the other is INTEL_IFC]"
  echo "       or at least reinstall GNU_GCC."
  $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\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 INTEL_IFC]"
  echo "       or at least another version of GNU_GCC."
  $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\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
  echo -n $ECHO_OPT "\t\t   linking... \t\t\t "
  # added -lpthread because OpenBLAS is multithreaded
  cmd="$f90_comp $ld_opt -o lapack_test lapack_test.o -L$lapack_path -llapack -L$blas_path -lblas $add_lib -lpthread"
  $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 "$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."
    $COLOR_NORMAL
    rm -f lapack_test.o
    abort
  fi
  echo -n $ECHO_OPT "\t\t   executing... \t\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
fi

rm -f lapack_test.* lapack_test

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

# which executable
echo -n $ECHO_OPT "\n  Checking for C compiler... \t\t\t "
if test "$c_comp" = ""; then
  c_comp=gcc
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

# version should be the same as the version of gfortran
echo -n $ECHO_OPT "  Checking for C comp. version... \t\t "
set `read_gcc_version $c_comp`
if test $# = 1; then
  VERSION_GCC=$1
  echo $VERSION_GCC
  if test $VERSION_GCC != $VERSION_GFC; then
    echo
    $COLOR_WARNING
    echo "  Warning: version of gcc should be the same as version of gfortran"
    echo "  -> try at your own risk."
    echo
    $COLOR_NORMAL
  fi
else
  echo "not found"
  echo
  $COLOR_WARNING
  echo "  Warning: it seems that $c_comp is not the GNU gcc compiler!"
  echo "  -> try at your own risk."
  echo
  $COLOR_NORMAL
fi

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

# which executable
echo -n $ECHO_OPT "\n  Checking for C++ compiler... \t\t\t "
if test "$cxx_comp" = ""; then
  cxx_comp=g++
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

# version should be the same as the version of gfortran
echo -n $ECHO_OPT "  Checking for C++ comp. version... \t\t "
set `read_gcc_version $cxx_comp`
if test $# = 1; then
  VERSION_GXX=$1
  echo $VERSION_GXX
  if test $VERSION_GXX != $VERSION_GFC; then
    echo
    $COLOR_WARNING
    echo "  Warning: version of g++ should be the same as version of gfortran"
    echo "  -> try at your own risk."
    echo
    $COLOR_NORMAL
  fi
else
  echo "not found"
  echo
  $COLOR_WARNING
  echo "  Warning: it seems that $cxx_comp is not the GNU g++ compiler!"
  echo "  -> try at your own risk."
  echo
  $COLOR_NORMAL
fi

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

# testing mixed-language link
echo -n $ECHO_OPT "\n  Testing a C++/Fortran program... \t\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\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
    $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\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'."
      echo
      $COLOR_NORMAL
    fi

    echo -n $ECHO_OPT "  Does termcap solve the link? \t "
    $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."
      echo
      $COLOR_NORMAL
    fi
  fi
  rm -f readline_test.* readline_test
fi

# -- check if the 'backtrace' GNU extension is available -----------------------
cat > backtrace_test.f90 <<EOF
program test
   implicit none
   integer :: i
   i = 1
   call backtrace
end program
EOF
echo
echo -n $ECHO_OPT "  Is the 'backtrace' GNU extension available? \t "
$f90_comp -o backtrace_test backtrace_test.f90 > /dev/null 2>&1
if test $? = 0; then
  echo '"yes"'
  GFORTRAN_HAS_BACKTRACE='"yes"'
  STATIC_LIBGFORTRAN='"no"'
else
  echo '"no"'
  GFORTRAN_HAS_BACKTRACE='"no"'
  # -- fallback: check static version of libgfortran ---------------------------
  cat > libgfortran_test.f90 <<EOF
program test
   implicit none
   integer :: i
   i = 1
end program
EOF
  echo
  echo -n $ECHO_OPT "  Checking if the static version of libgfortran exists... "
  $f90_comp -static-libgfortran -o libgfortran_test libgfortran_test.f90 > /dev/null 2>&1
  if test $? = 0; then
    echo '"yes"'
    STATIC_LIBGFORTRAN='"yes"'
  else
    echo '"no"'
    STATIC_LIBGFORTRAN='"no"'
    $COLOR_WARNING
    echo "  Warning: neither the static version of libgfortran, or the 'backtrace'"
    echo "           extension is present!"
    echo "  -> The MUESLI 'backtrace' will not be available."
    echo
    $COLOR_NORMAL
  fi
rm -f libgfortran_test*
fi
rm -f backtrace_test*

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

echo -n $ECHO_OPT "\n  Does link need '-lrt'? \t\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 GCC --------------------------------------------
echo $ECHO_OPT "#-- special for GCC ------------------------------------------------------------\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
echo $ECHO_OPT "GCC_FAMILY_MAJOR = $GCC_FAMILY_MAJOR\n" >> Makefile.config.tmp
echo $ECHO_OPT "GCC_FAMILY_MINOR = $GCC_FAMILY_MINOR\n" >> Makefile.config.tmp
echo $ECHO_OPT "GFORTRAN_HAS_BACKTRACE = $GFORTRAN_HAS_BACKTRACE\n" >> Makefile.config.tmp
echo $ECHO_OPT "STATIC_LIBGFORTRAN = $STATIC_LIBGFORTRAN\n" >> Makefile.config.tmp

exit 0
