#*******************************************************************************
# E.S.O. - VLT project
#
# "@(#) $Id: vtactmtlbMakefile 345204 2021-08-06 08:48:12Z gzins $"
#
# who       when        what
# --------  ----------  ----------------------------------------------
# gzins     2021-08-06  created from spartaMakefile implemented by crosenqu
#
#*******************************************************************************
# This Makefile follows VLT Standards (see Makefile(5) for more).
#*******************************************************************************
# NAME
# vtactmtlbMakefile - makefile for Matlab routine compilation
# 
# DESCRIPTION
#
# Variables
# GET_ROOT  	   Macro that expands a path to INTROOT, VLTROOT or empty if
# 	           path is not found in either.
#
# MATLAB
# ------
#
# MATLAB_EXECUTABLES List of MATLAB executable targets to create.
# MATLAB_LIBRARIES   List of MATLAB library targets to create.
# Each MATLAB target <t> listed as executable or library must then be further 
# defined with
#
# <t>_MFILES   List of MATLAB source files.
# <t>_CFLAGS   [Optional] mcc compiler options, e.g. -I <path>.
#
# MATLAB_CFLAGS  Common mcc flags for added to all MATLAB executables
# and libraries.
#
# MATLAB_PKG     Name of the archive package used with "matlab-pack" and 
# "matlab-unpack" targets, default is "matlab-$(VLTSW_RELEASE).tar.gz".
#
# MAKE_WITH_MATLAB      Set to non-empty value to build MATLAB targets from 
#                       MATLAB in which case the license will be released 
#                       immediately after compilation.
#
# This Makefile takes care of 
#     - Building the targets (accessible via the "matlab" target)
#     - Creating "matlab-pack" target that compresses the MATLAB targets for
#       binary distribution.
#     - Creating "matlab-unpack" target that unpacks the previously created
#       MATLAB targets.
#     - Add dependencies so that unpack is performed with "all" target.
#     - Install/uninstall via standard "install"/"uninstall" targets.
#     - Cleaning up.
#
# Targets
#
# matlab         Pseudo target that builds all MATLAB exeuctables and libraries.
# matlab-pack    Pseudo target that builds (if needed) and packs MATLAB targets.
# matlab-unpack  Pseudo target that unpacks MATLAB targets.
#
#
# REMARKS
#    None
#------------------------------------------------------------------------
ifdef __ACSMAKEFILE__
  $(error "vltMakefile (acsMakefile) has already been included.")
endif
ifdef __VISTAMAKEFILE__
  $(error "vtactmtlbMakefile has already been included.")
endif

__VISTAMAKEFILE__:=__VISTAMAKEFILE__

# RELEASE_ARCH is set to '64' or 'mixed' based on the 
# $VLTSW_RELEASE variable.
RELEASE_ARCH := $(shell [ `echo "$(VLTSW_RELEASE)" | grep -o "[0-9]\+"` -ge 2015 ] && echo 64 || echo mixed)


# Macro that automatically selects between INTROOT or VLTROOT based
# on if the argument path exists there or not.
# Args:
#   $1: Path relative to directories listed in $2
#   $2: Optional: Directories to try, defaults to "$INTROOT $VLTROOT".
#   $3: Optional: Value to return if nothing is found, defaults to
#       GET_ROOT-ERROR-NOT-FOUND
# Returns:
#   First expanded path to a file/directory that exists of $1/$2.
#   If the file/directory doesn't exist $3 is returned.
#
# Usage:
#   $(call GET_ROOT,<path>,<search directories>,<error value>)
#   e.g. 
#   $(call GET_ROOT,vw/include/boot/pfx,../custom/dir,ERROR:PFX-NOT-FOUND)
GET_ROOT=$(strip \
		$(firstword\
		  $(foreach p,$(if $2,$2,$(INTROOT) $(VLTROOT)),\
		    $(if $(wildcard $p/$1),$p/$1)) \
	  	  $(if $3,$3,GET_ROOT-ERROR-NOT-FOUND)))


#
# MATLAB Install files to INTROOT
#
# $1: Source files
# $2: permission bit
define genInstallFiles
$(foreach f,$1,$(call genInstallFile,$f,$2))
endef

