# 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.
#

#
#
# include
#
include ../utils/gccversion.mk
include ../utils/clangversion.mk
include CommonMakefile.in

# Optimize
#OPTIMIZE=-O2

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

ifdef _DEBUG
CXXFLAGS += -ggdb
endif

ifdef USE_COVERAGE
CXXFLAGS += -coverage
ifndef CCOV
CCOV=$(USE_COVERAGE)
endif
endif

#
#
# compiler
#

#
# 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

#
# scan-build
#
ifeq ($(findstring c++-analyzer, $(CXX)),c++-analyzer)
USE_SCANBUILD=yes
endif

ifdef OUTPUTXML
CXXFLAGS +=-DOUTPUTXML
endif

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

ifdef USE_GNU_EXTENSION
STDFLAG:=$(subst c++,gnu++, $(STDFLAG))
endif

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

MAKEFILE=GNUmakefile CommonMakefile.in

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

ifeq ($(USE_GTEST)$(USE_GMOCK)$(USE_COVERAGE)$(USE_SCANBUILD),)
ERR_TARGETS = $(COMPILEERROR_TARGETS)
endif

BUILD_TARGETS = $(RUN_TARGETS) $(BUILD_ONLY)
TARGETS = $(BUILD_TARGETS) $(ERR_TARGETS)

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

ifdef USE_FUSEDD
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 lint

default : $(TARGETS)

all : clean default test

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

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

lint : cpplint/Makefile $(IUTEST_HEADERS) $(MAKEFILE)
	make -C cpplint

showcxxversion:
	$(CXX) --version
ifdef GCCMAJOR
	@echo g++-$(GCCMAJOR).$(GCCMINOR)
endif
ifdef CLANGMAJOR
	@echo clang++-$(CLANGMAJOR).$(CLANGMINOR)
endif

showcxxmacros:
	$(CXX) $(STDFLAG) -dM -E -x c++ - < /dev/null

showcxxflags:
	@echo $(CXXFLAGS)

%_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

run_% : %_run
	@echo $< > /dev/null

#
#
# fused
#

FUSED_PY= ../tools/fused/*.py 

fused: $(IUTEST_HEADERS) $(MAKEFILE) ../tools/fused/Makefile $(FUSED_PY)
	make -C ../tools/fused

fused_min: $(IUTEST_HEADERS) $(MAKEFILE) ../tools/fused/Makefile $(FUSED_PY)
	make -C ../tools/fused min

#
#
# 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

coverage:
	$(CCOV) -v
ifeq ($(USE_COVERAGE),lcov)
	$(CCOV) -c -d . -o coverage.info && $(CCOV) -r coverage.info *gcc* -o coverage.info && $(CCOV) -r coverage.info */test/* -o coverage.info
endif
ifeq ($(USE_COVERAGE),gcov)
ifeq ($(findstring relative-only, $(shell $(CCOV) --help)), relative-only)
	$(CCOV) -r *.gcda;
else
	$(CCOV) *.gcda;
endif
endif

send-coveralls: coverage
ifeq ($(USE_COVERAGE),lcov)
	cd ../; lcoveralls --retry-count 3 ./test/coverage.info
endif
ifeq ($(USE_COVERAGE),gcov)
	cd ../; coveralls -n -r ./ -b ./test $(COVARALLS_EXCLUDE_PATTERN) $(COVARALLS_EXCLUDE)
endif

send-codecov: coverage
	curl -s https://codecov.io/bash | bash /dev/stdin

#
#
# 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

BENCHMARK_MAKE_OPTION=--no-print-directory -C benchmark

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 $(BENCHMARK_MAKE_OPTION) clean; \
		{ time -p make $(BENCHMARK_MAKE_OPTION) -j 1 basis 2>&1; } 2>> benchmark_basis_time.log; \
		make $(BENCHMARK_MAKE_OPTION) clean prebuild; \
		{ time -p make $(BENCHMARK_MAKE_OPTION) -j 1 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 $(NO_UNUSED_LOCAL_TYPEDEFS)
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 $(NO_UNUSED_LOCAL_TYPEDEFS)
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 $(IUTEST_CXX_WARN_FLAGS)

ifdef USE_LIB
CXXFLAGS += -DIUTEST_USE_LIB=1 -L../lib
IUTEST_LIB_ = -liutest
endif

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

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

$(ERR_TARGETS) : $(SRCS) $(IUTEST_HEADERS) $(MAKEFILE)
	#-$(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) -o $@ $@.cpp $(IUTEST_LIB_) $(LDFLAGS)
	$(CXX) $(IUTEST_INCLUDE) $(CXXFLAGS) -o $@ $@.cpp $(IUTEST_LIB_) $(LDFLAGS) 2>&1 | python ../tools/python/iutest_compile_error_test.py -c $(CXX)

endif

endif

check_stdlib: check_stdlib.cpp $(IUTEST_HEADERS)
	$(CXX) $(CXXFLAGS) -v -o $@ $@.cpp
	./$@
