TOP_MAKEFILE := $(firstword $(MAKEFILE_LIST))
COMMON_MAKEFILE := $(lastword $(MAKEFILE_LIST))
FARDIR := $(dir $(COMMON_MAKEFILE))

#The following variables can be set by the user:
#
# DEBUG - set if a debug build is needed
# USE_LTO - use link-time optimisation in release mode
# CLANG - use Clang compiler and LLD linker
# USE_LLD - use LLD linker (useful for debug builds where ld is insanely slow)

# Toolchain setup
TOOLSDIR = $(FARDIR)tools/
FARINCLUDE = $(FARDIR)Include/

DEVNULL = /dev/null

ifneq ($(shell echo %comspec%),%comspec%)
 # Native Windows shell
 os_name = $(subst /,\,$(1))
 UTILS_PREFIX = $(call os_name,$(FARDIR)scripts/gnu.cmd )
 TOOLS_PREFIX = $(TOOLSDIR)
 HOST_TYPE = Windows
 DEVNULL = nul
else
 # Something else
 os_name = $(1)
 HOST_TYPE = $(shell uname -o)
 ifneq (Msys,$(HOST_TYPE))
  ifneq (Cygwin,$(HOST_TYPE))
   HOST_TYPE = Unix
   WINE_CMD = wine #space required
  endif
 else
  TOOLS_PREFIX = $(TOOLSDIR)
  HOST_TYPE = Windows
 endif
endif

LS=$(UTILS_PREFIX)ls
MKDIR = $(UTILS_PREFIX)mkdir -p
RM = $(UTILS_PREFIX)rm -f
CP = $(UTILS_PREFIX)cp -f
MV = $(UTILS_PREFIX)mv -f

ifdef CLANG
CXX = clang++
CC = clang
else # CLANG
CXX = $(GCC_PREFIX)g++$(DW2)
CC = $(GCC_PREFIX)gcc$(DW2)
endif # CLANG

WINDRES = $(GCC_PREFIX)windres
DLLTOOL = $(GCC_PREFIX)dlltool
RANLIB = $(GCC_PREFIX)ranlib
AR = $(GCC_PREFIX)ar

M4 = $(strip $(call os_name, $(TOOLS_PREFIX)m4)) -P -DFARBIT=$(DIRBIT) -DBUILD_TYPE=$(FARMANAGER_BUILD_TYPE) -DSCM_REVISION=$(FARMANAGER_SCM_REVISION) -DHOSTTYPE=$(HOST_TYPE)
GAWK = $(strip $(call os_name, $(TOOLS_PREFIX)gawk))
LGEN = $(WINE_CMD)$(strip $(call os_name, $(TOOLSDIR)lng.generator.exe))
# Toolchain setup end

# Output directory setup
ifdef DEBUG
 DIRNAME=Debug
else # DEBUG
 DIRNAME=Release
endif # DEBUG

ifndef DIRBIT
 ifneq (,$(findstring i686-w64,$(shell $(CC) -dumpmachine)))
  DIRBIT = 32
 else
  ifeq (,$(findstring 64,$(shell $(CC) -dumpmachine)))
   DIRBIT = 32
  else
   DIRBIT = 64
  endif
 endif
endif # DIRBIT
# Output directory setup end

# Main flags setup
CFLAGS += \
	-D UNICODE \
	-D _UNICODE \
	-m$(DIRBIT) \
	-masm=intel \
	-fno-common \
	-fdiagnostics-show-option \
	-pipe \
	-funsigned-char \
	-pedantic-errors \
	-Wall \
	-Wextra \
	-Wpedantic \
	-Wfatal-errors \
	-Werror=odr \
	-Werror=return-type \
	-Werror=cast-align=strict \
	-Werror=cast-qual \
	-Werror=implicit-fallthrough=5 \
	-Wdouble-promotion \
	-Wduplicated-branches \
	-Wduplicated-cond \
	-Wformat=2 \
	-Winvalid-pch \
	-Wlogical-op \
	-Wmissing-declarations \
	-Wredundant-decls \
	-Wundef \
	-include $(FARDIR)disabled_warnings.hpp \
	-D NOMINMAX \
	-D WIN32_LEAN_AND_MEAN \
	-D PSAPI_VERSION=1 \

CPPFLAGS = $(CFLAGS)\
	-std=c++20 \
	-fvisibility=hidden \
	-Werror=old-style-cast \
	-Wctor-dtor-privacy \
	-Wextra-semi \
	-Wimplicit-fallthrough \
	-Wnon-virtual-dtor \
	-Woverloaded-virtual \
	-Wsuggest-override \
	-Wzero-as-null-pointer-constant \

LNKFLAGS += \
	-ladvapi32 \
	-lnetapi32 \
	-lmpr \
	-lwinspool \
	-lole32 \
	-loleaut32 \
	-lsecur32 \
	-lsetupapi \
	-lpsapi \
	-lrpcrt4 \
	-luuid \
	-lversion \
	-luserenv \
	-lcomdlg32 \
	-m$(DIRBIT) \
	-static \
	-Xlinker --tsaware \
	-Xlinker --dynamicbase \
	-Xlinker --nxcompat \

# Configuration-specific flags
ifdef DEBUG
# Debug mode
CFLAGS += \
	-D_DEBUG \
	-D_GLIBCXX_ASSERTIONS \
	-g \
	-Wa,-mbig-obj \
#	-D_GLIBCXX_DEBUG \
#	-D_GLIBCXX_DEBUG_PEDANTIC \

else # DEBUG
# Release mode
CFLAGS += \
	-DNDEBUG \
	-O3 \
	-fomit-frame-pointer \

ifeq ($(USE_LTO),1)
CFLAGS += \
	-flto \
	-flto-odr-type-merging \

endif # USE_LTO

LNKFLAGS += \
	-Xlinker --gc-sections

endif # DEBUG
# Configuration-specific flags end

# Platform-specific flags
ifeq ($(DIRBIT),32)
LNKFLAGS += \
	-Xlinker --large-address-aware \

WINDRES += -F pe-i386 \

else
WINDRES += -F pe-x86-64 \

endif
# Platform-specific flags end

# Compiler-specific flags
ifdef CLANG
ifeq ($(DIRBIT), 32)
CLANG_TARGET = i686-pc-windows-gnu
else
CLANG_TARGET = x86_64-pc-windows-gnu
endif

CLANG_FLAGS = \
	-target $(CLANG_TARGET) \
	-Wno-unknown-warning-option \
	-fms-extensions \
	-Weverything \

CFLAGS += $(CLANG_FLAGS)
CFLAGS += -D __FLOAT_H # 8.1 incompatibility

LNKFLAGS += \
	$(CLANG_FLAGS) \
	-fuse-ld=lld \
	-Xlinker --allow-multiple-definition \
	-Xlinker -Map \
	-Xlinker $(MAP) \

ifndef DEBUG
LNKFLAGS += \
	-Xlinker --strip-all \

endif

else
# LD map files are unusable for tracing,
# so we keep the symbols, objdump them and strip manually.
# LLD, on the contrary, generates good maps and doesn't need this trickery.
USE_OBJDUMP_MAPS=1
endif
# Compiler-specific flags end

ifdef USE_LLD
LNKFLAGS += \
	-fuse-ld=lld \

endif

ifeq ($(findstring ----,---$(strip $(MAKEFLAGS))-),)
 MK_FLAGS := -$(strip $(MAKEFLAGS))
else
 MK_FLAGS := $(strip $(MAKEFLAGS))
endif