#
# MATLAB Install files to INTROOT
#
# $1: Source file
# $2: permission bit
define genInstallFile
name_$1    := $(shell basename $1)
fulldir_$1 := $(shell dirname  $1)
dir_$1     = $(if $(filter ../%,$1),$(patsubst ../%,%,$(dir $1)), $(shell basename $(fulldir_$1)))

.PHONY: install_$$(name_$1)
install_$$(name_$1):
	@echo ".....MATLAB install: $1 -> $(INTROOT)/$$(dir_$1)$$(name_$1) $(if $2,(perm $2))"
	$$(AT)cp $1 $(INTROOT)/$$(dir_$1)
	$(if $2,$$(AT)chmod $2 $(INTROOT)/$$(dir_$1)$$(name_$1))

# Add dependency to install to install_matlab
install_matlab: install_$$(name_$1)
endef

.PHONY:
install_matlab:
install: install_matlab

# The dependencies and compilation can't be generated until all sources have been
# generated, otherwise stale dependencies can be picked up by mistake
# from outside the module.

# OPTIMIZE should be 1 if not explicitly set in module makefiles
OPTIMIZE?=1

# vltMakefile does not support DEBUG=off, so we can't simply set a default value for DEBUG with ?=
# If a module wants to override DEBUG it can be specified with DEBUG=off
ifdef DEBUG
  ifneq ($(DEBUG),on)
    undefine DEBUG
  endif
else
  DEBUG=on
endif

#
# This makefiles provides compilation flags for MATLAB
# to enable compilation under 32 and 64 bits
#

ARCH=$(shell arch)


#
# MATLAB and MCR VERSION
#
ifndef MATLAB_VERSION
  # If not defines R2012a and MCR 7.0.1 is assumed (valid for VLT2014)
  MATLAB_VERSION = R2012a
  MCR_VERSION = 7.0.1
endif

MATLAB_MCC = $(MATLAB_HOME)/bin/mcc
MATLAB     = $(MATLAB_HOME)/bin/matlab

#------------------------------------------------------------------------

USER_CFLAGS += -fexceptions -iquote /usr/include/asm 


ifeq "$(BUILD_MODE)" "RELEASE"
  USER_CFLAGS += -DNO_TRACES
else ifeq "$(BUILD_MODE)" "DEBUG"
  ASAN_CFLAGS=-ggdb3 -fsanitize=address -fsanitize-recover=address,undefined --param asan-globals=0
  ASAN_LDFLAGS=-fsanitize=address
  DEBUG=on
else
  DEBUG=on
endif

#
# MCR 
#
USER_INC += -I$(MCRROOT)/extern/include

USER_LIB32 += -L/usr/lib
USER_LIB64 += -L/usr/lib64 -L/usr/local/lib64

#
# Matlab libraries
#
MATLAB_LDFLAGS32 += -L$(MCRROOT)/runtime/glnx86
MATLAB_LDFLAGS64 += -L$(MCRROOT)/runtime/glnxa64 

#
# Custom MATLAB targets
# ============================

# Selects how mcc is invoked first form locks the MATLAB license for 30 mins
# $1 Command line
define genMatlabMcc
ifndef MAKE_WITH_MATLAB
	$$(AT)$(MATLAB_MCC) $1
else
	@echo "note: MAKE_WITH_MATLAB enabled"
	$$(AT)$(MATLAB) -nodisplay -r "mcc $1; quit"
endif
endef

# genMatlabStd
# $1 name
# $2 prerequisites
# $3 files to install (relative paths) (deprecated)
# $4 extra files that needs to be deleted on cleanup
define genMatlabStd
# Add MATLAB targets to list
ALL_MATLAB_TARGETS = $(ALL_MATLAB_TARGETS) $2
$(MATLAB_PKG): $2

#
# Build shortcut targets
.PHONY: $1
$1: $2
matlab: $1

#
# Clean target
clean_$1:
	@echo "== MATLAB clean: $1"
	$$(AT)rm -f $2 $4 ../object/mccExcludedFiles.log ../object/readme.txt 2> /dev/null || true

clean_all: clean_$1

endef
# define genMatlabStd

