
UNAME_S := $(shell uname -s)


# Build for website (WASM)
ifeq ($(OS), web)
CMAKE=cmake
CC=emcc
CXX=em++
LD=ld

else
# Linux specific options 
ifeq ($(UNAME_S), Linux)
# For checking if using systemd
INITSYSTEM := $(shell ps --no-headers -o comm 1)
OS=Linux
CMAKE=cmake
CC=gcc
CXX=g++
LD=ld
PYTHON_CONFIG=$(shell which python3-config)
endif


# Mac OSX specific options 
ifeq ($(UNAME_S), Darwin)
OS=macOS
CMAKE=cmake
CC=clang
CXX=clang++
LD=clang++
PYTHON_CONFIG=$(shell which python3-config)
endif

# Windows cross compilation
ifeq ($(OS), Windows)
CMAKE=x86_64-w64-mingw32-cmake
CC=x86_64-w64-mingw32-gcc
CXX=x86_64-w64-mingw32-g++
LD=x86_64-w64-mingw32-ld
PYTHON_CONFIG=$(shell which python3-config)
endif

endif

_PRGNAME=wc-api-test

ifeq ($(OS), Windows)
	PRGNAME=$(_PRGNAME).exe
else
ifeq ($(OS), web )
	PRGNAME=./web/index.html
else
	PRGNAME=$(_PRGNAME)
endif
endif

#Build options 
BUILD := DEBUG

#Version Number 
MAJOR	:= 0
MINOR	:= 1
PATCH	:= 0
VERSION := $(MAJOR).$(MINOR).$(PATCH)

DESTDIR ?= ./bin

# C Compiler Warnings
CWARNINGS  = -Wall -Wextra -Wdouble-promotion -Wformat -Wnull-dereference
CWARNINGS += -Wmissing-include-dirs -Wswitch-enum -Wsync-nand
CWARNINGS += -Wunused -Wuninitialized -Winit-self -Winvalid-memory-model
CWARNINGS += -Wmaybe-uninitialized  -Wstrict-aliasing -Wstrict-overflow=4
CWARNINGS += -Wstringop-overflow=2 -Wstringop-truncation 
CWARNINGS += -Wsuggest-attribute=noreturn -Wsuggest-attribute=const 
CWARNINGS += -Wsuggest-attribute=malloc -Wsuggest-attribute=format 
CWARNINGS += -Wmissing-format-attribute -Wduplicated-branches
CWARNINGS += -Wduplicated-cond -Wtautological-compare -Wtrampolines -Wfloat-equal
CWARNINGS += -Wundef -Wunused-macros -Wcast-align -Wconversion
CWARNINGS += -Wsizeof-pointer-div -Wsizeof-pointer-memaccess -Wstrict-prototypes
CWARNINGS += -Wmissing-prototypes -Wmissing-declarations 
CWARNINGS += -Wmissing-field-initializers -Wpacked -Wredundant-decls
CWARNINGS += -Winline -Wdisabled-optimization -Wunsuffixed-float-constants

# C++ Compiler Warnings
CXXWARNINGS  = -Wall -Wextra -Wdouble-promotion -Wformat -Wnull-dereference
CXXWARNINGS += -Wmissing-include-dirs -Wswitch-enum -Wsync-nand
CXXWARNINGS += -Wunused -Wuninitialized -Winit-self -Winvalid-memory-model
CXXWARNINGS += -Wmaybe-uninitialized  -Wstrict-aliasing -Wstrict-overflow=4
CXXWARNINGS += -Wstringop-overflow=2 -Wstringop-truncation 
CXXWARNINGS += -Wsuggest-attribute=noreturn -Wsuggest-attribute=const 
CXXWARNINGS += -Wsuggest-attribute=malloc -Wsuggest-attribute=format 
CXXWARNINGS += -Wmissing-format-attribute -Wduplicated-branches
CXXWARNINGS += -Wduplicated-cond -Wtautological-compare -Wtrampolines -Wfloat-equal
CXXWARNINGS += -Wundef -Wunused-macros -Wcast-align -Wconversion
CXXWARNINGS += -Wsizeof-pointer-div -Wsizeof-pointer-memaccess
CXXWARNINGS += -Wmissing-declarations 
CXXWARNINGS += -Wmissing-field-initializers -Wpacked -Wredundant-decls
CXXWARNINGS += -Winline -Wdisabled-optimization 

#Debugging options

CFLAGS.DEBUG=  -ggdb3
CXXFLAGS.DEBUG=  -ggdb3 

# clang doesn't support these options
ifneq ($(CC), clang)

