#
#
#  Makefile for Trinity (GS2) / AstroGK Gyrokinetic Turbulence code 
#               GSP Gyrokinetic PIC code
#               rmhdper reduced MHD code
#
#  (requires GNU's gmake)
#
GK_PROJECT ?= gs2
#
#  Makefile written by Bill Dorland and Ryusuke Numata
#
#  LAST UPDATE: 10/12/09
#
# * Changelogs
# 26/09/10: added targets doc_depend and doc to make doxygen documentation. EGH.
#	12/17/09: make it explicit that the codes are written in
#		  Fortran 95 Standard
#	10/12/09: share the Makefile with gsp gyrokinetic PIC code
#	04/11/09: * share the Makefile with rmhdper reduced MHD code
#		  * include progject specific target definitions
#		    Makefile.target_$(GK_PROJECT)
#	04/06/09: SYSTEM environment variable is replaced by GK_SYSTEM
#	02/25/09: gs2 replaced by trinity (MAB)
#	01/26/09: USE_C_INDEX is imported to gs2 by TT
#       12/11/08: add support for NAGWare and Lahey compilers
#       10/28/08: some non-standard macros respect environment variables
#       10/27/08: default commands for MPI and HDF5 are defined
#       09/26/08: hack for treating intermediate f90 files properly
#	 	 (this is to keep all intermediate f90 files when 
#		 .PRECIOUS is given)
#	07/01/08: new switches USE_LOCAL_SPFUNC and USE_NAGLIB
#	06/16/08: clean up unused statements related to PLATFORM_LINKS
#
# * Available Compilers (tested on limited hosts)
#   (must be Fortran 95 Standard compliant)
#
# Intel ifort
# GNU's gfortran and g95
# IBM XL Fortran xlf90
# PathScale Compiler Suite pathf90
# The Portland Group pgf90
# NAGWare f95 (v5.1)
# Lahey/Fujitsu Fortran lf95
# 
# * Frequently Tested Hosts, Systems
#
# Standard Linux
# Standard Mac OS X with MacPorts
# Franklin at NERSC and Jaguar at NCCS (Cray XT4 with PGI)
# Bassi at NERSC (IBM Power 5 with IBM XL Fortran)
# Ranger (Sun Constellation Linux Cluster with Intel)
#
# * Switches:
#
# Here is a list of switches with simple explanation.
# In the brackets, values accepted are shown,
# where "undefined" means blank.
# Switches with (bin) are checked if they are defined or not
# What values they have do not matter.
# Be careful that DEBUG=off means DEBUG=on.
#
# Fortran Standard Specification (95, 2003, 2008, undefined)
FORTRAN_SPEC ?=
# turns on debug mode (bin)
DEBUG ?=
# turns on scalasca instrumentation mode (bin)
SCAL ?=
# turns on profile mode (gprof,ipm)
PROF ?=
# optimization (on,aggressive,undefined)
OPT ?= on
# prevents linking with shared libraries (bin)
STATIC ?=
# promotes precisions of real and complex (bin)
DBLE ?= on
# promotes precisions of double and double complex (bin)
QUAD ?=
# turns on distributed memory parallelization using MPI (mpi2, mpi3)
USE_MPI ?= mpi2
# turns on SHMEM parallel communications on SGI (bin)
USE_SHMEM ?=
# which FFT library to use (fftw,fftw3,mkl_fftw,undefined) 
USE_FFT ?= fftw3
# uses netcdf library (bin)
USE_NETCDF ?= on
# uses parallel netcdf library
USE_PARALLEL_NETCDF ?= 
# uses hdf5 library (bin)
USE_HDF5 ?=  
# Use function pointer in layouts_indices.c (bin)
# see also README
USE_C_INDEX ?= 
# Use local random number generator (mt,undefined)
# see also README
USE_LOCAL_RAN ?=
# Use posix for command_line (bin)
USE_POSIX ?=
# Use Fortran 2003, 2008 Intrinsics (bin)
# (Note this overwhelms other special function options)
USE_F200X_INTRINSICS ?=
# Use local special functions (bin)
USE_LOCAL_SPFUNC ?= 
# Use nag libraray (spfunc,undefined)
USE_NAGLIB ?= 
# Make GS2 into a library which can be called by external programs
MAKE_LIB ?=
# Include higher-order terms in GK equation arising from low-flow physics
LOWFLOW ?=
# Compile with PETSC/SLEPC support for determining eigensystem (bin).
# TODO : Rename USE_EIG for consistency
WITH_EIG ?=
# Include LAPACK and GSL libraries for genquad scheme
GENQUAD ?=
# Compile with gcov flags to check for code coverage
USE_GCOV ?=
HAS_GCOV=$(USE_GCOV)

