#+++++++++++++++++++++++++++++++++configure++++++++++++++++++++++++++++++++++++++++
# OS=Windows,Linux,Android
# ARCH=x86,x86_64,arm,aarch64
# CC  = $(CROSS_COMPILE)gcc
# CXX = $(CROSS_COMPILE)g++
# CPPFLAGS += $(addprefix -D, $(DEFINES))
# CPPFLAGS += $(addprefix -I, $(SRCDIRS))
# CPPFLAGS += $(addprefix -I, $(INCDIRS))
# LDFLAGS  += $(addprefix -L, $(LIBDIRS))
# LDFLAGS  += $(addprefix -l, $(LIBS))
#
# Usage:
# make all TARGET=libxx TARGET_TYPE=SHARED \
# CROSS_COMPILE=arm-linux-androideabi- \
# DEFINES=USE_OPENCV \
# LIBS="opencv_core opencv_highgui"
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

# VARIABLES
TARGET=test
#BUILD_TYPE=DEBUG,RELEASE
BUILD_TYPE=RELEASE
#TARGET_TYPE=EXECUTABLE,SHARED,STATIC
TARGET_TYPE=EXECUTABLE

# COMMANDS
ifdef CROSS_COMPILE
CC 	= $(CROSS_COMPILE)gcc
CXX = $(CROSS_COMPILE)g++
CPP = $(CC) -E
AS 	= $(CROSS_COMPILE)as
LD	= $(CROSS_COMPILE)ld
AR	= $(CROSS_COMPILE)ar
NM	= $(CROSS_COMPILE)nm
STRIP 	= $(CROSS_COMPILE)strip
OBJCOPY	= $(CROSS_COMPILE)objcopy
OBJDUMP	= $(CROSS_COMPILE)objdump
endif

MKDIR = -mkdir -p 2>/dev/null
CP = -cp -r 2>/dev/null
RM = -rm -r 2>/dev/null

# PLATFORM: OS, ARCH
CC_VERSION=$(shell $(CC) --version 2>&1 | head -n 1)
TARGET_PLATFORM=$(shell $(CC) -v 2>&1 | grep Target | sed 's/Target: //')
ifneq ($(findstring mingw, $(TARGET_PLATFORM)), )
	OS=Windows
endif
ifneq ($(findstring android, $(TARGET_PLATFORM)), )
	OS=Android
endif
ifndef OS
	OS=Linux
endif

ifndef ARCH
ARCH=$(shell echo $(TARGET_PLATFORM) | awk -F'-' '{print $$1}')
endif

# CFLAGS, CXXFLAGS, ARFLAGS
ifeq ($(BUILD_TYPE), DEBUG)
	DEFAULT_CFLAGS = -g -Wall
endif
DEFAULT_CFLAGS += -O3 -fPIC

ifndef CFLAGS
CFLAGS := $(DEFAULT_CFLAGS) -std=c99
else
ifeq ($(findstring -fPIC, $(CFLAGS)), )
override CFLAGS += -fPIC
endif
ifeq ($(findstring -std, $(CFLAGS)), )
override CFLAGS += -std=c99
endif
endif

ifndef CXXFLAGS
CXXFLAGS := $(DEFAULT_CFLAGS) -std=c++11
else
ifeq ($(findstring -fPIC, $(CXXFLAGS)), )
override CXXFLAGS += -fPIC
endif
ifeq ($(findstring -std, $(CXXFLAGS)), )
override CXXFLAGS += -std=c++11
endif
endif

ifndef ARFLAGS
ARFLAGS := cr
endif

# DIRS
PREFIX = install
ifeq ($(OS), Linux)
	PREFIX = /usr/local
endif
INCDIR = include
LIBDIR = lib
SRCDIR = src
BINDIR = bin
DEPDIR = 3rd
CONFDIR = etc
DISTDIR = dist
DOCDIR  = doc

SRCDIRS += $(shell find $(SRCDIR) -type d)
override INCDIRS += $(INCDIR) $(DEPDIR) $(DEPDIR)/include
override LIBDIRS += $(LIBDIR) $(DEPDIR)/lib $(DEPDIR)/lib/$(TARGET_PLATFORM)

# CPPFLAGS
ifeq ($(OS), Windows)
	CPPFLAGS += -D_WIN32_WINNT=0x600
ifeq ($(TARGET_TYPE), SHARED)
	CPPFLAGS += -DDLL_EXPORTS
endif
endif

ifeq ($(TARGET_TYPE), STATIC)
	CPPFLAGS += -DHV_STATICLIB
endif

ifeq ($(BUILD_TYPE), DEBUG)
	CPPFLAGS += -DDEBUG
else
	CPPFLAGS += -DNDEBUG
endif

CPPFLAGS += $(addprefix -D, $(DEFINES))
CPPFLAGS += $(addprefix -I, $(INCDIRS))
CPPFLAGS += $(addprefix -I, $(SRCDIRS))

