INCLUDE_PATH := $(abspath ./)
LIBRARY_PATH := $(abspath ./)

AR?=ar
CMAKE_ARGS?=
BUILD_TYPE?=
NATIVE?=false
CUDA_LIBPATH?=/usr/local/cuda/lib64/
ONEAPI_VARS?=/opt/intel/oneapi/setvars.sh
# keep standard at C11 and C++11
CXXFLAGS = -I. -I$(INCLUDE_PATH)/sources/stablediffusion-ggml.cpp/thirdparty -I$(INCLUDE_PATH)/sources/stablediffusion-ggml.cpp/ggml/include -I$(INCLUDE_PATH)/sources/stablediffusion-ggml.cpp -O3 -DNDEBUG -std=c++17 -fPIC

GOCMD?=go
CGO_LDFLAGS?=
# Avoid parent make file overwriting CGO_LDFLAGS which is needed for hipblas
CGO_LDFLAGS_SYCL=
GO_TAGS?=
LD_FLAGS?=

# stablediffusion.cpp (ggml)
STABLEDIFFUSION_GGML_REPO?=https://github.com/leejet/stable-diffusion.cpp
STABLEDIFFUSION_GGML_VERSION?=eed97a5e1d054f9c1e7ac01982ae480411d4157e

# Disable Shared libs as we are linking on static gRPC and we can't mix shared and static
CMAKE_ARGS+=-DBUILD_SHARED_LIBS=OFF

ifeq ($(NATIVE),false)
	CMAKE_ARGS+=-DGGML_NATIVE=OFF
endif

# If build type is cublas, then we set -DGGML_CUDA=ON to CMAKE_ARGS automatically
ifeq ($(BUILD_TYPE),cublas)
	CMAKE_ARGS+=-DSD_CUDA=ON -DGGML_CUDA=ON
	CGO_LDFLAGS+=-lcublas -lcudart -L$(CUDA_LIBPATH) -L$(CUDA_LIBPATH)/stubs/ -lcuda
# If build type is openblas then we set -DGGML_BLAS=ON -DGGML_BLAS_VENDOR=OpenBLAS
# to CMAKE_ARGS automatically
else ifeq ($(BUILD_TYPE),openblas)
	CMAKE_ARGS+=-DGGML_BLAS=ON -DGGML_BLAS_VENDOR=OpenBLAS
# If build type is clblas (openCL) we set -DGGML_CLBLAST=ON -DCLBlast_DIR=/some/path
else ifeq ($(BUILD_TYPE),clblas)
	CMAKE_ARGS+=-DGGML_CLBLAST=ON -DCLBlast_DIR=/some/path
# If it's hipblas we do have also to set CC=/opt/rocm/llvm/bin/clang CXX=/opt/rocm/llvm/bin/clang++
else ifeq ($(BUILD_TYPE),hipblas)
	CMAKE_ARGS+=-DSD_HIPBLAS=ON -DGGML_HIPBLAS=ON
# If it's OSX, DO NOT embed the metal library - -DGGML_METAL_EMBED_LIBRARY=ON requires further investigation
# But if it's OSX without metal, disable it here
else ifeq ($(BUILD_TYPE),vulkan)
	CMAKE_ARGS+=-DSD_VULKAN=ON -DGGML_VULKAN=ON
	CGO_LDFLAGS+=-lvulkan
else ifeq ($(OS),Darwin)
	ifneq ($(BUILD_TYPE),metal)
		CMAKE_ARGS+=-DSD_METAL=OFF -DGGML_METAL=OFF
	else
		CMAKE_ARGS+=-DSD_METAL=ON -DGGML_METAL=ON
		CMAKE_ARGS+=-DGGML_METAL_EMBED_LIBRARY=ON
		TARGET+=--target ggml-metal
	endif
endif

ifeq ($(BUILD_TYPE),sycl_f16)
	CMAKE_ARGS+=-DGGML_SYCL=ON \
		-DCMAKE_C_COMPILER=icx \
		-DCMAKE_CXX_COMPILER=icpx \
		-DSD_SYCL=ON \
		-DGGML_SYCL_F16=ON
	export CC=icx
	export CXX=icpx
	CGO_LDFLAGS_SYCL += -fsycl -L${DNNLROOT}/lib -ldnnl ${MKLROOT}/lib/intel64/libmkl_sycl.a -fiopenmp -fopenmp-targets=spir64 -lOpenCL
	CGO_LDFLAGS_SYCL += $(shell pkg-config --libs mkl-static-lp64-gomp)
	CGO_CXXFLAGS += -fiopenmp -fopenmp-targets=spir64
	CGO_CXXFLAGS += $(shell pkg-config --cflags mkl-static-lp64-gomp )
