# Makefile for GNU-make
# Fortran: GNU gfortran 4.9 to 13
#
# É. Canot -- IPR/CNRS -- 27 Dec 2023
#
# this Makefile has no option. See the main Makefile.
#

include ../make_opt.inc

include ../Makefile.config

# configurable options (OS dependent)

# for optimization
OPT_FLAGS = -O3 -funroll-loops

# path to shared libraries of GNU compilers
#F90_LIB_DIR = $(GCC_LIB)

ifdef F90_LIB_DIR
  F90_LIB = -Wl,-rpath,$(F90_LIB_DIR) -L$(F90_LIB_DIR) -lgfortran

  # for linking (SPQR is written in C++)
  # usually '-lstdc++' would be sufficient if you have only one version
  # of GCC on your system.
  #LIBSTDC++ = -lstdc++
  LIBSTDC++ = -Wl,-rpath,$(F90_LIB_DIR) -L$(F90_LIB_DIR) -lstdc++
endif

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

# special tag : vendor / f90 abbrev
F90C_TAG = GNU_GFC

# process MAKE options
ifeq '$(CFG)' 'debug'
  MAKE_CFG=CFG=debug
else # 'release'
  MAKE_CFG=CFG=release
endif
ifeq '$(MEMTR)' 'yes'
  MAKE_MEMTR=MEMTR=yes
else # 'no'
  MAKE_MEMTR=MEMTR=no
endif
ifeq '$(TCOV)' 'yes'
  MAKE_TCOV=TCOV=yes
else # 'no'
  MAKE_TCOV=TCOV=no
endif

# compiler -------------------------------------------------------------

F90C = $(F90_COMP)

GCOV = gcov-$(GCC_FAMILY_MAJOR)
ifeq '$(GCC_FAMILY_MAJOR)' '4'
  GCOV = gcov-4.$(GCC_FAMILY_MINOR)
endif

# OpenMP flag (specific for each compiler)
OMP_FLAG =# -fopenmp

ifeq '$(CFG)' 'debug'

  CFG_FLAGS = -fno-range-check \
              -g -fbounds-check -fbacktrace #-pg

#  CFG_FLAGS += -Warray-temporaries -fcheck-array-temporaries # 4.? only

  CFG_FLAGS_LIB_AUX = -g -fbounds-check -fbacktrace #-pg
  ifeq '$(STATIC_LIBGFORTRAN)' '"yes"'
    LD_FLAGS = -static-libgfortran #-pg
  endif

  ifeq '$(TCOV)' 'yes'

    CFG_FLAGS += -fprofile-arcs -ftest-coverage # for test coverage (gcov)
    CFG_FLAGS_LIB_AUX += -fprofile-arcs -ftest-coverage # for test coverage (gcov)
    LD_FLAGS += -fprofile-arcs -ftest-coverage # for test coverage (gcov)

  endif

else # 'release'

  CFG_FLAGS = -fno-range-check $(OPT_FLAGS)
  CFG_FLAGS_LIB_AUX = $(OPT_FLAGS)
  ifeq '$(DARWIN)' '"yes"'
    LD_FLAGS =
  else
    LD_FLAGS = -s
  endif

endif

CFG_FLAGS += -ffree-line-length-none

FPP_FLAGS = -D_$(F90C_TAG)

ifeq '$(NO_X11)' '"yes"'

  FPP_FLAGS += -D_NO_X11

endif

ifeq '$(DARWIN)' '"yes"'

  FPP_FLAGS += -D_DARWIN

endif

ifeq '$(HDF5)' '"yes"'

  FPP_FLAGS += -D_HDF5

endif

INCLUDES = -I../include

INCLUDES_DEV = -I../inc_dev

F90_FLAGS = $(INCLUDES) $(CFG_FLAGS) $(OMP_FLAG)

# [option added on 2011-06-30, in order to check the validity
#  of numerical results among all the compilers used]
F90_FLAGS += -fno-sign-zero

