SHELL       := @SHELL@

# Support out-of-tree builds
srcdir      := @srcdir@
VPATH       := @srcdir@

prefix      := @prefix@
exec_prefix := @exec_prefix@
datarootdir := @datarootdir@
bindir      := @bindir@
datadir     := @datadir@
sysconfdir  := @sysconfdir@
libdir      := @libdir@
includedir  := @includedir@
sbindir     := @sbindir@
localstatedir := @localstatedir@
systemdsystemunitdir := @systemdsystemunitdir@
CXX      := @CXX@
CXXFLAGS := -I$(srcdir)/include -Iinclude @CPPFLAGS@ @CXXFLAGS@
LDFLAGS  := @LDFLAGS@
LIBS     := @LIBS@
LIBZNC   := @LIBZNC@
LIBZNCDIR:= @LIBZNCDIR@
MODDIR   := @MODDIR@
DATADIR  := @DATADIR@
PKGCONFIGDIR := $(libdir)/pkgconfig
INSTALL         := @INSTALL@
INSTALL_PROGRAM := @INSTALL_PROGRAM@
INSTALL_SCRIPT  := @INSTALL_SCRIPT@
INSTALL_DATA    := @INSTALL_DATA@
GIT := @GIT@
SED := @SED@

GTEST_DIR := @GTEST_DIR@
GMOCK_DIR := @GMOCK_DIR@
ifeq "$(GTEST_DIR)" ""
GTEST_DIR := $(srcdir)/third_party/googletest/googletest
endif
ifeq "$(GMOCK_DIR)" ""
GMOCK_DIR := $(srcdir)/third_party/googletest/googlemock
endif
qt_CFLAGS := @qt_CFLAGS@ -fPIC -std=c++11 -pthread
qt_LIBS   := @qt_LIBS@ -pthread

# Force the simple internal regex engine to get consistent behavior on all platforms.
# See https://code.google.com/p/chromium/issues/detail?id=317224 for more details.
GTEST_FLAGS := -DGTEST_HAS_POSIX_RE=0 -I$(GMOCK_DIR)/include -I$(GTEST_DIR)/include
# Silence warnings about overload virtual Csock::Write(), and missing field
# initializers in both gtest and gmock
GTEST_FLAGS += -Wno-overloaded-virtual -Wno-missing-field-initializers

LIB_SRCS  := ZNCString.cpp Csocket.cpp znc.cpp IRCNetwork.cpp User.cpp IRCSock.cpp \
	Client.cpp Chan.cpp Nick.cpp Server.cpp Modules.cpp MD5.cpp Buffer.cpp Utils.cpp \
	FileUtils.cpp HTTPSock.cpp Template.cpp ClientCommand.cpp Socket.cpp SHA256.cpp \
	WebModules.cpp Listener.cpp Config.cpp ZNCDebug.cpp Threads.cpp version.cpp Query.cpp \
	SSLVerifyHost.cpp Message.cpp Translation.cpp
LIB_SRCS  := $(addprefix src/,$(LIB_SRCS))
BIN_SRCS  := src/main.cpp
LIB_OBJS  := $(patsubst %cpp,%o,$(LIB_SRCS))
BIN_OBJS  := $(patsubst %cpp,%o,$(BIN_SRCS))
TESTS     := StringTest ConfigTest UtilsTest ThreadTest NickTest ClientTest NetworkTest \
	MessageTest ModulesTest IRCSockTest QueryTest BufferTest UserTest
