#!/usr/bin/make -f
# -*- Makefile -*-

######
#   I. Establish the root module of this subtree.
#      That will allow the path prefix to be established.
######

ifndef PREFIX_ESTABLISHED

# set base before recursive loading begins
ifndef MK_START
MK_START := $M
ALL_MODULES :=
endif

ifneq ($(strip $($M/A_ROOT_MODULE)),1)

# start recursive loading of lower level makes until
#  root is found.
NEXT_M_STACK := $M $(NEXT_M_STACK)

M := $(subst /XxXx,,$(dir $M)XxXx)
NEXT_M_STACK := $M $(NEXT_M_STACK)
include $M/mevmake.mk

# pop
M := $(firstword $(NEXT_M_STACK))
NEXT_M_STACK := $(wordlist 2, 20, $(NEXT_M_STACK))

else

P := $(dir $M)
MK_ROOT := $M

endif

PREFIX_ESTABLISHED := 1

## generic stuff that just needs to be defined once
.PHONY: clean allclean debug
endif

######
#  II. Establish operating system specific variables
######

ifndef MK_VARIABLES_ONCE
MK_VARIABLES_ONCE := 1
ifneq ($(filter debug,$(MAKECMDGOALS)),)
DEBUG := 1

ifeq ($(filter-out debug,$(MAKECMDGOALS)),)
debug: build
endif
endif



.SUFFIXES:
.SUFFIXES: .c .cpp .h .d

ifeq ($(OS),Windows_NT)

# Windows extensions
O := obj
B := exe
E := exe
A := lib
L := lib
S := dll
D := d

CC := cl
CXX := cl
CPP := cl
AR  = lib /OUT:$@
RANLIB := rem

MK_INCLUDES := -I$(subst /XxXx,,$(dir $P)XxXx)
MK_LIBS :=
DEBUG_CPPFLAGS = /ZI /Gm /MLd /D "_DEBUG" 
DEBUG_LDFLAGS = /incremental:yes /debug /pdbtype:sept 

.SUFFIXES: .obj .exe .lib .dll

# this is a "function" to translate file name into dependency lists per .d files
GET_DEPS = $(foreach file, $($(1)), $($(file).DEPS))
GET_DEPS2 = $(foreach file, $($(1)), $($(addprefix $(MS)/,$(file)).DEPS))

else

# Linux extensions
O := o
B := e
E := e
A := a
L := a
S := s
D := d

CC := gcc
CXX := g++
CPP := gcc
AR  = ar cru $@
RANLIB := ranlib

MK_INCLUDES := -I$(subst /XxXx,,$(dir $P)XxXx)
MK_LIBS :=

.SUFFIXES: .o .a .s

# this is a "function" to translate file name into dependency lists per .d files
GET_DEPS = $(addsuffix .$O,$(basename $($(1))))
GET_DEPS2 = $(addsuffix .$O,$(basename $(addprefix $(MO)/,$($(1)))))

#GET_DEPS = $($1)

endif
endif

######
# III. Set up default compiler flags for module and global
######

ifeq ($(OS),Windows_NT)

$M/CFLAGS   = /nologo $(GCFLAGS)
$M/CPPFLAGS = /D "WIN32" /D "_CONSOLE" /D "_MBCS" $(GCPPFLAGS)
$M/CXXFLAGS = /nologo /W3 /GX /Od /GZ $(GCXXFLAGS) 
ifndef DEBUG
$M/CXXFLAGS += /ML
endif

$M/DEPS = /P

$M/LDFLAGS  = /link /nologo /subsystem:console /machine:I386 /pdb:"$(subst .$B,.pdb,$@)" /incremental:no $(GLDFLAGS)
$M/LDLIBS   = kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib $(GLDLIBS)
$M/OUTPUT_OPTION = /FD /Fo"$(MO)/" /Fe"$(MB)/" /Fd"$(basename $@)" 

else

#linux stuff
$M/CFLAGS = -g -O2 -Wall
$M/CPPFLAGS = -I/usr/local/include 
$M/CXXFLAGS = -g -O2

$M/DEPS = -M | sed -e 's@ /usr/i[^ ]*@@g' -e 's@^\(.*\).o:@$(MO)/\1.d $(MO)/\1.o:@' > $@

$M/LDFLAGS = 
$M/LDLIBS = -L/usr/local/lib