# Compile with the new simplified diagnostics module (bin)
USE_NEW_DIAG ?=on
# Does the compiler version support the iso_c_binding features of Fortran?
HAS_ISO_C_BINDING ?= on
# If on, build with position independent code, needed if GS2 is going to be included
# in a shared library or linked dynamically (e.g. it's needed by GRYFX).
# This *may* have performance implications, but it hasn't been tested yet.
USE_FPIC ?= 
# Defines the size of the constant character arrays that are used to store the run
# name. 2000 has been selected as the default as being longer than most people will 
# need. However, this can be overriden by setting this parameter either in the environment
# or when executing make. Make sure you rebuild constants.fpp if you want to change this.
# e.g. 
#       $ touch utils/constants.fpp
#       $ ./build_gs2 -c 'RUN_NAME_SIZE=<newsize>'
RUN_NAME_SIZE?=2000
# If defined, fpp files will be preprocessed and compiled in one step, as
# is normal for modern FORTRAN compilers (bin)
ONE_STEP_PP?=
#
# * Targets:
#
#  depend: generate dependency
#  test_make: print values of variables
#  clean: clean up
#  distclean: does "make clean" + removes platform links & executables
#  tar: pack
#
############################################################### DEFAULT VALUE
#
# These variables can be set in platform-dependent Makefile.
#
SHELL           = bash
MAKE		= make
CPP		= cpp
CPPFLAGS        = 
FC		= f90
MPIFC		?= mpif90
H5FC		?= h5fc
H5FC_par	?= h5pfc
F90FLAGS	=
F90OPTFLAGS	= 
CC		= cc
MPICC		?= mpicc
H5CC		?= h5cc
H5CC_par	?= h5pcc
CFLAGS		= 
COPTFLAGS 	=
LD 		= $(FC)
LDFLAGS 	= $(F90FLAGS)
ARCH 		= ar
ARCHFLAGS 	= cr
RANLIB		= ranlib
AWK 		= awk
PERL		= perl
FORD           ?= ford


MPI_INC	?=
MPI_LIB ?=
FFT_INC ?=
FFT_LIB ?=
EIG_INC ?=
EIG_LIB ?=
GENQUAD_INC ?=
GENQUAD_LIB ?=
NETCDF_INC ?=
NETCDF_LIB ?=
HDF5_INC ?=
HDF5_LIB ?=
NAG_LIB ?=
NAG_PREC ?= dble
MACRO_DEFS ?=

#Patch file
PATCHFILE:= .patch.make

################################################### SET COMPILE MODE SWITCHES

# It makes no sense to set USE_PARALLEL_NETCDF without
# setting USE_HDF5... so we set USE_HDF5 here. 
# If you want to use parallel-netcdf instead of netcdf/hdf5 you can 
# override this behaviour in the system makefile
ifdef USE_PARALLEL_NETCDF
ifndef USE_HDF5
	USE_HDF5=on
endif
endif

######################################################### PLATFORM DEPENDENCE

# compile mode switches (DEBUG, TEST, PROF, OPT, STATIC, DBLE)
# must be set before loading Makefile.$(GK_SYSTEM) because they may affect
# compiler options.
# However, Makefile.local may override some options set in Makefile.$(GK_SYSTEM),
# thus it is included before and after Makefile.$(GK_SYSTEM)
sinclude Makefile.local

# include system-dependent make variables
ifndef GK_SYSTEM
	ifdef SYSTEM
$(warning SYSTEM environment variable is obsolete)
$(warning use GK_SYSTEM instead)
	GK_SYSTEM = $(SYSTEM)
	else
$(error GK_SYSTEM is not set)
	endif
endif


include Makefile.$(GK_SYSTEM)

# Files that we know are going to be in the submodule directories.
# This is in case the directories exist but the submodules haven't
# actually been initialised
MAKEFILES_SENTINEL = Makefiles/Makefile.bitbucket
UTILS_SENTINEL = utils/Makefile

# Make sure the submodules exist; they all share the same recipe
$(MAKEFILES_SENTINEL) $(UTILS_SENTINEL) submodules:
	@echo "Downloading submodules"
	git submodule update --init --recursive
