##########################################################################################################################################################
#
#
#
#  Makefile for compiling the XCLASSInterface package for python
#  Copyright (C) 2012 - 2025  Thomas Moeller
#
#  I. Physikalisches Institut, University of Cologne
#
#
#
#  Versions of the program:
#
#  Who           When        What
#
#  T. Moeller    2016-04-19  Initial version
#
#
#
#
#  Makefile options:    - "all":    builds the XCLASS interface package for standard installation
#
#                                   Used files:     src/XCLASSInterface.f90
#
#                       - "new":    builds the XCLASS interface package for modern installation
#
#                                   Used files:     src/XCLASSInterface.f90
#                                                   ../core/src/Module_FunctionCalling.f90
#                                                   ../core/src/Module_myXCLASS__Core.f90
#                                                   ../core/src/Module_Variables.f90
#
#                       - "sig":    creates signature file
#
#
##########################################################################################################################################################


#=========================================================================================================================================================
#=========================================================================================================================================================
# define subdirectories
#=========================================================================================================================================================
#=========================================================================================================================================================


# standard MAGIX directories
bindir = bin


# define path to source file of XCLASS interface
srcdir = src
srcdir := $(realpath $(srcdir))


# define path to source files of XCLASS functions
xclassrcsdir := $(abspath ..)


# define path to additional source files of XCLASS functions
addsrcdir = $(xclassrcsdir)/core/src


# define path to external packages
extlibdir := $(abspath ../../external)


#=========================================================================================================================================================
#=========================================================================================================================================================
# define include directories
#=========================================================================================================================================================
#=========================================================================================================================================================


# define path of obj and mod files of XCLASS
INCLUDEDIR = $(xclassrcsdir)/core/obj


#=========================================================================================================================================================
#=========================================================================================================================================================
# define source and objects files
#=========================================================================================================================================================
#=========================================================================================================================================================


#---------------------------------------------------------------------------------------------------------------------------------------------------------
# define names of fortran source files


# define path and name of source file of XCLASS interface
FSRC = $(srcdir)/XCLASSInterface.f90


# define path and name of object files used for standard installation only
FOBJ = $(INCLUDEDIR)/Module_FunctionCalling.o \
       $(INCLUDEDIR)/Module_myXCLASS__Core.o \
       $(INCLUDEDIR)/Module_Variables.o


# define path and names of additional source files used for modern installation
FSRCM = $(srcdir)/XCLASSInterface.f90 \
        $(addsrcdir)/Module_FunctionCalling.f90 \
        $(addsrcdir)/Module_myXCLASS__Core.f90 \
        $(addsrcdir)/Module_Variables.f90


#=========================================================================================================================================================
#=========================================================================================================================================================
# add libraries
#=========================================================================================================================================================
#=========================================================================================================================================================


# add cfitsio library
libcfitsio = -L$(extlibdir)/CFITSIO/bin -lcfitsio
libcfitsio_static = $(extlibdir)/CFITSIO/lib/libcfitsio.a


# add fftw3 library
libfftw3 = -L$(extlibdir)/FFTW/bin -lfftw3
libfftw3_static = $(extlibdir)/FFTW/lib/libfftw3.a


# add SQLite3 library
libsqlite3 = -L$(extlibdir)/SQLite/bin -lsqlitex
libsqlite3_static = $(extlibdir)/SQLite/lib/libsqlite3.a


# Add runtime library path flags for rpath
RPATHDIRS=$(extlibdir)/CFITSIO/bin:$(extlibdir)/FFTW/bin:$(extlibdir)/SQLite/bin
RPATHFLAGS=--link-args=-Wl,-rpath,$(RPATHDIRS)


# add additional library
# -lm:          library of basic mathematical functions
# -lz:          dynamic library libz.so.x.y.z (library for data compression, required by cfitsio)
# -lcurl:       dynamic linking library (the multiprotocol file transfer library)
# -ldl:         dynamic linking library
# -lpthread:    POSIX threads library
# -lgomp:       GCC OpenMP shared support library
libadd = -lm -lz -lcurl -ldl -lpthread -lgomp


# define combined library flags
# environment variables "XCLASSFINCLUDE" and "XCLASSLDFLAGS" are needed to find libraries on arm-MAC machines
liball = ${XCLASSFINCLUDE} ${XCLASSLDFLAGS} $(libcfitsio) $(libfftw3) $(libsqlite3) $(libadd)
liball_static = ${XCLASSFINCLUDE} ${XCLASSLDFLAGS} $(libcfitsio_static) $(libfftw3_static) $(libsqlite3_static) $(libadd)


