CC = gcc
CFLAGS = -std=c17 \
  -pedantic \
  -pedantic-errors \
  -Werror \
  -Wall \
  -Wextra \
  -Wshadow \
  -Wstrict-prototypes \
  -Wmissing-prototypes \
  -Wold-style-definition \
  -Wformat=2 \
  -Wcast-qual \
  -Wwrite-strings \
  -Winit-self \
  -Wnull-dereference \
  -Wdouble-promotion \
  -Wconversion \
  -Wsign-conversion \
  -Wsign-compare \
  -Wtype-limits \
  -Wunreachable-code \
  -Wswitch-enum \
  -Wswitch-default \
  -Wundef \
  -Wendif-labels \
  -Wpointer-arith \
  -Wredundant-decls \
  -Wbad-function-cast \
  -Wmissing-noreturn \
  -Wnested-externs \
  -Wlogical-op \
  -Wclobbered \
  -Wfloat-equal \
  -Wrestrict \
  -Wsequence-point \
  -Waddress \
  -Wvla \
  -Wduplicated-cond \
  -Wduplicated-branches \
  -fno-common \
  -ftrapv \
  -fstack-protector-strong

DEBUG_FLAGS = -g3 -O0 -fsanitize=undefined -fno-omit-frame-pointer
RELEASE_FLAGS = -O2 -D NDEBUG
TEST_FLAGS = -g

PROJECT_NAME != basename "$$(pwd)"
VERSION != cat config/version 2>/dev/null
SOURCE_FILES != cat config/source_code_list 2>/dev/null
INCLUDES != cat config/header_list 2>/dev/null

# --- INCREMENTAL BUILD SETUP ---
# Map source files (.c) to object files (.o) in isolated directories
DEBUG_OBJ_FILES = $(patsubst %.c, output/obj_debug/%.o, $(SOURCE_FILES))
RELEASE_OBJ_FILES = $(patsubst %.c, output/obj_release/%.o, $(SOURCE_FILES))

# Map object files to dependency files (.d) generated by the compiler
DEP_FILES = $(DEBUG_OBJ_FILES:.o=.d) $(RELEASE_OBJ_FILES:.o=.d)

help:
	@echo "Please use: 'make init' 'make debug', 'make fast', 'make release', 'make synch', or 'make clean'"

init:
	@mkdir -p output source_code includes config
	@touch config/source_code_list config/version config/header_list source_code/main.c
	@date +_%y.%j.%H.%M%S > config/version
	@echo source_code/main.c > config/source_code_list


synch:
	@echo "Synchronizing source code files..."
	@find source_code -type f -name '*.c' | sort > config/source_code_list
	@echo "Synchronizing header files..."
	@find includes -type f -name '*.h' | sort > config/header_list
	@echo "Synchronization complete."

clean:
	rm -rf output/obj_debug output/obj_release output/$(PROJECT_NAME)*
	@echo "Project Cleaned"

debug: $(DEBUG_OBJ_FILES)
	$(CC) $(CFLAGS) $(DEBUG_FLAGS) -o output/$(PROJECT_NAME)$(VERSION) $(DEBUG_OBJ_FILES)

fast: $(RELEASE_OBJ_FILES)
	$(CC) $(CFLAGS) $(RELEASE_FLAGS) -o output/$(PROJECT_NAME)$(VERSION) $(RELEASE_OBJ_FILES)

release: $(RELEASE_OBJ_FILES)
	@echo "Project version updated from: $(VERSION)"
	@date +_%y.%j.%H.%M%S > config/version
	@echo "To: $$(cat config/version)"
	@echo ""
	$(CC) $(CFLAGS) $(RELEASE_FLAGS) -o output/$(PROJECT_NAME)$$(cat config/version) $(RELEASE_OBJ_FILES)

# --- COMPILATION PATTERN RULES ---
# Compile Debug Objects
output/obj_debug/%.o: %.c
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) $(DEBUG_FLAGS) -I includes -MMD -MP -c $< -o $@

# Compile Release/Fast Objects
output/obj_release/%.o: %.c
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) $(RELEASE_FLAGS) -I includes -MMD -MP -c $< -o $@

# Automatically pull in header dependencies
-include $(DEP_FILES)

.PHONY: help synch clean debug fast release
