# Path to the directory with the source files:
srcdir:= @srcdir@

# Path to the directory with the Fortran module files:
moddir:= mod

# Paths to the installation directories:
prefix= @prefix@
exec_prefix= @exec_prefix@

# Package tarname:
PACKAGE_TARNAME= @PACKAGE_NAME@-@PACKAGE_VERSION@

# Utilities:
SHELL= @SHELL@
FC= @FC@
PYTHON= @PYTHON@
DEPLIST= ${PYTHON} $(srcdir)/mkhelper/deplist.py
DEPGEN= ${PYTHON} $(srcdir)/mkhelper/depgen.py --src-root='@srcdir@' --pp-enable --pp-eval-expr \
        --pp-inc-flag='@FCINCFLAG_PP@' --pp-inc-order='@FCINCORDER_PP@' --pp-macro-flag='@FCDEF_PP@' \
        --fc-enable --fc-mod-ext='@FCMODEXT@.proxy' --fc-mod-upper='@FCMODUC@' --fc-inc-flag='@FCINCFLAG@' \
        --fc-inc-order='@FCINCORDER@' --fc-mod-dir-flag='@FCMODOUT@' --fc-external-mods='@DEPGEN_EXTERNAL_MODS@'
MODCMP= ${PYTHON} $(srcdir)/mkhelper/fortmodcmp.py
AR= @AR@
ARFLAGS= @ARFLAGS@
INSTALL= @INSTALL@
INSTALL_DATA= @INSTALL_DATA@
GIT= git
TAR= tar
BZIP2 = bzip2

# Fortran compiler and flags:
FCFLAGS= @FCMODINC@$(moddir) @FCMODOUT@$(moddir) @FCINCFLAG_PP@$(srcdir)/include @NETCDF_FCFLAGS@ @FCFLAGS@
LDFLAGS= @LDFLAGS@
LIBS= @NETCDF_FCLIBS@ @LIBS@

# Silent rule prefixes:
V= @DEFAULT_VERBOSITY@
ifeq ($(V), 0)
silent_FC=      @echo "  FC      " $@;
silent_MKDIR=   @echo "  MKDIR   " $(@D);
silent_DEPGEN=  @echo "  DEPGEN  " $@;
silent_AR=      @echo "  AR      " $@;
endif

lib_LIBRARIES:= libifsaux.a libifsrrtm.a libradiation.a libutilities.a

ignored_SOURCES:=                                \
    ifsrrtm/rrtm_ecrt_140gp_mcica.F90            \
    ifsrrtm/rrtm_rrtm_140gp_mcica.F90            \
    ifsrrtm/srtm_gas_optical_depth_test.F90      \
    ifsrrtm/srtm_spcvrt_mcica.F90                \
    ifsrrtm/srtm_srtm_224gp_mcica.F90            \
    radiation/radiation_adding_ica_sw_test.F90   \
    radiation/radiation_adding_ica_sw_test2.F90  \
    radiation/radiation_ice_optics_baran2016.F90 \
    radiation/radiation_psrad.F90                \
    radiation/radiation_psrad_rrtm.F90

libifsaux_a_SOURCES:= $(filter-out $(ignored_SOURCES),$(patsubst $(srcdir)/%,%,$(shell find $(srcdir)/ifsaux -name '*.F90')))
libifsrrtm_a_SOURCES:= $(filter-out $(ignored_SOURCES),$(patsubst $(srcdir)/%,%,$(shell find $(srcdir)/ifsrrtm -name '*.F90')))
libradiation_a_SOURCES:= $(filter-out $(ignored_SOURCES),$(patsubst $(srcdir)/%,%,$(shell find $(srcdir)/radiation -name '*.F90')))
libutilities_a_SOURCES:= $(filter-out $(ignored_SOURCES),$(patsubst $(srcdir)/%,%,$(shell find $(srcdir)/utilities -name '*.F90')))

all_SOURCES:= $(libifsaux_a_SOURCES) $(libifsrrtm_a_SOURCES) $(libradiation_a_SOURCES) $(libutilities_a_SOURCES)

# Dependency files:
deps:= $(addsuffix .d,$(all_SOURCES))

