####################################################
# Copyright 2010,2011,2012,2015,2019 Alois Schloegl
# This is part of the NaN-toolbox - a statistics and machine learning toolbox for data with and without missing values.
# http://pub.ist.ac.at/~schloegl/matlab/NaN/
####################################################
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA  02111-1307, USA.



### modify directories according to your needs

# Define non-default octave-version
# Octave - global install  (e.g. from debian package)
# OCTAVE_VERSION=
# Better alternative: define an OCTAVE_VERSION bash variable (or in .bashrc or .profile)
# OCTAVE_VERSION=-3.6.3

# Matlab configuration
#MATLABDIR = /usr/local/MATLAB/R2010b
# comment the following line if you use MATLAB on 32-bit operating system
#MEX_OPTION += -largeArrayDims
MEX_OPTION += -R2017b

# Mingw crosscompiler: available at http://www.nongnu.org/mingw-cross-env/
CROSS   = $(HOME)/src/mxe/usr/bin/i686-w64-mingw32.static-
CROSS64 = $(HOME)/src/mxe/usr/bin/x86_64-w64-mingw32.static-
# include directory for Win32-Matlab include
W32MAT_INC = $(HOME)/bin/win32/Matlab/R2010b/extern/include/
W64MAT_INC = $(HOME)/bin/win64/Matlab/R2010b/extern/include/
# path to GNUMEX libraries, available from here http://sourceforge.net/projects/gnumex/
GNUMEX   = $(HOME)/bin/win32/gnumex
GNUMEX64 = $(HOME)/bin/win64/gnumex
# building gnumex64 was difficult, these hints were quite useful:
# http://sourceforge.net/mailarchive/forum.php?thread_name=AANLkTinZvxgC9ezp2P3UCX_a7TAUYuVsp2U40MQUV6qr%40mail.gmail.com&forum_name=gnumex-users
# Instead of building "mex shortpath.c" and "mex uigetpath.c", I used empty m-functions within argout=argin;
####################################################
MKOCTFILE ?= mkoctfile$(OCTAVE_VERSION)
CC      ?= gcc
CXX     ?= g++
CFLAGS += -Wall -Wextra -Wconversion -O2
OCTMEX	= $(MKOCTFILE) --mex
RM      = rm


### in case libsvm is installed and should be used
# CFLAGS += -DHAVE_EXTERNAL_LIBSVM
### in case liblinear is installed and should be used
# CFLAGS += -DHAVE_EXTERNAL_LIBLINEAR


# Support Debian Hardening flags
# https://wiki.debian.org/HardeningWalkthrough#Handling_dpkg-buildflags_in_your_upstream_build_system
CFLAGS += $(CPPFLAGS)

ifeq ($(OS),Windows_NT)
  # CC need to be defined on Windows, see also http://savannah.gnu.org/bugs/?47559
  CC = gcc
else ifeq (Darwin,$(shell uname))
  # no OpenMP on MacOSX, neither for Matlab nor Octave
else
  # enable OpenMP support
  CFLAGS      += -fPIC -fopenmp
  OCTMEX      += -lgomp
  MATLABMEX  += -lgomp
  #MEX_OPTION  += CC\#$(CXX) CXX\#$(CXX) CFLAGS\#"$(CFLAGS) " CXXFLAGS\#"$(CFLAGS) "
endif

###REMOVE### MATMEX      = $(MATLABDIR)/bin/mex $(MEX_OPTION)

PROGS = histo_mex.mex covm_mex.mex kth_element.mex sumskipnan_mex.mex str2array.mex train.mex svmtrain_mex.mex svmpredict_mex.mex xptopen.mex

### per default only the mex-files for octave are built
mex4o octave: $(PROGS)


### Matlab configuration - search for a matlab directory if not defined above
ifeq (,$(MATLABDIR))
  ifneq (,$(shell ls -1 /usr/local/ |grep MATLAB))
    # use oldest, typically mex-files are compatible with newer Matlab versions
    MATLABDIR=/usr/local/MATLAB/$(shell ls -1rt /usr/local/MATLAB/  |grep "^R20*" |head -1)
  endif
endif


### if MATLABDIR has been found or defined
ifneq (,$(MATLABDIR))
  ifneq (,$(shell ls -1 $(MATLABDIR)/bin/mexext))
    MEX_EXT=$(shell $(MATLABDIR)/bin/mexext)
    mex4m matlab: $(patsubst %.mex, %.$(MEX_EXT), $(PROGS))
  endif
endif


mexw32 win32:  $(patsubst %.mex, %.mexw32, $(PROGS))
mexw64 win64:  $(patsubst %.mex, %.mexw64, $(PROGS))
all:    octave win32 win64 mex4m