# If we're running this recipe as a prerequisite, we need to rerun the
# original target in a clean process -- but don't do this if the
# target is explicitly "submodules", or we'll end up in an infinite
# loop! The actual submodules are directories so Make can see if they
# exist and therefore should skip the entire recipe
ifneq ($(MAKECMDGOALS),submodules)
	@$(MAKE) $(MAKECMDGOALS)
	@exit
endif

# CAREFUL! Defines a newline to be used in make's error
# function. Requires *two* blank lines for reasons
define newline_


endef

BITBUCKET_ISSUE_URL = https://bitbucket.org/gyrokinetics/gs2/issues/new

# This works because Make tries to read all the makefiles first, then
# update any that need updating. The pipe means order-only,
# i.e. doesn't check the timestamp. If we actually try to run the
# recipe that means something has gone wrong -- normally GK_SYSTEM is
# wrong
Makefile.$(GK_SYSTEM): | $(MAKEFILES_SENTINEL)
	$(error Could not find Makefile.$(GK_SYSTEM)$(newline_)\
	*** Looking in: $(PWD) $(.INCLUDE_DIRS)$(newline_)\
	***     Note: the above does not include non-existent directories!$(newline_)\
	***$(newline_)\
	*** Have you correctly set GK_SYSTEM and/or MAKEFLAGS?$(newline_)\
	***     GK_SYSTEM: $(GK_SYSTEM)$(newline_)\
	***     MAKEFLAGS: $(MAKEFLAGS)$(newline_)\
	***$(newline_)\
	*** If you are sure both GK_SYSTEM and MAKEFLAGS are correct, please try$(newline_)\
	*** running your 'make' command again. If you still get this error,$(newline_)\
	*** something else has gone wrong! Please report it at$(newline_)\
	***$(newline_)\
	***     $(BITBUCKET_ISSUE_URL)$(newline_)\
	***$(newline_)\
	*** including your 'make' command and its output$(newline_)\
	)

# include Makefile.local if exists
sinclude Makefile.local

#############################################################################

#Record the top level path
GK_HEAD_DIR:=$(PWD)
#TODO: Avoid this export as leads to a side effect (modifies user environment)
export GK_HEAD_DIR

UTILS=utils
GEO=geo

ifndef ONE_STEP_PP
CPPFLAGS	+= -P -traditional
endif

ifeq ($(MAKECMDGOALS),depend)
# must invoke full functionality when make depend
	MAKE += USE_HDF5=on USE_FFT=fftw USE_NETCDF=on USE_MPI=mpi3 \
		USE_LOCAL_SPFUNC=on USE_LOCAL_RAN=mt
endif

GIT_HASH=$(shell git rev-parse HEAD)
MACRO_DEFS+=-DGIT_HASH='"$(GIT_HASH)"'
# Find if there are any modified tracked files (except Makefile.depend)
ifeq ($(shell git status --short -uno -- . ':(exclude)Makefiles/Makefile.depend' | wc -l), 0)
	GIT_STATE="clean"
	MACRO_DEFS+=-DGIT_STATE='$(GIT_STATE)'
$(shell touch $(PATCHFILE))
else
	GIT_STATE="modified"
	MACRO_DEFS+=-DGIT_STATE='$(GIT_STATE)'

# Here we make a patch file, which could be read by the program if we wanted to keep a record
$(shell git diff -w -- . ':(exclude)Makefiles/Makefile.depend' > $(PATCHFILE))
endif
MACRO_DEFS+=-DGIT_PATCH_FILE='"$(PATCHFILE)"'


# Define RUN_NAME_SIZE
MACRO_DEFS+=-DRUN_NAME_SIZE=$(RUN_NAME_SIZE) 

############################################################################# Deal with user flags

# Define RELEASE based on the contents of the RELEASE
# file, which is empty unless we are in a release.
RELEASE_FILE = $(shell cat RELEASE)
ifneq ($(RELEASE_FILE),) # If the file is not empty
	RELEASE=$(RELEASE_FILE)
	MACRO_DEFS+=-DRELEASE=$(RELEASE_FILE)
	DOC_FOLDER=releases/$(RELEASE_FILE)/
endif

# Define GK_SYSTEM for runtime_tests so that we can get the system name
# at runtime
MACRO_DEFS+=-DGK_SYSTEM='"$(GK_SYSTEM)"'

ifdef USE_HDF5
	ifndef USE_MPI
$(error Currently, USE_HDF5 only works with USE_MPI)
	endif
endif


