DPP_ROOT = .
SYSROOT = mingw-w64-sysroot
SYSROOT_X64 = $(SYSROOT)/x86_64
ACTIVATE_SH = ./$(SYSROOT_X64)/activate.sh

MAKE_PID := $(shell echo $$PPID)
JOBS := $(shell ps T | sed -n 's/.*$(MAKE_PID).*$(MAKE).* \(-j\|--jobs=\) *\([0-9][0-9]*\).*/\2/p')

ifndef JOBS
JOBS := 1
endif

ifndef BUILD_NATIVE
include Makefile.inc
else
include Makefile.native.inc
endif

EASTL_DEPS := $(wildcard $(DPP_ROOT)/EASTL/source/*.cpp) $(wildcard $(DPP_ROOT)/EASTL/include/EASTL/*.h)

all: deps

$(LIBCRT_STATIC_LIB): $(LIBCRT_OBJECTS)
	$(Q)test -d '$(LIBCRT_BUILD_DIR)' || mkdir -p '$(LIBCRT_BUILD_DIR)'
ifneq ($(Q),@)
	$(Q)$(AR) -rsv '$@' $(LIBCRT_OBJECTS)
else
	$(Q)$(AR) -rs '$@' $(LIBCRT_OBJECTS) 2>/dev/null >/dev/null
endif
	@echo 'AR  $@'

$(LIBCXXRT_STATIC_LIB): $(LIBCXXRT_OBJECTS)
	$(Q)test -d '$(LIBCRT_BUILD_DIR)' || mkdir -p '$(LIBCRT_BUILD_DIR)'
ifneq ($(Q),@)
	$(Q)$(AR) -rsv '$@' $(LIBCXXRT_OBJECTS)
else
	$(Q)$(AR) -rs '$@' $(LIBCXXRT_OBJECTS) 2>/dev/null >/dev/null
endif
	@echo 'AR  $@'

$(LIBUSERCRT_STATIC_LIB): $(LIBUSERCRT_OBJECTS)
	$(Q)test -d '$(LIBCRT_BUILD_DIR)' || mkdir -p '$(LIBCRT_BUILD_DIR)'
ifneq ($(Q),@)
	$(Q)$(AR) -rsv '$@' $(LIBUSERCRT_OBJECTS)
else
	$(Q)$(AR) -rs '$@' $(LIBUSERCRT_OBJECTS) 2>/dev/null >/dev/null
endif
	@echo 'AR  $@'

$(LIBCRT_BUILD_DIR)/kcrt$(NAME_SUFFIX).o: $(CC) $(DPP_ROOT)/CRT/kcrt.c
	$(Q)test -d '$(LIBCRT_BUILD_DIR)' || mkdir -p '$(LIBCRT_BUILD_DIR)'
	$(Q)$(CC) -std=c99 $(CFLAGS) -c CRT/kcrt.c -o $@
	@echo 'CC  $@'

$(LIBCRT_BUILD_DIR)/ntdll_zw_functions$(NAME_SUFFIX).o: $(CC) $(DPP_ROOT)/CRT/ntdll_zw_functions.c
	$(Q)test -d '$(LIBCRT_BUILD_DIR)' || mkdir -p '$(LIBCRT_BUILD_DIR)'
	$(Q)$(CC) -std=c99 $(CFLAGS) -c CRT/ntdll_zw_functions.c -o $@
	@echo 'CC  $@'

$(LIBCRT_BUILD_DIR)/eastl_compat$(NAME_SUFFIX).opp: $(CXX) $(DPP_ROOT)/CRT/eastl_compat.cpp
	$(Q)test -d '$(LIBCRT_BUILD_DIR)' || mkdir -p '$(LIBCRT_BUILD_DIR)'
	$(Q)$(CXX) $(CFLAGS) -Wno-format -Wno-format-extra-args $(CXXFLAGS) $(EASTL_CXXFLAGS) -c CRT/eastl_compat.cpp -o $@
	@echo 'CXX $@'

$(LIBCRT_BUILD_DIR)/kcrt$(NAME_SUFFIX).opp: $(CXX) $(DPP_ROOT)/CRT/kcrt.cpp
	$(Q)test -d '$(LIBCRT_BUILD_DIR)' || mkdir -p '$(LIBCRT_BUILD_DIR)'
	$(Q)$(CXX) $(CFLAGS) $(CXXFLAGS) $(EASTL_CXXFLAGS) -c CRT/kcrt.cpp -o $@
	@echo 'CXX $@'

$(LIBCRT_BUILD_DIR)/ucrt$(NAME_SUFFIX).opp: $(CXX) $(DPP_ROOT)/CRT/ucrt.cpp
	$(Q)test -d '$(LIBCRT_BUILD_DIR)' || mkdir -p '$(LIBCRT_BUILD_DIR)'
	$(Q)$(CXX) $(CFLAGS) $(CXXFLAGS) $(EASTL_CXXFLAGS) -c CRT/ucrt.cpp -o $@
	@echo 'CXX $@'

$(LIBCRT_BUILD_DIR)/DriverThread$(NAME_SUFFIX).opp: $(CXX) $(DPP_ROOT)/CRT/DriverThread.cpp $(DPP_ROOT)/CRT/DriverThread.hpp
	$(Q)test -d '$(LIBCRT_BUILD_DIR)' || mkdir -p '$(LIBCRT_BUILD_DIR)'
	$(Q)$(CXX) $(CFLAGS) $(CXXFLAGS) $(EASTL_CXXFLAGS) -c CRT/DriverThread.cpp -o $@
	@echo 'CXX $@'

ifndef BUILD_NATIVE

deps-print-local-notice: $(CC)
ifeq ($(CC),$(LOCAL_MINGW64_CC))
	@echo
	@echo "-- [Build Config]"
	@echo "-- CC : $(realpath $(CC))"
	@echo "-- CXX: $(realpath $(CXX))"
	@echo "-- DDK: $(realpath $(DDK_INCLUDE_DIR))"
	@echo
endif

$(LOCAL_MINGW64_BUILD_SCRIPT):
ifeq ($(CC),$(LOCAL_MINGW64_CC))
	@echo
	@echo "-----------------------------------------------------------------------------"
	@echo "-- ./mingw-w64-build/mingw-w64-build does not exist, cloning git submodule --"
	@echo "-----------------------------------------------------------------------------"
	@echo
	git submodule update --init mingw-w64-build
endif

ifeq ($(USE_MINGW64_TARBALL),)
$(LOCAL_MINGW64_CC): $(LOCAL_MINGW64_BUILD_SCRIPT)
else
$(LOCAL_MINGW64_CC):
endif
ifneq ($(USE_MINGW64_TARBALL),)
	@echo
	@echo "------------------------------------------------------------------------------------------------"
	@echo "-- USE_MINGW64_TARBALL found: $(USE_MINGW64_TARBALL) --"
	@echo "------------------------------------------------------------------------------------------------"
	@echo
ifneq ($(Q),@)
	tar -xjvf '$(USE_MINGW64_TARBALL)'
else
	tar -xjf '$(USE_MINGW64_TARBALL)'
endif
else
ifeq ($(CC),$(LOCAL_MINGW64_CC))
	@echo
	@echo "------------------------------------------------------------------------------------------------"
	@echo "-- ./$(SYSROOT_X64)/bin/x86_64-w64-mingw32-gcc does not exist, building toolchain --"
	@echo "------------------------------------------------------------------------------------------------"
	@echo
	env -i ./mingw-w64-build/mingw-w64-build --root="$(shell realpath ./$(SYSROOT))" --disable-threads --jobs $(JOBS) x86_64
	@echo '#!/usr/bin/env bash' >$(ACTIVATE_SH)
	@echo >>$(ACTIVATE_SH)
	@echo 'MYDIR="$$(realpath $$(dirname $${BASH_SOURCE[0]}))"' >>$(ACTIVATE_SH)
	@echo 'export PATH="$${MYDIR}/$(SYSROOT_X64)/bin:$${MYDIR}/bin:$${PATH}"' >>$(ACTIVATE_SH)
	@chmod +x $(ACTIVATE_SH)
endif
endif

ifeq ($(CC),$(LOCAL_MINGW64_CC))
$(LOCAL_MINGW64_CXX): $(LOCAL_MINGW64_CC)
endif

deps-build: \
	$(LOCAL_MINGW64_BUILD_SCRIPT) \
	$(LOCAL_MINGW64_CC) \
	$(EASTL_STATIC_LIB) \
	$(LIBCRT_STATIC_LIB) \
	$(LIBCXXRT_STATIC_LIB) \
	$(LIBUSERCRT_STATIC_LIB) \
	$(SIGNTOOL_PREFIX)

deps: deps-print-local-notice deps-build

$(EASTL_STATIC_LIB): $(CXX) $(EASTL_DEPS)
	$(Q)test -d '$(EASTL_BUILDDIR)' || mkdir -p $(EASTL_BUILDDIR)
	cd $(EASTL_BUILDDIR) && \
		$(CMAKE) ../EASTL \
			-DCMAKE_CXX_COMPILER="$(realpath $(CXX))" \
			-DCMAKE_RC_COMPILER="$(realpath $(RC))" \
			-DCMAKE_SYSTEM_NAME="Windows" \
			-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \
			-DCMAKE_CXX_FLAGS='$(CFLAGS) $(CXXFLAGS) $(EASTL_CXXFLAGS)' && \
		$(MAKE) $(CMAKE_Q)

$(SIGNTOOL_PREFIX)-code.p12:
	./create_codesign_ca.sh $(SIGNTOOL_PREFIX)

$(SIGNTOOL_PREFIX): $(SIGNTOOL_PREFIX)-code.p12

package-mingw: deps
	@echo 'Adding mingw build directories..'
	tar --owner=0 --group=0 --no-same-owner --no-same-permissions \
		--no-acls --no-selinux --no-xattrs \
		--mtime ./Makefile.deps -rf mingw-w64-dpp.tar $(patsubst $(DPP_ROOT)/%,%,$(EASTL_STATIC_LIB)) \
		--transform 's,^,mingw-w64-dpp/,'
	tar --owner=0 --group=0 --no-same-owner --no-same-permissions \
		--no-acls --no-selinux --no-xattrs \
		--mtime ./Makefile.deps -rf mingw-w64-dpp.tar $(patsubst $(DPP_ROOT)/%,%,$(LIBCRT_BUILD_DIR)) \
		--transform 's,^,mingw-w64-dpp/,'
	tar --owner=0 --group=0 --no-same-owner --no-same-permissions \
		--no-acls --no-selinux --no-xattrs \
		--mtime ./Makefile.deps -rf mingw-w64-dpp.tar $(SYSROOT) \
		--transform 's,^,mingw-w64-dpp/,'

distclean: clean
	rm -f $(SIGNTOOL_PREFIX)-ca-* $(SIGNTOOL_PREFIX)-code*
	rm -rf $(LOCAL_MINGW64_BUILD_DIR)
	git submodule deinit --all

clean:
	rm -f $(LIBCRT_STATIC_LIB) $(LIBCXXRT_STATIC_LIB) $(LIBUSERCRT_STATIC_LIB) $(EASTL_STATIC_LIB)
	rm -rf $(LIBCRT_BUILD_DIR) $(EASTL_BUILDDIR)

else

deps-build: \
	$(EASTL_STATIC_LIB) \
	$(LIBUSERCRT_STATIC_LIB)

deps: deps-build

$(EASTL_STATIC_LIB): $(CXX) $(EASTL_DEPS)
	$(Q)test -d '$(EASTL_BUILDDIR)' || mkdir -p $(EASTL_BUILDDIR)
	cd $(EASTL_BUILDDIR) && \
		$(CMAKE) ../EASTL \
			-DCMAKE_CXX_COMPILER="$(realpath $(CXX))" \
			-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \
			-DCMAKE_CXX_FLAGS='$(CFLAGS) $(CXXFLAGS) $(EASTL_CXXFLAGS)' && \
		$(MAKE) $(CMAKE_Q)

package-native: deps
	@echo 'Adding native build directories..'
	tar --owner=0 --group=0 --no-same-owner --no-same-permissions \
		--no-acls --no-selinux --no-xattrs \
		--mtime ./Makefile.deps -rf mingw-w64-dpp.tar $(patsubst $(DPP_ROOT)/%,%,$(EASTL_STATIC_LIB)) \
		--transform 's,^,mingw-w64-dpp/,'
	tar --owner=0 --group=0 --no-same-owner --no-same-permissions \
		--no-acls --no-selinux --no-xattrs \
		--mtime ./Makefile.deps -rf mingw-w64-dpp.tar $(patsubst $(DPP_ROOT)/%,%,$(LIBCRT_BUILD_DIR)) \
		--transform 's,^,mingw-w64-dpp/,'

distclean: clean

clean:
	rm -f $(LIBUSERCRT_STATIC_LIB) $(EASTL_STATIC_LIB)
	rm -rf $(LIBCRT_BUILD_DIR) $(EASTL_BUILDDIR)

endif

package:
	@echo 'Creating package containing repository sources and binary mingw64 toolchain..'
	git archive --prefix 'mingw-w64-dpp/' -o mingw-w64-dpp.tar HEAD
	$(MAKE) -C $(DPP_ROOT) -f Makefile.deps package-mingw
	$(MAKE) -C $(DPP_ROOT) -f Makefile.deps BUILD_NATIVE=1 package-native
	bzip2 -c mingw-w64-dpp.tar >mingw-w64-dpp.tar.bz2

help:
	@echo '[Makefile.deps]'
	$(call HELP_MAKE_OPTIONS)
	@echo -e '\tJOBS            = $(JOBS)'
	@echo -e '\tWERROR          = $(WERROR)'
	@echo -e '\tQ               = $(Q)'

.PHONY: all deps-print-local-notice deps-build deps package distclean clean help
.DEFAULT_GOAL := all