# Test GNUmakefile (for GNU make)
#
# SYNOPSIS:
#
#   make [all]         - makes everything.
#   make test          - makes everything and run.
#   make TARGET        - makes the given target.
#   make run_$(TARGET) - makes the given target and run.
#   make clean         - removes all files generated by make.

#
# Flags passed to the C++ compiler.
#

# Optimize
#OPTIMIZE += -O2

CXXFLAGS += -g -Wall -Wextra $(OPTIMIZE)

ifdef _DEBUG
CXXFLAGS += -ggdb
endif

#
#
# compiler
#


#
# clang
#
ifeq ($(findstring clang, $(CXX)),clang)
#STDFLAG += -std=c++0x
endif


#
# GCC
#
ifeq ($(CXX),g++)

ifdef USE_COVERAGE
COVERAGE = coveralls
CXXFLAGS += -coverage
endif

GCCVERSION:=$(shell $(CXX) -dumpversion)

dot:=.
empty:=
space:=$(empty) $(empty)
GCCVERSION:=$(subst $(dot),$(space), $(GCCVERSION))
GCCMAJOR:=$(word 1, $(GCCVERSION))
GCCMINOR:=$(word 2, $(GCCVERSION))

ifeq (1,$(shell expr \( $(GCCMAJOR) \> 4 \) \| \( $(GCCMAJOR) \>= 4 \& $(GCCMINOR) \>= 8 \)))
# 4.8 later
STDFLAG += -std=c++1y
else
ifeq (1,$(shell expr \( $(GCCMAJOR) \> 4 \) \| \( $(GCCMAJOR) \>= 4 \& $(GCCMINOR) \>= 7 \)))
# 4.7 later
STDFLAG += -std=c++11
else
#ifeq (1,$(shell expr \( $(GCCMAJOR) \> 4 \) \| \( $(GCCMAJOR) \>= 4 \& $(GCCMINOR) \>= 4 \)))
# 4.4 later
#STDFLAG += -std=c++0x
#endif
endif
endif

endif

#
# MINGW
#
ifeq ($(findstring mingw, $(CXX)),mingw)
LIBS+=ws2_32
CXXFLAGS += -static-libgcc -static-libstdc++
endif

#
# Wine g++
#
ifeq ($(CXX),wineg++)
LIBS+=ws2_32
CXXFLAGS += -static-libgcc -static-libstdc++ -m32
endif


ifdef OUTPUTXML
CXXFLAGS +=-DOUTPUTXML
endif

ifeq ($(HOST),WINE)
WINE_ =wine
else
WINE_ =
endif

CXXFLAGS += $(DEFS) $(STDFLAG)
LIBS_ = $(LIBS:%=-l%)
LDFLAGS += $(LIBS_)

MAKEFILE=GNUmakefile CommonMakefile.in

#
#
# include
#
include CommonMakefile.in

ifneq ($(USE_GTEST)$(USE_GMOCK),)
RUN_TARGETS = $(ALLTESTS_TARGET) $(TARGETS1) $(TARGETS2)
else
RUN_TARGETS = $(ALLTESTS_TARGET) $(TARGETS1) $(TARGETS2) $(TARGETS_IUTEST_ONLY)
endif
BUILD_TARGETS = $(RUN_TARGETS) $(BUILD_ONLY)
TARGETS = $(BUILD_TARGETS)

SRCS   = $(BUILD_TARGETS:%=%.cpp)
RUNNER = $(RUN_TARGETS:%=run_%)

ifdef USE_FUSED
IUTEST_INCLUDE=-I$(IUTEST_DIR)/fused-src
IUTEST_HEADERS+=$(IUTEST_DIR)/fused-src/iutest.hpp
endif

#
#
# build targets.
#

.PHONY: clean default all run test bench benchmark

default : $(TARGETS)

all : clean default test

clean :
	$(RM) $(TARGETS) *.o *.stackdump *.log
ifdef OUTPUTXML
	$(RM) *.xml
endif
ifdef COVERAGE
	$(RM) *.xml *.gcov *.gcno *.gcda coverage.info
endif

check : test
run : test
test : $(BUILD_ONLY) $(RUNNER)

showcxxversion:
	$(CXX) --version

run_% : %
	@echo $<
ifdef USE_COVERAGE
	${WINE_} ./$< $(RUN_OPTION) --iutest_output=xml:$<.xml > /dev/null
