## ==============================================================================
##
##     makefile for pTatin3d
##
## ==============================================================================

# The user should NOT edit this file.
#   Instead, place your custom configuration in makefile.arch

.SECONDEXPANSION:           # To expand $$(@D)/.DIR
.SUFFIXES:                  # Clear .SUFFIXES because we don't use implicit rules
.DELETE_ON_ERROR:           # Delete likely-corrupt target file if rule fails

# Include PETSc variables. Note that for prefix installs, $(PETSC_ARCH) should
#  be empty
include $(PETSC_DIR)/$(PETSC_ARCH)/lib/petsc/conf/petscvariables

all : info tests drivers save_config

# Compilation options are to be placed in makefile.arch;
# if that (untracked) file does not exist, defaults are copied there
makefile.arch:
	-@echo "[pTatin config] using config/makefile.arch.default as makefile.arch"
	-@cp config/makefile.arch.default $@
-include makefile.arch

# installation is into a local directory named $(PETSC_ARCH), or for prefix
#  installs when this value is empy, directly into the local directory.
#  Note that this implies that you cannot have two different prefix builds
#  in the same directory.
INSTALL_DIR = $(PWD)/$(PETSC_ARCH)

# Logic to copy makefile.arch to the $(INSTALL_DIR) directory for savekeeping
MAKEFILE_ARCH_SAVE_LOC=$(INSTALL_DIR)/makefile.arch.log
save_config: $(INSTALL_DIR)/.DIR makefile.arch
	@echo '############################################'    > $(MAKEFILE_ARCH_SAVE_LOC)
	@echo '# DO NOT EDIT THIS FILE - it is just a log #'   >> $(MAKEFILE_ARCH_SAVE_LOC)
	@echo '# To change your configuration, edit       #'   >> $(MAKEFILE_ARCH_SAVE_LOC)
	@echo '# makefile.arch, which will automatically  #'   >> $(MAKEFILE_ARCH_SAVE_LOC)
	@echo '# be copied here                           #'   >> $(MAKEFILE_ARCH_SAVE_LOC)
	@echo '############################################\n' >> $(MAKEFILE_ARCH_SAVE_LOC)
	@cat makefile.arch >> $(MAKEFILE_ARCH_SAVE_LOC)
.PHONY : save_config

OBJDIR    ?= $(INSTALL_DIR)/obj
LIBDIR    ?= $(INSTALL_DIR)/lib
BINDIR    ?= $(INSTALL_DIR)/bin
INCDIRGEN ?= $(INSTALL_DIR)/include_gen

# Configuration option defaults
CONFIG_SPMA      ?= n
CONFIG_FASTSCAPE ?= n

CONFIG_FORTRAN = y
CONFIG_CUDA ?= n
CONFIG_OPENCL ?= n

# Populate includes, libraries, and compiler flags
TATIN_INC := $(PETSC_CC_INCLUDES) -I$(INCDIRGEN) -I$(PWD)/include

ifeq ($(CONFIG_CUDA),y)
TATIN_CFLAGS += -DTATIN_HAVE_CUDA
TATIN_LIB += $(CUDA_LIB)
TATIN_INC += $(CUDA_INC)     #Note: This is usually set by NVCC automatically
endif

ifeq ($(CONFIG_OPENCL),y)
TATIN_CFLAGS += -DTATIN_HAVE_OPENCL
TATIN_LIB += $(OPENCL_LIB)
TATIN_INC += $(OPENCL_INC)
endif

# Directory that contains most recently-parsed makefile (current)
thisdir = $(addprefix $(dir $(lastword $(MAKEFILE_LIST))),$(1))
incsubdirs = $(addsuffix /local.mk,$(call thisdir,$(1)))

libptatin3d-y.c :=
libptatin3d-y.cu :=
libptatin3d-y.f :=
libptatin3dmodels-y.c :=
libptatin3dmodels-y.f :=
ptatin-tests-y.c :=
ptatin-drivers-y.c :=
ptatin-externals-y.o :=

# Recursively include files for all targets
include local.mk

#### Rules ####
ifeq ($(V),)
  quiet_HELP := "Use \"$(MAKE) V=1\" to see the verbose compile lines.\n"
  quiet = @printf $(quiet_HELP)$(eval quiet_HELP:=)"  %10s %s\n" "$1$2" "$@"; $($1)
