.SUFFIXES: .F90 .o

extension = .F90

# Need CVMix root directory
# If using old version of make, pass in CVMIX_ROOT
ifeq ($(wildcard $(MAKEFILE_LIST)),)
  CVMIX_ROOT = ..
else
  ThisMakefile=$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
  ifeq (/,$(findstring /,$(ThisMakefile)))
    ThisDir=$(shell x=$(ThisMakefile) && echo $${x%/*})/
  endif
  CVMIX_ROOT = $(realpath $(ThisDir)..)
  # Note: gmake does not handle pathnames with spaces in them. If the absolute
  #       path contains a space in it, create a link without spaces and pass
  #       CVMIX_ROOT in when you run make
endif

# Directories needed by Makefile
LIB_DIR = $(CVMIX_ROOT)/lib
INC_DIR = $(CVMIX_ROOT)/include
BLD_DIR = $(CVMIX_ROOT)/bld
OBJ_DIR = $(BLD_DIR)/obj
SRC_DIR = $(CVMIX_ROOT)/src
SRC_DRIVE_DIR = $(SRC_DIR)/drivers
SRC_SHARED_DIR = $(SRC_DIR)/shared

# Name of executable
EXE = $(CVMIX_ROOT)/bin/cvmix

# File containing information about compiler (generated by $BLD_DIR/cvmix_setup)
ENV_FILE = $(BLD_DIR)/.CVMix_env

# File containing information about whether or not the last build linked to
# netCDF (see below for more details)
INFO_FILE = $(BLD_DIR)/.netcdf_info

ifeq ($(wildcard $(ENV_FILE)),)
  NEED_ENV_FILE = TRUE
else
  NEED_ENV_FILE = FALSE
  include $(ENV_FILE)
  SHR_FLAGS = FC=$(FC) FCFLAGS="$(FCFLAGS)" SRC_DIR=$(SRC_SHARED_DIR)         \
              OBJ_DIR=$(OBJ_DIR) LIB_DIR=$(LIB_DIR) INC_DIR=$(INC_DIR)        \
              UCASE=$(UCASE)
endif

# update FCFLAGS based on compiler
include $(BLD_DIR)/CompileFlags.mak
LINKING_FLAGS = -L$(LIB_DIR) -lcvmix

# Dependency generation
MAKE_DEP = $(SRC_SHARED_DIR)/makedep.py
DEP_FILE = $(OBJ_DIR)/standalone_deps.d

# If you build without netCDF and then decide you want to build with netCDF (or
# vice versa), you need to clean the cvmix_io and cvmix_driver object files.
# The way this is handled is by storing whether the last compilation used netCDF
# or not in the hidden file .netcdf_info; whether the current built is using
# netCDF or not is stored in the variable NEW_NETCDF while the contents of
# .netcdf_info is stored in the variable OLD_NETCDF. The target "check" compares
# these two variables and deletes the necessary object and module files  if they
# differ. If the file doesn't exist, the two variables are equal.
ifeq ($(USE_NETCDF),TRUE)
  ifeq ($(FC),xlf90)
    FCFLAGS += -WF,-D_NETCDF
  else
    FCFLAGS += -D_NETCDF
  endif
  ifeq ($(wildcard $(NETCDF_BIN)/nc-config),)
    # If $(NETCDF_BIN)/nc-config exists, we will use it to determine both the
    # compile flags and linking flags needed, otherwise we depend on the
    # directories $(NETCDF_INC) and $(NETCDF_LIB)
    FCFLAGS += -I$(NETCDF_INC)
    # Check for netcdf4 library
    ifeq ($(wildcard $(NETCDF_LIB)/libnetcdff.a),)
      LINKING_FLAGS += -L$(NETCDF_LIB) -lnetcdf
    else
      # with netcdf4, need to know whether to include hdf5 or not
      # That comes from either $(NETCDF_BIN)/nc-config or from
      # $(NETCDF_LIB)/pkgconfig/netcdf.pc
      # (Note: some distributions now have netcdf-fortran.pc in addition to
      # netcdf.pc... so check for netcdf-fortran.pc first)
      NETCDF_PC = $(NETCDF_LIB)/pkgconfig/netcdf-fortran.pc
      ifeq ($(wildcard $(NETCDF_PC)),)
        NETCDF_PC = $(NETCDF_LIB)/pkgconfig/netcdf.pc
      endif
      ifeq ($(wildcard $(NETCDF_PC)),)
        LINKING_FLAGS += -L$(NETCDF_LIB) -lnetcdff -lnetcdf
      else
        # get flibs from netcdf.pc
        FLIBS = $(subst flibs=,,$(shell grep flibs $(NETCDF_PC)))
        # Workaround for yellowstone, I need to figure out where this
        # @NC_FLIBS@ comes from
        ifeq ($(FLIBS),@NC_FLIBS@)
          FLIBS = -lnetcdf
        endif
        LINKING_FLAGS += -L$(NETCDF_LIB) $(FLIBS)
      endif
    endif
  else
    LINKING_FLAGS += $(shell $(NETCDF_BIN)/nc-config --flibs)
    FCFLAGS += -I$(shell $(NETCDF_BIN)/nc-config --includedir)
  endif
  NEW_NETCDF = YES
else
  NEW_NETCDF = NO
endif

# Need to include cvmix_kinds_and_types.mod from include (not from bld/obj)
FCFLAGS += -I$(INC_DIR)

ifneq ($(wildcard $(INFO_FILE)),)
  OLD_NETCDF = $(shell cat $(INFO_FILE))
else
  OLD_NETCDF = $(NEW_NETCDF)
endif

ifneq ($(OLD_NETCDF), $(NEW_NETCDF))
  REBUILD = TRUE
endif

# Dependencies: all drivers use cvmix_io
# Note that these are separated
OBJS = cvmix_driver.o \
       cvmix_io.o
DRIVER_OBJS = cvmix_bgrnd_BL.o      \
              cvmix_shear_drv.o     \
              cvmix_tidal_Simmons.o \
              cvmix_ddiff_drv.o     \
              cvmix_kpp_drv.o
ifeq ($(UCASE),TRUE)
  MODS_TMP = $(shell echo $(OBJS) | tr '[a-z]' '[A-Z]')
  MODS = ${MODS_TMP:.O=.mod}
else
  MODS = ${OBJS:.o=.mod}
endif

ifeq ($(USE_DEPS),TRUE)
  include $(DEP_FILE)
endif

### TARGETS ###

all: exe

$(EXE): $(addprefix $(OBJ_DIR)/,$(OBJS) $(DRIVER_OBJS))        \
        $(LIB_DIR)/libcvmix.a
	$(FC) -o $(EXE) $(addprefix $(OBJ_DIR)/,$(OBJS) $(DRIVER_OBJS)) $(LINKING_FLAGS)

# Create all object and module files
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.F90
	$(FC) $(FCFLAGS) -c $< -o $@

$(OBJ_DIR)/%.o: $(SRC_DRIVE_DIR)/%.F90
	$(FC) $(FCFLAGS) -c $< -o $@

# Dependencies are read in from standalone_deps.d
$(DEP_FILE): $(MAKE_DEP) $(SRC_DIR)/*.F90 $(SRC_DRIVE_DIR)/*.F90
	$(MAKE_DEP) $(DEP_FILE) $(OBJ_DIR) $(SRC_DIR) $(SRC_DRIVE_DIR) $(INC_DIR)
	@echo "Generated dependencies!"

# The variables FC, NETCDF_INC, NETCDF_LIB, and NETCDF_LINK are read in from
# CVMix_env. If the file doesn't exist, then the python script "cvmix_setup"
# is run to generate the file.
$(ENV_FILE):
	@(cd $(BLD_DIR); ./cvmix_setup $(SETUP_ARGS))
	$(MAKE) -f $(SRC_DIR)/Makefile

.PHONY: exe netcdf depends check lib remove_exe clean libclean allclean       \
        distclean

# Possible executables: with and without netCDF
exe: check $(ENV_FILE) lib depends
# If NEED_ENV_FILE is TRUE, the check target recursively calls make
# With NEED_ENV_FILE equal to FALSE, so the executable will be built
ifeq ($(NEED_ENV_FILE),FALSE)
	cd $(SRC_DIR); $(MAKE) $(EXE) USE_DEPS=TRUE
	$(shell echo $(NEW_NETCDF) > $(INFO_FILE))
endif

netcdf:
	$(MAKE) -f $(SRC_DIR)/Makefile USE_NETCDF=TRUE

# Shorthand for making dependency file
depends: $(DEP_FILE)

# Determine if output needs to be rebuilt with or without netcdf
check:
	$(if $(REBUILD), rm -f $(addprefix $(OBJ_DIR)/,cvmix_io.o $(DRIVER_OBJS)))

lib: $(ENV_FILE)
# For some reason, changing the way $(ENV_FILE) is build made it necessary
# to only call this when NEED_ENV_FILE is FALSE
ifeq ($(NEED_ENV_FILE),FALSE)
	$(MAKE) -f $(SRC_SHARED_DIR)/Makefile $(SHR_FLAGS)
endif

# Delete the executable
remove_exe:
	/bin/rm -rf $(EXE)

# Delete object and module files, as well as the dependency file
# Also deletes the executable
clean: remove_exe
	/bin/rm -rf $(INFO_FILE) $(DEP_FILE)                                \
              $(addprefix $(OBJ_DIR)/,$(MODS) $(OBJS) $(DRIVER_OBJS))

# Delete all object and module files from the shared directory, as well as
# libcvmix.a
libclean:
	$(MAKE) -f $(SRC_SHARED_DIR)/Makefile clean SRC_DIR=$(SRC_SHARED_DIR)       \
              OBJ_DIR=$(OBJ_DIR) LIB_DIR=$(LIB_DIR) INC_DIR=$(INC_DIR)        \
              UCASE=TRUE
	$(MAKE) -f $(SRC_SHARED_DIR)/Makefile clean SRC_DIR=$(SRC_SHARED_DIR)       \
              OBJ_DIR=$(OBJ_DIR) LIB_DIR=$(LIB_DIR) INC_DIR=$(INC_DIR)        \
              UCASE=FALSE

allclean:
	$(MAKE) -f $(SRC_DIR)/Makefile libclean
	$(MAKE) -f $(SRC_DIR)/Makefile clean UCASE=TRUE
	$(MAKE) -f $(SRC_DIR)/Makefile clean UCASE=FALSE

# Deletes $(ENV_FILE) in addition to everything else
distclean:
	$(MAKE) -f $(SRC_DIR)/Makefile allclean
	/bin/rm -rf $(ENV_FILE)