endif

ifeq ($(BUILD_TYPE),sycl_f32)
	CMAKE_ARGS+=-DGGML_SYCL=ON \
		-DCMAKE_C_COMPILER=icx \
		-DCMAKE_CXX_COMPILER=icpx \
		-DSD_SYCL=ON
	export CC=icx
	export CXX=icpx
	CGO_LDFLAGS_SYCL += -fsycl -L${DNNLROOT}/lib -ldnnl ${MKLROOT}/lib/intel64/libmkl_sycl.a -fiopenmp -fopenmp-targets=spir64 -lOpenCL
	CGO_LDFLAGS_SYCL += $(shell pkg-config --libs mkl-static-lp64-gomp)
	CGO_CXXFLAGS += -fiopenmp -fopenmp-targets=spir64
	CGO_CXXFLAGS += $(shell pkg-config --cflags mkl-static-lp64-gomp )
endif

# warnings
# CXXFLAGS += -Wall -Wextra -Wpedantic -Wcast-qual -Wno-unused-function

# Find all .a archives in ARCHIVE_DIR
# (ggml can have different backends cpu, cuda, etc., each backend generates a .a archive)
GGML_ARCHIVE_DIR := build/ggml/src/
ALL_ARCHIVES := $(shell find $(GGML_ARCHIVE_DIR) -type f -name '*.a')
ALL_OBJS := $(shell find $(GGML_ARCHIVE_DIR) -type f -name '*.o')

# Name of the single merged library
COMBINED_LIB := libggmlall.a

# Instead of using the archives generated by GGML, use the object files directly to avoid overwriting objects with the same base name
$(COMBINED_LIB): $(ALL_ARCHIVES)
	@echo "Merging all .o into $(COMBINED_LIB): $(ALL_OBJS)"
	rm -f $@
	ar -qc $@ $(ALL_OBJS)
	# Ensure we have a proper index
	ranlib $@

build/libstable-diffusion.a:
	@echo "Building SD with $(BUILD_TYPE) build type and $(CMAKE_ARGS)"
ifneq (,$(findstring sycl,$(BUILD_TYPE)))
	+bash -c "source $(ONEAPI_VARS); \
	mkdir -p build && \
	cd build && \
	cmake $(CMAKE_ARGS) ../sources/stablediffusion-ggml.cpp && \
	cmake --build . --config Release"
else
	mkdir -p build && \
	cd build && \
	cmake $(CMAKE_ARGS) ../sources/stablediffusion-ggml.cpp && \
	cmake --build . --config Release
endif
	$(MAKE) $(COMBINED_LIB)

gosd.o:
ifneq (,$(findstring sycl,$(BUILD_TYPE)))
	+bash -c "source $(ONEAPI_VARS); \
	$(CXX) $(CXXFLAGS) gosd.cpp -o gosd.o -c"
else
	$(CXX) $(CXXFLAGS) gosd.cpp -o gosd.o -c
endif

## stablediffusion (ggml)
sources/stablediffusion-ggml.cpp:
	git clone --recursive $(STABLEDIFFUSION_GGML_REPO) sources/stablediffusion-ggml.cpp && \
	cd sources/stablediffusion-ggml.cpp && \
	git checkout $(STABLEDIFFUSION_GGML_VERSION) && \
	git submodule update --init --recursive --depth 1 --single-branch

libsd.a: sources/stablediffusion-ggml.cpp build/libstable-diffusion.a gosd.o
	cp $(INCLUDE_PATH)/build/libstable-diffusion.a ./libsd.a
	$(AR) rcs libsd.a gosd.o

stablediffusion-ggml: libsd.a
	CGO_LDFLAGS="$(CGO_LDFLAGS) $(CGO_LDFLAGS_SYCL)" C_INCLUDE_PATH="$(INCLUDE_PATH)" LIBRARY_PATH="$(LIBRARY_PATH)" \
	CC="$(CC)" CXX="$(CXX)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" \
	$(GOCMD) build -ldflags "$(LD_FLAGS)" -tags "$(GO_TAGS)" -o stablediffusion-ggml ./

package:
	bash package.sh

build: stablediffusion-ggml package

clean:
	rm -rf gosd.o libsd.a build $(COMBINED_LIB)
