From 5ef2e8e8d901cab4fd6ee3ec5c0a6c4449146fc8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= <tseeker@nocternity.net>
Date: Sun, 16 Dec 2018 11:57:58 +0100
Subject: [PATCH] Windows build + instructions

---
 Makefile             |   3 +
 Makefile.main        | 141 +++++++++++++++++++++++++++++++------------
 default-config       |   4 +-
 doc/WindowsBuild.txt |  10 +++
 4 files changed, 117 insertions(+), 41 deletions(-)
 create mode 100644 doc/WindowsBuild.txt

diff --git a/Makefile b/Makefile
index cc17595..c7d004e 100644
--- a/Makefile
+++ b/Makefile
@@ -4,6 +4,9 @@ export CONFIG
 all:	$(CONFIG)
 	+make -f Makefile.main
 
+run-tests:
+	+make -f Makefile.main run-tests
+
 clean:
 	+make -f Makefile.main clean
 
diff --git a/Makefile.main b/Makefile.main
index 3e554d3..3e5b1b6 100644
--- a/Makefile.main
+++ b/Makefile.main
@@ -1,23 +1,38 @@
 include $(CONFIG)
+ifeq ($(shell uname),Linux)
 BUILD_FOR ?= linux
+else
+BUILD_FOR ?= win
+endif
 
-# Select compiler (g++ for linux, mingw-w64/posix for windows)
+# Select compiler (g++ for linux, mingw-w64 for windows)
 ifeq ($(BUILD_FOR),linux)
 CXX=x86_64-linux-gnu-g++
 else
 ifeq ($(BUILD_FOR),win)
-CXX=x86_64-w64-mingw32-g++-posix
+CXX=x86_64-w64-mingw32-g++
 else
-$(error Invalid target "$(BUILD_FOR)")
+$(error Invalid target "$(BUILD_FOR) (valid choices: linux win)")
 endif
 endif
 
-# FIXME: temporarily used for Windows build
+# Output directory, based on target OS, unless defined manually
+OUTDIR ?= $(OUTDIRBASE)/$(BUILD_FOR)
+
+# CPPUnit
+CPPUNIT = $(OUTDIR)/cppunit
+CPPUNIT_SOURCE = $(OUTDIRBASE)/cppunit
+CPPUNIT_BUILD = $(OUTDIR)/cppunit-build
+ifeq ($(BUILD_FOR),linux)
+CPPUNIT_HOST=x86_64-linux-gnu
+endif
 ifeq ($(BUILD_FOR),win)
-CPPFLAGS += -I/tmp/cppunit/include
-LDFLAGS += -L/tmp/cppunit/src/cppunit/.libs/
+CPPUNIT_HOST=x86_64-w64-mingw32
 endif
+CPPFLAGS += -I$(CPPUNIT)/include
+LDFLAGS += -L$(CPPUNIT)/lib
 
+# Compiler and linker flags
 CPPFLAGS += -Iinclude -I$(OUTDIR) -I$(OUTDIR)/data -DEBCL_BUILD -D_USE_MATH_DEFINES
 CXXFLAGS += -std=c++14 -Wall -Wextra
 LDFLAGS += -L$(OUTDIR) -pthread
@@ -35,27 +50,24 @@ endif
 # Libs for either Linux or Windows
 ifeq ($(BUILD_FOR),linux)
 LIBS_LIB = -ldl -latomic
-else
+endif
 ifeq ($(BUILD_FOR),win)
 LIBS_LIB = -latomic
-else
-$(error Invalid target "$(BUILD_FOR)")
-endif
 endif
 
 # Library and progam suffixes
 ifeq ($(BUILD_FOR),linux)
 SUFFIX_LIB=.so
 SUFFIX_EXE=
-else
+endif
 ifeq ($(BUILD_FOR),win)
 SUFFIX_LIB=.dll
 SUFFIX_EXE=.exe
-else
-$(error Invalid target "$(BUILD_FOR)")
-endif
 endif
 
+# Library
+include src/files.mk
+LIB_OBJS = $(addprefix $(OUTDIR)/,$(addsuffix .o, $(subst src/,, $(basename $(LIB_SOURCES)))))
 CXXFLAGS_LIB = $(CXXFLAGS)
 LIB_DYNAMIC = $(OUTDIR)/libebcorelib$(SUFFIX_LIB)
 LIB_STATIC = $(OUTDIR)/libebcorelib.a