ifneq ($(OS), web)
CFLAGS.DEBUG += -fvar-tracking -fvar-tracking-assignments -ginline-points -gstatement-frontiers # -fprofile-arcs -ftest-coverage
CXXFLAGS.DEBUG += -fvar-tracking -fvar-tracking-assignments -ginline-points -gstatement-frontiers
endif

endif


# Standard compile options
CFLAGS.RELEASE= -O2
CXXFLAGS.RELEASE= -O2

#Compiler options 
#OPTIONS  = -fipa-pure-const -ftrapv -freg-struct-return -fno-plt
#OPTIONS += -ftabstop=4
#OPTIONS += -finline-functions -findirect-inlining -finline-functions-called-once
#OPTIONS += -fipa-sra -fmerge-all-constants -fthread-jumps -fauto-inc-dec
#OPTIONS += -fif-conversion -fif-conversion2 -free -fexpensive-optimizations
#OPTIONS += -fshrink-wrap -fhoist-adjacent-loads
OPTIONS  += -fstack-protector -fstack-clash-protection -D_FORTIFY_SOURCES=2 -D_GNU_SOURCE 
ifneq ($(OS), Windows)
#OPTIONS  += -fsanitize=undefined
#OPTIONS  += -fsanitize=address
#OPTIONS  += -fsanitize=thread 
endif

COPTIONS += $(OPTIONS)

CXXOPTIONS  += -std=gnu++17
CXXOPTIONS += $(OPTIONS)

# Rust library

ifeq ($(OS), Windows)
WC_API_LIB_DIR.DEBUG = ./target/x86_64-pc-windows-gnu/debug
WC_API_LIB_DIR.RELEASE = ./target/x86_64-pc-windows-gnu/release
WC_API_LIB_DIR = ${WC_API_LIB_DIR.${BUILD}} 
WC_API_LIB.DEBUG = $(WC_API_LIB_DIR.DEBUG)/wc_api.dll
WC_API_LIB.RELEASE = $(WC_API_LIB_DIR.RELEASE)/wc_api.dll
else ifeq ($(OS), Linux)
WC_API_LIB_DIR.DEBUG = ./target/debug
WC_API_LIB_DIR.RELEASE = ./target/release
WC_API_LIB_DIR = ${WC_API_LIB_DIR.${BUILD}} 
WC_API_LIB.DEBUG = $(WC_API_LIB_DIR.DEBUG)/libwc_api.so
WC_API_LIB.RELEASE = $(WC_API_LIB_DIR.RELEASE)/libwc_api.so
endif

WC_API_LIB = ${WC_API_LIB.${BUILD}} 

#Include Directories
INC  = -I./
INC	+= -I./include

#Library options for each OS
ifeq ($(OS), Windows)
LDFLAGS += -lmsvcrt
LDFLAGS += -L/usr/x86_64-w64-mingw32/lib -L/usr/x86_64-w64-mingw32/bin -L$(LIB_INSTALL_DIR)/lib 
LIBS     = /usr/x86_64-w64-mingw32/lib/libws2_32.a 
else
ifeq ($(OS), web)
LDFLAGS += -lc
else
ifeq ($(OS), Linux)
LDFLAGS  += -lc

endif

ifeq ($(OS), macOS)
LDFLAGS += -lc
LDFLAGS += -L/usr/local/lib -L/opt/local/lib -L/opt/homebrew/lib

endif

endif

endif
LDFLAGS += -L$(WC_API_LIB_DIR) -lwc_api


CFLAGS  += -std=gnu17 -DHAVE_INLINE
CFLAGS	+= $(INC)

#Add build type flags
CFLAGS += ${CFLAGS.${BUILD}} 

CFLAGS += $(COPTIONS)
CFLAGS += $(WARNINGS)

CXXFLAGS	+= $(INC)	

#Add build type flags

CXXFLAGS += $(CXXOPTIONS) -D_GLIBCXX_USE_CXX11_ABI=0
CXXFLAGS += ${CFLAGS.${BUILD}} 

CXXFLAGS += $(WARNINGS)


# emscripten specific flags
ifeq ( $(OS), web )
CXXFLAGS += -s USE_SDL=2 -s DISABLE_EXCEPTION_CATCHING=1
LDFLAGS += -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=0 -s ASSERTIONS=1 --shell-file ./web/shell_minimal.html
endif

