#####
# default Makefile behaviour, mandatory
#
include Makefile.inc



#####
# options
#

# -O2 is sufficient for linux
OPTIMIZE = -O2
COMPILE_OPT = -fPIC
ifeq ($(OS_TYPE),WIN32)
	OPTIMIZE = -O3
	COMPILE_OPT =
endif

ifeq ($(DEBUG),1)
	STRIP_OLD=$(STRIP)
	STRIP = @echo DISABLED $(STRIP_OLD)
	STRIP_OLD=
endif



#####
# general command lines
#
INCLUDES = -I./include -I./tools -I./tests
# disable fortify mode, mostly for linux targets, cf https://wiki.ubuntu.com/CompilerFlags
DEFS_FLAGS += $(DEBUG_FLAGS) -D_FORTIFY_SOURCE=0
CFLAGS = $(OPTIMIZE) -g -Wall $(DEFS_FLAGS)
#CXXFLAGS = $(OPTIMIZE) -g -Wall $(DEFS_FLAGS)
COMPILE = $(CC) $(CFLAGS) $(INCLUDES) $(COMPILE_OPT)
#COMPILEXX = $(CXX) $(CXXFLAGS) $(INCLUDES) $(COMPILE_OPT)
LDFLAGS = 
LINK = $(CC) $(LDFLAGS)


#####
# target binaries
#
DEP_LIBS = $(NET_LIB) $(SYSTEM_LIB) $(THREAD_LIB) $(TIME_LIB) $(MATH_LIB)
DEP_LIBS := $(sort $(DEP_LIBS))


LIB_OBJ = 
LIB_OBJ += src/Array.o
LIB_OBJ += src/CliParser.o
LIB_OBJ += src/Console.o
LIB_OBJ += src/FileSystem.o
LIB_OBJ += src/Hash.o
LIB_OBJ += src/INIFile.o
LIB_OBJ += src/IPHelpers.o
LIB_OBJ += src/Log.o
LIB_OBJ += src/MathTools.o
LIB_OBJ += src/NetHelpers.o
LIB_OBJ += src/ProcessTools.o
LIB_OBJ += src/Random.o
LIB_OBJ += src/Strings.o
LIB_OBJ += src/System.o
LIB_OBJ += src/Threads.o
LIB_OBJ += src/TimeTools.o
LIB_OBJ += src/TLV.o
ifeq ($(DEBUG),1)
LIB_OBJ += src/Debug.o
endif
LIB_OBJ += src/Sort.o
LIB_OBJ += src/Dictionary.o
LIB_OBJ += src/Runtime.o


# main out
BIN += libshred.a
ifeq ($(OS_TYPE),WIN32)
	BIN += libshred.def
	BIN += libshred.dll
	LIBSHRED_DYNLIB = libshred.dll.a
else
ifeq ($(OS_TYPE),APPLE)
	BIN += libshred.dylib
	LIBSHRED_DYNLIB = libshred.dylib
else
	BIN += libshred.so
	LIBSHRED_DYNLIB = libshred.so
endif
endif

# tools
BIN += tools/system_error$(BIN_EXT)
BIN += tools/system_info$(BIN_EXT)
BIN += tools/hash$(BIN_EXT)
BIN += tools/dns$(BIN_EXT)
BIN += tools/b64$(BIN_EXT)
BIN += tools/mkfile$(BIN_EXT)
BIN += tools/ipconfig$(BIN_EXT)
BIN += tools/netping$(BIN_EXT)
BIN += tools/timestamp$(BIN_EXT)
BIN += tools/memtest$(BIN_EXT)
BIN += tools/benchmark$(BIN_EXT)
ifeq ($(OS_TYPE),LINUX)
	BIN += tools/telnetd$(BIN_EXT)
endif
ifneq ($(OS_TYPE),WIN32)
	BIN += tools/daemonizer$(BIN_EXT)
endif
BIN += tools/tftpd$(BIN_EXT)
BIN += tools/smtp$(BIN_EXT)
BIN += tools/process_list$(BIN_EXT)
BIN += tools/file_info$(BIN_EXT)

