CC ?= cc
AR ?= ar

BUILD_DIR ?= build
TARGET := $(BUILD_DIR)/libgame_mp_uo_recovered.a
SHARED_BUILD_DIR ?= $(BUILD_DIR)-shared
SHARED_TARGET := $(SHARED_BUILD_DIR)/game.mp.uo.x86_64.so
NATIVE64_BUILD_DIR ?= build-native64
NATIVE64_TARGET := $(NATIVE64_BUILD_DIR)/libgame_mp_uo_recovered.a
NATIVE64_SHARED_BUILD_DIR ?= build-native64-shared
NATIVE64_SHARED_TARGET := $(NATIVE64_SHARED_BUILD_DIR)/game.mp.uo.x86_64.so
I386_SHARED_BUILD_DIR ?= build-i386-shared
I386_SHARED_TARGET ?= $(I386_SHARED_BUILD_DIR)/game.mp.uo.i386.so
I386_CFLAGS ?= -m32 -march=i386
I386_LDFLAGS ?= -m32
# Stock i386 uses x87 implicitly, but it still needs the same per-assignment
# binary32 spills and unoptimized local-store shape as the original build.
# -march=i386 also preserves the retail status-word comparison lowering instead
# of allowing modern GCC to select the later FCOMI/FUCOMI instruction family.
I386_FLOAT_FLAGS := -O0 -fexcess-precision=fast
MINGW32_CC ?= i686-w64-mingw32-gcc
WINDOWS_I386_BUILD_DIR ?= build-windows-i386
WINDOWS_I386_TARGET ?= $(WINDOWS_I386_BUILD_DIR)/uo_game_mp_x86.dll
WINDOWS_I686_BUILD_DIR ?= build-windows-i686
WINDOWS_I686_TARGET ?= $(WINDOWS_I686_BUILD_DIR)/uo_game_mp_x86.dll
WINDOWS_I386_CFLAGS ?= -march=i386
WINDOWS_I686_CFLAGS ?= -march=i686
WINDOWS_FLOAT_FLAGS := -O0 -mfpmath=387 -fexcess-precision=fast
WINDOWS_LDFLAGS ?= -shared -static-libgcc
WINDOWS_LIBS ?= -lm
WINDOWS_MODULE_DEF := uo_game_mp_x86.def
SRCS := $(wildcard src/*.c)
QCOMMON_DIR := ../shared-qcommon
QCOMMON_SRCS := $(QCOMMON_DIR)/src/com_sprintf.c \
	$(QCOMMON_DIR)/src/info.c \
	$(QCOMMON_DIR)/src/q_string_compare.c
MATH_DIR := ../shared-math
MATH_SRCS := $(MATH_DIR)/src/q_math.c \
	$(MATH_DIR)/src/byte_directions.c \
	$(MATH_DIR)/src/set_plane_signbits.c
CODUO_DEFAULT_BEHAVIOR := linux
include ../build-mk/platform-behavior.mk

# Shared reconstruction of the CRT math routines (../shared-libm). Built from
# here so the server carries no dependency on the platform libm; see
# ../docs/x87-transcendental-reconstruction-scope.md.
LIBM_DIR := ../shared-libm
LIBM_SRCS := $(wildcard $(LIBM_DIR)/src/*.c)

OBJS := $(patsubst src/%.c,$(BUILD_DIR)/%.o,$(SRCS)) \
        $(patsubst $(LIBM_DIR)/src/%.c,$(BUILD_DIR)/libm_%.o,$(LIBM_SRCS)) \
        $(patsubst $(QCOMMON_DIR)/src/%.c,$(BUILD_DIR)/qcommon_%.o,$(QCOMMON_SRCS)) \
        $(patsubst $(MATH_DIR)/src/%.c,$(BUILD_DIR)/math_%.o,$(MATH_SRCS))
SHARED_OBJS := $(patsubst src/%.c,$(SHARED_BUILD_DIR)/%.o,$(SRCS)) \
        $(patsubst $(LIBM_DIR)/src/%.c,$(SHARED_BUILD_DIR)/libm_%.o,$(LIBM_SRCS)) \
        $(patsubst $(QCOMMON_DIR)/src/%.c,$(SHARED_BUILD_DIR)/qcommon_%.o,$(QCOMMON_SRCS)) \
        $(patsubst $(MATH_DIR)/src/%.c,$(SHARED_BUILD_DIR)/math_%.o,$(MATH_SRCS))
NATIVE64_OBJS := $(patsubst src/%.c,$(NATIVE64_BUILD_DIR)/%.o,$(SRCS)) \
        $(patsubst $(LIBM_DIR)/src/%.c,$(NATIVE64_BUILD_DIR)/libm_%.o,$(LIBM_SRCS)) \
        $(patsubst $(QCOMMON_DIR)/src/%.c,$(NATIVE64_BUILD_DIR)/qcommon_%.o,$(QCOMMON_SRCS)) \
        $(patsubst $(MATH_DIR)/src/%.c,$(NATIVE64_BUILD_DIR)/math_%.o,$(MATH_SRCS))
NATIVE64_SHARED_OBJS := $(patsubst src/%.c,$(NATIVE64_SHARED_BUILD_DIR)/%.o,$(SRCS)) \
        $(patsubst $(LIBM_DIR)/src/%.c,$(NATIVE64_SHARED_BUILD_DIR)/libm_%.o,$(LIBM_SRCS)) \
        $(patsubst $(QCOMMON_DIR)/src/%.c,$(NATIVE64_SHARED_BUILD_DIR)/qcommon_%.o,$(QCOMMON_SRCS)) \
        $(patsubst $(MATH_DIR)/src/%.c,$(NATIVE64_SHARED_BUILD_DIR)/math_%.o,$(MATH_SRCS))
I386_SHARED_OBJS := $(patsubst src/%.c,$(I386_SHARED_BUILD_DIR)/%.o,$(SRCS)) \
        $(patsubst $(LIBM_DIR)/src/%.c,$(I386_SHARED_BUILD_DIR)/libm_%.o,$(LIBM_SRCS)) \
        $(patsubst $(QCOMMON_DIR)/src/%.c,$(I386_SHARED_BUILD_DIR)/qcommon_%.o,$(QCOMMON_SRCS)) \
        $(patsubst $(MATH_DIR)/src/%.c,$(I386_SHARED_BUILD_DIR)/math_%.o,$(MATH_SRCS))
WINDOWS_I386_OBJS := $(patsubst src/%.c,$(WINDOWS_I386_BUILD_DIR)/%.o,$(SRCS)) \
        $(patsubst $(LIBM_DIR)/src/%.c,$(WINDOWS_I386_BUILD_DIR)/libm_%.o,$(LIBM_SRCS)) \
        $(patsubst $(QCOMMON_DIR)/src/%.c,$(WINDOWS_I386_BUILD_DIR)/qcommon_%.o,$(QCOMMON_SRCS)) \
        $(patsubst $(MATH_DIR)/src/%.c,$(WINDOWS_I386_BUILD_DIR)/math_%.o,$(MATH_SRCS))
WINDOWS_I686_OBJS := $(patsubst src/%.c,$(WINDOWS_I686_BUILD_DIR)/%.o,$(SRCS)) \
        $(patsubst $(LIBM_DIR)/src/%.c,$(WINDOWS_I686_BUILD_DIR)/libm_%.o,$(LIBM_SRCS)) \
        $(patsubst $(QCOMMON_DIR)/src/%.c,$(WINDOWS_I686_BUILD_DIR)/qcommon_%.o,$(QCOMMON_SRCS)) \
        $(patsubst $(MATH_DIR)/src/%.c,$(WINDOWS_I686_BUILD_DIR)/math_%.o,$(MATH_SRCS))
DEPS := $(OBJS:.o=.d)
SHARED_DEPS := $(SHARED_OBJS:.o=.d)
NATIVE64_DEPS := $(NATIVE64_OBJS:.o=.d)
NATIVE64_SHARED_DEPS := $(NATIVE64_SHARED_OBJS:.o=.d)
I386_SHARED_DEPS := $(I386_SHARED_OBJS:.o=.d)
WINDOWS_I386_DEPS := $(WINDOWS_I386_OBJS:.o=.d)
WINDOWS_I686_DEPS := $(WINDOWS_I686_OBJS:.o=.d)

CPPFLAGS += -Iinclude -I$(LIBM_DIR)/include -I$(QCOMMON_DIR)/include \
            -I$(MATH_DIR)/include \
            -I../shared-include \
            -I../vendor/softfloat/source/include
# Stock i386 uses signed plain char, 32-bit enum-backed domains, and wrapping
# ADD/SUB/IMUL semantics. GCC, Clang, and MinGW support explicit switches for
# those rules, preventing host defaults or inherited flags from changing them.
CFLAGS += -std=c99 -Wall -Wextra -Werror -pedantic -fsigned-char \
	-fno-short-enums -fwrapv -MMD -MP

# x87 floating-point faithfulness policy (shared with the engine, and the single
# source of truth for FP faithfulness across both). Governs whether the x86-64
# library reproduces the original's x87 float rounding (-mfpmath=387 on GCC/x86)
# or is an acknowledged non-exact build. See ../build-mk/x87-policy.mk and
# ../engine_lnxded_recovery/docs/fp-faithfulness.md.
X87_POLICY_ARCH := $(shell uname -m)
X87_POLICY_CC := $(CC)
include ../build-mk/x87-policy.mk
# A relaxed (acknowledged non-exact) build also relaxes the source-level x87
# long-double equivalence assert in recovered_game.h, since a non-x87 host
# cannot satisfy it. (This is the axis the retired NATIVE64_FP_MODE knob used to
# control; it is now derived from CODUO_FP_FAITHFUL like everything else.)
ifeq ($(CODUO_FP_FAITHFUL),relaxed)
X87_ALLOW_CPPFLAGS += -DGAME_REQUIRE_X87_LONG_DOUBLE=0 -DGAME_ALLOW_NON_EQUIVALENT_LONG_DOUBLE=1
endif

SHARED_CFLAGS += -fPIC
SHARED_LD ?= $(CC)
SHARED_LDFLAGS += -shared
SHARED_LIBS += -lm
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
STRICT_UNDEFINED_LDFLAGS ?= -Wl,-undefined,error
else
STRICT_UNDEFINED_LDFLAGS ?= -Wl,--no-undefined
endif

.PHONY: all check shared shared-check shared-check-link shared-i386 \
	native64-check native64-shared windows windows-i386 windows-i686

all: $(TARGET)

check: all

shared: $(SHARED_TARGET)

shared-i386: $(I386_SHARED_TARGET)

native64-check: $(NATIVE64_TARGET)

native64-shared: $(NATIVE64_SHARED_TARGET)

windows: windows-i686

windows-i386: $(WINDOWS_I386_TARGET)

windows-i686: $(WINDOWS_I686_TARGET)

shared-check: shared-check-link

shared-check-link: override SHARED_LDFLAGS += $(STRICT_UNDEFINED_LDFLAGS)
shared-check-link: $(SHARED_OBJS)
	$(SHARED_LD) $(SHARED_LDFLAGS) -o $(SHARED_TARGET) $^ $(SHARED_LIBS)

$(BUILD_DIR):
	mkdir -p $(BUILD_DIR)

$(SHARED_BUILD_DIR):
	mkdir -p $(SHARED_BUILD_DIR)

$(NATIVE64_BUILD_DIR):
	mkdir -p $(NATIVE64_BUILD_DIR)

$(NATIVE64_SHARED_BUILD_DIR):
	mkdir -p $(NATIVE64_SHARED_BUILD_DIR)

$(I386_SHARED_BUILD_DIR):
	mkdir -p $(I386_SHARED_BUILD_DIR)

$(WINDOWS_I386_BUILD_DIR):
	mkdir -p $(WINDOWS_I386_BUILD_DIR)

$(WINDOWS_I686_BUILD_DIR):
	mkdir -p $(WINDOWS_I686_BUILD_DIR)

$(BUILD_DIR)/%.o: src/%.c | $(BUILD_DIR)
	$(CC) $(CPPFLAGS) $(PLATFORM_BEHAVIOR_CPPFLAGS) $(X87_ALLOW_CPPFLAGS) $(CFLAGS) $(X87_FLOAT_FLAGS) -c $< -o $@

$(SHARED_BUILD_DIR)/%.o: src/%.c | $(SHARED_BUILD_DIR)
	$(CC) $(CPPFLAGS) $(PLATFORM_BEHAVIOR_CPPFLAGS) $(X87_ALLOW_CPPFLAGS) $(CFLAGS) $(SHARED_CFLAGS) $(X87_FLOAT_FLAGS) -c $< -o $@

$(NATIVE64_BUILD_DIR)/%.o: src/%.c | $(NATIVE64_BUILD_DIR)
	$(CC) $(CPPFLAGS) $(PLATFORM_BEHAVIOR_CPPFLAGS) $(X87_ALLOW_CPPFLAGS) $(CFLAGS) $(X87_FLOAT_FLAGS) -c $< -o $@

$(NATIVE64_SHARED_BUILD_DIR)/%.o: src/%.c | $(NATIVE64_SHARED_BUILD_DIR)
	$(CC) $(CPPFLAGS) $(PLATFORM_BEHAVIOR_CPPFLAGS) $(X87_ALLOW_CPPFLAGS) $(CFLAGS) $(SHARED_CFLAGS) $(X87_FLOAT_FLAGS) -c $< -o $@

# 32-bit x86 already uses x87 for all float math. I386_FLOAT_FLAGS still
# supplies the separately required stock spill/rounding policy.
$(I386_SHARED_BUILD_DIR)/%.o: src/%.c | $(I386_SHARED_BUILD_DIR)
	$(CC) $(CPPFLAGS) $(PLATFORM_BEHAVIOR_CPPFLAGS) $(CFLAGS) $(SHARED_CFLAGS) $(I386_CFLAGS) \
		$(I386_FLOAT_FLAGS) -c $< -o $@

$(WINDOWS_I386_BUILD_DIR)/%.o: src/%.c | $(WINDOWS_I386_BUILD_DIR)
	$(MINGW32_CC) $(CPPFLAGS) -DWINDOWS_BEHAVIOR $(CFLAGS) $(WINDOWS_FLOAT_FLAGS) \
		$(WINDOWS_I386_CFLAGS) -c $< -o $@

$(WINDOWS_I686_BUILD_DIR)/%.o: src/%.c | $(WINDOWS_I686_BUILD_DIR)
	$(MINGW32_CC) $(CPPFLAGS) -DWINDOWS_BEHAVIOR $(CFLAGS) $(WINDOWS_FLOAT_FLAGS) \
		$(WINDOWS_I686_CFLAGS) -c $< -o $@

# Shared libm objects, prefixed so they cannot collide with src/ basenames.
$(BUILD_DIR)/libm_%.o: $(LIBM_DIR)/src/%.c | $(BUILD_DIR)
	$(CC) $(CPPFLAGS) $(X87_ALLOW_CPPFLAGS) $(CFLAGS) $(X87_FLOAT_FLAGS) -c $< -o $@

$(SHARED_BUILD_DIR)/libm_%.o: $(LIBM_DIR)/src/%.c | $(SHARED_BUILD_DIR)
	$(CC) $(CPPFLAGS) $(X87_ALLOW_CPPFLAGS) $(CFLAGS) $(SHARED_CFLAGS) $(X87_FLOAT_FLAGS) -c $< -o $@

$(NATIVE64_BUILD_DIR)/libm_%.o: $(LIBM_DIR)/src/%.c | $(NATIVE64_BUILD_DIR)
	$(CC) $(CPPFLAGS) $(X87_ALLOW_CPPFLAGS) $(CFLAGS) $(X87_FLOAT_FLAGS) -c $< -o $@

$(NATIVE64_SHARED_BUILD_DIR)/libm_%.o: $(LIBM_DIR)/src/%.c | $(NATIVE64_SHARED_BUILD_DIR)
	$(CC) $(CPPFLAGS) $(X87_ALLOW_CPPFLAGS) $(CFLAGS) $(SHARED_CFLAGS) $(X87_FLOAT_FLAGS) -c $< -o $@

$(I386_SHARED_BUILD_DIR)/libm_%.o: $(LIBM_DIR)/src/%.c | $(I386_SHARED_BUILD_DIR)
	$(CC) $(CPPFLAGS) $(CFLAGS) $(SHARED_CFLAGS) $(I386_CFLAGS) \
		$(I386_FLOAT_FLAGS) -c $< -o $@

$(WINDOWS_I386_BUILD_DIR)/libm_%.o: $(LIBM_DIR)/src/%.c | $(WINDOWS_I386_BUILD_DIR)
	$(MINGW32_CC) $(CPPFLAGS) $(CFLAGS) $(WINDOWS_FLOAT_FLAGS) \
		$(WINDOWS_I386_CFLAGS) -c $< -o $@

$(WINDOWS_I686_BUILD_DIR)/libm_%.o: $(LIBM_DIR)/src/%.c | $(WINDOWS_I686_BUILD_DIR)
	$(MINGW32_CC) $(CPPFLAGS) $(CFLAGS) $(WINDOWS_FLOAT_FLAGS) \
		$(WINDOWS_I686_CFLAGS) -c $< -o $@

# Shared qcommon objects, prefixed so they cannot collide with src/ basenames.
$(BUILD_DIR)/qcommon_%.o: $(QCOMMON_DIR)/src/%.c | $(BUILD_DIR)
	$(CC) $(CPPFLAGS) $(PLATFORM_BEHAVIOR_CPPFLAGS) $(X87_ALLOW_CPPFLAGS) $(CFLAGS) $(X87_FLOAT_FLAGS) -c $< -o $@

$(SHARED_BUILD_DIR)/qcommon_%.o: $(QCOMMON_DIR)/src/%.c | $(SHARED_BUILD_DIR)
	$(CC) $(CPPFLAGS) $(PLATFORM_BEHAVIOR_CPPFLAGS) $(X87_ALLOW_CPPFLAGS) $(CFLAGS) $(SHARED_CFLAGS) $(X87_FLOAT_FLAGS) -c $< -o $@

$(NATIVE64_BUILD_DIR)/qcommon_%.o: $(QCOMMON_DIR)/src/%.c | $(NATIVE64_BUILD_DIR)
	$(CC) $(CPPFLAGS) $(PLATFORM_BEHAVIOR_CPPFLAGS) $(X87_ALLOW_CPPFLAGS) $(CFLAGS) $(X87_FLOAT_FLAGS) -c $< -o $@

$(NATIVE64_SHARED_BUILD_DIR)/qcommon_%.o: $(QCOMMON_DIR)/src/%.c | $(NATIVE64_SHARED_BUILD_DIR)
	$(CC) $(CPPFLAGS) $(PLATFORM_BEHAVIOR_CPPFLAGS) $(X87_ALLOW_CPPFLAGS) $(CFLAGS) $(SHARED_CFLAGS) $(X87_FLOAT_FLAGS) -c $< -o $@

$(I386_SHARED_BUILD_DIR)/qcommon_%.o: $(QCOMMON_DIR)/src/%.c | $(I386_SHARED_BUILD_DIR)
	$(CC) $(CPPFLAGS) $(PLATFORM_BEHAVIOR_CPPFLAGS) $(CFLAGS) $(SHARED_CFLAGS) $(I386_CFLAGS) \
		$(I386_FLOAT_FLAGS) -c $< -o $@

$(WINDOWS_I386_BUILD_DIR)/qcommon_%.o: $(QCOMMON_DIR)/src/%.c | $(WINDOWS_I386_BUILD_DIR)
	$(MINGW32_CC) $(CPPFLAGS) -DWINDOWS_BEHAVIOR $(CFLAGS) $(WINDOWS_FLOAT_FLAGS) \
		$(WINDOWS_I386_CFLAGS) -c $< -o $@

$(WINDOWS_I686_BUILD_DIR)/qcommon_%.o: $(QCOMMON_DIR)/src/%.c | $(WINDOWS_I686_BUILD_DIR)
	$(MINGW32_CC) $(CPPFLAGS) -DWINDOWS_BEHAVIOR $(CFLAGS) $(WINDOWS_FLOAT_FLAGS) \
		$(WINDOWS_I686_CFLAGS) -c $< -o $@

# Shared math objects, prefixed so they cannot collide with src/ basenames.
$(BUILD_DIR)/math_%.o: $(MATH_DIR)/src/%.c | $(BUILD_DIR)
	$(CC) $(CPPFLAGS) $(PLATFORM_BEHAVIOR_CPPFLAGS) $(X87_ALLOW_CPPFLAGS) $(CFLAGS) $(X87_FLOAT_FLAGS) -c $< -o $@

$(SHARED_BUILD_DIR)/math_%.o: $(MATH_DIR)/src/%.c | $(SHARED_BUILD_DIR)
	$(CC) $(CPPFLAGS) $(PLATFORM_BEHAVIOR_CPPFLAGS) $(X87_ALLOW_CPPFLAGS) $(CFLAGS) $(SHARED_CFLAGS) $(X87_FLOAT_FLAGS) -c $< -o $@

$(NATIVE64_BUILD_DIR)/math_%.o: $(MATH_DIR)/src/%.c | $(NATIVE64_BUILD_DIR)
	$(CC) $(CPPFLAGS) $(PLATFORM_BEHAVIOR_CPPFLAGS) $(X87_ALLOW_CPPFLAGS) $(CFLAGS) $(X87_FLOAT_FLAGS) -c $< -o $@

$(NATIVE64_SHARED_BUILD_DIR)/math_%.o: $(MATH_DIR)/src/%.c | $(NATIVE64_SHARED_BUILD_DIR)
	$(CC) $(CPPFLAGS) $(PLATFORM_BEHAVIOR_CPPFLAGS) $(X87_ALLOW_CPPFLAGS) $(CFLAGS) $(SHARED_CFLAGS) $(X87_FLOAT_FLAGS) -c $< -o $@

$(I386_SHARED_BUILD_DIR)/math_%.o: $(MATH_DIR)/src/%.c | $(I386_SHARED_BUILD_DIR)
	$(CC) $(CPPFLAGS) $(PLATFORM_BEHAVIOR_CPPFLAGS) $(CFLAGS) $(SHARED_CFLAGS) $(I386_CFLAGS) \
		$(I386_FLOAT_FLAGS) -c $< -o $@

$(WINDOWS_I386_BUILD_DIR)/math_%.o: $(MATH_DIR)/src/%.c | $(WINDOWS_I386_BUILD_DIR)
	$(MINGW32_CC) $(CPPFLAGS) -DWINDOWS_BEHAVIOR $(CFLAGS) $(WINDOWS_FLOAT_FLAGS) \
		$(WINDOWS_I386_CFLAGS) -c $< -o $@

$(WINDOWS_I686_BUILD_DIR)/math_%.o: $(MATH_DIR)/src/%.c | $(WINDOWS_I686_BUILD_DIR)
	$(MINGW32_CC) $(CPPFLAGS) -DWINDOWS_BEHAVIOR $(CFLAGS) $(WINDOWS_FLOAT_FLAGS) \
		$(WINDOWS_I686_CFLAGS) -c $< -o $@

$(TARGET): $(OBJS)
	$(AR) rcs $@ $^

$(SHARED_TARGET): $(SHARED_OBJS)
	$(SHARED_LD) $(SHARED_LDFLAGS) -o $@ $^ $(SHARED_LIBS)

$(NATIVE64_TARGET): $(NATIVE64_OBJS)
	$(AR) rcs $@ $^

$(NATIVE64_SHARED_TARGET): $(NATIVE64_SHARED_OBJS)
	$(SHARED_LD) $(SHARED_LDFLAGS) -o $@ $^ $(SHARED_LIBS)

$(I386_SHARED_TARGET): $(I386_SHARED_OBJS)
	$(SHARED_LD) $(I386_LDFLAGS) $(SHARED_LDFLAGS) -o $@ $^ $(SHARED_LIBS)

$(WINDOWS_I386_TARGET): $(WINDOWS_I386_OBJS) $(WINDOWS_MODULE_DEF)
	$(MINGW32_CC) $(WINDOWS_LDFLAGS) $(WINDOWS_I386_CFLAGS) \
		-o $@ $(WINDOWS_I386_OBJS) $(WINDOWS_MODULE_DEF) $(WINDOWS_LIBS)

$(WINDOWS_I686_TARGET): $(WINDOWS_I686_OBJS) $(WINDOWS_MODULE_DEF)
	$(MINGW32_CC) $(WINDOWS_LDFLAGS) $(WINDOWS_I686_CFLAGS) \
		-o $@ $(WINDOWS_I686_OBJS) $(WINDOWS_MODULE_DEF) $(WINDOWS_LIBS)

-include $(DEPS) $(SHARED_DEPS) $(NATIVE64_DEPS) $(NATIVE64_SHARED_DEPS) \
	$(I386_SHARED_DEPS) $(WINDOWS_I386_DEPS) $(WINDOWS_I686_DEPS)