else
ifdef OUTPUTXML
	${WINE_} ./$< $(RUN_OPTION) --iutest_output=xml:$<.xml
else
	${WINE_} ./$< $(RUN_OPTION)
endif
endif

#
#
# fuse
#

FUSE_PY= ../tools/fuse/*.py 

fuse: $(IUTEST_HEADERS) $(MAKEFILE) ../tools/fuse/Makefile $(FUSE_PY)
	make -C ../tools/fuse

fuse_min: $(IUTEST_HEADERS) $(MAKEFILE) ../tools/fuse/Makefile $(FUSE_PY)
	make -C ../tools/fuse min

#
#
# coverage
#

ifdef COVERAGE
COVARALLS_EXCLUDE=-e doc -e projects -e samples -e tools
COVARALLS_EXCLUDE_PATTERN  =-E ".*/test/[^\.].*" -E ".*/include/tr1/.*" -E ".*/include/gtest/.*"
# define and constant only header
#COVARALLS_EXCLUDE_PATTERN +=-E ".*iutest_ver\.hpp" -E ".*iutest_config\.hpp" -E ".*iutest_ignore\.hpp"
#COVARALLS_EXCLUDE_PATTERN +=-E ".*iutest_compiler\.hpp" -E ".*iutest_constant\.hpp" -E ".*iutest_util\.hpp"
#COVARALLS_EXCLUDE_PATTERN +=-E ".*iutest_internal\.hpp" -E ".*iutest_pp\.hpp" -E ".*iutest_pragma\.hpp"
#COVARALLS_EXCLUDE_PATTERN +=-E ".*iutest_typelist\.hpp" -E ".*iutest_type_traits\.hpp" -E ".*iutest_typed_util\.hpp"
#COVARALLS_EXCLUDE_PATTERN +=-E ".*iutest_all\.cpp" -E ".*iutest_util_output\.hpp" -E ".*iutest_tuple\.hpp"
COVARALLS_SRCEXT=-x .h -x .hpp -x .cpp -x .ipp
endif

send-coverage: send-gcoverage