# Generate MATLAB library target
# $1 canonical name (without lib prefix and .so extension)
# $2 list of MATLAB files
define genMatlabLibrary
$1_files      := $($1_MFILES)
$1_libname    := lib$1.so
$1_headername := $$(basename $$($1_libname)).h
$1_header     := ../include/$$($1_headername)
# Have to use absolute path here, otherwise vltMakefile VPATH will pick up
# dependency from INTROOT.
$1_reltarget  := ../lib64/$$($1_libname)
$1_target     := $(CURDIR)/$$($1_reltarget)

# Serialize any dependency to header
$$($1_header): $$($1_target)

# Main target that generates the library from MATLAB files
$$($1_target): $$($1_files)
	@echo == MATLAB library: $$(@F)
$(call genMatlabMcc, $(MATLAB_CFLAGS) $$($1_CFLAGS) -W cpplib:$$(basename $$($1_libname)) -T link:lib -d ../object $$($1_files))
	$$(AT)mv ../object/$$($1_libname) $$($1_target)
	$$(AT)mv ../object/$$($1_headername) $$($1_header)
	$$(AT)rm -f ../object/readme.txt ../object/mccExcludedFiles.log 2> /dev/null || true

$$(eval $$(call genMatlabStd,$1,$$($1_header) $$($1_target),\
                                      $$($1_header) $$($1_reltarget),\
				      ../object/$$(basename $$($1_libname))*))
# Install files
$$(eval $$(call genInstallFiles,$$($1_header),664))
$$(eval $$(call genInstallFiles,$$($1_reltarget),775))
endef 
# define genMatlabLibrary


# Generate MATLAB executable target
# $1 canonical name
# $2 list of MATLAB files
define genMatlabExecutable
$1_files   := $($1_MFILES)
$1_binname := $1
$1_target  := ../bin/$$($1_binname)

# Main target that generates the library from MATLAB files
$$($1_target): $$($1_files)
	@echo == MATLAB executable: $$(@F)
$(call genMatlabMcc, $(MATLAB_CFLAGS) $$($1_CFLAGS) -W main:$$($1_binname) -T link:exe -d ../object -o $1 $$($1_files))
	$$(AT)mv ../object/$$($1_binname) $$@
	$$(AT)rm -f ../object/readme.txt ../object/mccExcludedFiles.log 2> /dev/null || true

$(call genMatlabStd,$1,$$($1_target),\
                             $$($1_target),\
			     ../object/run_$1.sh)

# Install files
$$(eval $$(call genInstallFiles,$$($1_target),775))

endef 
# define genMatlabExecutable

# MATLAB_PKG needs to be defined before the targets are generated.
MATLAB_PKG := $(if $(MATLAB_PKG),$(MATLAB_PKG),matlab-$(VLTSW_RELEASE).tar.gz)

# Create the MATLAB targets
$(foreach l,$(MATLAB_LIBRARIES),\
  $(eval $(call genMatlabLibrary,$l)))
$(foreach e,$(MATLAB_EXECUTABLES),\
  $(eval $(call genMatlabExecutable,$e)))

# If there's MATLAB targets, we need to unpack before compiling.
ifneq ($(strip $(MATLAB_LIBRARIES)$(MATLAB_EXECUTABLES)),)
do_all: matlab-unpack
endif

.PHONY: matlab
matlab:

# Simple unpack target
# The files are touched after unpack for vltMakefile INSTALL_FILES rules to
# not trigger a rebuild because sources are newer.
.PHONY: matlab-unpack
matlab-unpack:
	@echo "== MATLAB unpack: $(MATLAB_PKG)"
	$(AT)tar -C .. -xzvf $(MATLAB_PKG)
	$(AT)tar -tf $(MATLAB_PKG) | xargs -I{} touch ../{}

$(MATLAB_PKG):
	@echo "== MATLAB pack: $@"
	$(AT)tar -czvf $@ -C .. $(subst ../,,$(subst $(CURDIR)/,,$^))

#Shorthand rules for pack and unpack
.PHONY: matlab-pack
matlab-pack: $(MATLAB_PKG)

# VLT standard makefile
MAKEDIR:=
include $(call GET_ROOT,include/vltMakefile)



