export LANG=en_US
ALL_CONFIGURATIONS := POSIX WIN32
.PHONY: all clean tests docs cleandocs distr DUMMY

# Configurations
TITAN_HOME    = C:/Eclipse/Titan
OPENSSL_WIN32 = C:/OpenSSL/Win32

CSHAREDDIR ?= cshared 
CXMLDIR ?= cxml

ifeq ($(ARCH),)
 ARCH = $(shell gcc -dumpmachine)
 GCC := gcc
 GPP := g++
else
 GCC := $(addprefix $(addsuffix -,$(ARCH)), gcc)
 GPP := $(addprefix $(addsuffix -,$(ARCH)), g++)
endif

ifneq ($(findstring w32,$(ARCH)),)
 packages := $(filter-out readline threads, $(packages))
 CFG  += WIN32
else 
 CFG  += POSIX
 ifeq ($(findstring cygwin,$(ARCH)),)
  cflags += -fPIC
 endif
endif

cflags   += -Wall

ifeq ($(DEBUG),)
 DEBUG=no
endif

ifeq ($(DEBUG),yes)
  cflags  += -g -O0
  defines += DEBUG
  dsuffix = -d
else
  defines += NDEBUG
  cflags  += -O2
endif

ifneq ($(filter readline, $(packages)),)
  defines += USE_READLINE
  libs    += -lreadline
endif

ifneq ($(filter dmalloc, $(packages)),)
  defines  += DMALLOC DMALLOC_FUNC_CHECK
  libs     += -ldmalloc
  dsuffix   = -dmalloc
endif

ifneq ($(filter thread, $(packages)),)
  defines += USE_THREADS
  libs    += -lpthread
endif

ifneq ($(filter profile, $(packages)),)
  cflags += -pg
endif

ifneq ($(filter openssl, $(packages)),)
 ifneq ($(findstring mingw32,$(ARCH)),)
  includes += $(OPENSSL_WIN32)/include
  libs     += $(OPENSSL_WIN32)/lib/MinGW/libeay32.a $(OPENSSL_WIN32)/lib/MinGW/ssleay32.a
 else
  libs    += -lssl -lcrypto
 endif
endif

ifneq ($(filter cxml, $(packages)),)
  predirs += $(CXMLDIR)
  includes += $(CXMLDIR)
endif

ifneq ($(filter cshared, $(packages)),)
  predirs += $(CSHAREDDIR)
  includes += $(CSHAREDDIR)
endif

ifneq ($(filter titan, $(packages)),)
  includes += $(TITAN_HOME)/include $(BUILDROOT)
endif

ifeq ($(testdir), )
  testdir := tests
endif

includes  += $(foreach cfg,$(CFG),$(includes-$(cfg)))
defines   += $(foreach cfg,$(CFG),$(defines-$(cfg)))
libs      += $(foreach cfg,$(CFG),$(libs-$(cfg)))
sources   += $(foreach cfg,$(CFG),$(sources-$(cfg)))
headers   += $(foreach cfg,$(CFG),$(headers-$(cfg)))
tests     += $(foreach cfg,$(CFG),$(tests-$(cfg)))
distfiles += $(foreach cfg,$(CFG),$(distfiles-$(cfg)))
predirs   += $(foreach cfg,$(CFG),$(predirs-$(cfg)))
postdirs  += $(foreach cfg,$(CFG),$(postdirs-$(cfg)))

tests     := $(addprefix $(addsuffix /,$(testdir)),$(tests))
sources   := $(addprefix $(addsuffix /,$(srcdir)),$(sources))
headers   := $(addprefix $(addsuffix /,$(incdir)),$(headers))

cflags    += $(addprefix -I, $(includes)) $(addprefix -D, $(defines))

csources  := $(filter %.c, $(sources))
cppsources:= $(filter %.cpp, $(sources))
ccsources := $(filter %.cc, $(sources))
othsources:= $(filter-out $(csources) $(cppsources) $(ccsources), $(sources))