ifndef USE_NETCDF
ifdef USE_NEW_DIAG
$(error 'USE_NETCDF is off/undefined. The new diagnostics module requires netcdf. Please build without the new diagnostics module (i.e. set USE_NEW_DIAG=) ')
endif
endif

ifndef USE_FFT
$(warning USE_FFT is undefined/off)
$(warning Nonlinear runs are therefore not sensible)
endif

ifdef USE_MPI
	FC = $(MPIFC)
	CC = $(MPICC)
	MACRO_DEFS += -DMPI
endif

ifeq ($(USE_MPI),mpi3)
	MACRO_DEFS += -DMPI3
endif

ifdef HAS_ISO_C_BINDING
	MACRO_DEFS += -DISO_C_BINDING
endif

ifeq ($(USE_NEW_DIAG),on)
	MACRO_DEFS += -DNEW_DIAG
endif

ifeq ($(USE_FPIC),on)
	CFLAGS+=-fPIC
	F90FLAGS += -fPIC
endif

ifdef USE_SHMEM
	MACRO_DEFS += -DSHMEM
endif

ifeq ($(USE_FFT),fftw)
	MACRO_DEFS += -DFFT=_FFTW_
	FFT_LIB ?= -lfftw -lrfftw
endif

ifeq ($(USE_FFT),fftw3)
	MACRO_DEFS += -DFFT=_FFTW3_
        CPPFLAGS += $(FFT_INC)
	FFT_LIB ?= -lfftw -lrfftw
endif

ifdef GENQUAD
	GENQUAD_LIB ?= -llapack 
	MACRO_DEFS += -DGENQUAD
endif

ifeq ($(USE_FFT),mkl_fftw)
	MACRO_DEFS += -DFFT=_FFTW_
endif

ifdef USE_NETCDF
	NETCDF_LIB ?= -lnetcdf
	MACRO_DEFS += -DNETCDF
endif

ifdef USE_HDF5
	FC = $(H5FC_par)
	CC = $(H5CC_par)
	ifdef USE_PARALLEL_NETCDF
		MACRO_DEFS += -DNETCDF_PARALLEL
	endif
	MACRO_DEFS += -DHDF
endif

ifdef USE_C_INDEX
	MACRO_DEFS += -DUSE_C_INDEX
endif

ifeq ($(USE_LOCAL_RAN),mt)
	MACRO_DEFS += -DRANDOM=_RANMT_
endif

ifdef USE_POSIX
	MACRO_DEFS += -DPOSIX
endif

ifdef USE_F200X_INTRINSICS
	MACRO_DEFS += -DF200X_INTRINSICS -DSPFUNC=_SPF200X_
else
	ifdef USE_LOCAL_SPFUNC
		MACRO_DEFS += -DSPFUNC=_SPLOCAL_
	else
		ifeq ($(findstring spfunc,$(USE_NAGLIB)),spfunc)
			MACRO_DEFS += -DSPFUNC=_SPNAG_
		endif
	endif
endif

ifdef USE_NAGLIB
	ifeq ($(NAG_PREC),dble)
		ifndef DBLE
$(warning Precision mismatch with NAG libarray)	
		endif
		MACRO_DEFS += -DNAG_PREC=_NAGDBLE_
	endif
	ifeq ($(NAG_PREC),sngl)
		ifdef DBLE
$(warning Precision mismatch with NAG libarray)	
		endif
		MACRO_DEFS += -DNAG_PREC=_NAGSNGL_
	endif
endif

ifndef DBLE
	MACRO_DEFS += -DSINGLE_PRECISION
endif

ifdef QUAD
	DBLE = on
	MACRO_DEFS += -DQUAD_PRECISION
endif

ifdef MAKE_LIB
	MACRO_DEFS += -DMAKE_LIB
endif

ifdef LOWFLOW
	MACRO_DEFS += -DLOWFLOW
endif

ifdef USE_LE_LAYOUT
	MACRO_DEFS += -DUSE_LE_LAYOUT
endif

#Setup the flags for using the eigensolver
ifdef WITH_EIG
	EIG_INC += -I$(PETSC_DIR)/include -I$(SLEPC_DIR)/include
	ifdef PETSC_ARCH
		EIG_LIB += -L$(PETSC_DIR)/$(PETSC_ARCH)/lib
		EIG_INC += -I$(PETSC_DIR)/$(PETSC_ARCH)/include
	else
		EIG_LIB += -L$(PETSC_DIR)/lib
	endif
	ifdef SLEPC_ARCH
		EIG_LIB += -L$(SLEPC_DIR)/$(SLEPC_ARCH)/lib
		EIG_INC += -I$(SLEPC_DIR)/$(SLEPC_ARCH)/include
	else
		EIG_LIB += -L$(SLEPC_DIR)/lib
	endif
	EIG_LIB += -lslepc -lpetsc

	MACRO_DEFS += -DWITH_EIG
	CPPFLAGS += $(EIG_INC)
	CFLAGS += -DWITH_EIG 