clean:
	-$(RM) *.o *.obj *.o64 core octave-core *.oct *~ *.mex*

#$(PROGS): Makefile


#########################################################
#       Matlab 2016b and later
#########################################################
# https://se.mathworks.com/matlabcentral/answers/377799-compiling-mex-files-without-the-mex-command
DEFINES   := -D_GNU_SOURCE
MATLABMEX := -DMATLAB_MEX_FILE
# Matrix APIs:
# -DMX_COMPAT_32: compatibleArrayDims
# -DMATLAB_DEFAULT_RELEASE=R2017b: largeArrayDims
# -DMATLAB_DEFAULT_RELEASE=R2018a: Interleaved Complex
MATLABMEX += -DMATLAB_DEFAULT_RELEASE=R2017b

CFLAGS += -fexceptions -fPIC -fno-omit-frame-pointer -pthread
COPTIMFLAGS := -O -DNDEBUG
CDEBUGFLAGS := -g
INCLUDE := -I"$(MWROOT)/extern/include" -I"$(MWROOT)/simulink/include"
LD := gcc
LDFLAGS += -pthread
LDTYPE := -shared
LINKEXPORTVER := -Wl,--version-script,"$(MWROOT)/extern/lib/glnxa64/c_exportsmexfileversion.map"
LINKLIBS := -Wl,--as-needed -Wl,-rpath-link,$(MWROOT)/bin/glnxa64 -L"$(MWROOT)/bin/glnxa64" -Wl,-rpath-link,$(MWROOT)/extern/bin/glnxa64 -L"$(MWROOT)/extern/bin/glnxa64" -lmx -lmex     -lmat -lm -lstdc++
BLAS_LIBS := $(shell $(MKOCTFILE) -p BLAS_LIBS)


c_mexapi_version.o : $(MWROOT)/extern/version/c_mexapi_version.c Makefile
	$(CC) -c $< -o $@ $(MATLABMEX) $(DEFINES) $(CFLAGS) $(COPTIMFLAGS) $(INCLUDE)
%.$(MEX_EXT) : %.o c_mexapi_version.o
	$(LD) $(LDFLAGS) $(LDTYPE) $(LINKEXPORTVER) $< $(LINKLIBS) -o $@
%.o : %.cpp Makefile
	$(CC) -c $< -o $@ $(MATLABMEX) $(DEFINES) $(CFLAGS) $(COPTIMFLAGS) $(INCLUDE)
%.o : %.c Makefile
	$(CC) -c $< -o $@ $(MATLABMEX) $(DEFINES) $(CFLAGS) $(COPTIMFLAGS) $(INCLUDE)
train.o : train.c tron.cpp Makefile
	$(CC) -c $< -o $@ $(MATLABMEX) $(DEFINES) $(CFLAGS) $(COPTIMFLAGS) $(INCLUDE)
svm%_mex.$(MEX_EXT) : svm%_mex.o svm.o svm_model_matlab.o c_mexapi_version.o
	$(LD) $(LDFLAGS) $(LDTYPE) $(LINKEXPORTVER) $^ $(LINKLIBS) -o $@


#########################################################
#	Octave, MATLAB on Linux
#########################################################
ifneq (,)
svm%_mex.mex: svm%_mex.cpp svm_model_octave.o
	$(OCTMEX) $(CFLAGS) $< svm_model_octave.o -lsvm -o $@
else
svm.o: svm.cpp
	$(CC) $(CFLAGS) -c svm.cpp
svm%_mex.mex: svm%_mex.cpp svm_model_octave.o svm.o
	$(OCTMEX) $^ -o $@
endif

svm_model_octave.o: svm_model_matlab.c
	$(MKOCTFILE) -o "$@" -c "$<"
svm_model_matlab.o: svm_model_matlab.c
	$(CXX) $(CFLAGS) -I $(MATLABDIR)/extern/include -o "$@" -c "$<"

ifneq (,)
train.$(MEX_EXT) predict.$(MEX_EXT): train.c tron.o linear_model_matlab.c
	$(CXX) $(CFLAGS) -I $(MATLABDIR)/extern/include -c linear_model_matlab.c
	$(MATMEX)  -lblas train.c tron.o -llinear linear_model_matlab.o
	#$(MATMEX) -lblas predict.c tron.o linear.o linear_model_matlab.o
train.mex predict.mex: train.c tron.o linear_model_matlab.c
	$(OCTMEX) $(BLAS_LIBS) train.c tron.o -llinear linear_model_matlab.c
