.PHONY: help full prng testing uuid core primitives all clean builddir build-test run-test codegen install build-lib ccodegen

# External variables
CC             = clang
CXX            = clang++
AR             = ar
BUILD_TYPE     = Debug
BUILD_DIR      = libwapp-build/$(PLATFORM)-$(BUILD_TYPE)
INSTALL_PREFIX = dist
CODEGEN_INPUT  = ""

# Internal variables
override CFLAGS              = -Wall -Wextra -Werror -pedantic -Isrc
override LIBFLAGS            = -fPIC
override CSTD               := -std=gnu11
override CXXSTD             := -std=gnu++11
override KERNEL             := $(shell uname -s)
override MACHINE            := $(shell uname -m)
override PLATFORM           := $(KERNEL)_$(MACHINE)
override TEST_INCLUDE       := -Isrc $(shell find tests -type d | xargs -I{} echo -n "-I{} ")
override TEST_SRC           := $(shell find tests -type f -name "*.c" | xargs -I{} echo -n "{} ")
override TEST_C_SRC         := src/wapp.c $(TEST_SRC)
override TEST_CXX_SRC       := $(shell find tests -type f -name "*.cc" | xargs -I{} echo -n "{} ")
override LIB_NAME           := wapp
override OBJ_OUT            := $(BUILD_DIR)/$(LIB_NAME).o
override LIB_OUT            := $(BUILD_DIR)/lib$(LIB_NAME).a
override TEST_C_OUT         := $(BUILD_DIR)/wapptest
override TEST_CXX_OUT       := $(BUILD_DIR)/wapptestcc
override ABS_INSTALL_PREFIX := $(shell mkdir -p $(INSTALL_PREFIX) && realpath $(INSTALL_PREFIX))
override INCLUDE_INSTALL    := $(ABS_INSTALL_PREFIX)/include/$(LIB_NAME)
override LIB_INSTALL        := $(ABS_INSTALL_PREFIX)/lib
override HEADER_INSTALL_CMD := scripts/header_install.sh

ifeq ($(origin BUILD_FLAGS), undefined)
ifeq ($(BUILD_TYPE),Debug)
	BUILD_FLAGS += -g -fsanitize=address,undefined -DWAPP_DEBUG_ASSERT
else ifeq ($(BUILD_TYPE),RelWithDebInfo)
	BUILD_FLAGS += -g -O2 -fsanitize=address,undefined -DWAPP_DEBUG_ASSERT
else ifeq ($(BUILD_TYPE),Release)
	BUILD_FLAGS += -O3
else
	$(error Invalid BUILD type '$(BUILD_TYPE)'. Use 'Debug', 'RelWithDebInfo' or 'Release')
endif
endif

ifeq ($(CC),gcc)
  # Used to disable the "ASan runtime does not come first in initial library list" error when compiling with gcc
  export ASAN_OPTIONS=verify_asan_link_order=0
endif

all: clean builddir codegen run-c-test full run-cc-test

help:
	@echo "Available build variables:"
	@echo "  CC                C compiler to use (Default: clang)."
	@echo "  CXX               C++ compiler to use (Default: clang++)."
	@echo "  AR                Archiving utility to use for building static libraries (Default: ar)."
	@echo "  BUILD_TYPE        Build type. Choose from \`Debug\`, \`RelWithDebInfo\` or \`Release\` (Default: Debug)."
	@echo "  BUILD_DIR         Directory where build files will be written."
	@echo "  INSTALL_PREFIX    Prefix where library and include files will be installed."
	@echo "  CODEGEN_INPUT     Input file for code generation (See codegen_custom_data_example.json for an example)."
	@echo
	@echo "Available targets:"
	@echo "  make              Build, install and test the full wapp library."
	@echo "  make full         Build and install the full wapp library."
	@echo "  make core         Build and install only the \`core\` component of the wapp library with all its dependencies."
	@echo "  make prng         Build and install only the \`prng\` component of the wapp library with all its dependencies."
	@echo "  make uuid         Build and install only the \`uuid\` component of the wapp library with all its dependencies."
	@echo "  make testing      Build and install only the \`testing\` component of the wapp library with all its dependencies."
	@echo "  make primitives   Build and install only the \`primitives\` component of the wapp library with all its dependencies."
	@echo "  make clean        Clean build directory."
	@echo "  make help         Print this help message and exit."

full: LIB_SRC = src/wapp.c
full: INCLUDES = common core primitives prng testing uuid
full: install

prng: LIB_SRC = src/prng/wapp_prng.c
prng: INCLUDES = common prng
prng: install

testing: LIB_SRC = src/testing/wapp_testing.c
testing: INCLUDES = common core testing
testing: install

uuid: LIB_SRC = src/uuid/wapp_uuid.c
uuid: INCLUDES = common primitives prng
uuid: install

core: LIB_SRC = src/core/wapp_core.c
core: INCLUDES = common core primitives
core: install

primitives: LIB_SRC = src/primitives/wapp_primitives.c
primitives: INCLUDES = common primitives
primitives: install

clean:
	@rm -rf $(BUILD_DIR)

builddir:
	@mkdir -p $(BUILD_DIR)

build-c-test:
	$(CC) $(CSTD) $(CFLAGS) $(BUILD_FLAGS) $(TEST_INCLUDE) $(TEST_C_SRC) -o $(TEST_C_OUT)

run-c-test: build-c-test
	@echo -e "\n\033[34;1mRUNNING C TESTS\033[0m"
	@$(TEST_C_OUT)
	@rm $(TEST_C_OUT)

build-cc-test:
	$(CXX) $(CXXSTD) $(CFLAGS) $(BUILD_FLAGS) $(TEST_INCLUDE) $(TEST_CXX_SRC) $(LIB_OUT) -o $(TEST_CXX_OUT)

run-cc-test: build-cc-test
	@echo -e "\n\033[34;1mRUNNING C++ TESTS\033[0m"
	@export LD_LIBRARY_PATH=$$LD_LIBRARY_PATH:$(BUILD_DIR) && $(TEST_CXX_OUT)
	@rm $(TEST_CXX_OUT)

codegen:
	python3 -m codegen -f $(CODEGEN_INPUT)

install: codegen build-lib
	@mkdir -p $(LIB_INSTALL)
	@cp -v $(LIB_OUT) $(LIB_INSTALL)
	@mkdir -p $(INCLUDE_INSTALL)
	@bash $(HEADER_INSTALL_CMD) $(LIB_SRC) $(INCLUDE_INSTALL) $(INCLUDES)

build-lib: builddir
	$(CC) -c $(CSTD) $(CFLAGS) $(BUILD_FLAGS) $(LIBFLAGS) $(LIB_SRC) -o $(OBJ_OUT)
	$(AR) r $(LIB_OUT) $(OBJ_OUT)
	@rm $(OBJ_OUT)

ccodegen:
	$(CC) $(CSTD) $(CFLAGS) $(BUILD_FLAGS) $(LIBFLAGS) -Isrc/core src/core/wapp_core.c ccodegen/*.c -o ccgen
