SOURCEDIR := $(abspath $(patsubst %/,%,$(dir $(abspath $(lastword \
	$(MAKEFILE_LIST))))))

CC ?= cc
CXX ?= c++
CFLAGS ?= -O2
CXXFLAGS ?= -O2
FLAGS := -std=c++17
FLAGS_C := -std=c99
DEFS := -DMELONDS_VERSION=\"0.9.5\"

PKG_CONFIG ?= pkg-config
CFLAGS_JG := $(shell $(PKG_CONFIG) --cflags jg)

WARNINGS_SAMPLERATE := -Wall -Wextra -Wshadow -Wmissing-prototypes -pedantic

# Only relative include paths are used in melonDS
INCLUDES_JG := -I$(SOURCEDIR)/../src

# Only used by the vendored teakra
CFLAGS_TEAKRA := -I$(SOURCEDIR)/../src/teakra/include

LIBS := -lm -lstdc++
PIC := -fPIC
SHARED := $(PIC)

NAME := melonds
PREFIX ?= /usr/local
LIBDIR ?= $(PREFIX)/lib
DATAROOTDIR ?= $(PREFIX)/share
DOCDIR ?= $(DATAROOTDIR)/doc/$(NAME)

USE_VENDORED_SAMPLERATE ?= 0

UNAME := $(shell uname -s)
ifeq ($(UNAME), Darwin)
	SHARED += -dynamiclib
	TARGET := $(NAME).dylib
else ifeq ($(OS), Windows_NT)
	SHARED += -shared
	TARGET := $(NAME).dll
else
	SHARED += -shared
	TARGET := $(NAME).so
endif

ifeq ($(UNAME), Linux)
	LIBS += -Wl,--no-undefined
endif

# Core
CSRCS := src/fatfs/diskio.c \
	src/fatfs/ff.c \
	src/fatfs/ffsystem.c \
	src/fatfs/ffunicode.c \
	src/sha1/sha1.c \
	src/tiny-AES-c/aes.c \
	src/xxhash/xxhash.c

CXXSRCS := src/teakra/src/ahbm.cpp \
	src/teakra/src/apbp.cpp \
	src/teakra/src/btdmp.cpp \
	src/teakra/src/disassembler.cpp \
	src/teakra/src/disassembler_c.cpp \
	src/teakra/src/dma.cpp \
	src/teakra/src/memory_interface.cpp \
	src/teakra/src/mmio.cpp \
	src/teakra/src/parser.cpp \
	src/teakra/src/processor.cpp \
	src/teakra/src/teakra.cpp \
	src/teakra/src/test_generator.cpp \
	src/teakra/src/timer.cpp \
	src/ARCodeFile.cpp \
	src/AREngine.cpp \
	src/ARM.cpp \
	src/ARMInterpreter.cpp \
	src/ARMInterpreter_ALU.cpp \
	src/ARMInterpreter_Branch.cpp \
	src/ARMInterpreter_LoadStore.cpp \
	src/CP15.cpp \
	src/CRC32.cpp \
	src/DMA.cpp \
	src/DSi.cpp \
	src/DSi_AES.cpp \
	src/DSi_Camera.cpp \
	src/DSi_DSP.cpp \
	src/DSi_I2C.cpp \
	src/DSi_NAND.cpp \
	src/DSi_NDMA.cpp \
	src/DSi_NWifi.cpp \
	src/DSi_SD.cpp \
	src/DSi_SPI_TSC.cpp \
	src/FATStorage.cpp \
	src/GBACart.cpp \
	src/GPU.cpp \
	src/GPU2D.cpp \
	src/GPU2D_Soft.cpp \
	src/GPU3D.cpp \
	src/GPU3D_Soft.cpp \
	src/NDS.cpp \
	src/NDSCart.cpp \
	src/RTC.cpp \
	src/SPI.cpp \
	src/SPU.cpp \
	src/Savestate.cpp \
	src/Wifi.cpp \
	src/WifiAP.cpp \
	jg.cpp

#	src/ARM_InstrInfo.cpp \

ifneq ($(USE_VENDORED_SAMPLERATE), 0)
	Q_SAMPLERATE :=
	CFLAGS_SAMPLERATE := -I$(SOURCEDIR)/deps/libsamplerate
	LIBS_SAMPLERATE :=
	CSRCS += deps/libsamplerate/samplerate.c \
		deps/libsamplerate/src_linear.c \
		deps/libsamplerate/src_sinc.c \
		deps/libsamplerate/src_zoh.c
else
	Q_SAMPLERATE := @
	CFLAGS_SAMPLERATE := $(shell $(PKG_CONFIG) --cflags samplerate)
	LIBS_SAMPLERATE := $(shell $(PKG_CONFIG) --libs samplerate)
endif

INCLUDES_JG += $(CFLAGS_SAMPLERATE)
LIBS += $(LIBS_SAMPLERATE)

# Object dirs
MKDIRS := deps/libsamplerate \
	src/teakra/src \
	src/fatfs \
	src/sha1 \
	src/tiny-AES-c \
	src/xxhash

OBJDIR := objs

# List of object files
OBJS := $(patsubst %,$(OBJDIR)/%,$(CSRCS:.c=.o) $(CXXSRCS:.cpp=.o))

# Compiler command
COMPILE = $(strip $(1) $(CPPFLAGS) $(PIC) $(2) -c $< -o $@)
COMPILE_C = $(call COMPILE, $(CC) $(CFLAGS), $(1))
COMPILE_CXX = $(call COMPILE, $(CXX) $(CXXFLAGS), $(1))

# Info command
COMPILE_INFO = $(info $(subst $(SOURCEDIR)/,,$(1)))

# Dependency commands
BUILD_C = $(call COMPILE_C, $(FLAGS_C))
BUILD_SAMPLERATE = $(call COMPILE_C, $(FLAGS_C) $(WARNINGS_SAMPLERATE))
BUILD_TEAKRA = $(call COMPILE_CXX, $(FLAGS) $(CFLAGS_TEAKRA))

# Core commands
BUILD_JG = $(call COMPILE_CXX, $(FLAGS) $(DEFS) $(INCLUDES_JG) $(CFLAGS_JG))
BUILD_MAIN = $(call COMPILE_CXX, $(FLAGS) $(DEFS))

.PHONY: all clean install install-strip uninstall

all: $(NAME)/$(TARGET)

# Dep rules
$(OBJDIR)/src/%.o: $(SOURCEDIR)/../src/%.c $(OBJDIR)/.tag
	$(call COMPILE_INFO, $(BUILD_C))
	@$(BUILD_C)

$(OBJDIR)/src/teakra/%.o: $(SOURCEDIR)/../src/teakra/%.cpp $(OBJDIR)/.tag
	$(call COMPILE_INFO, $(BUILD_TEAKRA))
	@$(BUILD_TEAKRA)

# libsamplerate rules
$(OBJDIR)/deps/libsamplerate/%.o: $(SOURCEDIR)/deps/libsamplerate/%.c $(OBJDIR)/.tag
	$(call COMPILE_INFO, $(BUILD_SAMPLERATE))
	@$(BUILD_SAMPLERATE)

# Core rules
$(OBJDIR)/src/%.o: $(SOURCEDIR)/../src/%.cpp $(OBJDIR)/.tag
	$(call COMPILE_INFO, $(BUILD_MAIN))
	@$(BUILD_MAIN)

# Shim rules
$(OBJDIR)/%.o: $(SOURCEDIR)/%.cpp $(OBJDIR)/.tag
	$(call COMPILE_INFO, $(BUILD_JG))
	@$(BUILD_JG)

$(OBJDIR)/.tag:
	@mkdir -p -- $(patsubst %,$(OBJDIR)/%,$(MKDIRS))
	@touch $@

$(NAME)/$(TARGET): $(OBJS)
	@mkdir -p $(NAME)
	$(CXX) $^ $(LDFLAGS) $(LIBS) $(SHARED) -o $@

clean:
	rm -rf $(OBJDIR) $(NAME)

install: all
	@mkdir -p $(DESTDIR)$(DOCDIR)
	@mkdir -p $(DESTDIR)$(LIBDIR)/jollygood
	cp $(NAME)/$(TARGET) $(DESTDIR)$(LIBDIR)/jollygood/
	cp $(SOURCEDIR)/README $(DESTDIR)$(DOCDIR)
	cp $(SOURCEDIR)/../LICENSE $(DESTDIR)$(DOCDIR)
	$(Q_SAMPLERATE)if test $(USE_VENDORED_SAMPLERATE) != 0; then \
		cp $(SOURCEDIR)/deps/libsamplerate/COPYING \
			$(DESTDIR)$(DOCDIR)/COPYING-libsamplerate; \
	fi

install-strip: install
	strip $(DESTDIR)$(LIBDIR)/jollygood/$(TARGET)

uninstall:
	rm -rf $(DESTDIR)$(DOCDIR)
	rm -f $(DESTDIR)$(LIBDIR)/jollygood/$(TARGET)