$M/OUTPUT_OPTION = -o $@
endif


## globals, ensure the definition only happens once

ifdef DEBUG
ifndef DEBUG_DONE
GCPPFLAGS += $(DEBUG_CPPFLAGS)
GLDFLAGS += $(DEBUG_LDFLAGS)
DEBUG_DONE:=1
endif
endif

ifdef MK_THREADS
ifndef MK_THREADS_DONE

MK_THREADS_DONE :=1
endif
endif


######
# III. Recursively load makefiles for other modules
#####

# protect against duplicates
$M/MODULES_NEEDED := $(addprefix $P,$(sort $($M/MODULES_NEEDED)))

# what modules still need to be loaded
$M/NEW_MODULES := $(filter-out $(ALL_MODULES), $($M/MODULES_NEEDED))
ALL_MODULES += $($M/NEW_MODULES)

# load any missing modules
ifneq ($($M/NEW_MODULES),)

$M/NEW_MAKES := $(addsuffix /mevmake.mk, $($M/NEW_MODULES))

# push
MODULE_STACK := $M $(MODULE_STACK)

# the next sequence assumes that NONE of the mevmake's 
#  will be configured dynamically (might still work, but
#  not tested)
NEXT_M_STACK := $($M/NEW_MODULES) $(NEXT_M_STACK)
include $($M/NEW_MAKES)

## NOTE: if NEXT_M_STACK fails, 
##  try "include $(foreach dir,$(M/NEW_MODULES),$(call M,$dir)
##  with M := $(1) in the line before ... just a thought ...

# pop
M := $(firstword $(MODULE_STACK))
MODULE_STACK := $(wordlist 2, 20, $(MODULE_STACK))
endif

######
#  IV. Build module specific path variables
#####

# Establish default Windows Visual Studio Paths
ifeq ($(OS),Windows_NT)

ifdef DEBUG
WIN_DEFAULT :=Debug
else
WIN_DEFAULT :=Release
endif

$M/OBJ_PATH := $(if $($M/OBJ_PATH),$($M/OBJ_PATH),$(WIN_DEFAULT))
$M/LIB_PATH := $(if $($M/LIB_PATH),$($M/LIB_PATH),$(WIN_DEFAULT))
$M/BIN_PATH := $(if $($M/BIN_PATH),$($M/BIN_PATH),$(WIN_DEFAULT))

endif

MS := $M$(if $($M/SRC_PATH),/$($M/SRC_PATH),)
MI := $M$(if $($M/INC_PATH),/$($M/INC_PATH),)
MO := $M$(if $($M/OBJ_PATH),/$($M/OBJ_PATH),)
ML := $M$(if $($M/LIB_PATH),/$($M/LIB_PATH),)
MB := $M$(if $($M/BIN_PATH),/$($M/BIN_PATH),)
ME := $(MB)

$M/BUILD_BINS := $(addsuffix .$B,$($M/BUILD_BINS))
$M/BUILD_ARCS := $(addsuffix .$A,$($M/BUILD_ARCS))
$M/BUILD_DLLS := $(addsuffix .$D,$($M/BUILD_DLLS))

$M/BUILD_DEPS := $(addprefix $(MO)/,$(addsuffix .$D,$(basename $($M/BUILD_SRCS))))
$M/BUILD_OBJS := $(addprefix $(MO)/,$(addsuffix .$O,$(basename $($M/BUILD_SRCS))))

$M/BUILD_SRCS := $(addprefix $(MS)/,$($M/BUILD_SRCS))
$M/BUILD_BINS := $(addprefix $(MB)/,$($M/BUILD_BINS))
$M/BUILD_ARCS := $(addprefix $(ML)/,$($M/BUILD_ARCS))
$M/BUILD_DLLS := $(addprefix $(ML)/,$($M/BUILD_DLLS))

######
#   V. Target specific variables and implicit rules
#####

# only define implicit rules once
#ifeq ($(MK_START),$M)
ifndef MK_RULES_ONCE
MK_RULES_ONCE := 1

# add DEFS to the underlying compile macros
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(MK_INCLUDES) $(TARGET_ARCH) -c 
COMPILE.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(MK_INCLUDES) $(TARGET_ARCH) -c 
LINK.o = $(CC) $(TARGET_ARCH) 
LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(MK_INCLUDES) $(TARGET_ARCH) 
LINK.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(MK_INCLUDES) $(TARGET_ARCH) 
#OUTPUT_OPTION =