F90_FLAGS_DEV = $(INCLUDES_DEV) $(CFG_FLAGS) $(OMP_FLAG)

F90_FLAGS_LIB_AUX = $(INCLUDES) $(CFG_FLAGS_LIB_AUX) $(OMP_FLAG)

LD_FLAGS += $(OMP_FLAG)

#----------------------------- libraries -------------------------------

ifeq '$(CFG)' 'debug'

  MUESLI_LIBS = ../lib/libfml.a

  ifeq '$(HDF5)' '"yes"'
    HDF5_F90_LIBS = $(HDF5_F90_DIR)/libhdf5_fortran.a
  else
    HDF5_F90_LIBS =
  endif

else # 'release' (absolute path, comma after -rpath)
     # fix: doublequotes around `pwd` are required to take into account
     # some blanks in the path...

  ifeq '$(DARWIN)' '"yes"'
    MUESLI_LIBS =
  else
    MUESLI_LIBS = -Wl,-rpath,"`pwd`"/../lib
  endif

  MUESLI_LIBS += -L"`pwd`"/../lib -lfml

  ifeq '$(HDF5)' '"yes"'
    HDF5_F90_LIBS = -Wl,-rpath,$(HDF5_F90_DIR) -L$(HDF5_F90_DIR) -lhdf5_fortran
  else
    HDF5_F90_LIBS =
  endif

endif

# BLAS/LAPACK
ifeq '$(DARWIN)' '"yes"'
  LAPACK_LIBS =
else
  LAPACK_LIBS = -Wl,-rpath,$(LAPACK_DIR) -Wl,-rpath,$(BLAS_DIR)
endif
LAPACK_LIBS += -L$(LAPACK_DIR) -llapack -L$(BLAS_DIR) -lblas $(ADD_LIB)

# PAPI (PerfCtr)
ifeq '$(PAPI)' 'yes'
  PAPI_LIBS = $(PAPI_DIR)/libpapi.a
else # linux kernel not patched with PERFCTR, or PAPI not installed
  PAPI_LIBS =
endif

# recent READLINE library includes TERMCAP
ifeq '$(NEED_TERMCAP)' '"yes"'
  TERMCAP_LIB = -ltermcap
else
  TERMCAP_LIB =
endif

ifeq '$(HDF5)' '"yes"'
  HDF5_LIBS = -L$(HDF5_1_6) -lhdf5
else
  HDF5_LIBS =
endif

ZLIB_LIBS = -L$(ZLIB_DIR) -lz

ifeq '$(CFG)' 'debug'
  LIBS = obj/test_aux.o \
         $(MUESLI_LIBS) $(LIBSTDC++) $(PAPI_LIBS) $(LAPACK_LIBS) \
         $(HDF5_F90_LIBS) $(HDF5_LIBS) $(ZLIB_LIBS) \
         -lpthread $(TERMCAP_LIB) $(F90_LIB)
else # mode OPTIM
  # most of external libraries are already linked in the shared versions of FML
  LIBS = obj/test_aux.o \
         $(MUESLI_LIBS) $(F90_LIB)
endif

ifeq '$(CFG)' 'debug'
  ifeq '$(READLINE)' '"yes"'
    ifeq '$(DARWIN)' '"yes"'
      LIBS += -lreadline
    else
      LIBS += -lreadline -lhistory
    endif
  endif
endif

ifeq '$(DARWIN)' '"no"'
  ifeq '$(CFG)' 'debug'
    ifeq '$(NEED_LRT)' '"yes"'
      LIBS += -lrt
    endif
  endif
endif

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

PROGS = test_mod_physunits \
        test_mod_core \
        test_mod_sparse_1 \
        test_mod_sparse_2 \
        test_mod_elmat \
        test_mod_fileio \
        test_mod_elfun \
        test_mod_ops \
        test_mod_specfun \
        test_mod_datafun \
        test_mod_matfun_1 \
        test_mod_matfun_2 \
        test_mod_polyfun \
        test_mod_funfun