endif 

ifdef SCAL
   FC:= scalasca -instrument $(FC)
endif

#Make empty targets if not using the new diagnostics
ifeq ($(USE_NEW_DIAG),on)
	sinclude diagnostics/Makefile.diagnostics
else
distclean_simpledataio:
clean_simpledataio:
diagnostics:
simpledataio:
endif

############################################################################# Done dealing with user flags

LIBS	+= $(DEFAULT_LIB) $(MPI_LIB) $(NETCDF_LIB) $(HDF5_LIB) $(FFT_LIB) \
		   $(NAG_LIB) $(EIG_LIB) $(GENQUAD_LIB)
INCLUDES = $(DEFAULT_INC) $(MPI_INC) $(NETCDF_INC) $(HDF5_INC) $(FFT_INC)\
		   $(SIMPLEDATAIO_INC) $(EIG_INC) $(GENQUAD_INC)
F90FLAGS+= $(F90OPTFLAGS) $(INCLUDES)
CFLAGS += $(COPTFLAGS) \
	   $(DEFAULT_INC) $(MPI_INC) $(NETCDF_INC) $(HDF5_INC) $(FFT_INC) 


DATE=$(shell date +%y%m%d)
TARDIR=$(GK_PROJECT)_$(DATE)
TOPDIR=$(CURDIR)
ifeq ($(notdir $(CURDIR)), $(UTILS))
	TOPDIR=$(subst /$(UTILS),,$(CURDIR))
endif
ifeq ($(notdir $(CURDIR)), $(GEO))
	TOPDIR=$(subst /$(GEO),,$(CURDIR))
endif
ifneq ($(TOPDIR),$(CURDIR))
	SUBDIR=true
endif

VPATH = $(UTILS):$(GEO):Aux:diagnostics:../$(UTILS):../$(GEO):../diagnostics$(SIMPLEDATAIO_VPATH)
# this just removes non-existing directory from VPATH
VPATH_tmp := $(foreach tmpvp,$(subst :, ,$(VPATH)),$(shell [ -d $(tmpvp) ] && echo $(tmpvp)))
VPATH = .:$(shell echo $(VPATH_tmp) | sed "s/ /:/g")
#
ifdef SUBDIR
	VPATH +=:..
endif
DEPEND=Makefile.depend
DEPEND_CMD=$(PERL) scripts/fortdep

# most common include and library directories
DEFAULT_INC_LIST = . $(UTILS) $(GEO) .. ../$(UTILS) ../$(GEO)
DEFAULT_LIB_LIST =
# This default library path list can simplify the procedure of porting,
# however, I found this (actually -L/usr/lib flag) causes an error
# when linking gs2 at bassi (RS6000 with xl fortran)
DEFAULT_INC=$(foreach tmpinc,$(DEFAULT_INC_LIST),$(shell [ -d $(tmpinc) ] && echo -I$(tmpinc)))
DEFAULT_LIB=$(foreach tmplib,$(DEFAULT_LIB_LIST),$(shell [ -d $(tmplib) ] && echo -L$(tmplib)))

# List of fortran files generated by ruby. 
# Note these are not deleted at the end of the compilation:
# in fact, they are stored in the repository 
# because some antique systems don't have ruby
FORTFROMRUBY=$(subst generate_,,$(patsubst %.rb,%.f90,$(wildcard *.rb */*.rb)))
FORTFROMRUBY+= gs2_init.f90 overrides.f90

# list of intermediate f90 files generated by preprocessor
F90FROMFPP = $(patsubst %.fpp,%.f90,$(notdir $(wildcard *.fpp */*.fpp)))
F90FROMFPP += tests/unit_tests/nonlinear_terms/test_nonlinear_terms.f90
F90FROMFPP += tests/unit_tests/gs2_diagnostics_new/test_gs2_diagnostics_new.f90
ifdef USE_NEW_DIAG
F90FROMFPP += simpledataiof.f90 simpledataio_write.f90 simpledataio_read.f90
endif

####################################################################### RULES