# LDFLAGS
ifeq ($(OS), Windows)
	LDFLAGS += -static-libgcc -static-libstdc++
endif
ifneq ($(findstring WITH_CURL, $(DEFINES)), )
override LIBS += curl
ifeq ($(OS), Windows)
LIBS += wldap32 advapi32 crypt32
endif
endif
ifneq ($(findstring WITH_NGHTTP2, $(DEFINES)), )
override LIBS += nghttp2
endif
ifneq ($(findstring WITH_OPENSSL, $(DEFINES)), )
override LIBS += ssl crypto
endif
LDFLAGS += $(addprefix -L, $(LIBDIRS))
LDFLAGS += $(addprefix -l, $(LIBS))

ifeq ($(OS), Windows)
	LDFLAGS += -lwinmm -liphlpapi -lws2_32
ifneq ($(findstring WITH_WINDUMP, $(DEFINES)), )
	LDFLAGS += -ldbghelp
endif
	LDFLAGS += -Wl,-Bstatic -lstdc++ -lpthread -lm
else
ifeq ($(OS), Android)
	LDFLAGS += -lstdc++ -lm -llog -ldl
else
	LDFLAGS += -lstdc++ -lpthread -lm -ldl -lrt
endif
endif

override SRCS += $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c $(dir)/*.cc $(dir)/*.cpp))
ifeq ($(SRCS), )
	SRCS = $(wildcard *.c *.cc *.cpp)
endif
#OBJS += $(patsubst %.c, %.o, $(SRCS))
#OBJS += $(patsubst %.cc, %.o, $(SRCS))
#OBJS += $(patsubst %.cpp, %.o, $(SRCS))
OBJS := $(addsuffix .o, $(basename $(SRCS)))

INSTALLED_INCS=$(addprefix $(PREFIX)/$(INCDIR)/, $(shell ls $(INCDIR)))
INSTALLED_LIBS=$(addprefix $(PREFIX)/$(LIBDIR)/, $(shell ls $(LIBDIR)))
INSTALLED_BINS=$(addprefix $(PREFIX)/$(BINDIR)/, $(shell ls $(BINDIR)))

# info
$(info $(CC_VERSION))

$(info OS   = $(OS))
$(info ARCH = $(ARCH))
$(info MAKE = $(MAKE))
$(info CC   = $(CC))
$(info CXX  = $(CXX))

$(info CFLAGS   = $(CFLAGS))
$(info CXXFLAGS = $(CXXFLAGS))
$(info CPPFLAGS = $(CPPFLAGS))
$(info LDFLAGS  = $(LDFLAGS))

$(info TARGET           = $(TARGET))
$(info TARGET_TYPE      = $(TARGET_TYPE))
$(info TARGET_PLATFORM  = $(TARGET_PLATFORM))
$(info BUILD_TYPE       = $(BUILD_TYPE))

$(info SRCS=$(SRCS))
$(info OBJS=$(OBJS))

#$(info INSTALLED_INCS=$(INSTALLED_INCS))
#$(info INSTALLED_LIBS=$(INSTALLED_LIBS))
#$(info INSTALLED_BINS=$(INSTALLED_BINS))

default: all

all: prepare $(TARGET)

prepare:
	$(MKDIR) $(BINDIR) $(LIBDIR)

$(TARGET): $(OBJS)
ifeq ($(TARGET_TYPE), SHARED)
ifeq ($(OS), Windows)
	$(CC) -shared $^ -o $(LIBDIR)/$@.dll $(LDFLAGS) -Wl,--output-def,$(LIBDIR)/$(@).def
else
	$(CC) -shared $^ -o $(LIBDIR)/$@.so $(LDFLAGS)
endif
else
ifeq ($(TARGET_TYPE), STATIC)
	$(AR) $(ARFLAGS) $(LIBDIR)/$@.a $^
else
ifeq ($(OS), Windows)
	$(CC) $^ -o $(BINDIR)/$@.exe $(LDFLAGS)
else
	$(CC) $^ -o $(BINDIR)/$@ $(LDFLAGS)
endif
endif
endif

clean:
	$(RM) $(OBJS)
	#$(RM) $(LIBDIR)
	#$(RM) $(BINDIR)

install:
	$(CP) $(INCDIR)/* $(PREFIX)/$(INCDIR)/
	$(CP) $(LIBDIR)/* $(PREFIX)/$(LIBDIR)/
	$(CP) $(BINDIR)/* $(PREFIX)/$(BINDIR)/

uninstall:
	$(RM) $(INSTALLED_INCS)
	$(RM) $(INSTALLED_LIBS)
	$(RM) $(INSTALLED_BINS)

dist:
	$(MKDIR) $(DISTDIR)
	$(CP) $(INCDIR) $(LIBDIR) $(BINDIR) $(CONFDIR) $(DOCDIR) $(DISTDIR)

undist:
	$(RM) $(DISTDIR)

.PHONY: default all prepare clean install uninstall dist undist