SRC_DIR 	 = ./c_test
CSRC		 = $(wildcard $(SRC_DIR)/*.c)
COBJ		 = $(CSRC:.c=.o)
CDEP	 	 = $(COBJ:.o=.d)

CXXSRC		+= $(wildcard $(SRC_DIR)/*.cpp)
CXXOBJ		 = $(CXXSRC:.cpp=.o)
CXXDEP		 = $(CXXOBJ:.o=.d)

RUSTSRC_DIR	 = ./src
RUSTSRC 	 = $(wildcard $(SRC_DIR)/*.rs)
RUSTSRC 	+= $(wildcard $(SRC_DIR)/boms/*.rs)
RUSTSRC 	+= $(wildcard $(SRC_DIR)/parts/*.rs)
RUSTSRC 	+= $(wildcard $(SRC_DIR)/prjs/*.rs)
RUSTSRC 	+= $(wildcard $(SRC_DIR)/invs/*.rs)

ifeq ($(OS), Windows)
all: $(PRGNAME) 
$(PRGNAME): $(COBJ) $(CXXOBJ) $(WC_API_LIB) $(LIBS) 
	@echo "Linking $@"
	$(CXX) -static $(CXXFLAGS) $(LDFLAGS) $^ -o $@

$(WC_API_LIB.DEBUG): $(RUSTSRC)
	cargo build --target x86_64-pc-windows-gnu

$(WC_API_LIB.RELEASE): $(RUSTSRC)
	cargo build -r --target x86_64-pc-windows-gnu

run: $(PRGNAME) wc-api.h
	cp $(WC_API_LIB) $(HOME)/.wine/drive_c/windows/system32
	wine ./$(PRGNAME)
#	env LD_LIBRARY_PATH=$(WC_API_LIB_DIR) LD_PRELOAD=$(WC_API_LIB) wine ./$(PRGNAME)

endif

ifeq ($(OS), web)
all: $(PRGNAME) 
$(PRGNAME): $(COBJ) $(CXXOBJ) $(LIBS)
	@echo "Linking $@"
	$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@
endif

ifeq ($(OS), macOS)
all: $(PRGNAME)
$(PRGNAME): $(COBJ) $(CXXOBJ) $(LIBS)
	@echo "Linking $@"
	$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@
endif

ifeq ($(OS), Linux)
all: $(PRGNAME)
$(PRGNAME): $(COBJ) $(CXXOBJ) $(LIBS) $(RUSTSRC)
	-@echo "Linking $@"
	-@$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $^

$(WC_API_LIB.DEBUG): $(RUSTSRC)
	cargo build

$(WC_API_LIB.RELEASE): $(RUSTSRC)
	cargo build -r

run: $(PRGNAME) wc-api.h
	env LD_LIBRARY_PATH=$(WC_API_LIB_DIR) LD_PRELOAD=$(WC_API_LIB) ./$(PRGNAME)

endif	

valgrind: memcheck leakcheck

memcheck: $(PRGNAME)
	env LD_LIBRARY_PATH=$(WC_API_LIB_DIR) LD_PRELOAD=$(WC_API_LIB) valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --track-origins=yes --show-reachable=yes --read-inline-info=yes --show-leak-kinds=possible  --gen-suppressions=all --log-file="valgrind.log" ./$(PRGNAME)
	mv ./valgrind.log ./memcheck.log

leakcheck: $(PRGNAME)
	env LD_LIBRARY_PATH=$(WC_API_LIB_DIR) LD_PRELOAD=$(WC_API_LIB) valgrind --leak-check=yes --track-origins=yes --show-reachable=yes --read-inline-info=yes --show-leak-kinds=possible --xtree-leak=yes --xtree-memory=full --gen-suppressions=all --xtree-memory-file="xtree_mem.log" --log-file="valgrind.log" ./$(PRGNAME)
	mv ./valgrind.log ./leakcheck.log


#run: $(PRGNAME) wc-api.h
#	env LD_LIBRARY_PATH=$(WC_API_LIB_DIR) LD_PRELOAD=$(WC_API_LIB) ./$(PRGNAME)

gdb: $(PRGNAME) wc-api.h
	env LD_LIBRARY_PATH=$(WC_API_LIB_DIR) LD_PRELOAD=$(WC_API_LIB) gdb ./$(PRGNAME)

wc-api.h: $(WC_API_LIB.${BUILD})

%.d: %.c
	@$(CC) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@

%.d: %.cpp
	@$(CXX) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@

.PHONY: clean clean-lib tests check wc-api.h $(WC_API_LIB.DEBUG) $(WC_API_LIB.RELEASE)
clean:
	-@echo "Cleaning project files"
	-@rm -f $(COBJ)
	-@rm -f $(CXXOBJ)
	-@rm -f $(CDEP)
	-@rm -f $(CXXDEP)
	-@rm -f $(PRGNAME)
	-@rm -f $(SRC_DIR)/*.gcda
	-@rm -f $(SRC_DIR)/*.gcno
	-@rm -f ./**/*.d
	-@rm -f *.gcov
	-@rm -rf ./release
	-@rm -f ./*.log
	-@rm -f ./xtleak*
	-@cargo clean

-include $(CDEP) $(CXXDEP)
