
# Arguments:
# MODOBJFILES
# UserLDFLAGS
# UserINCFLAGS
# LinkCoreNEURON
# Rules to build MODOBJFILES from mod files are found in makemod2c_inc

# Mechanisms version are by default 0.0, but should be overriden
MECH_NAME =
MECH_VERSION = 0.0
MODS_PATH = .
# in the ppc64 folder
OUTPUT = .
DESTDIR =
UserINCFLAGS =
UserLDFLAGS =

# install dirs
bindir := ${ROOT}/lib/nrn/bin
libdir := ${ROOT}/lib/nrn
incdir := ${ROOT}/include
datadir:= ${ROOT}/share/nrn
datadir_lib := ${ROOT}/share/nrn/lib

# Additional variables set in CMAKE usable here
# - @NRN_COMPILE_DEFS
# - @NRN_LINK_DEFS
LDFLAGS = $(LINKFLAGS) $(UserLDFLAGS)   /usr/lib/powerpc64-linux-gnu/libreadline.so -Wl,-rpath,/usr/lib/powerpc64-linux-gnu /usr/lib/powerpc64-linux-gnu/libcurses.so -Wl,-rpath,/usr/lib/powerpc64-linux-gnu /usr/lib/powerpc64-linux-gnu/libform.so -Wl,-rpath,/usr/lib/powerpc64-linux-gnu /usr/lib/powerpc64-linux-gnu/openmpi/lib/libmpi.so -Wl,-rpath,/usr/lib/powerpc64-linux-gnu/openmpi/lib /usr/lib/powerpc64-linux-gnu/libX11.so -Wl,-rpath,/usr/lib/powerpc64-linux-gnu /usr/lib/powerpc64-linux-gnu/libXext.so -Wl,-rpath,/usr/lib/powerpc64-linux-gnu

# In GPU wheel distributions then the shipped libnrniv.so is linked against
# some NVIDIA runtime libraries that are shipped with the wheel. If we use
# nrnivmodl on the user machine then the NVIDIA compilers will link the local
# versions of these libraries too, causing duplication.
libnrniv_without_nvidia: $(libdir)/libnrniv.so
	cp -v $(libdir)/libnrniv.so $(OUTPUT)/libnrniv-without-nvidia.so
	patchelf $(OUTPUT)/libnrniv-without-nvidia.so --print-needed | grep '^libnv\(hpcatm\|omp\|cpumath\|cpumath-avx2\|c\)-[a-f0-9]\{8\}\.so' | xargs -t -r -n 1 patchelf $(OUTPUT)/libnrniv-without-nvidia.so --remove-needed
	patchelf $(OUTPUT)/libnrniv-without-nvidia.so --set-soname libnrniv-without-nvidia.so
	patchelf $(OUTPUT)/libnrniv-without-nvidia.so --print-rpath
	ldd $(OUTPUT)/libnrniv-without-nvidia.so

# In a GPU wheel build then we need to fudge libnrniv.so before linking to it.
# NEURONDEMO should be set when we run this as part of the wheel build, in
# which case we do *not* want this hack.
ifeq (OFFOFF$(if $(NRNDEMO),OFF,ON), ONONONON)
  NRNLIB_FLAGS = -L$(OUTPUT) -lnrniv-without-nvidia
  NRNLIB_RPATH_FLAGS = -Wl,-rpath,\$$ORIGIN -Wl,-rpath,\$$ORIGIN/..
  nrn_lib = libnrniv_without_nvidia
else
  NRNLIB_FLAGS = -L$(libdir) -lnrniv
  NRNLIB_RPATH_FLAGS = -Wl,-rpath,$(libdir)
  nrn_lib =
endif

OS_NAME := $(shell uname)
_cm =,

# We rebuild the include dirs since a lot of stuff changes place
INCLUDES = -I. $(INCFLAGS) $(UserINCFLAGS) -I$(incdir)
ifeq (ON, ON)
  INCLUDES += $(if /usr/lib/powerpc64-linux-gnu/openmpi/include;/usr/lib/powerpc64-linux-gnu/openmpi/include/openmpi, -I$(subst ;, -I,/usr/lib/powerpc64-linux-gnu/openmpi/include;/usr/lib/powerpc64-linux-gnu/openmpi/include/openmpi),)
endif

# CC/CXX are always defined. If the definition comes from default change it
ifeq ($(origin CC), default)
    CC = /usr/bin/cc
    CXX = /usr/bin/c++
endif
CFLAGS = -g  -O2 -Wno-write-strings -g -O2 -Werror=implicit-function-declaration -ffile-prefix-map=/build/reproducible-path/neuron-8.2.6=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -std=c11
CXXFLAGS = -g  -O2 -Wno-write-strings -g -O2 -ffile-prefix-map=/build/reproducible-path/neuron-8.2.6=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -std=c++11

COMPILE = $(CC) $(CFLAGS) -DMPI_NO_CPPBIND=1 -DOMPI_SKIP_MPICXX=1 -DMPICH_SKIP_MPICXX=1 -DHAVE_CONFIG_H 
CXXCOMPILE = $(CXX) $(CXXFLAGS) -DMPI_NO_CPPBIND=1 -DOMPI_SKIP_MPICXX=1 -DMPICH_SKIP_MPICXX=1 -DHAVE_CONFIG_H 
CXX_LINK_EXE = $(CXX) $(CXXFLAGS) -Wl,-z,relro 
CXX_LINK_SHARED = $(CXX) $(CXXFLAGS) -shared -fPIC -Wl,-z,relro

