# Makefile for MEQ
# Must be run from meq directory
#
# To choose a particular version of MATLAB/MEX
#   define either the MATPATH or MATLAB variable
#   to point to the root of your MATLAB installation
#   i.e. $(MATPATH)/bin/matlab should exist
#
# [+MEQ MatlabEQuilibrium Toolbox+] Swiss Plasma Center EPFL Lausanne 2022. All rights reserved.

# Set up MATLAB-related path
include genlib/mexargs/Makefile.mex
# Export some variables for reuse in genlib's Makefile
export CC MATPATH

# Phony targets
.PHONY: clean clear csf mex lib librt ld rt scd all tbx genlib doc pub

all-nort: tbx doc csf

all: all-nort rt

tbx: lib mex genlib

rt: librt rtwmakecfg.m ld

doc: pub

MEQROOT :=$(shell pwd)
BLASLIB ?=
# Default is to link to MATLAB's mwblas and mwlapack.
# alternatively: BLASLIB=MKL links to Intel's MKL, BLASLIB=CBLAS links to CBLAS/LAPACKE

# Include OS-specific Makefile, if exists.
ifneq (,$(wildcard Makefile.$(OS)))
include Makefile.$(OS)
endif

# Type of build
BUILD?=optimized
ifeq ($(BUILD),$(filter-out optimized debug,$(BUILD)))
  $(error Possible values for BUILD are optimized and debug, received BUILD="$(BUILD)")
endif

CC        =icc
CCRT      =icc

ifeq ($(BUILD),optimized)
  CFLAGS    +=-O3
else ifeq ($(BUILD),debug)
  CFLAGS    +=-g -O0 -DDEBUG
  MEXOPTIONS+=-g
endif
CFLAGS   +=-std=c99 -fPIC $(SYSROOT)
CFLAGSRT +=-std=c99 -DMKL -fPIC -O2 $(SYSROOT)
ifeq ($(CCRT),icc)
  CFLAGSRT +=-axAVX
else
  CFLAGSRT +=-mavx
endif
MEX_CFLAGS+=-std=c99 -fPIC -I. $(MEX_CFLAGS_HOST)

MEXBLD    =$(MEXCMD) $(MEXOPTIONS)

ifeq ($(BLASLIB),CBLAS)
  # CBLAS/LAPACKE (does not have vector mathematics - use private library vblas)
  LINKLINE=libmeq.a libv/libvblas.a ${LAPACKLIBS} ${CBLASLIBS} 
  CFLAGS+=-DCBLAS ${LAPACKCFLAGS} ${CBLASCFLAGS} -Ilibv
  MEX_CFLAGS+=-DCBLAS ${LAPACKCFLAGS} ${CBLASCFLAGS} -Ilibv
  ifeq ($(CC),gcc)
    # gcc math library
    LINKLINE+=-lm
  endif
  LIBTARGETS+=libv/libvblas.a
  LIBRTTARGETS+=libv/libvblas.a
else ifeq ($(BLASLIB),MKL)
  # Intel MKL
  CFLAGS+=-DMKL
  MEX_CFLAGS+=-DMKL
else
  # MATLAB mwblas/mwlapack (does not have vector mathematics - use private library vblas)
  LINKLINE+=libmeq.a libv/libvblas.a libmatmkl.a -lmwblas -lmwlapack
  CFLAGS+=-Ilibv -Imatmkl -I$(MATPATH)/extern/include
  MEX_CFLAGS+=-Ilibv -Imatmkl
  LIBTARGETS+=libv/libvblas.a libmatmkl.a
  LIBRTTARGETS+=libv/libvblas.a libmatmkl.a
endif

SUBDIRS=csfc obj

## RECIPES

# genlib
genlib:
	$(MAKE) -C genlib

# lib
LIB      =gszr nfdb asxy bavx fbnd pdom bbox iata uata fl4p resp bf3p bf3i bfef bfpr fsgi vizr bslv rtci ipm1 ipm2 ipmh ipmj wclk shap asgn locQ minQ qint bint
LIBSRC   =$(LIB:%=libmeq/%.c)
LIBOBJ   =$(LIB:%=obj/d%.o  ) $(LIB:%=obj/s%.o  )
LIBOBJRT =$(LIB:%=obj/d%rt.o) $(LIB:%=obj/s%rt.o)
LIBV     =vblas
LIBVOBJ  =$(LIBV:%=obj/d%.o  ) $(LIBV:%=obj/s%.o  )
LIBM     =axpy copy dot gemv spmv gemm syrk pptrf pptrs sysv
LIBMOBJ  =$(LIBM:%=obj/d%.o  ) $(LIBM:%=obj/s%.o  )
meq.h: mkmeqh.m meqh.h $(LIBSRC)
	$(MATCMD) "try, mkmeqh('$(LIB)');exit(0); catch ME, disp(getReport(ME));exit(1); end"
obj/d%.o:libmeq/%.c meq.h | obj
	$(CC) -c $< -o $@ -I. $(CFLAGS)
obj/s%.o:libmeq/%.c meq.h | obj
	$(CC) -c $< -o $@ -I. $(CFLAGS) -DSINGLE
obj/d%rt.o:libmeq/%.c meq.h | obj
	$(CCRT) -c $< -o $@ -I. $(CFLAGSRT)
obj/s%rt.o:libmeq/%.c meq.h | obj
	$(CCRT) -c $< -o $@ -I. $(CFLAGSRT) -DSINGLE