# Stamp files of the building subdirectories:
dirstamps= $(addsuffix .dirstamp, $(sort $(dir $(deps)))) $(moddir)/.dirstamp

# PGI cross-file function inlining via an inline library:
INLIB= @DEFAULT_INLIB@
ifeq ($(INLIB), 1)

# Additional silence prefixes:
ifeq ($(V), 0)
silent_FCEX= @echo "  FC (EX) " $@;
silent_FCIN= @echo "  FC (IL) " $@;
endif

# Name of the inline library (a directory):
inlib_name:= ecrad.il

# Additional compiler flags enabling the inline library generation:
inlib_extract_FCFLAGS:= -Mextract=lib:$(inlib_name),reshape,name:adding_ica_sw,name:beta2alpha,name:calc_fluxes_no_scattering_lw,name:calc_ice_optics_baran,name:calc_ice_optics_baran2016,name:calc_ice_optics_baran2017,name:calc_ice_optics_fu_lw,name:calc_ice_optics_fu_sw,name:calc_ice_optics_yi_lw,name:calc_ice_optics_yi_sw,name:calc_liq_optics_lindner_li,name:calc_liq_optics_slingo,name:calc_liq_optics_socrates,name:calc_no_scattering_transmittance_lw,name:calc_ref_trans_lw,name:calc_ref_trans_sw,name:calc_two_stream_gammas_lw,name:calc_two_stream_gammas_sw,name:cloud_generator_acc,name:delta_eddington_extensive,name:delta_eddington_scat_od,name:fast_adding_ica_lw,name:initialize_acc,name:radiation_liquid_optics_socrates,name:uniform_distribution_acc


# Additional compiler flags enabling the inline library usage:
inlib_inline_FCFLAGS:= -Minline=lib:$(inlib_name),reshape

# List of source files containing functions that need to be inlined:
inlib_SOURCES:=                    \
		radiation/radiation_adding_ica_lw.F90 \
		radiation/radiation_adding_ica_sw.F90 \
		radiation/radiation_aerosol_optics.F90 \
		radiation/radiation_cloud_generator_acc.F90 \
		radiation/radiation_cloud_optics.F90 \
		radiation/radiation_ice_optics_baran.F90 \
		radiation/radiation_ice_optics_baran2017.F90 \
		radiation/radiation_ice_optics_fu.F90 \
		radiation/radiation_ice_optics_yi.F90 \
		radiation/radiation_liquid_optics_slingo.F90 \
		radiation/radiation_liquid_optics_socrates.F90 \
		radiation/radiation_two_stream.F90 \
		radiation/radiation_random_numbers.F90

		#radiation/radiation_cloud_cover.F90 \ # leads to cyclic dependency, missing inlinling is acceptable for now, affected: beta2alpha

# List of files where we need to manually limit GPU register usage
inlib_limit_registers_OBJECTS:=            \
		radiation/radiation_mcica_acc_lw.o \
		radiation/radiation_mcica_acc_sw.o

# And limiting flags
inlib_limit_registers_FCFLAGS:= -gpu=maxregcount:96

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

# Object files that correspond to the source files in $(inlib_SOURCES):
inlib_objs:= $(inlib_SOURCES:.F90=.@OBJEXT@)

# List of objects that are generated using the inline library:
inlib_target_objs:= $(filter %.@OBJEXT@,$(shell $(DEPLIST) -p $(inlib_objs) -f $(deps)))

# To avoid circular dependencies, we need to account for situations when we
# have a dependency A -> B -> C, where A and C belong to $(inlib_objs) but B
# does not. In order to get all such B files and include them into
# $(inlib_objs), we find the intersection of two sets: dependencies
# (prerequisites) and dependents (targets) of $(inlib_objs):
inlib_objs:= $(filter $(inlib_target_objs),$(shell $(DEPLIST) -t $(inlib_objs) -f $(deps)))

# The commented code below generates a warning message if the list of source
# files to be included into the inline library is automatically extended:
#
# inlib_extra_objs = $(filter-out $(inlib_SOURCES:.F90=.@OBJEXT@),$(inlib_objs))
# ifneq ($(inlib_extra_objs),)
# $(warning Additional files to be included into the inline library: $(inlib_extra_objs:.@OBJEXT@=.F90))
# endif

