# KHY OS Kernel Makefile

# Toolchain
ASM      = nasm
CC       = gcc
LD       = ld

# Directories
BOOT_DIR = boot
SRC_DIR  = src
BUILD    = build
MOONBIT_DIR = moonbit

# Detect GCC version for -isystem path
GCC_VER := $(shell $(CC) -dumpversion)

# Compiler flags — freestanding x86_64 kernel
CFLAGS   = -ffreestanding -nostdlib -nostdinc -fno-builtin \
           -fno-stack-protector -mno-red-zone -mcmodel=kernel \
           -fno-pic -fno-pie \
           -Wall -Wextra -O2 -g \
           -isystem /usr/lib/gcc/x86_64-linux-gnu/$(GCC_VER)/include

# MoonBit generated C flags — same as kernel but with MOONBIT_NATIVE_NO_SYS_HEADER
MOONBIT_CFLAGS = $(CFLAGS) -DMOONBIT_NATIVE_NO_SYS_HEADER -Wno-unused-function -Wno-unused-variable

ASMFLAGS = -f elf64
LDFLAGS  = -n -T linker.ld -nostdlib

# Source files
ASM_SRC  = $(BOOT_DIR)/boot.asm $(BOOT_DIR)/long_mode.asm $(BOOT_DIR)/isr.asm $(BOOT_DIR)/context_switch.asm $(BOOT_DIR)/usermode.asm
C_SRC    = $(wildcard $(SRC_DIR)/*.c)

# MoonBit paths
MOONBIT_INCLUDE = $(HOME)/.moon/include
MOONBIT_RUNTIME = $(HOME)/.moon/lib/runtime.c
MOONBIT_GEN_DIR = $(MOONBIT_DIR)/_build/native/debug/build/lib/khy_kernel
MOONBIT_GEN_C   = $(BUILD)/moonbit_gen.c

# Object files
ASM_OBJ  = $(patsubst $(BOOT_DIR)/%.asm,$(BUILD)/%.o,$(ASM_SRC))
C_OBJ    = $(patsubst $(SRC_DIR)/%.c,$(BUILD)/%.o,$(C_SRC))
MOONBIT_OBJ = $(BUILD)/moonbit_gen.o $(BUILD)/moonbit_runtime.o
ALL_OBJ  = $(ASM_OBJ) $(C_OBJ) $(MOONBIT_OBJ)

# Output (kernel ISO is named -kernel to distinguish from the Alpine-based dist ISO)
KERNEL   = $(BUILD)/khy-os.bin
ISO      = $(BUILD)/khy-os-kernel.iso

# Default target
.PHONY: all clean run run-serial iso moonbit-build

all: $(ISO)

# Step 1: Build MoonBit project to generate .c file
moonbit-build:
	@echo "[MOONBIT] Building MoonBit module..."
	cd $(MOONBIT_DIR) && moon build --target native 2>&1 | grep -v "Cannot find TCC"
	@echo "[MOONBIT] Patching generated C: rename main() -> moonbit_entry()"
	@sed 's/^int main(int argc, char\*\* argv)/int moonbit_entry(int argc, char** argv)/' \
		$(MOONBIT_GEN_DIR)/khy_kernel.c > $(MOONBIT_GEN_C)
	@echo "[MOONBIT] Generated C ready: $(MOONBIT_GEN_C)"

# Step 2: Compile MoonBit generated C
$(BUILD)/moonbit_gen.o: moonbit-build | $(BUILD)
	$(CC) $(MOONBIT_CFLAGS) -I$(MOONBIT_INCLUDE) -I$(SRC_DIR) -c $(MOONBIT_GEN_C) -o $@

# Step 3: Compile MoonBit runtime
$(BUILD)/moonbit_runtime.o: $(MOONBIT_RUNTIME) | $(BUILD)
	$(CC) $(MOONBIT_CFLAGS) -I$(MOONBIT_INCLUDE) -I$(SRC_DIR) -c $< -o $@

# Assemble .asm files
$(BUILD)/%.o: $(BOOT_DIR)/%.asm | $(BUILD)
	$(ASM) $(ASMFLAGS) $< -o $@

# Compile .c files
$(BUILD)/%.o: $(SRC_DIR)/%.c | $(BUILD)
	$(CC) $(CFLAGS) -c $< -o $@

# Link kernel binary
$(KERNEL): $(ALL_OBJ)
	$(LD) $(LDFLAGS) -o $@ $^

# Build ISO with GRUB
$(ISO): $(KERNEL)
	@mkdir -p $(BUILD)/isofiles/boot/grub
	cp $(KERNEL) $(BUILD)/isofiles/boot/khy-os.bin
	cp iso/boot/grub/grub.cfg $(BUILD)/isofiles/boot/grub/grub.cfg
	grub-mkrescue -o $(ISO) $(BUILD)/isofiles 2>/dev/null

# Create build directory
$(BUILD):
	mkdir -p $(BUILD)

# Run in QEMU with serial output to terminal
run: $(ISO)
	qemu-system-x86_64 -cdrom $(ISO) -serial stdio -display none -no-reboot

# Run in QEMU with VGA display
run-vga: $(ISO)
	qemu-system-x86_64 -cdrom $(ISO) -serial stdio

# Run with both serial and monitor
run-debug: $(ISO)
	qemu-system-x86_64 -cdrom $(ISO) -serial stdio -monitor telnet:127.0.0.1:1234,server,nowait -d int -no-reboot

# Build ISO only
iso: $(ISO)

# Clean build artifacts (including MoonBit build)
clean:
	rm -rf $(BUILD)
	cd $(MOONBIT_DIR) && moon clean 2>/dev/null || true