NOCMODL = $(bindir)/nocmodl
NRNUNITS = $(datadir_lib)/nrnunits.lib

# File path config (internal)
MODC_DIR = .
OBJS_DIR = .
mod_objs   = $(MODOBJFILES)

mod_func_o = $(OBJS_DIR)/mod_func.o
mod_func_cpp = $(MODC_DIR)/mod_func.cpp

special  = $(OUTPUT)/special
LIB_SUFFIX_ = $(if $(MECH_NAME),_$(MECH_NAME),)
mech_libname = nrnmech

# In case of static library we need to link NRNLIB_FLAGS twice to avoid undefined
# symbols from circular dependencies. But for shared library we don't do it to avoid
# pthread linking with wheels.
ifeq (ON, ON)
    mech_lib = $(OUTPUT)/lib$(mech_libname).so
    mech_lib_type = mech_lib_shared
    extra_lib_link =
else
    mech_lib = $(OUTPUT)/lib$(mech_libname).a
    mech_lib_type = mech_lib_static
    extra_lib_link = $(NRNLIB_FLAGS)
endif

# add coreneuron flags
ifeq ($(LinkCoreNEURON), true)
    EXTRA_LDFLAGS = 
endif

# If no DESTDIR (we are probably just building) we use $ORIGIN (@loader_path in OSX)
_ORIGIN := $(if $(filter Darwin,$(OS_NAME)),@loader_path,$$ORIGIN)
_SONAME := -Wl,$(if $(filter Darwin,$(OS_NAME)),-install_name${_cm}@rpath/,-soname${_cm})$(notdir ${mech_lib})
DESTDIR_RPATH = $(if $(DESTDIR),$(DESTDIR)/lib,$(_ORIGIN))

C_RESET := \033[0m
C_GREEN := \033[32m


# ======== MAIN BUILD RULES ============

# Take the main and link with nrnmech.
# RPATH is set for DESTDIR_RPATH and coreneuron lib
special: $(mech_lib)
	@printf " => $(C_GREEN)LINKING$(C_RESET) executable $(special) LDFLAGS are: $(LDFLAGS)\n"
	$(CXX_LINK_EXE) -I $(incdir) -I $(incdir)/nrncvode -DAUTO_DLOPEN_NRNMECH=0 $(datadir)/nrnmain.cpp -o $(special) \
	  -L $(OBJS_DIR) -l$(mech_libname) $(NRNLIB_FLAGS) -l$(mech_libname) $(extra_lib_link) -Wl,-rpath,'$(DESTDIR_RPATH)' -Wl,-rpath,$(libdir) $(LDFLAGS) $(EXTRA_LDFLAGS)

$(mech_lib): $(mech_lib_type)

mech_lib_shared: mod_func.o $(mod_objs) $(nrn_lib) build_always
	@printf " => $(C_GREEN)LINKING$(C_RESET) shared library $(mech_lib)\n"
	$(CXX_LINK_SHARED) -I $(incdir) -o ${mech_lib} ${_SONAME} \
	  $(mod_func_o) $(mod_objs) $(NRNLIB_FLAGS) $(NRNLIB_RPATH_FLAGS) $(LDFLAGS)
	rm -f $(OBJS_DIR)/.libs/libnrnmech.so ; mkdir -p $(OBJS_DIR)/.libs ; cp $(mech_lib) $(OBJS_DIR)/.libs/libnrnmech.so

mech_lib_static: mod_func.o $(mod_objs) $(nrn_lib) build_always
	@printf " => $(C_GREEN)LINKING$(C_RESET) static library $(mech_lib)\n"
	ar cq ${mech_lib} $(mod_func_o) $(mod_objs) $(cobjs);

mod_func.o: mod_func.cpp
	@printf " -> $(C_GREEN)Compiling$(C_RESET) $<\n"
	$(CXXCOMPILE) $(INCLUDES) -fPIC -c $< -o $@

# Generic build c->o. Need PIC for shared lib
$(OBJS_DIR)/%.o: $(MODC_DIR)/%.c | $(OBJS_DIR)
	@printf " -> $(C_GREEN)Compiling$(C_RESET) $<\n"
	$(COMPILE) $(INCLUDES) -fPIC -c $< -o $@


include makemod2c_inc

# If .mod doesnt exist attempt from previously built opt mods in shared/
$(MODC_DIR)/%.cpp: $(datadir_lib)/%.cpp | $(MODC_DIR)
	ln -s $< $@

install: special $(mech_lib)
	install -d $(DESTDIR)/bin $(DESTDIR)/lib
	install $(mech_lib) $(DESTDIR)/lib
	install $(special) $(DESTDIR)/bin

libnrnmech.la: $(mech_lib)

# == INIT ==
$(MODC_DIR):
	(cd .. ; mkdir -p $(MODC_DIR))
#$(OBJS_DIR):
#	mkdir -p $(OBJS_DIR)

.PHONY: build_always

$(VERBOSE).SILENT:
