##
# Library locations
##
EIGEN ?= $(MATH)lib/eigen_3.3.3
BOOST ?= $(MATH)lib/boost_1.66.0
BOOST_LIB ?= $(MATH)lib/boost_1.66.0/stage/lib
GTEST ?= $(MATH)lib/gtest_1.7.0
CPPLINT ?= $(MATH)lib/cpplint_4.45
OPENCL ?= $(MATH)lib/opencl_1.2.8
SUNDIALS ?= $(MATH)lib/sundials_3.1.0
BOOST_PARALLEL_BUILD ?= $(or $(PARALLEL),1)

##
# Build rules for cvodes
##

SUNDIALS_CVODES := $(patsubst %.c,%.o,\
  $(addprefix $(SUNDIALS)/src/cvodes/, cvodes.c cvodes_io.c cvodea.c cvodea_io.c cvodes_direct.c cvodes_diag.c cvodes_spils.c cvodes_bandpre.c cvodes_bbdpre.c) \
  $(wildcard $(SUNDIALS)/src/sundials/*.c) \
  $(wildcard $(SUNDIALS)/src/sunmat_band/*.c) \
  $(wildcard $(SUNDIALS)/src/sunmat_dense/*.c) \
  $(wildcard $(SUNDIALS)/src/sunlinsol_band/*.c) \
  $(wildcard $(SUNDIALS)/src/sunlinsol_dense/*.c))

SUNDIALS_IDAS := $(patsubst %.c,%.o,\
  $(addprefix $(SUNDIALS)/src/idas/, idaa.c idaa_io.c idas.c idas_bbdpre.c idas_direct.c idas_ic.c idas_io.c idas_spils.c) \
  $(wildcard $(SUNDIALS)/src/sundials/*.c) \
  $(wildcard $(SUNDIALS)/src/sunmat_band/*.c) \
  $(wildcard $(SUNDIALS)/src/sunmat_dense/*.c) \
  $(wildcard $(SUNDIALS)/src/sunlinsol_band/*.c) \
  $(wildcard $(SUNDIALS)/src/sunlinsol_dense/*.c))

SUNDIALS_NVECSERIAL := $(patsubst %.c,%.o,\
  $(addprefix $(SUNDIALS)/src/, nvec_ser/nvector_serial.c sundials/sundials_math.c))

$(sort $(SUNDIALS_CVODES) $(SUNDIALS_IDAS) $(SUNDIALS_NVECSERIAL)) : %.o : %.c
	@mkdir -p $(dir $@)
	$(COMPILE.c) -x c -O$(O) -include $(SUNDIALS)/include/stan_sundials_printf_override.hpp -isystem $(SUNDIALS)/include $< -o $@

$(SUNDIALS)/lib/libsundials_cvodes.a: $(SUNDIALS_CVODES)
	@mkdir -p $(dir $@)
	$(AR) -rs $@ $^

$(SUNDIALS)/lib/libsundials_idas.a: $(SUNDIALS_IDAS)
	@mkdir -p $(dir $@)
	$(AR) -rs $@ $^

$(SUNDIALS)/lib/libsundials_nvecserial.a: $(SUNDIALS_NVECSERIAL)
	@mkdir -p $(dir $@)
	$(AR) -rs $@ $^

LIBSUNDIALS = $(SUNDIALS)/lib/libsundials_nvecserial.a $(SUNDIALS)/lib/libsundials_cvodes.a $(SUNDIALS)/lib/libsundials_idas.a

STAN_CVODES_HEADERS := $(shell find stan -name *cvodes*.hpp)
$(STAN_CVODES_HEADERS) : $(LIBSUNDIALS)

STAN_IDAS_HEADERS := $(shell find stan -name *idas*.hpp)
$(STAN_IDAS_HEADERS) : $(LIBSUNDIALS)

##
# Build rules for MPI
##

# turn BOOST_LIB into absolute path
BOOST_LIB_ABS = $(shell mkdir -p "$(BOOST_LIB)" && cd -- "$(BOOST_LIB)" && pwd)

$(BOOST)/user-config.jam:
	echo "# In case of a compiler mismatch used by mpicxx and" >> $(BOOST)/user-config.jam
	echo "# the compiler used for Stan, consider configuring" >> $(BOOST)/user-config.jam
	echo "# the boost toolset here" >> $(BOOST)/user-config.jam
	echo "using mpi ;" >> $(BOOST)/user-config.jam

$(BOOST_LIB)/mpi.so: $(BOOST)/user-config.jam
	@mkdir -p $(dir $@)
	cd $(BOOST); ./bootstrap.sh
	cd $(BOOST); ./b2 --user-config=user-config.jam --layout=system --with-mpi --with-serialization -j$(BOOST_PARALLEL_BUILD) variant=release link=shared threading=multi runtime-link=shared

$(BOOST_LIB)/libboost_serialization.so: $(BOOST_LIB)/mpi.so

$(BOOST_LIB)/libboost_serialization.dylib: $(BOOST_LIB)/mpi.so
	install_name_tool -add_rpath "$(BOOST_LIB_ABS)" "$(BOOST_LIB)/libboost_serialization.dylib"
	install_name_tool -id @rpath/libboost_serialization.dylib "$(BOOST_LIB)/libboost_serialization.dylib"

$(BOOST_LIB)/libboost_mpi.so: $(BOOST_LIB)/mpi.so

$(BOOST_LIB)/libboost_mpi.dylib: $(BOOST_LIB)/mpi.so $(BOOST_LIB)/libboost_serialization.dylib
	install_name_tool -add_rpath "$(BOOST_LIB_ABS)" "$(BOOST_LIB)/libboost_mpi.dylib"
	install_name_tool -change libboost_serialization.dylib @rpath/libboost_serialization.dylib "$(BOOST_LIB)/libboost_mpi.dylib"
	install_name_tool -id @rpath/libboost_mpi.dylib "$(BOOST_LIB)/libboost_mpi.dylib"

.PHONY: clean-libraries
clean-libraries:
	$(RM) $(sort $(SUNDIALS_CVODES) $(SUNDIALS_IDAS) $(SUNDIALS_NVECSERIAL) $(LIBSUNDIALS) $(LIBMPI))
	$(RM) -rf $(BOOST_LIB)/*
	$(RM) -rf $(BOOST)/bin.v2 $(BOOST)/tools/build/src/engine/bootstrap/ $(BOOST)/tools/build/src/engine/bin.* $(BOOST)/project-config.jam* $(BOOST)/b2 $(BOOST)/bjam $(BOOST)/bootstrap.log
	$(RM) -rf bin