else ifeq ($(V),0) # Same, but do not print any help
  quiet = @printf "  %10s %s\n" "$1$2" "$@"; $($1)
else # Show the full command line
  quiet = $($1)
endif

.PHONY: libptatin3d libptatin3dmodels externals tests drivers

libptatin3d = $(LIBDIR)/libptatin3d.$(AR_LIB_SUFFIX)
libptatin3d : $(libptatin3d)

$(libptatin3d) : $(libptatin3d-y.c:%.c=$(OBJDIR)/%.o) $(libptatin3d-y.cu:%.cu=$(OBJDIR)/%.o) $(libptatin3d-y.f:%.f90=$(OBJDIR)/%.o) $(ptatin-externals-y.o)

libptatin3dmodels = $(LIBDIR)/libptatin3dmodels.$(AR_LIB_SUFFIX)
libptatin3dmodels : $(libptatin3dmodels)
$(libptatin3dmodels) : $(libptatin3dmodels-y.c:%.c=$(OBJDIR)/%.o) $(libptatin3dmodels-y.f:%.f90=$(OBJDIR)/%.o)

info:
	-@echo "—————————————————————————————————————————————————————————————————"
	-@echo " pTatin3D"
	-@echo "    git url: https://bitbucket.org/ptatin/ptatin3d.git"
	-@echo "    update version information by running \"make releaseinfo\""
	-@echo "—————————————————————————————————————————————————————————————————"

releaseinfo: $(INCDIRGEN)/.DIR
	$(shell python utils/mgmt/ptatin3d-generate-git-info.py)
	$(shell mv ptatin_git_version_info.h  $(INCDIRGEN)/ptatin_git_version_info.h)
	-@touch include/ptatin_version_info.h
	-@echo "—————————————————————————————————————————————————————————————————————————————————————————————————————————————"
	-@echo "  Generated the file ptatin_git_version_info.h from: https://bitbucket.org/ptatin/ptatin3d.git"
	-@echo "  pTatin3D version info appears in: stdout; ptatin3d log files; generated PETSc summary/options files"
	-@echo "  Execute 'make all' to propagate the version information into your pTatin3D executables"
	-@echo "—————————————————————————————————————————————————————————————————————————————————————————————————————————————"

externals:
	-@echo ——————— EXTERNAL PACKAGE OBJECT FILES ———————
	-@echo $(ptatin-externals-y.o)
	-@echo ——————— EXTERNAL PACKAGE OBJECT INCLUDE PATH ———————
	-@echo $(TATIN_INC)
	-@echo ——————— EXTERNAL PACKAGE OBJECT CFLAGS ———————
	-@echo $(TATIN_CFLAGS)

ifeq ($(CONFIG_CUDA),n)
TEST_IGNORE:=$(TEST_IGNORE),cuda
TEST_IGNORE:=$(TEST_IGNORE),avx_cuda
endif
ifeq ($(CONFIG_OPENCL),n)
TEST_IGNORE:=$(TEST_IGNORE),opencl
endif

PTH_CONF_FILE=$(INSTALL_DIR)/pth.conf

test :
	cd tests && ./runTests.py -t $(shell ./tests/getTestGroup.py --smoke) -w $(PTH_CONF_FILE)
	-@echo "—————————————————————————————————————————————————————————————————————————————————————————————————————————————"
	-@echo "To check test results (after waiting, if on a batch system), use"
	-@echo "   make testcheck"
	-@echo "To run a larger set of tests, use "
	-@echo "   make testall"

testcheck :
	cd tests && ./runTests.py -t $(shell ./tests/getTestGroup.py --smoke) --verify -w $(PTH_CONF_FILE)

testall :
	cd tests && ./runTests.py -t $(shell ./tests/getTestGroup.py --skip=$(TEST_IGNORE)) -w $(PTH_CONF_FILE)
	-@echo "—————————————————————————————————————————————————————————————————————————————————————————————————————————————"
	-@echo "To check test results (after waiting, if on a batch system), use"
	-@echo "   make testallcheck"

testallcheck :
	cd tests && ./runTests.py --verify -t $(shell ./tests/getTestGroup.py --skip=$(TEST_IGNORE)) -w $(PTH_CONF_FILE)