clean:
	$(RM) $($M/BUILD_ARCS) $($M/BUILD_BINS) $($M/BUILD_OBJS) $($M/BUILD_DEPS) $(MO)/*.idb $(MO)/*.pdb
	$(if $(wildcard $^),$(RM) $(wildcard $^))

allclean:
	$(if $^,$(RM) $^)
endif

# set default target on start make only
ifeq ($(MK_START),$M)
build: $($M/BUILD_ARCS) $($M/BUILD_BINS)
endif

$(MO)/%.$O: $(MS)/%.c  
	$(COMPILE.c) $< $(OUTPUT_OPTION)

$(MO)/%.$O: $(MS)/%.cpp
	$(COMPILE.cc) $< $(OUTPUT_OPTION)

$(MO)/%.$D: $(MS)/%.c  
	@echo -- Creating dependency file for $<
	$(patsubst /Z%,,@$(COMPILE.c) $< $($M/DEPS))
ifeq ($(OS),Windows_NT)
	@mvdeps $(addsuffix .i,$(basename $(notdir $<))) $@
	@$(RM) $(addsuffix .i,$(basename $(notdir $<)))
endif

$(MO)/%.$D: $(MS)/%.cpp
	@echo -- Creating dependency file for $<
	$(patsubst /Z%,,@$(COMPILE.cc) $< $($M/DEPS))
ifeq ($(OS),Windows_NT)
	@mvdeps $(addsuffix .i,$(basename $(notdir $<))) $@
	@$(RM) $(addsuffix .i,$(basename $(notdir $<)))
endif

$(MB)/%.$B: $(MO)/%.$O
	$(LINK.o) $(filter %.$O,$^) $(OUTPUT_OPTION) $(LDFLAGS) $(MK_LIBS) $(LDLIBS)

#$(MB)/%.$B: $(MS)/%.c
#	$(LINK.c) $(filter %.c,$^) $(OUTPUT_OPTION) $(LDFLAGS) $(MK_LIBS) $(LDLIBS)

#$(MB)/%.$B: $(MS)/%.cpp
#	$(LINK.cc) $(filter %.cpp,$^) $(OUTPUT_OPTION) $(LDFLAGS) $(MK_LIBS) $(LDLIBS)

$(MB)/%.$B:
	$(if $(filter %.c,$^), $(LINK.c)  $(filter %.c,$^) $(OUTPUT_OPTION) $(LDFLAGS) $(MK_LIBS) $(LDLIBS))
	$(if $(filter %.cpp,$^), $(LINK.cc) $(filter %.cpp,$^) $(OUTPUT_OPTION) $(LDFLAGS) $(MK_LIBS) $(LDLIBS))

$(ML)/%.$L:
	$(if $(filter %.c,$^), $(COMPILE.c)  $(filter %.c,$^) $(OUTPUT_OPTION))
	$(if $(filter %.cpp,$^), $(COMPILE.cc) $(filter %.cpp,$^) $(OUTPUT_OPTION))
	$(RM) $@
	$(AR) $(patsubst  $(MS)/%.c,$(MO)/%.$O,$(filter %.c,$^)) $(patsubst $(MS)/%.cpp,$(MO)/%.$O,$(filter %.cpp,$^)) $(filter %.$O,$^)



#setup include paths and libraries based upon needed modules & libs
$M/ARCS_PUBLISHED := $(addsuffix .$A,$($M/ARCS_PUBLISHED))
$M/ARCS_PUBLISHED := $(addprefix $(ML)/,$($M/ARCS_PUBLISHED))

$M/BINS_PUBLISHED := $(addsuffix .$B,$($M/BINS_PUBLISHED))
$M/BINS_PUBLISHED := $(addprefix $(MB)/,$($M/BINS_PUBLISHED))


ifeq ($(OS),Windows_NT)
MK_LIBS += $($M/ARCS_PUBLISHED)
else
MK_LIBS := $(foreach lib,$($M/ARCS_PUBLISHED),-L$(dir $(lib)) -l$(patsubst lib%,%,$(basename $(notdir $(lib))))) $(MK_LIBS)
endif

MK_INCLUDES += $(sort $(if $($M/INC_PATH_PUBLISHED),$(addprefix -I$M/,$($M/INC_PATH_PUBLISHED))) -I$M $(if $($M/INC_PATH),-I$M/$($M/INC_PATH)))


# create prerequisites out of libraries_need list
MK_TEMP := $(addsuffix .$A,$($M/LIBRARIES_NEEDED))
MK_TEMP := $(addprefix %/,$(MK_TEMP))
MK_TEMP := $(foreach mod, $($M/MODULES_NEEDED), $(filter $(MK_TEMP),$($(mod)/ARCS_PUBLISHED)))

ifneq ($(words $(MK_TEMP)),$(words $($M/LIBRARIES_NEEDED)))
$(error Libraries needed not found in published list of modules needed.)
endif

$M/LIBRARIES_NEEDED := $(MK_TEMP)

ifneq ($(strip $($M/BUILD_ARCS)),)
$($M/BUILD_ARCS): $($M/LIBRARIES_NEEDED)
endif

ifneq ($(strip $($M/BUILD_BINS)),)
$($M/BUILD_BINS): $($M/ARCS_PUBLISHED) $($M/LIBRARIES_NEEDED)
endif

allclean: $(wildcard $($M/BUILD_ARCS) $($M/BUILD_BINS) $($M/BUILD_OBJS) $($M/BUILD_DEPS) $(MO)/*.idb $(MO)/*.pdb)


# set up rules based upon target paths

MK_TEMP := $(if $(wildcard $(MB)),,$(shell mkdir $(MB)))
$(MB)/% : CFLAGS   = $($M/CFLAGS)
$(MB)/% : CPPFLAGS = $($M/CPPFLAGS)
$(MB)/% : CXXFLAGS = $($M/CXXFLAGS)
$(MB)/% : LDFLAGS  = $($M/LDFLAGS)
$(MB)/% : LDLIBS   = $($M/LDLIBS)
$(MB)/% : OUTPUT_OPTION = $($M/OUTPUT_OPTION)
$(MB)/% : M        := $M
$(MB)/% : MS       := $(MS)
$(MB)/% : MI       := $(MI)
$(MB)/% : MO       := $(MO)
$(MB)/% : ML       := $(ML)
$(MB)/% : MB       := $(MB)
$(MB)/% : ME       := $(ME)

ifneq ($(MB),$(ML))
MK_TEMP := $(shell mkdir $(ML))
$(ML)/% : CFLAGS   = $($M/CFLAGS)
$(ML)/% : CPPFLAGS = $($M/CPPFLAGS)
$(ML)/% : CXXFLAGS = $($M/CXXFLAGS)
$(ML)/% : LDFLAGS  = $($M/LDFLAGS)
$(ML)/% : LDLIBS   = $($M/LDLIBS)
$(ML)/% : OUTPUT_OPTION = $($M/OUTPUT_OPTION)
$(ML)/% : M        := $M
$(ML)/% : MS       := $(MS)
$(ML)/% : MI       := $(MI)
$(ML)/% : MO       := $(MO)
$(ML)/% : ML       := $(ML)
$(ML)/% : MB       := $(MB)
$(ML)/% : ME       := $(ME)
endif

ifneq ($(MB),$(MO))
MK_TEMP := $(shell mkdir $(MO))
$(MO)/% : CFLAGS   = $($M/CFLAGS)
$(MO)/% : CPPFLAGS = $($M/CPPFLAGS)
$(MO)/% : CXXFLAGS = $($M/CXXFLAGS)
$(MO)/% : LDFLAGS  = $($M/LDFLAGS)
$(MO)/% : LDLIBS   = $($M/LDLIBS)
$(MO)/% : OUTPUT_OPTION = $($M/OUTPUT_OPTION)
$(MO)/% : M        := $M
$(MO)/% : MS       := $(MS)
$(MO)/% : MI       := $(MI)
$(MO)/% : MO       := $(MO)
$(MO)/% : ML       := $(ML)
$(MO)/% : MB       := $(MB)
$(MO)/% : ME       := $(ME)
endif


######
#  VI. Create dependency files ... and load them
#####

ifeq ($(filter clean allclean,$(MAKECMDGOALS)),)
ifneq ($($M/BUILD_DEPS),)
include $($M/BUILD_DEPS)
endif
endif