ifeq ($(BUILDROOT),)
 BUILDROOT = .
endif

outdir    := $(BUILDROOT)/$(ARCH)$(dsuffix)
objdir    := $(outdir)/$(PROJECT)
testbins  := $(patsubst %.c, $(outdir)/%, $(tests))
dirs      := $(objdir) $(outdir)/tests

cobjects  := $(patsubst %.c,   $(objdir)/%.o, $(csources))
cppobjects:= $(patsubst %.cpp, $(objdir)/%.o, $(cppsources))
ccobjects := $(patsubst %.cc,  $(objdir)/%.o, $(ccsources))
objects   := $(cobjects) $(cppobjects) $(ccobjects)

alibnames  := $(patsubst %, $(outdir)/lib%.a,  $(alibs))
solibnames := $(patsubst %, $(outdir)/lib%.so, $(solibs))
binnames   := $(patsubst %, $(outdir)/%, $(bins))

ldflags += $(patsubst %, -L%, $(outdir) $(libdirs))

ifneq ($(filter cxml, $(packages)),)
  libs += $(outdir)/libcxml.a
endif

ifneq ($(filter cshared, $(packages)),)
  libs += $(outdir)/libcshared.a
endif


all: $(dirs) $(predirs) $(alibnames) $(solibnames) $(binnames) $(postdirs)

tests: all $(testbins)

$(predirs) $(postdirs): DUMMY
	$(MAKE) -C $@ BUILDROOT=$(realpath $(BUILDROOT)) DEBUG=$(DEBUG)

$(alibnames): $(outdir)/lib%.a : $(objects)
	ar rcs $@ $^

$(solibnames): $(outdir)/lib%.so : $(objects)
	$(GCC) $(cflags) -shared $(ldflags) -o $@ $^ $(csharedlib) $(libs)

$(binnames): $(outdir)/% : $(objects)
	$(GCC) $(cflags)  $(ldflags) -o $@ $^ $(csharedlib) $(libs)

$(testbins): $(alibnames)
$(testbins): $(outdir)/tests/% : tests/%.c
	$(GCC) $(cflags) -o $@ $< $(alibnames) $(libs)

$(dirs):
	mkdir -p $@

$(cobjects): $(objdir)/%.o: %.c
	@mkdir -p $(dir $@)
	$(GCC)  $(cflags) -o $@ -MMD -MF $(objdir)/$*.d -c $<

$(cppobjects): $(objdir)/%.o: %.cpp
	@mkdir -p $(dir $@)
	$(GPP)  $(cflags) $(ccflags) -o $@ -MMD -MF $(objdir)/$*.d -c $<

$(ccobjects): $(objdir)/%.o: %.cc
	@mkdir -p $(dir $@)
	$(GPP)  $(cflags) $(ccflags) -o $@ -MMD -MF $(objdir)/$*.d -c $<

clean:
	rm -rf $(alibnames) $(solibnames) $(binnames) $(testbins) $(objects)

distfiles += $(wildcard Makefile $(DOXYFILE))
dist:
	-rm -rf $(PROJECT) $(PROJECT)-$(shell date -u '+%Y%m%d').tar.gz
	mkdir $(PROJECT)
	cp --parents $(sources) $(headers) $(distfiles) $(addprefix tests/, $(tests)) $(PROJECT)
	tar -zcvf $(PROJECT)-$(shell date -u '+%Y%m%d').tar.gz $(PROJECT)
	rm -rf $(PROJECT)
#	tar -zcvf $(PROJECT)-$(shell date -u '+%Y%m%d').tar.gz $(sources) $(headers) $(distfiles) $(addprefix tests/, $(tests))

ifneq (,$(DOXYFILE))
docs: $(DOXYFILE)
	doxygen $(DOXYFILE)

cleandocs:
	rm -rf doc/html
endif

include $(wildcard $(addsuffix /*.d, $(objdir)))
