#===============================================================================
# Copyright 2004-2022 Intel Corporation.
#
# This software and the related documents are Intel copyrighted  materials,  and
# your use of  them is  governed by the  express license  under which  they were
# provided to you (License).  Unless the License provides otherwise, you may not
# use, modify, copy, publish, distribute,  disclose or transmit this software or
# the related documents without Intel's prior written permission.
#
# This software and the related documents  are provided as  is,  with no express
# or implied  warranties,  other  than those  that are  expressly stated  in the
# License.
#===============================================================================

##  Content:
##      Intel(R) oneAPI Math Kernel Library Custom Shared Object builder
##
##******************************************************************************

help:
	@echo
	@echo "Custom Shared Object builder creates MKL custom library"
	@echo
	@echo "Usage: make <target> [<options>]"
	@echo
	@echo "  target"
	@echo "    (static builder: uses static oneMKL interface+threading+core,"
	@echo "                     and, possibly, cluster libraries)"
	@echo "      libia32    - for IA-32 architecture"
	@echo "      libintel64 - for Intel(R) 64 architecture"
	@echo "    help         - prints this help"
	@echo
	@echo "    <options>"
	@echo "        interface={lp64|ilp64} (for libintel64 only)"
	@echo "            Specifies programming interface for libintel64."
	@echo "            Default: lp64."
	@echo "        export=<file_name>"
	@echo "            The name of the file that contains the list of entry points"
	@echo "            to be included to the shared object."
	@echo "            Default: user_example_list (no extension)."
	@echo "        name=<so_name>"
	@echo "            The name of the shared object to be created. The extension .so will be added."
	@echo "            Default: mkl_custom."
	@echo "        xerbla=<err_handlr>"
	@echo "            The name of the object file that contains the user's error handler."
	@echo "            By the default native oneMKL XERBLA is used."
	@echo "        threading={parallel|sequential}"
	@echo "            Specifies whether to use oneMKL in the threaded or sequential mode."
	@echo "            Default: parallel."
	@echo "        parallel={intel|tbb|gnu} (for libia32 and libintel64)"
	@echo "            Specifies whether to use Intel OpenMP, Intel oneTBB or GNU* OpenMP (for GNU compiler only)."
	@echo "            Default: intel."
	@echo "        cluster={yes|no} (for libintel64 only)"
	@echo "            Specifies whether oneMKL cluster components (BLACS, ScaLAPACK or/and CDFT)"
	@echo "            are needed to build the custom shared object."
	@echo "            Default: no."
	@echo "        blacs_mpi={intelmpi|openmpi}"
	@echo "            Specifies which pre-compiled oneMKL BLACS library to use. Ignored if 'cluster=no'."
	@echo "            'blacs_mpi' is also ignored if 'blacs_name' was specified."
	@echo "            Default: intelmpi."
	@echo "        blacs_name=<lib_name>"
	@echo "            Specifies the name of the custom oneMKL BLACS library to use (without .a prefix)."
	@echo "            Ignored if 'cluster=no'."
	@echo "            Default: libmkl_blacs_<blacs_mpi>_<interface>."
	@echo "        MKLROOT=<MKL_directory>"
	@echo "            Specifies the location of oneMKL libraries used to build the custom shared object."
	@echo "            Default: the oneMKL installation directory."
	@echo "        BLACSDIR=<BLACS_directory>"
	@echo "            Specifies the path to a custom oneMKL BLACS library. Ignored if 'cluster=no'."
	@echo "            Default: <MKL_directory>/lib/intel64"
	@echo
	@echo "Usage examples:"
	@echo
	@echo "  make libia32"
	@echo "    Creates mkl_custom.so for IA-32 architecture."
	@echo "    Function list is taken from the predefined file user_example_list."
	@echo "    The static-parallel oneMKL libraries are used to build mkl_custom.so."
	@echo "    Native oneMKL error handler is used."
	@echo
	@echo "  make libintel64 export=my_blas_list interface=ilp64 name=my_blas"
	@echo "    Creates my_blas.so for Intel(R) 64 architecture."
	@echo "    Function list is taken from the user file my_blas_list."
	@echo "    The static-parallel-ilp64 oneMKL libraries are used to build my_blas.so."
	@echo
	@echo "  make libintel64 cluster=yes export=cluster_example_list interface=ilp64 blacs_mpi=mpich name=my_cluster"
	@echo "    Creates my_cluster.so for Intel(R) 64 architecture with support of cluster libraries."
	@echo "    Function list is taken from the user file cluster_example_list."
	@echo

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

ifndef MKLROOT
MKLROOT = ../../../..
endif

mklia32_libpath=$(MKLROOT)/lib32
mklintel64_libpath=$(MKLROOT)/lib

ifndef CMPLR_ROOT
compileria32_libpath=$(ONEAPI_ROOT)/lib32
compilerintel64_libpath=$(ONEAPI_ROOT)/lib
else
compileria32_libpath=$(CMPLR_ROOT)/lib32
compilerintel64_libpath=$(CMPLR_ROOT)/lib
endif

ifndef TBBROOT
tbbia32_libpath=$(ONEAPI_ROOT)/lib32
tbbintel64_libpath=$(ONEAPI_ROOT)/lib
else
tbbia32_libpath=$(TBBROOT)/lib32
tbbintel64_libpath=$(TBBROOT)/lib
endif

#ifndef export
export=user_example_list
#endif

#ifndef name
name=mkl_custom
#endif

ifdef xerbla
XERBLA="$(xerbla)"
else
XERBLA=
endif

ifndef interface
interface=lp64
endif

ifneq ($(interface),ilp64)
ifneq ($(interface),lp64)
interface=lp64
endif
endif

ifndef threading
threading=parallel
endif
ifndef parallel
parallel=intel
endif

IFACE_COMP_PART=intel

ifeq ($(parallel),gnu)
IFACE_THREADING_PART=gnu
LOPT_IA32=-lgomp
LOPT_INTEL64=-lgomp
else ifeq ($(parallel),tbb)
IFACE_THREADING_PART=tbb
LOPT_IA32=-L"$(tbbia32_libpath)" -ltbb
LOPT_INTEL64=-L"$(tbbintel64_libpath)" -ltbb
else
IFACE_THREADING_PART=intel
LOPT_IA32=-L"$(compileria32_libpath)" -liomp5
LOPT_INTEL64=-L"$(compilerintel64_libpath)" -liomp5
endif

IFACE_LIB=libmkl_$(IFACE_COMP_PART)_$(interface).a

ifeq ($(threading),sequential)
THREADING_LIB=libmkl_sequential.a
LOPT_IA32=
LOPT_INTEL64=
else
THREADING_LIB=libmkl_$(IFACE_THREADING_PART)_thread.a
endif
LOPT_IA32 += -lpthread
LOPT_INTEL64 += -lpthread

CORE_LIB=libmkl_core.a
PURE_IFACE_LIB=-lmkl_rt

ifeq ($(cluster),yes)
ifndef blacs_mpi
blacs_mpi=intelmpi
endif

ifneq ($(blacs_name),)
ifndef BLACSDIR
BLACSDIR="$(mklintel64_libpath)"
endif
BLACS_LIB="$(BLACSDIR)/$(blacs_name).a"
else
BLACS_LIB="$(mklintel64_libpath)/libmkl_blacs_$(blacs_mpi)_$(interface).a"
endif
SCALAPACK_LIB="$(mklintel64_libpath)/libmkl_scalapack_$(interface).a"
CDFT_LIB="$(mklintel64_libpath)/libmkl_cdft_core.a"
else
BLACS_LIB=
SCALAPACK_LIB=
CDFT_LIB=
endif

SYSTEM_LIBS = -lm -ldl

libia32 ia32: check_export_file_name
	export LIBRARY_PATH=$(LIBRARY_PATH):$(LD_LIBRARY_PATH); \
	gcc -m32 -shared -Wl,-z,relro,-z,now -Bdynamic \
	$(XERBLA) $(addprefix -u ,$(shell grep -v '^[\#;]' "$(export)")) \
	-u mkl_serv_finalize -Wl,-fini=mkl_serv_finalize \
	-Wl,--start-group \
	"$(mklia32_libpath)/libmkl_intel.a" \
	"$(mklia32_libpath)/$(THREADING_LIB)" \
	"$(mklia32_libpath)/$(CORE_LIB)" \
	-Wl,--end-group \
	$(LOPT_IA32) $(SYSTEM_LIBS) \
	-o "$(name).so"

libintel64 intel64 em64t: check_export_file_name
	export LIBRARY_PATH=$(LIBRARY_PATH):$(LD_LIBRARY_PATH); \
	gcc -shared -Wl,-z,relro,-z,now -Bdynamic \
	$(XERBLA) $(addprefix -u ,$(shell grep -v '^[\#;]' "$(export)")) \
	-u mkl_serv_finalize -Wl,-fini=mkl_serv_finalize \
	-Wl,--start-group \
	$(SCALAPACK_LIB) $(CDFT_LIB) $(BLACS_LIB) \
	"$(mklintel64_libpath)/$(IFACE_LIB)" \
	"$(mklintel64_libpath)/$(THREADING_LIB)" \
	"$(mklintel64_libpath)/$(CORE_LIB)" \
	-Wl,--end-group \
	$(LOPT_INTEL64) $(SYSTEM_LIBS) \
	-o "$(name).so"

check_export_file_name: $(export)