.SUFFIXES: .fpp .f90 .c .o .F90 .rb

.PHONY: all $(GK_PROJECT)_all unit_tests linear_tests nonlinear_tests benchmarks clean_tests submodules
.PHONY: depend clean distclean tar test_make diagnostics simpledataio
.PHONY: doc docs/html docs/graphs cleandoc check_ford_install

# comment this out to keep intermediate .f90 files
#.PRECIOUS: $(F90FROMFPP)

# Can we replace the following with `.INTERMEDIATE: $(F90FROMFPP)`?
.INTERMEDIATE: $(GK_PROJECT)_transforms.f90 $(GK_PROJECT)_io.f90 $(GK_PROJECT)_save.f90 \
		mp.f90 fft_work.f90

####################################################################### Source code targets

# This is to ensure the utils submodule gets initialised. The file
# mp.o is not important, we just need to add prerequisite for some
# file in utils
mp.o: | $(UTILS_SENTINEL)

.rb.f90:
	$(call RUBY_GENERATE,$@,$<)

.f90.o: 
	$(FC) $(F90FLAGS) $(F90FLAGS_SFXJUNK) -c $<

# The depend command needs the preprocessed source files. 
# This is a little clunky, and maybe could be fixed in the future.
.fpp.f90:
	$(CPP) $(CPPFLAGS) $(MACRO_DEFS) $< $@
.F90.f90:
	$(CPP) $(CPPFLAGS) $(MACRO_DEFS) $< $@

# On many systems the two steps of preprocessing and compiling
# can be done simultaneously. This has many advantages, the
# most important of which is correctly reporting line numbers in 
# the .fpp when debugging. 
#
# On some systems (e.g. Mac OS X) using cpp doesn't work at all
# and you HAVE to preprocess and compile in one step.
ifdef ONE_STEP_PP
.fpp.o:
	$(FC) $(MACRO_DEFS) $(F90FLAGS) $(F90FLAGS_SFXJUNK) -c $<
.F90.o:
	$(FC) $(MACRO_DEFS) $(F90FLAGS) $(F90FLAGS_SFXJUNK) -c $<

else
# These are special rules for the suffix problem of absoft
# (not tested)
$(GK_PROJECT)_transforms.o: $(GK_PROJECT)_transforms.f90
	$(FC) $(F90FLAGS) $(F90FLAGS_SFX0) -c $<
$(GK_PROJECT)_io.o: $(GK_PROJECT)_io.f90
	$(FC) $(F90FLAGS) $(F90FLAGS_SFX2) -c $<
$(GK_PROJECT)_save.o: $(GK_PROJECT)_save.f90
	$(FC) $(F90FLAGS) $(F90FLAGS_SFX2) -c $<
mp.o: mp.f90
	$(FC) $(F90FLAGS) $(F90FLAGS_SFX1) -c $<
fft_work.o: fft_work.f90
	$(FC) $(F90FLAGS) $(F90FLAGS_SFX0) -c $<
endif

.c.o:
	$(CC) $(CFLAGS) $(subst -traditional,,$(subst -C,,$(subst -P,,$(CPPFLAGS)))) -c $<

# This prevents error messages like m2c: Command not found
# This is from a implicit makefile rule that we're overriding
%.o : %.mod

depend: $(FORTFROMRUBY) $(F90FROMFPP)
	@$(DEPEND_CMD) -m "$(MAKE)" -1 -o -v=1 $(VPATH)

##################################################################### Main TARGETS
# .DEFAULT_GOAL works for GNU make 3.81 (or higher)
# For 3.80 or less, see all target
.DEFAULT_GOAL := $(GK_PROJECT)_all
ifeq ($(notdir $(CURDIR)),utils)
	.DEFAULT_GOAL := utils_all
endif
ifeq ($(notdir $(CURDIR)),geo)
	.DEFAULT_GOAL := geo_all
endif

all: $(.DEFAULT_GOAL)

#TODO : Add a rule to automatically build the depend file when appropriate.
include $(DEPEND)

#If we're using fft(w) then we want to link the fft_save_wisdom object file
#this currently has to be handled specially as it comes from a c source file
#rather than fortran (so isn't picked up by fortdep).
ifdef USE_FFT
    utils_mod += fft_save_wisdom.o
    gs2_mod += fft_save_wisdom.o
    ingen_mod += fft_save_wisdom.o
    generate_fftw_wisdom_mod += fft_save_wisdom.o
endif

ifdef USE_C_INDEX
    gs2_mod += layouts_indices.o