all : $(PROGS)

test_mod_core : obj/test_mod_core.o obj/lib_aux.o
	$(F90C) $(LD_FLAGS) -o $@ $^ $(LIBS)

test_mod_sparse_1 : obj/test_mod_sparse_1.o obj/lib_aux.o
	$(F90C) $(LD_FLAGS) -o $@ $^ $(LIBS)

test_mod_sparse_2 : obj/test_mod_sparse_2.o obj/lib_aux.o
	$(F90C) $(LD_FLAGS) -o $@ $^ $(LIBS)


test_mod_fileio : obj/test_mod_fileio.o obj/lib_aux.o
	$(F90C) $(LD_FLAGS) -o $@ $^ $(LIBS)

test_mod_elmat : obj/test_mod_elmat.o obj/lib_aux.o
	$(F90C) $(LD_FLAGS) -o $@ $^ $(LIBS)

test_mod_elfun : obj/test_mod_elfun.o obj/lib_aux.o
	$(F90C) $(LD_FLAGS) -o $@ $^ $(LIBS)

test_mod_specfun : obj/test_mod_specfun.o obj/lib_aux.o
	$(F90C) $(LD_FLAGS) -o $@ $^ $(LIBS)

test_mod_ops : obj/test_mod_ops.o obj/lib_aux.o
	$(F90C) $(LD_FLAGS) -o $@ $^ $(LIBS)

test_mod_datafun : obj/test_mod_datafun.o obj/lib_aux.o
	$(F90C) $(LD_FLAGS) -o $@ $^ $(LIBS)

test_mod_matfun_1 : obj/test_mod_matfun_1.o obj/lib_aux.o
	$(F90C) $(LD_FLAGS) -o $@ $^ $(LIBS)

test_mod_matfun_2 : obj/test_mod_matfun_2.o obj/lib_aux.o
	$(F90C) $(LD_FLAGS) -o $@ $^ $(LIBS)

test_mod_polyfun : obj/test_mod_polyfun.o obj/lib_aux.o
	$(F90C) $(LD_FLAGS) -o $@ $^ $(LIBS)

test_mod_funfun : obj/test_mod_funfun.o obj/lib_aux.o obj/funfun_aux.o
	$(F90C) $(LD_FLAGS) -o $@ $^ $(LIBS)

test_mod_physunits : obj/test_mod_physunits.o obj/lib_aux.o
	$(F90C) $(LD_FLAGS) -o $@ $^ $(LIBS)

test_mod_core_flops : obj/test_mod_core_flops.o obj/lib_aux.o
	$(F90C) $(LD_FLAGS) -o $@ $^ \
       obj/test_aux.o $(LIBS)

test_progress : obj/test_progress.o obj/lib_aux.o
	$(F90C) $(LD_FLAGS) -o $@ $^ $(LIBS)

ifeq '$(CFG)' 'debug'
  OBJ_1_DEP = ../lib/libfml.a
else
  OBJ_1_DEP = ../lib/libfml.so
endif
OBJ_1_DEP += ../include/fml.mod

obj/test_aux.o : test_aux.f90 $(OBJ_1_DEP)

obj/lib_aux.o : lib_aux.F90 $(OBJ_1_DEP)
	$(F90C) $(FPP_FLAGS) $(F90_FLAGS_LIB_AUX) -c $< -o $@

OBJ_2_DEP = $(OBJ_1_DEP) obj/test_aux.o obj/lib_aux.o

obj/test_mod_core.o : test_mod_core.F90 $(OBJ_2_DEP)

obj/test_mod_sparse_1.o : test_mod_sparse_1.F90 $(OBJ_2_DEP)

obj/test_mod_sparse_2.o : test_mod_sparse_2.F90 $(OBJ_2_DEP)


obj/test_mod_fileio.o : test_mod_fileio.F90 $(OBJ_2_DEP)