# Now we need to create a list of Fortran module files that must be created
# before any of the object files $(inlib_objs) gets generated. First, we need a
# subset of dependency files that correspond to $(inlib_objs):
inlib_deps:= $(inlib_objs:.@OBJEXT@=.F90.d)

# List of Fortran module files that at least on element of $(inlib_objs)
# depends on:
inlib_mods:= $(filter %.@FCMODEXT@.proxy,$(shell $(DEPLIST) -f $(inlib_deps)))

# List of Fortran modules declared in source files that correspond to
# $(inlib_objs):
inlib_internal_mods:= $(filter %.@FCMODEXT@.proxy,$(shell $(DEPLIST) -p $(inlib_objs) -f $(inlib_deps)))

# List of Fortran modules that must be created before the inline library:
inlib_prereq_mods:= $(filter-out $(inlib_internal_mods),$(inlib_mods))

endif # INLIB == 1

# Selective search path:
vpath %.F90 $(srcdir)

# Disable built-in suffix rules:
.SUFFIXES:
# Targets not associated with files:
.PHONY: all depend dummy-depend mostlyclean clean distclean \
        maintainer-clean install install-libs install-mods dist \
        check sanitize-mod-proxies
# Targets that do not need the inclusion of the dependency files:
NO_INC_TARGETS:= depend dummy-depend mostlyclean clean distclean \
                 maintainer-clean dist
# Keep directory stamps:
.PRECIOUS: $(dirstamps)

# Default rule:
all: $(lib_LIBRARIES)

# Explicit dependency generation rule:
depend: $(deps)