TESTS     := $(addprefix test/,$(addsuffix .o,$(TESTS)))
CLEAN     := znc src/*.o test/*.o core core.* .version_extra .depend modules/.depend \
	unittest $(LIBZNC)
DISTCLEAN := Makefile config.log config.status znc-buildmod include/znc/zncconfig.h \
	modules/Makefile man/Makefile znc.pc znc-uninstalled.pc test/Makefile

CXXFLAGS += -D_MODDIR_=\"$(MODDIR)\" -D_DATADIR_=\"$(DATADIR)\"

ifneq "$(V)" ""
VERBOSE=1
endif
ifeq "$(VERBOSE)" ""
Q=@
E=@echo
C=-s
else
Q=
E=@\#
C=
endif

.PHONY: all man modules clean distclean install version_extra_recompile test
.SECONDARY:

all: znc man modules $(LIBZNC)
	@echo ""
	@echo " ZNC was successfully compiled."
	@echo " Use '$(MAKE) install' to install ZNC to '$(prefix)'."

ifeq "$(LIBZNC)" ""
OBJS := $(BIN_OBJS) $(LIB_OBJS)

znc: $(OBJS)
	$(E) Linking znc...
	$(Q)$(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)

else
znc: $(BIN_OBJS) $(LIBZNC)
	$(E) Linking znc...
	$(Q)$(CXX) $(LDFLAGS) -o $@ $(BIN_OBJS) -L. -lznc -Wl,-rpath,$(LIBZNCDIR) $(LIBS)

$(LIBZNC): $(LIB_OBJS)
	$(E) Linking $(LIBZNC)...
	$(Q)$(CXX) $(LDFLAGS) -shared -o $@ $(LIB_OBJS) $(LIBS) -Wl,--out-implib=libznc.dll.a
endif

unittest: $(LIB_OBJS) test/gtest-all.o test/gmock-all.o test/gmock-main.o $(TESTS)
	$(E) Linking unit test...
	$(Q)$(CXX) $(LDFLAGS) -o $@ $(LIB_OBJS) test/gtest-all.o test/gmock-all.o test/gmock-main.o $(TESTS) $(LIBS)

inttest: test/Integration.o test/Int-gtest-all.o test/Int-gmock-all.o
	$(E) Linking integration test...
	$(Q)g++ -std=c++11 -o $@ test/Integration.o test/Int-gtest-all.o test/Int-gmock-all.o $(LIBS) $(qt_LIBS)

man:
	@$(MAKE) -C man $(C)

modules: $(LIBZNC) include/znc/Csocket.h
	@$(MAKE) -C modules $(C)

clean:
	rm -rf $(CLEAN)
	@$(MAKE) -C modules clean;
	@$(MAKE) -C man clean

distclean: clean
	rm -rf $(DISTCLEAN)

src/%.o: src/%.cpp Makefile include/znc/Csocket.h
	@mkdir -p .depend src
	$(E) Building core object $*...
	$(Q)$(CXX) $(CXXFLAGS) -c -o $@ $< -MD -MF .depend/$*.dep -MT $@

test/%.o: test/%.cpp Makefile include/znc/Csocket.h
	@mkdir -p .depend test
	$(E) Building test object $*...
	$(Q)$(CXX) $(CXXFLAGS) $(GTEST_FLAGS) -c -o $@ $< -MD -MF .depend/$*.test.dep -MT $@

test/gtest-all.o: $(GTEST_DIR)/src/gtest-all.cc Makefile
	@mkdir -p .depend test
	$(E) Building test object gtest-all...
	$(Q)$(CXX) $(CXXFLAGS) $(GTEST_FLAGS) -I$(GTEST_DIR) -c -o $@ $< -MD -MF .depend/gtest-all.dep -MT $@

test/gmock-all.o: $(GMOCK_DIR)/src/gmock-all.cc Makefile
	@mkdir -p .depend test
	$(E) Building test object gmock-all...
	$(Q)$(CXX) $(CXXFLAGS) $(GTEST_FLAGS) -I$(GMOCK_DIR) -c -o $@ $< -MD -MF .depend/gmock-all.dep -MT $@

test/gmock-main.o: $(GMOCK_DIR)/src/gmock_main.cc Makefile
	@mkdir -p .depend test
	$(E) Building test object gmock-main...
	$(Q)$(CXX) $(CXXFLAGS) $(GTEST_FLAGS) -c -o $@ $< -MD -MF .depend/gmock-main.dep -MT $@

# Qt fails under TSAN, so CXXFLAGS/LDFLAGS can't be used.
test/Integration.o: test/integration/autoconf-all.cpp Makefile
	@mkdir -p .depend test
	$(E) Building test object Integration...
	$(Q)g++ $(qt_CFLAGS) $(GTEST_FLAGS) -I$(srcdir)/test/integration/framework -c -o $@ $< -MD -MF .depend/Integration.test.dep -MT $@ '-DZNC_BIN_DIR="$(bindir)"' '-DZNC_SRC_DIR="$(realpath $(srcdir))"'
test/Int-gtest-all.o: $(GTEST_DIR)/src/gtest-all.cc Makefile
	@mkdir -p .depend test
	$(E) Building test object Int-gtest-all...
	$(Q)g++ $(qt_CFLAGS) $(GTEST_FLAGS) -I$(GTEST_DIR) -c -o $@ $< -MD -MF .depend/Int-gtest-all.dep -MT $@
test/Int-gmock-all.o: $(GMOCK_DIR)/src/gmock-all.cc Makefile
	@mkdir -p .depend test
	$(E) Building test object Int-gmock-all...
	$(Q)g++ $(qt_CFLAGS) $(GTEST_FLAGS) -I$(GMOCK_DIR) -c -o $@ $< -MD -MF .depend/Int-gmock-all.dep -MT $@
test/Int-gmock-main.o: $(GMOCK_DIR)/src/gmock_main.cc Makefile
	@mkdir -p .depend test
	$(E) Building test object Int-gmock-main...
	$(Q)g++ $(qt_CFLAGS) $(GTEST_FLAGS) -c -o $@ $< -MD -MF .depend/Int-gmock-main.dep -MT $@

ifneq "THIS_IS_NOT_TARBALL" ""
# If git commit was changed since previous build, add a phony target to dependencies, forcing version.o to be recompiled
# Nightlies have pregenerated version.cpp
src/version.cpp: Makefile version.sh $(shell if [ x`cat .version_extra 2> /dev/null` != x`$(srcdir)/version.sh "$(GIT)" 3>&2 2> /dev/null` ]; then echo version_extra_recompile; fi)
	@mkdir -p .depend src
	$(E) Building source file version.cpp...
	$(Q)WRITE_OUTPUT=yes $(srcdir)/version.sh "$(GIT)" > .version_extra 2> /dev/null

CLEAN += src/version.cpp
endif

CLEAN += src/Csocket.cpp include/znc/Csocket.h

src/Csocket.cpp: third_party/Csocket/Csocket.cc
	@rm -f $@
	@mkdir -p src
	@sed -e 's:#include "Csocket.h":#include <znc/Csocket.h>:' $^ > $@
include/znc/Csocket.h: third_party/Csocket/Csocket.h
	@rm -f $@
	@mkdir -p include/znc
	@sed -e 's:#include "defines.h":#include <znc/defines.h>:' $^ > $@
third_party/Csocket/Csocket.h third_party/Csocket/Csocket.cc:
	@echo It looks like git submodules are not initialized. Run: git submodule update --init --recursive
	@exit 1

znc.service: znc.service.in
	@sed -e "s:\@CMAKE_INSTALL_FULL_BINDIR\@:$(bindir):" $^ > $@

CLEAN += znc.service

install: znc znc.service $(LIBZNC)
	test -d $(DESTDIR)$(bindir) || $(INSTALL) -d $(DESTDIR)$(bindir)
	test -d $(DESTDIR)$(includedir)/znc || $(INSTALL) -d $(DESTDIR)$(includedir)/znc
	test -d $(DESTDIR)$(PKGCONFIGDIR) || $(INSTALL) -d $(DESTDIR)$(PKGCONFIGDIR)
	test -d $(DESTDIR)$(MODDIR) || $(INSTALL) -d $(DESTDIR)$(MODDIR)
	test -d $(DESTDIR)$(DATADIR) || $(INSTALL) -d $(DESTDIR)$(DATADIR)
	cp -R $(srcdir)/webskins $(DESTDIR)$(DATADIR)
	find $(DESTDIR)$(DATADIR)/webskins -type d -exec chmod 0755 '{}' \;
	find $(DESTDIR)$(DATADIR)/webskins -type f -exec chmod 0644 '{}' \;
	$(INSTALL_PROGRAM) znc $(DESTDIR)$(bindir)
	$(INSTALL_SCRIPT) znc-buildmod $(DESTDIR)$(bindir)
	$(INSTALL_DATA) $(srcdir)/include/znc/*.h $(DESTDIR)$(includedir)/znc
	$(INSTALL_DATA) include/znc/*.h $(DESTDIR)$(includedir)/znc
	$(INSTALL_DATA) znc.pc $(DESTDIR)$(PKGCONFIGDIR)
	@$(MAKE) -C modules install DESTDIR=$(DESTDIR);
	if test -n "$(LIBZNC)"; then \
		test -d $(DESTDIR)$(LIBZNCDIR) || $(INSTALL) -d $(DESTDIR)$(LIBZNCDIR) || exit 1 ; \
		$(INSTALL_PROGRAM) $(LIBZNC) $(DESTDIR)$(LIBZNCDIR) || exit 1 ; \
		$(INSTALL_PROGRAM) libznc.dll.a $(DESTDIR)$(libdir) || exit 1 ; \
	fi
	@$(MAKE) -C man install DESTDIR=$(DESTDIR)
	@HAVE_SYSTEMD_TRUE@test -d $(DESTDIR)$(systemdsystemunitdir) || $(INSTALL) -d $(DESTDIR)$(systemdsystemunitdir)
	@HAVE_SYSTEMD_TRUE@$(INSTALL_DATA) $(srcdir)/znc.service $(DESTDIR)$(systemdsystemunitdir)
	@echo ""
	@echo "******************************************************************"
	@echo " ZNC was successfully installed."
	@echo " You can use '$(bindir)/znc --makeconf'"
	@echo " to generate a config file."
	@echo ""
	@echo " If you need help with using ZNC, please visit our wiki at:"
	@echo "   https://znc.in"

uninstall:
	rm $(DESTDIR)$(bindir)/znc
	rm $(DESTDIR)$(bindir)/znc-buildmod
	rm $(DESTDIR)$(includedir)/znc/*.h
	rm $(DESTDIR)$(PKGCONFIGDIR)/znc.pc
	rm -rf $(DESTDIR)$(DATADIR)/webskins
	if test -n "$(LIBZNC)"; then \
		rm $(DESTDIR)$(LIBZNCDIR)/$(LIBZNC) || exit 1 ; \
		rmdir $(DESTDIR)$(LIBZNCDIR) || exit 1 ; \
	fi
	@$(MAKE) -C man uninstall DESTDIR=$(DESTDIR)
	@if test -n "modules"; then \
		$(MAKE) -C modules uninstall DESTDIR=$(DESTDIR); \
	fi
	rmdir $(DESTDIR)$(bindir)
	rmdir $(DESTDIR)$(includedir)/znc
	rmdir $(DESTDIR)$(PKGCONFIGDIR)
	@echo "Successfully uninstalled, but empty directories were left behind"

test: unittest
	$(Q)./unittest

# This test uses files at <prefix>/lib/znc, which is less than ideal, especially from build scripts of distros.
# That's why it's a separate make target.
test2: inttest
	$(Q)./inttest

-include $(wildcard .depend/*.dep)