obj/test_mod_elmat.o : test_mod_elmat.F90 $(OBJ_2_DEP)

obj/test_mod_elfun.o : test_mod_elfun.F90 $(OBJ_2_DEP)

obj/test_mod_specfun.o : test_mod_specfun.F90 $(OBJ_2_DEP)

obj/test_mod_ops.o : test_mod_ops.f90 $(OBJ_2_DEP)

obj/test_mod_datafun.o : test_mod_datafun.F90 $(OBJ_2_DEP)

obj/test_mod_matfun_1.o : test_mod_matfun_1.F90 $(OBJ_2_DEP)

obj/test_mod_matfun_2.o : test_mod_matfun_2.F90 $(OBJ_2_DEP)

obj/test_mod_polyfun.o : test_mod_polyfun.F90 $(OBJ_2_DEP)

obj/test_mod_funfun.o : test_mod_funfun.F90 $(OBJ_2_DEP) obj/funfun_aux.o

obj/test_mod_physunits.o : test_mod_physunits.f90 $(OBJ_2_DEP)

obj/test_mod_core_flops.o : test_mod_core_flops.f90 $(OBJ_2_DEP)

obj/test_progress.o : test_progress.f90 $(OBJ_2_DEP)

# official referenced results (ref) are built with GCC
ref : test_mod_core.ref \
      test_mod_sparse_1.ref \
      test_mod_sparse_2.ref \
      test_mod_fileio.ref \
      test_mod_elmat.ref \
      test_mod_elfun.ref \
      test_mod_specfun.ref \
      test_mod_ops.ref \
      test_mod_datafun.ref \
      test_mod_matfun_1.ref \
      test_mod_matfun_2.ref \
      test_mod_polyfun.ref \
      test_mod_funfun.ref \
      test_mod_physunits.ref

test_mod_core.ref : test_mod_core
	./$< > $@ 2>&1

test_mod_sparse_1.ref : test_mod_sparse_1
	./$< > $@ 2>&1

test_mod_sparse_2.ref : test_mod_sparse_2
	./$< > $@ 2>&1


test_mod_fileio.ref : test_mod_fileio
	./$< > $@ 2>&1

test_mod_elmat.ref : test_mod_elmat
	./$< > $@ 2>&1

test_mod_elfun.ref : test_mod_elfun
	./$< > $@ 2>&1

test_mod_specfun.ref : test_mod_specfun
	./$< > $@ 2>&1

test_mod_ops.ref : test_mod_ops
	./$< > $@ 2>&1

test_mod_datafun.ref : test_mod_datafun
	./$< > $@ 2>&1

test_mod_matfun_1.ref : test_mod_matfun_1
	./$< > $@ 2>&1

test_mod_matfun_2.ref : test_mod_matfun_2
	./$< > $@ 2>&1

test_mod_polyfun.ref : test_mod_polyfun
	./$< > $@ 2>&1

test_mod_funfun.ref : test_mod_funfun
	./$< > $@ 2>&1

test_mod_physunits.ref : test_mod_physunits
	./$< > $@ 2>&1

check : test_mod_core.dif \
        test_mod_sparse_1.dif \
        test_mod_sparse_2.dif \
        test_mod_fileio.dif \
        test_mod_elmat.dif \
        test_mod_elfun.dif \
        test_mod_specfun.dif \
        test_mod_ops.dif \
        test_mod_datafun.dif \
        test_mod_matfun_1.dif \
        test_mod_matfun_2.dif \
        test_mod_polyfun.dif \
        test_mod_funfun.dif \
        test_mod_physunits.dif

# *.dif must not depend on *.ref (otherwise, the ref files could be updated):
# the aim is to check new numerical results in comparing with old results.

%.dif : %
	./$< > $<.out 2>&1
ifeq '$(MEMTR)' 'yes'
	../bin/mem_debug_check < mem_debug.out > $<.mem_check.out