send-lcoverage:
ifdef COVERAGE
	lcov -v
	lcov -c -d . -o coverage.info && lcov -r coverage.info *gcc* -o coverage.info && lcov -r coverage.info */test/* -o coverage.info
	cd ../; lcoveralls --retry-count 3 ./test/coverage.info
endif

send-gcoverage:
ifdef COVERAGE
	gcov -v
	gcov -r *.gcda; cd ../; $(COVERAGE) -n -r ./ -b ./test $(COVARALLS_EXCLUDE_PATTERN) $(COVARALLS_EXCLUDE)
endif

#
#
# benchmark
#
bench: benchmark
benchmark: build_benchmark
	@awk 'BEGIN{ sum=0; max=0; min=-1; num=0; } \
		{ if($$1=="user") { num+=1; if(min==-1){ min=$$2; } sum+=$$2; if($$2>max){max=$$2}; if(min>$$2){min=$$2}; } }\
		END{ num-=2; sum-=min; sum-=max; print("basis", sum/num); }' benchmark_basis_time.log >> benchmark_build_time.log
	@awk 'BEGIN{ sum=0; max=0; min=-1; num=0; basis=0; } \
		{ if($$1=="user") { num+=1; if(min==-1){ min=$$2; } sum+=$$2; if($$2>max){max=$$2}; if(min>$$2){min=$$2}; } }\
		{ if($$1=="basis") { basis=$$2; } } \
		END{ print("Total:", sum, "(",num,")" ); num-=2; sum-=min; sum-=max; print("Min:", min); print("Max:", max); \
		avg=sum/num; print("Avg:", avg); print("Score:", basis/avg*100); print("Basis:", basis); }' benchmark_build_time.log

build_benchmark:
	@if [ -a benchmark_basis_time.log ]; then rm benchmark_basis_time.log; fi
	@if [ -a benchmark_build_time.log ]; then rm benchmark_build_time.log; fi
	@num=1; while [[ $$num -le 10 ]]; do \
		make -C benchmark clean; \
		{ time -p make -j 1 -C benchmark basis 2>&1; } 2>> benchmark_basis_time.log; \
		make -C benchmark clean prebuild; \
		{ time -p make -j 1 -C benchmark build 2>&1; } 2>> benchmark_build_time.log; \
		((num = num + 1)); \
	done

#
#
# Build tests.
#

ifdef USE_GTEST

ifdef GTEST_ROOT

GTEST_ROOT_=$(subst \,/,$(GTEST_ROOT))
GTEST_INC_=-I$(GTEST_ROOT_)/include
#GTEST_LIB_=$(GTEST_ROOT_)/make/gtest.a
GTEST_LIB_=$(GTEST_ROOT_)/make/gtest-all.o

else

GTEST_INC_=
GTEST_LIB_=-lgtest -lpthread

endif

CXXFLAGS += -DIUTEST_USE_GTEST -DIUTEST_HAS_SOCKET=0
GTESTFLAGS=$(GTEST_INC_) $(GTEST_LIB_)


$(BUILD_ONLY) : $(SRCS) $(IUTEST_HEADERS) $(MAKEFILE)
	$(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) -o $@ $@.cpp $(GTESTFLAGS)

$(ALLTESTS_TARGET) : $(ALLTESTS_SRCS) $(IUTEST_HEADERS) $(MAKEFILE)
	$(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) -o $@ $(ALLTESTS_SRCS) $(GTESTFLAGS)

$(TARGETS1) : $(SRCS) $(IUTEST_HEADERS) $(MAKEFILE)
	$(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) -o $@ $@.cpp $(GTESTFLAGS)

$(TARGETS2) : $(SRCS) $(IUTEST_HEADERS) $(MAKEFILE)
	$(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) -o $@ $@.cpp $(GTEST_INC_)

else

ifdef USE_GMOCK

ifdef GMOCK_ROOT

GMOCK_ROOT_=$(subst \,/,$(GMOCK_ROOT))
GMOCK_INC_=-I$(GMOCK_ROOT_)/include -I$(GMOCK_ROOT_)/gtest/include
GMOCK_LIB_=$(GMOCK_ROOT_)/make/gmock-all.o $(GMOCK_ROOT_)/make/gtest-all.o

else

GMOCK_INC_=
GMOCK_LIB_=-lgmock -lgtest -lpthread

endif

CXXFLAGS += -DIUTEST_USE_GTEST -DIUTEST_USE_GMOCK -DIUTEST_HAS_SOCKET=0
GMOCKFLAGS=$(GMOCK_INC_) $(GMOCK_LIB_)

$(BUILD_ONLY) : $(SRCS) $(IUTEST_HEADERS) $(MAKEFILE)
	$(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) -o $@ $@.cpp $(GMOCKFLAGS)

$(ALLTESTS_TARGET) : $(ALLTESTS_SRCS) $(IUTEST_HEADERS) $(MAKEFILE)
	$(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) -o $@ $(ALLTESTS_SRCS) $(GMOCKFLAGS)

$(TARGETS1) : $(SRCS) $(IUTEST_HEADERS) $(MAKEFILE)
	$(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) -o $@ $@.cpp $(GMOCKFLAGS)

$(TARGETS2) : $(SRCS) $(IUTEST_HEADERS) $(MAKEFILE)
	$(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) -o $@ $@.cpp $(GMOCK_INC_)

else

TARGETS_EXCLUDE_ALLTESTS= $(TARGETS1) $(TARGETS2) $(TARGETS_IUTEST_ONLY) $(BUILD_ONLY)
CXXFLAGS += -Werror=undef

ifdef USE_LIB
CXXFLAGS += -DIUTEST_USE_LIB=1 -L../lib
$(ALLTESTS_TARGET) : $(ALLTESTS_SRCS) $(IUTEST_HEADERS) $(MAKEFILE)
	$(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) -o $@ $(ALLTESTS_SRCS) -liutest $(LDFLAGS)

$(TARGETS_EXCLUDE_ALLTESTS) : $(SRCS) $(IUTEST_HEADERS) $(MAKEFILE)
	$(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) -o $@ $@.cpp -liutest $(LDFLAGS)

else

$(ALLTESTS_TARGET) : $(ALLTESTS_SRCS) $(IUTEST_HEADERS) $(MAKEFILE)
	$(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) -o $@ $(ALLTESTS_SRCS) $(LDFLAGS)

$(TARGETS_EXCLUDE_ALLTESTS) : $(SRCS) $(IUTEST_HEADERS) $(MAKEFILE)
	$(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) -o $@ $@.cpp $(LDFLAGS)

endif

endif

endif