@@ -68,14 +80,13 @@ ifeq ($(BUILD_STATIC_LIB),y)
 LIB_TARGETS += $(LIB_STATIC)
 endif
 
-include src/files.mk
-LIB_OBJS = $(addprefix $(OUTDIR)/,$(addsuffix .o, $(subst src/,, $(basename $(LIB_SOURCES)))))
-
+# Tests
 include tests/list.mk
 TEST_SUITES := $(addsuffix $(SUFFIX_EXE), $(addprefix $(OUTDIR)/test-,$(TESTS)))
 TEST_ALL := $(OUTDIR)/run-all-tests$(SUFFIX_EXE)
 TEST_MAIN := $(OUTDIR)/tests/run-test.o
 TEST_OBJS := $(addsuffix .o,$(addprefix $(OUTDIR)/tests/,$(TESTS))) $(TEST_MAIN)
+# Required libraries
 LIBS_TESTS = -lcppunit
 ifeq ($(BUILD_DYNAMIC_LIB),y)
 LIBS_TESTS += -lebcorelib
@@ -84,14 +95,20 @@ else
 LIBS_TESTS += $(OUTDIR)/libebcorelib.a $(LIBS_LIB)
 TEST_NEEDS = $(LIB_STATIC)
 endif
+# Linker flags
+TEST_LDFLAGS =
+ifeq ($(BUILD_FOR),win)
+TEST_LDFLAGS += -mconsole
+endif
 
+# Objects and dependencies
 ALL_OBJS = $(LIB_OBJS)
 ifeq ($(BUILD_TESTS),y)
 ALL_OBJS += $(TEST_OBJS)
 endif
 DEPS := $(addsuffix .d,$(ALL_OBJS))
 
-
+# Default targets
 TARGETS = $(LIB_TARGETS)
 ifeq ($(BUILD_TESTS),y)
 TARGETS += tests
@@ -106,37 +123,28 @@ run: tests
 		echo "\n\nPlease define E\n\n"; \
 		exit 1; \
 	else \
-		LD_LIBRARY_PATH=$(OUTDIR) $(OUTDIR)/$(E); \
-	fi
-
-debug: tests
-	@if [ -z "$(E)" ]; then \
-		echo "\n\nPlease define E\n\n"; \
-		exit 1; \
-	else \
-		LD_LIBRARY_PATH=$(OUTDIR) debug $(OUTDIR)/$(E); \
+		LD_LIBRARY_PATH=$(OUTDIR):$(CPPUNIT)/lib $(OUTDIR)/$(E); \
 	fi
 
 run-tests: tests
-	LD_LIBRARY_PATH=$(OUTDIR) ./$(TEST_ALL)
+	LD_LIBRARY_PATH=$(OUTDIR):$(CPPUNIT)/lib ./$(TEST_ALL)
 
 clean:
 	rm -f $(TEST_SUITES) $(TEST_ALL) $(TEST_OBJS) \
 		$(LIB_OBJS) $(LIB_TARGETS)
 
-fullclean:	clean
-	rm -f $(DEPS)
-	-rmdir $(sort $(dir $(TEST_OBJS)) $(dir $(LIB_OBJS)))
-	-rmdir $(OUTDIR)
+fullclean:
+	rm --preserve-root -rf $(OUTDIR)
 
-tests:  $(TEST_OBJS) $(TEST_SUITES) $(TEST_ALL)
+tests:  copy-libraries $(TEST_OBJS) $(TEST_SUITES) $(TEST_ALL)
 
 
 .PHONY: all run debug run-tests clean fullclean tests
 
 
-#------------------------------------------------------------------------------
-# Actual building
+# ---------------------------------------------------------------------------- #
+# - LIBRARY AND TESTS                                                        - #
+# ---------------------------------------------------------------------------- #
 
 -include $(DEPS)
 
@@ -151,11 +159,10 @@ $(LIB_STATIC): $(LIB_OBJS)
 
 # Tests
 $(TEST_SUITES): $(OUTDIR)/test-%$(SUFFIX_EXE): $(OUTDIR)/tests/%.o $(TEST_MAIN) $(TEST_NEEDS)
-	$(CXX) $(LDFLAGS) -o $@ $< $(TEST_MAIN) $(LIBS_TESTS)
+	$(CXX) $(LDFLAGS) $(TEST_LDFLAGS) -o $@ $< $(TEST_MAIN) $(LIBS_TESTS)
 
 $(TEST_ALL): $(TEST_OBJS)