testallclean :
	cd tests && ./runTests.py -p -w $(PTH_CONF_FILE)

.PHONY: test testall testallcheck testallclean

%.$(AR_LIB_SUFFIX) : | $$(@D)/.DIR
	$(call quiet,AR) $(AR_FLAGS) $@ $^
	$(call quiet,RANLIB) $@

ifeq ($(PETSC_LANGUAGE),CXXONLY)
  cc_name := CXX
else
  cc_name := CC
endif

# gcc/gfortran style dependency flags; these are set in petscvariables starting with petsc-3.5
C_DEPFLAGS ?= -MMD -MP
FC_DEPFLAGS ?= -MMD -MP

# GNU extensions flag
TATIN_CFLAGS_EXTENSIONS+=-D_GNU_SOURCE

TATIN_COMPILE.c = $(call quiet,$(cc_name)) -c $(PCC_FLAGS) $(CCPPFLAGS) $(TATIN_CFLAGS) $(TATIN_INC) $(CFLAGS) $(C_DEPFLAGS) $(TATIN_CFLAGS_EXTENSIONS)
TATIN_COMPILE.f90 = $(call quiet,FC) -c $(FC_FLAGS) $(FCPPFLAGS) $(TATIN_INC) $(FFLAGS) $(FC_DEPFLAGS)
TATIN_COMPILE.cu = $(CUDA_NVCC) -c -Xcompiler "$(PCC_FLAGS) $(CCPPFLAGS) $(TATIN_CFLAGS) $(TATIN_INC) $(CFLAGS) $(TATIN_CFLAGS_EXTENSIONS)"


# Test executables
tests: $(ptatin-tests-y.c:%.c=$(BINDIR)/%.app)
$(ptatin-tests-y.c:%.c=$(BINDIR)/%.app) : $(libptatin3dmodels) $(libptatin3d)
.SECONDARY: $(ptatin-tests-y.c:%.c=$(OBJDIR)/%.o) # don't delete the intermediate files


# Drivers
drivers: $(ptatin-drivers-y.c:%.c=$(BINDIR)/%.app)
$(ptatin-drivers-y.c:%.c=$(BINDIR)/%.app) : $(libptatin3dmodels) $(libptatin3d)
.SECONDARY: $(ptatin-drivers-y.c:%.c=$(OBJDIR)/%.o)

$(BINDIR)/%.app : $(OBJDIR)/%.o | $$(@D)/.DIR
	$(call quiet,PCC_LINKER) $(TATIN_CFLAGS) -o $@ $^ $(PETSC_SNES_LIB) $(TATIN_LIB)
#@mv $@ $(BINDIR)
	@ln -sf $(abspath $@) $(BINDIR)

$(OBJDIR)/%.o: %.c | $$(@D)/.DIR
	$(TATIN_COMPILE.c) $(abspath $<) -o $@

$(OBJDIR)/%.o: %.f90 | $$(@D)/.DIR
	$(TATIN_COMPILE.f90) $(abspath $<) -o $@

$(OBJDIR)/%.o: %.cu | $$(@D)/.DIR
	$(TATIN_COMPILE.cu) $(abspath $<) -o $@

%/.DIR :
	@mkdir -p $(@D)
	@touch $@

.PRECIOUS: %/.DIR

.PHONY: clean all print

clean:
	rm -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(INCGENDIR)

# make print VAR=the-variable
print:
	@echo $($(VAR))

srcs.c := $(libptatin3d-y.c) $(libptatin3dmodels-y.c) $(ptatin-tests-y.c) $(ptatin-drivers-y.c)
srcs.cu := $(libptatin3d-y.cu)
# Bundle in objects from external packages
%srcs.o := $(srcs.c:%.c=$(OBJDIR)/%.o) $(srcs.cu:%.cu=$(OBJDIR)/%.o)
srcs.o := $(srcs.c:%.c=$(OBJDIR)/%.o) $(srcs.cu:%.cu=$(OBJDIR)/%.o) $(ptatin-externals-y.o)
srcs.d := $(srcs.o:%.o=%.d)
# Tell make that srcs.d are all up to date.  Without this, the include
# below has quadratic complexity, taking more than one second for a
# do-nothing build of PETSc (much worse for larger projects)
$(srcs.d) : ;

-include $(srcs.d)