# examples
BIN += examples/sample_threads$(BIN_EXT)
BIN += examples/sample_cliparser$(BIN_EXT)
BIN += examples/sample_log$(BIN_EXT)


# unit tests
UTEST += tests/utest_all$(BIN_EXT)
UTEST += tests/utest_hash$(BIN_EXT)
UTEST += tests/utest_strings$(BIN_EXT)
UTEST += tests/utest_dictionary$(BIN_EXT)

# speed tests, for optimizations
STEST += tests/stest_string_match$(BIN_EXT)
STEST += tests/stest_sort$(BIN_EXT)
STEST += tests/stest_dictionary$(BIN_EXT)

# quality tests, like stability
QTEST += tests/qtest_tlv$(BIN_EXT)

ifeq ($(DEBUG),1)
QTEST += tests/qtest_debug$(BIN_EXT)
endif

TEST = $(UTEST) $(STEST) $(QTEST)



####
# main rules
#
default: $(BIN) $(TEST)
	

clean:
	@echo cleaning folder
	@rm -f *.a *.o *.dll *.so *.tmp *.map *.def *.dylib
	@rm -f src/*.o src/*.tmp
	@rm -f examples/*.o examples/*.tmp
	@rm -f tools/*.o tools/*.tmp
	@rm -f tests/*.o tests/*.tmp
	@rm -f msvc/vs2005/*
	@rm -f $(BIN) $(TEST)
	@rm -f include/libshred/Debug.h


install-dev:
ifneq ($(OS_TYPE),WIN32)
	@echo "installing dev files into $(DESTDIR)"
	
	@mkdir -p $(DESTDIR)/usr/include/libshred
	@cp -a include/libshred/*.h $(DESTDIR)/usr/include/libshred
	@cp -a include/*.h $(DESTDIR)/usr/include
	
	@mkdir -p $(DESTDIR)/usr/lib/libshred
	@cp libshred.a $(DESTDIR)/usr/lib
	@cp $(LIBSHRED_DYNLIB) $(DESTDIR)/usr/lib
	@cp Makefile.inc $(DESTDIR)/usr/lib/libshred
else
	@echo "make install-dev not supported for this system: $(OS_TYPE)"
endif


install:
	@echo "installing files into $(DESTDIR)"
ifneq ($(OS_TYPE),WIN32)
	@mkdir -p $(DESTDIR)/usr/lib
	@cp $(LIBSHRED_DYNLIB) $(DESTDIR)/usr/lib
	
	@mkdir -p $(DESTDIR)/usr/bin
	@cp tools/timestamp $(DESTDIR)/usr/bin
	@cp tools/daemonizer $(DESTDIR)/usr/bin
else
	@mkdir -p $(DESTDIR)
	@cp $(LIBSHRED_DYNLIB) $(DESTDIR)
endif



###
# debug switch
#
include/libshred/Debug.h: include/libshred/Debug.h.in
	@rm -f $@
ifeq ($(DEBUG),1)
	@echo "compile with debug support"
	@cp $@.in $@
else
	@echo "compile without debug support"
	@touch $@
endif



####
# main libs
#

# static lib
libshred.a: $(LIB_OBJ)
ifeq ($(OS_TYPE),APPLE)
	libtool -static -o $@ $^
else
	@rm -f $@
	$(AR) cru $@ $^
	@$(STRIP) $(STRIP_OPT) $@
endif


# dynamic lib, for non WIN32
libshred.map: $(LIB_OBJ)
	@# build tmp lib
	@rm -f $@.tmp
	$(COMPILE) -shared -o $@.tmp $^
	
	@# use '/bin/echo' instead of 'echo' because of dummy sh->dash on various linux systems which does not implement '-e'
	@echo '{' > libshred.map
	@/bin/echo -e '\tglobal:' >> libshred.map
	@$(NM) --dynamic --extern-only --format=posix $@.tmp | grep "^[a-zA-Z0-9][a-zA-Z0-9_]* T" | sort | awk '{print "\t\t" $$1 ";"}' >> libshred.map
	@/bin/echo -e '\tlocal: *;' >> libshred.map
	@echo '};' >> libshred.map
	
	@# clean tmp lib
	@rm -f $@.tmp

libshred.so: $(LIB_OBJ)
	$(COMPILE) -shared -o $@.tmp $(LIB_OBJ) $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@.tmp
	mv $@.tmp $@

libshred.dylib: $(LIB_OBJ)
	$(COMPILE) -dynamiclib -o $@ $(LIB_OBJ) $(DEP_LIBS)
	$(STRIP) -x $@


# dynamic lib, win32 specific
libshred.def: $(LIB_OBJ)
	$(COMPILE) -shared -o libshred.dll.tmp $^ $(DEP_LIBS) -Wl,--output-def,libshred.def.tmp
	@rm -f libshred.dll.tmp
	cat libshred.def.tmp | grep "^[ ]*[a-zA-Z0-9][a-zA-Z0-9_]*" > libshred.def
	@rm -f libshred.def.tmp

libshred.dll: $(LIB_OBJ) libshred.def
	dllwrap --def libshred.def -o $@ $(LIB_OBJ) $(DEP_LIBS) --output-lib libshred.dll.a
	$(STRIP) $(STRIP_OPT) $@
ifneq ($(OS_BITS),64)
	upx -9 $@
endif

libshred.dll.a: libshred.dll
	



####
# tools binaries
#

# for tools, we strip all in a discardable error way (do not use indermediate $@.tmp)
tools/system_error$(BIN_EXT): tools/system_error.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

tools/system_info$(BIN_EXT): tools/system_info.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

tools/hash$(BIN_EXT): tools/hash.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

tools/dns$(BIN_EXT): tools/dns.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

tools/b64$(BIN_EXT): tools/b64.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

tools/mkfile$(BIN_EXT): tools/mkfile.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

tools/ipconfig$(BIN_EXT): tools/ipconfig.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

tools/netping$(BIN_EXT): tools/netping.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

tools/telnetd$(BIN_EXT): tools/telnetd.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

tools/daemonizer$(BIN_EXT): tools/daemonizer.o $(LIBSHRED_DYNLIB)
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

tools/timestamp$(BIN_EXT): tools/timestamp.o $(LIBSHRED_DYNLIB)
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

tools/memtest$(BIN_EXT): tools/memtest.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

tools/benchmark$(BIN_EXT): tools/benchmark.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

tools/tftpd$(BIN_EXT): tools/tftpd.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

tools/smtp$(BIN_EXT): tools/smtp.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

tools/process_list$(BIN_EXT): tools/process_list.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

tools/file_info$(BIN_EXT): tools/file_info.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@



####
# example binaries
#

# as for tools, we strip all in an discardable error way
examples/sample_threads$(BIN_EXT): examples/sample_threads.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

examples/sample_cliparser$(BIN_EXT): examples/sample_cliparser.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@

examples/sample_log$(BIN_EXT): examples/sample_log.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)
	$(STRIP) $(STRIP_OPT) $@



####
# test binaries
#

utest:
	@./tests/utest.sh $(UTEST)


tests/utest_hash$(BIN_EXT): tests/utest_hash.o tests/UnitTest.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)

tests/utest_strings$(BIN_EXT): tests/utest_strings.o tests/UnitTest.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)

tests/utest_dictionary$(BIN_EXT): tests/utest_dictionary.o tests/UnitTest.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)

tests/utest_all$(BIN_EXT): tests/utest_all.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)


tests/stest_string_match$(BIN_EXT): tests/stest_string_match.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)

tests/stest_sort$(BIN_EXT): tests/stest_sort.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)

tests/stest_dictionary$(BIN_EXT): tests/stest_dictionary.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)


tests/qtest_tlv$(BIN_EXT): tests/qtest_tlv.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)

tests/qtest_debug$(BIN_EXT): tests/qtest_debug.o libshred.a
	$(LINK) -o $@ $^ $(DEP_LIBS)



####
# default objects
#

%.o: %.c include/libshred/Debug.h
	$(COMPILE) -o $@ -c $<