# Delete the results of compilation and linking:
mostlyclean: $(bundled_subdirs)
	rm -f $(lib_LIBRARIES) $(all_SOURCES:.F90=.@OBJEXT@)
	rm -f $(moddir)/*.@FCMODEXT@ $(moddir)/*.@FCMODEXT@.proxy
	rm -f $(notdir $(all_SOURCES:.F90=.i))
	test x'$(INLIB)' != x1 || rm -rf $(inlib_name)

# Delete files generated at the building stage:
clean: mostlyclean

# Delete everything generated at the configure stage (and clean the created directories if they are empty):
distclean: clean
	find . -name '*.pyc' -delete -o -name '*.pyo' -delete -o -name '__pycache__' -delete
	rm -f $(deps) $(dirstamps)
	@for dir in ifsaux ifsrrtm radiation utilities $(moddir); do \
	  if test -d "$$dir"; then \
	    echo "find '$$dir' -type d -empty -delete"; \
	    find "$$dir" -type d -empty -delete; \
	  fi; \
	done
	rm -f config.log config.status Makefile

# Delete files generated at the autoreconf stage:
maintainer-clean: distclean
	rm -rf autom4te.cache

# Installation rules:
install: all install-libs install-mods

# Check rule:
check: all

# Tarball creation rule:
dist:
	@if test ! -e @top_srcdir@/.git; then echo "'@top_srcdir@' is not a git repository" >&2; exit 1; fi
	$(GIT) -C @top_srcdir@ archive --prefix=$(PACKAGE_TARNAME)/ --format tar -o @abs_top_builddir@/$(PACKAGE_TARNAME).tar HEAD
	rm -f $(PACKAGE_TARNAME).tar.bz2 && BZIP2=$${BZIP2--9} $(BZIP2) $(PACKAGE_TARNAME).tar

ifeq ($(INLIB), 1)

# Pattern- and target-specific assignments are propagated to the prerequisites
# and override the global assignments. Therefore, we introduce the following
# match-anything pattern assignments to prevent that (the eval/value combination
# is required to keep the original global values of the variables without
# changing their flavors, i.e. keep them recursively expanded):
${eval %: silent_FC= $(value silent_FC)}
${eval %: FCFLAGS= $(value FCFLAGS)}

# Target-specific variables for objects that use the inline library:
$(inlib_target_objs): silent_FC= $(silent_FCIN)
$(inlib_target_objs): FCFLAGS+= $(inlib_inline_FCFLAGS)
$(inlib_limit_registers_OBJECTS): FCFLAGS+= $(inlib_limit_registers_FCFLAGS)

# All object that can be built with the inline library depend on it:
$(inlib_target_objs): $(inlib_name)

# The inline library generation rule. Note that the source files are provided
# to the compiler in the topological order. We also have to delete the partially
# generated library if the compiler fails:
$(inlib_name): $(inlib_prereq_mods) $(inlib_objs:.@OBJEXT@=.F90)
	$(silent_FCEX)rm -rf $@ && $(FC) $(FCFLAGS) $(inlib_extract_FCFLAGS) @FCFLAGS_F90@ $(filter-out $(inlib_prereq_mods),$^) || (ec=$$?; rm -rf $@; exit $$ec)

endif # INLIB == 1

# Fortran compilation rule:
%.@OBJEXT@: %.F90 | $(dirstamps)
	$(silent_FC)$(FC) -o $@ -c $(FCFLAGS) @FCFLAGS_F90@ $<

# Static library generation rule:
%.a:
	$(silent_AR)rm -f $@ && $(AR) $(ARFLAGS) $@ $^

# Fortran module file rule:
$(moddir)/%.@FCMODEXT@.proxy:| sanitize-mod-proxies
	@if test -z '$<'; then \
	  echo "Cannot find Fortran source file providing module '$(basename $(@F:.proxy=))'." >&2; \
	else \
	  if test ! -f '$(@:.proxy=)'; then rm -f '$<'; $(MAKE) '$<'; fi; \
	  if cmp '$@' '$(@:.proxy=)' >/dev/null 2>&1 || $(MODCMP) '$@' '$(@:.proxy=)' @FC_VENDOR@ 2>/dev/null; then :; \
	  else cp '$(@:.proxy=)' '$@' 2>/dev/null; fi; \
	fi

# Delete all Fortran module proxy files that do not have an existing module to
# be a proxy of, i.e. if <filename>.proxy exists but <filename> does not,
# delete <filename>.proxy:
sanitize-mod-proxies:
	@rm -f $(filter-out $(addsuffix .proxy,$(wildcard $(moddir)/*.@FCMODEXT@)),$(wildcard $(moddir)/*.@FCMODEXT@.proxy))

# Directory creation rule:
%/.dirstamp:
	$(silent_MKDIR)@MKDIR_P@ $(@D) && touch $@

# Fortran dependency generation rule:
%.F90.d: %.F90 Makefile | $(dirstamps)
	$(silent_DEPGEN)$(DEPGEN) -o $@ --obj-name $(@:.F90.d=.@OBJEXT@) -i $< -- $(FCFLAGS)

# Dummy dependency file generation rule (called by config.status): 
dummy-depend: | $(dirstamps)
	@for file in $(deps); do \
	  test -e "$$file" || touch "$$file"; \
	done

# Library installation rule:
install-libs: $(lib_LIBRARIES)
	$(INSTALL) -d $(DESTDIR)@libdir@ && $(INSTALL_DATA) $^ $(DESTDIR)@libdir@

# Fortran module files installation rule:
install-mods: $(filter %.@FCMODEXT@.proxy,$(shell $(DEPLIST) -f $(deps)))
	$(INSTALL) -d $(DESTDIR)@includedir@ && $(INSTALL_DATA) $(basename $^) $(DESTDIR)@includedir@

libifsaux.a: $(libifsaux_a_SOURCES:.F90=.@OBJEXT@)
libifsrrtm.a: $(libifsrrtm_a_SOURCES:.F90=.@OBJEXT@)
libradiation.a: $(libradiation_a_SOURCES:.F90=.@OBJEXT@)
libutilities.a: $(libutilities_a_SOURCES:.F90=.@OBJEXT@)

current_targets:= $(strip $(MAKECMDGOALS))
ifeq (,$(current_targets))
current_targets:= all
endif

ifneq (,$(filter-out $(NO_INC_TARGETS),$(current_targets)))
include $(deps)
endif