-	$(CXX) $(LDFLAGS) -o $@ $(TEST_OBJS) $(LIBS_TESTS)
-
+	$(CXX) $(LDFLAGS) $(TEST_LDFLAGS) -o $@ $(TEST_OBJS) $(LIBS_TESTS)
 
 #------------------------------------------------------------------------------
 # .cc -> .o
@@ -165,8 +172,64 @@ $(LIB_OBJS): $(OUTDIR)/%.o: src/%.cc
 	$(CXX) $(CPPFLAGS) $(CXXFLAGS_LIB) -c -o $@ $<
 	$(CXX) $(CPPFLAGS) $(CXXFLAGS_LIB) -M -MF $@.d -MT $@ $<
 
-$(TEST_OBJS): $(OUTDIR)/%.o: %.cc
+$(TEST_OBJS): $(OUTDIR)/%.o: %.cc | cppunit
 	@if [ ! -d "$(dir $@)" ]; then mkdir -p "$(dir $@)"; fi
 	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
 	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -M -MF $@.d -MT $@ $<
 
+
+# ---------------------------------------------------------------------------- #
+# - CPPUNIT                                                                  - #
+# ---------------------------------------------------------------------------- #
+
+cppunit:		| $(CPPUNIT_SOURCE)/configure
+	+if [ ! -d "$(CPPUNIT)" ]; then \
+		if [ ! -d "$(CPPUNIT_BUILD)" ]; then \
+			mkdir -p "$(CPPUNIT_BUILD)"; \
+		fi; \
+		cd "$(CPPUNIT_BUILD)" && \
+			"$(abspath $(CPPUNIT_SOURCE))"/configure \
+				--host=$(CPPUNIT_HOST) \
+				--prefix="$(abspath $(CPPUNIT))" \
+				--disable-doxygen \
+				--enable-silent-rules && \
+			make && \
+			make install; \
+	fi
+	-rm -rf "$(CPPUNIT_BUILD)"
+
+$(CPPUNIT_SOURCE)/configure: | cppunit-dl
+	cd "$(CPPUNIT_SOURCE)"; ./autogen.sh
+
+cppunit-dl:
+	if [ ! -d "$(CPPUNIT_SOURCE)" ]; then \
+		git clone git://anongit.freedesktop.org/git/libreoffice/cppunit/ "$(CPPUNIT_SOURCE)"; \
+	fi
+
+.PHONY: cppunit cppunit-linux cppunit-windows cppunit-dl
+
+
+# ---------------------------------------------------------------------------- #
+# - DLL COPYING                                                              - #
+# ---------------------------------------------------------------------------- #
+
+# On Windows, we need all the external DLLs to be copied to the output directory
+
+ifeq ($(BUILD_FOR),win)
+
+MINGW_DIR ?= /usr/x86_64-w64-mingw32/sys-root/mingw/bin
+
+copy-libraries:	| cppunit
+	cp $(CPPUNIT)/bin/*dll $(OUTDIR)
+	cp $(MINGW_DIR)/libgcc_s_seh-1.dll $(OUTDIR)
+	cp $(MINGW_DIR)/libatomic-1.dll $(OUTDIR)
+	cp $(MINGW_DIR)/libstdc++-6.dll $(OUTDIR)
+	cp $(MINGW_DIR)/libwinpthread-1.dll $(OUTDIR)
+
+else
+
+copy-libraries:
+
+endif
+
+.PHONY: copy-libraries
diff --git a/default-config b/default-config
index 83ee67e..5a91871 100644
--- a/default-config
+++ b/default-config
@@ -6,7 +6,7 @@ DEBUG = n
 OPTIMIZE = y
 BUILD_TESTS = y
 
-OUTDIR = output
+OUTDIRBASE = output
 
 export BUILD_STATIC_LIB BUILD_DYNAMIC_LIB DEBUG OPTIMIZE BUILD_TESTS
-export OUTDIR
+export OUTDIRBASE
diff --git a/doc/WindowsBuild.txt b/doc/WindowsBuild.txt
new file mode 100644
index 0000000..d20034c
--- /dev/null
+++ b/doc/WindowsBuild.txt
@@ -0,0 +1,10 @@
+1/ Install Babun from https://babun.github.io/
+
+2/ Force an update using update.bat
+
+3/ Install the mingw C++ compiler in the Babun terminal:
+	pact install mingw-x86_64-gcc-g++
+
+4/ Copy the source directory somewhere, then build:
+	cd corelib
+	make