else
train.$(MEX_EXT) predict.$(MEX_EXT): train.c tron.o linear.o linear_model_matlab.c
	$(CXX) $(CFLAGS) -I $(MATLABDIR)/extern/include -c linear_model_matlab.c
	$(MATMEX)  -lblas train.c tron.o linear.o linear_model_matlab.o
	#$(MATMEX) -lblas predict.c tron.o linear.o linear_model_matlab.o
train.mex predict.mex: train.c tron.o linear.o linear_model_matlab.c
	$(OCTMEX) $(BLAS_LIBS) train.c tron.o linear.o linear_model_matlab.c
linear.o: linear.cpp
	$(CXX) $(CFLAGS) -c linear.cpp
endif
tron.o: tron.cpp tron.h
	$(CXX) $(CFLAGS) -c tron.cpp

%.oct: %.cc
	mkoctfile$(OCTAVE_VERSION) "$<"

%.mex: %.cpp
	$(OCTMEX) "$<"


ifneq (,@HAVE_EXTERNAL_LIBTENSORFLOW@)
PROGS += mexTF

mexTF.mex: mexTF.c
	mkoctfile -mex $< -ltensorflow -o $@

mexTF.$(MEX_EXT): mexTF.c
	$(MATMEX) $< -ltensorflow -o $@

endif

#########################################################
#	MATLAB/WIN32
#########################################################
%.obj: %.cpp
	$(CROSS)$(CXX) -fopenmp -c -DMATLAB_MEX_FILE -x c++ -o "$@" -I$(W32MAT_INC) -O2 -DMX_COMPAT_32 "$<"
%.obj: %.c
	$(CROSS)$(CXX) -fopenmp -c -DMATLAB_MEX_FILE -x c++ -o "$@" -I$(W32MAT_INC) -O2 -DMX_COMPAT_32 "$<"

train.mexw32 predict.mexw32:  train.obj linear.obj linear_model_matlab.obj tron.obj
	$(CROSS)$(CXX) -shared $(GNUMEX)/mex.def -o "$@" -L$(GNUMEX) -s "$<" linear_model_matlab.obj linear.obj tron.obj -llibmx -llibmex -llibmat -lblas

svmpredict_mex.mexw32 :  svmpredict_mex.obj svm.obj svm_model_matlab.obj
	$(CROSS)$(CXX) -shared $(GNUMEX)/mex.def -o "$@" -L$(GNUMEX) -s "$<" svm_model_matlab.obj svm.obj -llibmx -llibmex -llibmat
svmtrain_mex.mexw32 : svmtrain_mex.obj svm.obj svm_model_matlab.obj
	$(CROSS)$(CXX) -shared $(GNUMEX)/mex.def -o "$@" -L$(GNUMEX) -s "$<" svm_model_matlab.obj svm.obj -llibmx -llibmex -llibmat

%.mexw32: %.obj
	$(CROSS)$(CXX) -shared $(GNUMEX)/mex.def -o "$@" -L$(GNUMEX) -s "$<" -llibmx -llibmex -llibmat -lgomp -lpthread


#########################################################
#	MATLAB/WIN64
#########################################################

## ToDO: fix OpenMP support: currently -fopenmp causes Matlab to crash
%.o64: %.cpp
	$(CROSS64)$(CXX) -c -DMATLAB_MEX_FILE -x c++ -o "$@" -I$(W64MAT_INC) -O2 "$<"
%.o64: %.c
	$(CROSS64)$(CXX) -c -DMATLAB_MEX_FILE -x c++ -o "$@" -I$(W64MAT_INC) -O2 "$<"

train.mexw64 predict.mexw64:  train.o64 linear.o64 linear_model_matlab.o64 tron.o64
	$(CROSS64)$(CXX) -shared $(GNUMEX64)/mex.def -o "$@" -L$(GNUMEX64) -s "$<" linear_model_matlab.o64 linear.o64 tron.o64 -llibmx -llibmex -llibmat -lblas

svmpredict_mex.mexw64 :  svmpredict_mex.o64 svm.o64 svm_model_matlab.o64
	$(CROSS64)$(CXX) -shared $(GNUMEX64)/mex.def -o "$@" -L$(GNUMEX64) -s "$<" svm_model_matlab.o64 svm.o64 -llibmx -llibmex -llibmat
svmtrain_mex.mexw64 : svmtrain_mex.o64 svm.o64 svm_model_matlab.o64
	$(CROSS64)$(CXX) -shared $(GNUMEX64)/mex.def -o "$@" -L$(GNUMEX64) -s "$<" svm_model_matlab.o64 svm.o64 -llibmx -llibmex -llibmat

%.mexw64: %.o64
	$(CROSS64)$(CXX) -shared $(GNUMEX64)/mex.def -o "$@" -L$(GNUMEX64) -s "$<" -llibmx -llibmex -llibmat -lgomp -lpthread