endif
	diff $<.ref $<.out > $<.dif || :
	@echo "  *** $* : checked ***"
	@echo

ifeq '$(MEMTR)' 'yes'

mem_check : test_mod_core.mem_check.out \
            test_mod_sparse_1.mem_check.out \
            test_mod_sparse_2.mem_check.out \
            test_mod_fileio.mem_check.out \
            test_mod_elmat.mem_check.out \
            test_mod_elfun.mem_check.out \
            test_mod_specfun.mem_check.out \
            test_mod_ops.mem_check.out \
            test_mod_datafun.mem_check.out \
            test_mod_matfun_1.mem_check.out \
            test_mod_matfun_2.mem_check.out \
            test_mod_polyfun.mem_check.out \
            test_mod_funfun.mem_check.out \
            test_mod_physunits.mem_check.out

%.mem_check.out : %
	./$< > /dev/null 2> mem_debug.out
	../bin/mem_debug_check < mem_debug.out > $@

else

mem_check :
	@echo
	@echo "  *** you must use the 'MEMTR=yes' option ***"
	@echo

endif

#---------------------------- test coverage ----------------------------

ifeq '$(TCOV)' 'yes'

test_cov : clean_gcda \
           test_mod_core.F90.gcov \
           test_mod_sparse_1.F90.gcov \
           test_mod_sparse_2.F90.gcov \
           test_mod_fileio.F90.gcov \
           test_mod_elmat.F90.gcov \
           test_mod_elfun.F90.gcov \
           test_mod_specfun.F90.gcov \
           test_mod_ops.f90.gcov \
           test_mod_datafun.F90.gcov \
           test_mod_matfun_1.F90.gcov \
           test_mod_matfun_2.F90.gcov \
           test_mod_polyfun.F90.gcov \
           test_mod_funfun.F90.gcov \
           test_mod_physunits.f90.gcov \
           make_cov

make_cov :
	(cd ..; $(GCOV) -o obj mod_core)
	(cd ..; $(GCOV) -o obj mod_sparse)
	(cd ..; $(GCOV) -o obj mod_fileio)
	(cd ..; $(GCOV) -o obj mod_elmat)
	(cd ..; $(GCOV) -o obj mod_elfun)
	(cd ..; $(GCOV) -o obj mod_specfun)
	(cd ..; $(GCOV) -o obj mod_ops)
	(cd ..; $(GCOV) -o obj mod_datafun)
	(cd ..; $(GCOV) -o obj mod_matfun)
	(cd ..; $(GCOV) -o obj mod_polyfun)
	(cd ..; $(GCOV) -o obj mod_funfun)
	(cd ..; $(GCOV) -o obj mod_physunits)

# in order to avoid the warning: "Merge mismatch for summaries" when
# updating previously created GCDA files.
clean_gcda :
	rm -f obj/*.gcda
	(cd ..; rm -f obj/*.gcda lib/*.gcda; rm -f *.gcov)

%.F90.gcov : %
	./$< > /dev/null 2> $<.out
	$(GCOV) -o obj $<

%.f90.gcov : %
	./$< > /dev/null 2> $<.out
	$(GCOV) -o obj $<

else

test_cov :
	@echo
	@echo "  *** you must use the 'TCOV=yes' option ***"
	@echo

endif

#-------------------------------- rules --------------------------------

.SUFFIXES :
.SUFFIXES : .F90 .f90 .o

obj/%.o : %.F90
	$(F90C) $(FPP_FLAGS) $(F90_FLAGS) -c $< -o $@

obj/%.o : %.f90
	$(F90C) $(F90_FLAGS) -c $< -o $@

clean :
	rm -f obj/* *.mod *.smod \
	      *_tmp.* *.c *.out *.res *.dif *.gcov *.prof \
	      mem_debug.out

distclean : clean
	rm -f $(PROGS) \
	      test_mod_core_flops \
	      test_progress \
	      exam_traceback