obj/d%.o:libv/%.c | obj
	$(CC) -c $< -o $@ -I. $(CFLAGS)
obj/s%.o:libv/%.c | obj
	$(CC) -c $< -o $@ -I. $(CFLAGS) -DSINGLE

obj/d%.o:matmkl/%.c meqh.h | obj
	$(CC) -c $< -o $@ -I. $(CFLAGS)
obj/s%.o:matmkl/%.c meqh.h | obj
	$(CC) -c $< -o $@ -I. $(CFLAGS) -DSINGLE

libmeq.a: $(LIBOBJ)
libmeqrt.a: $(LIBOBJRT)
libv/libvblas.a:$(LIBVOBJ)
libmatmkl.a:$(LIBMOBJ)
%.a:
	ar rs $@ $^

LIBTARGETS   += libmeq.a 
LIBRTTARGETS += libmeqrt.a

lib: $(LIBTARGETS)
librt: $(LIBRTTARGETS)

# ld - Matlab 8.3 mex command refuses .ld extension but pass to ld .lib files
MKLLIBGRP   =libmkl_intel_lp64.a libmkl_intel_thread.a libmkl_core.a
ifdef MKLLIBGRPRT32
MKLLIBGRPRT =libmkl_intel.a      libmkl_sequential.a   libmkl_core.a
else
MKLLIBGRPRT =libmkl_intel_lp64.a libmkl_sequential.a   libmkl_core.a
endif

meqld.lib: meqld.lib.m4
	m4 --define MEQROOT="$(MEQROOT)" --define MKLLIBGRP="$(MKLLIBGRP)" $^ > $@
meqldrt.lib: meqld.lib.m4
	m4 --define MEQROOT="$(MEQROOT)" --define MKLLIBGRP="$(MKLLIBGRPRT)" --define RT $^ > $@
ld: meqld.lib meqldrt.lib

# mex
MEX    =gszr nfdb asxy bavx fbnd pdom iata uata fl4p resp bbox bf3p bf3i bfef bfpr bfab vizr bslv rtci fsgi chol ipm1 ipm2 ipmh ipmj shap locS locR minQ qint bint
MEXSRC =$(MEX:%=mexc/%mex.c)
MEXMEX =$(MEX:%=%mex.$(MEXEXT))
$(MEXMEX): $(LIBTARGETS)
%.$(MEXEXT):mexc/%.c
	$(MEXBLD) -output $@ $< $(LINKLINE) 
mex: $(MEXMEX)

# publish documentation
pub: tbx
	$(subst -r,-batch,$(MATCMD)) "run('documentation/publish_documentation.m');"

# csf
CSFSMKL =vvuv vinv vdivuv mdivuv mvunv mvutv mmunvn mmutvn mmunvt minv
CSFDMKL =mvunv mmunvn mmunvt
CSFSMEQ =gszr nfdb asxy bavx bavx2 fbnd fl4p pdom bbox bf3p1 bf3p3 bf3p6 bf3p8 bf3i1 bf3i2 bf3i3 bf3i4 bf3i6 bfef1 bfef3 bfef6 bfpr resp bslv iata rtci rtci1 fsgi vizr ipmh ipmj wclk shap asgn locS locR minQ qint bint
CSFSSRC =$(CSFSMKL:%=csfc/s%csf.c) $(CSFSMEQ:%=csfc/s%csf.c)
CSFSMEX =$(CSFSMKL:%=s%csf.$(MEXEXT)) $(CSFSMEQ:%=s%csf.$(MEXEXT))

CSFDMEQ =bslv iata ipmh ipmj
CSFDSRC =$(CSFDMKL:%=csfc/d%csf.c) $(CSFDMEQ:%=csfc/d%csf.c)
CSFDMEX =$(CSFDMKL:%=d%csf.$(MEXEXT)) $(CSFDMEQ:%=d%csf.$(MEXEXT))

$(CSFSMEX): $(LIBTARGETS)
$(CSFDMEX): $(LIBTARGETS)

# Only a pattern rule with one input and multiple outputs is correctly handled by make (including parallel builds)
CSFPAT :=$(CSFSMKL:%=csfc/s%%.c) $(CSFSMEQ:%=csfc/s%%.c) $(CSFDMKL:%=csfc/d%%.c) $(CSFDMEQ:%=csfc/d%%.c)
# But the first file becomes an intermediate file, so it needs to be protected against deletion
.SECONDARY: $(CSFSSRC) $(CSFDSRC)
$(CSFPAT) rtwmakecfg_%.m: mk%.m | csfc
	$(MATCMD) "try, mkcsf;exit(0); catch ME, disp(getReport(ME));exit(1); end"

.INTERMEDIATE: rtwmakecfg_csf.m
rtwmakecfg.m: rtwmakecfg_csf.m
	mv $^ $@

%.$(MEXEXT):csfc/%.c
	$(MEXBLD) -output $@ $< $(LINKLINE)
csf: $(CSFSMEX) $(CSFDMEX)

$(SUBDIRS):
	mkdir -p $@

clean: 
	$(RM) obj/*.o *.a *.lib
clear: 
	$(RM) -r lib*.a meq.h $(SUBDIRS) *.mex* *.tlc *.lib libv/libvblas.a rtwmakecfg.m
	$(MAKE) -C genlib clean
	find html -mindepth 1 -not -name 'helptoc.xml' -delete