endif

layouts_indices.o: layouts_type.h
layouts_type.h: layouts_type.f90
	$(AWK) -f makehead.awk $^ > $@

# Make sure template dependencies are specified
gs2_init.f90: templates/gs2_init_template.f90

geometry_c_interface.o: geometry_c_interface.h

gryfx_libs: utils.a geo.a geo/geometry_c_interface.o

############################################################# Get project specific targets
include Makefile.target_$(GK_PROJECT)

############################################################# System config targets
.PHONY: system_config
ifdef STANDARD_SYSTEM_CONFIGURATION
system_config:
	@echo "#!/bin/bash " > system_config
	@echo "$(STANDARD_SYSTEM_CONFIGURATION)" >> system_config

else
system_config:
	$(error "STANDARD_SYSTEM_CONFIGURATION is not defined for this system")
endif

doxygen_doc: $(F90FROMFPP) $(FORTFROMRUBY)
	doxygen doxygen_config 
	rm -f $(F90FROMFPP)

#TODO: This will need updating when documentation has migrated to bitbucket
sync_doc: 
	rsync -av --delete --exclude=releases doc/html/	${USER},gyrokinetics@web.sourceforge.net:htdocs/gs2_documentation/$(DOC_FOLDER)
	mkdir -p doc/html/releases
	echo "Options +Indexes" > doc/html/releases/.htaccess
	rsync -av doc/html/releases/ ${USER},gyrokinetics@web.sourceforge.net:htdocs/gs2_documentation/releases/

#This has an external dependency on coderunner
sync_input_doc:
	coderunner cc synchronise_variables . -C gs2
	curl 'http://sourceforge.net/apps/mediawiki/gyrokinetics/index.php?title=GS2_Input_Parameters&action=edit' | sed 's/&amp;/\&/g' | sed 's/&quot;/"/g' | sed 's/&gt;/>/g' | sed 's/&lt;/</g'  | sed 's/&nbsp;/ /g' > wiki_in.tmp
	coderunner cc read_mediawiki_documentation wiki_in.tmp -C gs2
	coderunner cc write_mediawiki_documentation > wiki_out.txt -C gs2

############################################################# Cleanup targets
clean: clean_simpledataio clean_coverage
	-rm -f *.o *.mod *.g90 *.h core */core

CLEANCOMMAND=echo $$$$PWD
CLEANCOMMAND=rm -f *.o *.error *.out *.out.nc *.gridgen.200 *.lpc *.vres *.fields *.g *.fort.?? *.mod .*.scratch *.timing.* *.moments *.cdf *.jext *.parity *.heat *.heat2 *.vres2 *.amoments *.eigenfunc *.nc* *.mom2 *.epar .*.in results_of_test.txt *.stop *.fftw_wisdom *.phase *.kpar *.interp *.dist 

ifdef CLEAN_TEXTFILES
	CLEANCOMMAND+= *~ *.orig
endif

export CLEANCOMMAND

cleanlib:
	-rm -f *.a

cleanconfig:
	rm -f system_config .tmp_output

clean_doxygendoc: #Doxygen documentation
	rm -rf doc/

clean_coverage:
	-rm -f *.gcov *.gcda *.gcno

distclean: unlink clean cleanlib clean_tests clean_benchmarks distclean_simpledataio cleanconfig clean_doxygendoc cleandoc clean_coverage

unlink:
	-rm -f $(F90FROMFPP) layouts_type.h

############################################################# Tar targets
tar:
	@[ ! -d $(TARDIR) ] || echo "ERROR: directory $(TARDIR) exists. Stop."
	@[ -d $(TARDIR) ] || $(MAKE) tar_exec

### setting tar_exec local $(TARLIST*) variables
# expand wildcards listed $(TARLIST_wild) in ( $(TARLIST_dir) + . )
# directories and add them into TARLIST
tar_exec: TARLIST = makehead.awk scripts/fortdep AstroGK.in
tar_exec: TARLIST_dir = Makefiles utils geo Aux
tar_exec: TARLIST_wild = *.f90 *.fpp *.inc *.c Makefile Makefile.* README README.*
tar_exec: TARLIST += $(foreach dir,. $(TARLIST_dir),$(wildcard $(addprefix $(dir)/,$(TARLIST_wild))))