#=========================================================================================================================================================
#=========================================================================================================================================================
# general settings
#=========================================================================================================================================================
#=========================================================================================================================================================


# define name of the executable file
EXEC = xclassinterface


#=========================================================================================================================================================
#=========================================================================================================================================================
# define command for F2PY compiler and corresponding flags
#=========================================================================================================================================================
#=========================================================================================================================================================


#---------------------------------------------------------------------------------------------------------------------------------------------------------
# get command for f2py compiler


# if environment variable 'XCLASS_F2PY_COMPILER' is not set, continue here
ifndef XCLASS_F2PY_COMPILER


	# Check if we're in a virtual environment and set PYTHONPATH variable
	ifneq ($(VIRTUAL_ENV),)
		# Dynamically get the Python executable path
		# PYTHON := $(VIRTUAL_ENV)/bin/python
		PYTHON := $(shell which python)


		# Ensure numpy is installed
		# $(shell $(PYTHON) -m pip install numpy 2>/dev/null)


		# Dynamically get the site-packages directory
		SITE_PACKAGES := $(shell python -c "import site; print(site.getsitepackages()[0])")


		# Set PYTHONPATH to include NumPy path
		export PYTHONPATH := $(SITE_PACKAGES):$(PYTHONPATH)


		# Remove duplicates from PYTHONPATH
		unique_pythonpath := $(shell echo $(PYTHONPATH) | tr ':' '\n' | awk '!seen[$0]++' | tr '\n' ':' | sed 's/:$$//')


		# Export the unique PYTHONPATH
		export PYTHONPATH := $(unique_pythonpath)


		# Set the FCPY command
		FCPY := $(PYTHON) -m numpy.f2py


	# if we're not in a virtual environment and if environment variable 'XCLASS_F2PY_COMPILER' is not set, use default command
	else
		FCPY = python3 -m numpy.f2py
	endif


# if environment variable 'XCLASS_F2PY_COMPILER' is set, use this
else
	FCPY = ${XCLASS_F2PY_COMPILER}
endif


#---------------------------------------------------------------------------------------------------------------------------------------------------------
# set compiler flags


# set f2py compiler and flags
FPYFLAGS = --f90flags="-O3 -ffree-form -ffree-line-length-none -fbounds-check -frange-check \
                       -fPIC -fmax-stack-var-size=32768 $(XCLASS_EXTRA_FORTRAN_FLAG)"


# set f2py compiler and flags for debugging
FPYFLAGSDBG = --f90flags="-g -O0 -fbacktrace -fopenmp -static -ffree-form -ffree-line-length-none \
                          -fbounds-check -frange-check -fPIC -Wall -Wextra $(XCLASS_EXTRA_FORTRAN_FLAG)"


#=========================================================================================================================================================
#=========================================================================================================================================================
# define rules
#=========================================================================================================================================================
#=========================================================================================================================================================


#---------------------------------------------------------------------------------------------------------------------------------------------------------
# define compilation rules


# define commands for standard method
all: fcomp clean move echo


# define commands for modern method
new: fnew clean move echo


# define standard method optimized for debugging
dbg: fdbg clean move


#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# compile f2py


# compile f2py (modern compilation)
fnew:
	$(FCPY) $(FPYFLAGS) $(liball) -c $(FSRCM) -m $(EXEC)


# compile f2py (standard compilation)
fcomp:
	$(FCPY) $(FPYFLAGS) -I$(INCLUDEDIR) $(FOBJ) $(liball_static) -c $(FSRC) -m $(EXEC)


# compile f2py optimized for debugging
fdbg:
	$(FCPY) $(FPYFLAGSDBG) -I$(INCLUDEDIR) $(liball) -c $(FSRC) -m $(EXEC)


# compile f2py to generate sig. file
sig:
	$(FCPY) $(FPYFLAGS) -I$(INCLUDEDIR) $(liball) -c $(FSRC) -m $(EXEC) -h $(EXEC).pyf


# compile f2py to generate sig. file
echo:
	echo $(FCPY) $(FPYFLAGS) -I$(INCLUDEDIR) $(liball) -c $(FSRC) -m $(EXEC)



#---------------------------------------------------------------------------------------------------------------------------------------------------------
# clean directories and previous compilations
clean:
	rm -f *.o *.pyf bin/*


#---------------------------------------------------------------------------------------------------------------------------------------------------------
# move module file to bin directory
move:
	mv *.so bin/$(EXEC).so


#---------------------------------------------------------------------------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------------------------------------------------------------
# done
#---------------------------------------------------------------------------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------------------------------------------------------------