tar_exec:
	@mkdir $(TARDIR)
	@for dir in $(TARLIST_dir) ;\
	  do ( [ ! -d $$dir ] ||  mkdir $(TARDIR)/$$dir ; ) ;\
	done
	@for name in $(TARLIST) ;\
	  do ( [ -f $$name ] && ln $$name $(TARDIR)/$$name ; ) ;\
	done
	@tar cvf - $(TARDIR) | bzip2 -9 > $(TARDIR).tar.bz2
	@rm -rf $(TARDIR)

############################################################# Testing targets
#This is the location of the individual test suites
TEST_DIR:=tests
sinclude $(TEST_DIR)/Makefile.tests_and_benchmarks

############################################################# Introspection targets
test_make:
	@echo GK_SYSTEM is $(GK_SYSTEM)
	@echo .DEFAULT_GOAL is $(.DEFAULT_GOAL)
	@echo VPATH is $(VPATH)
	@echo CURDIR is $(CURDIR)
	@echo TOPDIR is $(TOPDIR)
	@echo NETCDF_LIB is $(NETCDF_LIB)
	@echo NETCDF_DIR is $(NETCDF_DIR)
	@echo FFT_LIB is $(FFT_LIB)
	@echo FFT_DIR is $(FFT_DIR)
	@echo LD_LIBRARY_PATH is $(LD_LIBRARY_PATH)
	@echo FORD is $(FORD)
	@echo USE_GCOV is $(USE_GCOV)
	@echo GIT_HASH is $(GIT_HASH)
	@echo GIT_STATE is $(GIT_STATE)
	@echo PATCHFILE is $(PATCHFILE)
	@echo
	@echo Compile mode:
	@echo  COMPILER is $(COMPILER)
	@echo  FC is $(FC)
	@echo  CC is $(CC)
	@echo  DEBUG is $(DEBUG)
	@echo  SCAL is $(SCAL)
	@echo  TEST is $(TEST)
	@echo  PROF is $(PROF)
	@echo  OPT is $(OPT)
	@echo  STATIC is $(STATIC)
	@echo  DBLE is $(DBLE)
	@echo
	@echo Functions:
	@echo  USE_MPI is $(USE_MPI)
	@echo  USE_SHMEM is $(USE_SHMEM)
	@echo  USE_FFT is $(USE_FFT)
	@echo  USE_NETCDF is $(USE_NETCDF)
	@echo  USE_HDF5 is $(USE_HDF5)
	@echo  USE_C_INDEX is $(USE_C_INDEX)
	@echo  USE_POSIX is $(USE_POSIX)
	@echo  USE_LOCAL_RAN is $(USE_LOCAL_RAN)
	@echo  USE_LOCAL_SPFUNC is $(USE_LOCAL_SPFUNC)
	@echo  USE_NAGLIB is $(USE_NAGLIB)
	@echo  USE_NEW_DIAG is $(USE_NEW_DIAG)
	@echo  DEFAULT_LIB is $(DEFAULT_LIB)
	@echo  MPI_LIB is $(MPI_LIB)
	@echo
	@echo FC is $(FC)
	@echo F90FLAGS is $(F90FLAGS)
	@echo F90OPTFLAGS is $(F90OPTFLAGS)
	@echo CC is $(CC)
	@echo CFLAGS is $(CFLAGS)
	@echo COPTFLAGS is $(COPTFLAGS)
	@echo LD is $(LD)
	@echo LDFLAGS is $(LDFLAGS)
	@echo CPP is $(CPP)
	@echo CPPFLAGS is $(CPPFLAGS)
	@echo MACRO_DEFS is $(MACRO_DEFS)
	@echo LIBS is $(LIBS)
	@echo WITH_EIG is $(WITH_EIG)

revision:
	@LANG=C git rev-parse HEAD > Revision

#This only works if a helplocal rule has been defined in the specific system makefile.
#It would be nice to provide a default helplocal target that just says no help available
help: helplocal

TAGS:	*.f90 *.fpp */*.f90 */*.fpp
	etags $^

############################################################# Documentation

ifneq ("$(wildcard $(shell which $(FORD) 2>/dev/null))","")
check_ford_install:
	@echo "Using ford at $(shell which $(FORD))"
else
check_ford_install:
	@echo "Ford command $(FORD) not in path -- is it installed?\\n\\tConsider installing with 'pip install --user ford' and add ${HOME}/.local/bin to PATH" ; which $(FORD)
endif

docs/html:
doc: docs/.docs.config.md check_ford_install
	$(FORD) $(subst -D,--macro ,$(MACRO_DEFS)) $(INCLUDES) $<

cleandoc: docs/html docs/graphs
	-@rm -rf $^

