# opencoreC - Root Unified Makefile
# Target Architecture: x86_64 Long Mode (Microkernel OS)

SHELL := /usr/bin/env bash

# Toolchain definitions
CC      := gcc
CXX     := g++
LD      := ld
CARGO   := cargo
QEMU    := qemu-system-x86_64

# Directory layout
BUILD_DIR   := build
CONFIG_DIR  := config
INCLUDE_DIR := include
LIB_DIR     := lib
HAL_DIR     := hal
SERVERS_DIR := servers
KERNEL_DIR  := kernel
ISO_DIR     := $(BUILD_DIR)/iso_root

# Common Freestanding Flags
COMMON_FLAGS := -Wall -Wextra -O2 -ffreestanding -fno-stack-protector \
                -fno-pie -no-pie -mno-red-zone -m64 \
                -I$(INCLUDE_DIR) -I$(LIB_DIR)/libc/include

CFLAGS   := $(COMMON_FLAGS) -std=c11
CXXFLAGS := $(COMMON_FLAGS) -std=c++20 -fno-exceptions -fno-rtti -I$(LIB_DIR)/libipc_cpp/include

# Outputs
KERNEL_BIN   := target/x86_64-unknown-none/release/opencore_kernel
KERNEL_ELF   := $(BUILD_DIR)/opencore_kernel.elf
INIT_SERVER  := $(BUILD_DIR)/init_server.elf
UART_DRIVER  := $(BUILD_DIR)/uart_driver.elf
SH_SERVER    := $(BUILD_DIR)/sh.elf
PROCMGR      := $(BUILD_DIR)/procmgr.elf

LIBC_OBJS    := $(BUILD_DIR)/string.o $(BUILD_DIR)/syscalls.o $(BUILD_DIR)/stdlib.o

.PHONY: all kernel libc hal servers iso run clean help

all: kernel libc hal servers
	@mkdir -p $(BUILD_DIR)
	@cp $(KERNEL_BIN) $(KERNEL_ELF)
	@echo "======================================================="
	@echo " [SUCCESS] opencoreC Skeleton Build Complete!"
	@echo " Kernel:   $(KERNEL_ELF)"
	@echo " Servers:  $(INIT_SERVER), $(UART_DRIVER), $(SH_SERVER), $(PROCMGR)"
	@echo "======================================================="

kernel:
	@echo "[CARGO] Compiling Rust Microkernel (x86_64-unknown-none)..."
	@RUSTFLAGS="-C link-arg=-T$(CONFIG_DIR)/linker.ld -C code-model=kernel -C relocation-model=static" \
		$(CARGO) build --package opencore_kernel --target x86_64-unknown-none --release

libc:
	@mkdir -p $(BUILD_DIR)
	@echo "[CC] Compiling bare-metal freestanding libc..."
	@$(CC) $(CFLAGS) -c $(LIB_DIR)/libc/src/string.c -o $(BUILD_DIR)/string.o
	@$(CC) $(CFLAGS) -c $(LIB_DIR)/libc/src/syscalls.c -o $(BUILD_DIR)/syscalls.o
	@$(CC) $(CFLAGS) -c $(LIB_DIR)/libc/src/stdlib.c -o $(BUILD_DIR)/stdlib.o

hal: libc
	@mkdir -p $(BUILD_DIR)
	@echo "[CC] Compiling HAL and Hardware Drivers..."
	@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(HAL_DIR)/src/uart.c -o $(BUILD_DIR)/uart.o
	@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(HAL_DIR)/src/pci.c -o $(BUILD_DIR)/pci.o
	@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(HAL_DIR)/src/apic.c -o $(BUILD_DIR)/apic.o

servers: libc hal
	@mkdir -p $(BUILD_DIR)
	@echo "[CXX/CC] Linking Ring 3 User-space Servers..."
	@# C++ LibIPC
	@$(CXX) $(CXXFLAGS) -c $(LIB_DIR)/libipc_cpp/src/ipc.cpp -o $(BUILD_DIR)/ipc.o
	@# Init Root Server
	@$(CXX) $(CXXFLAGS) -c $(SERVERS_DIR)/init/main.cpp -o $(BUILD_DIR)/init_main.o
	@$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(INIT_SERVER) \
		$(BUILD_DIR)/init_main.o $(BUILD_DIR)/ipc.o $(LIBC_OBJS)
	@# Standalone UART Driver Server
	@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(SERVERS_DIR)/uart_driver/main.c -o $(BUILD_DIR)/uart_driver_main.o
	@$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(UART_DRIVER) \
		$(BUILD_DIR)/uart_driver_main.o $(BUILD_DIR)/uart.o $(LIBC_OBJS)
	@# Interactive Shell
	@$(CXX) $(CXXFLAGS) -c $(SERVERS_DIR)/sh/main.cpp -o $(BUILD_DIR)/sh_main.o
	@$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(SH_SERVER) \
		$(BUILD_DIR)/sh_main.o $(BUILD_DIR)/ipc.o $(LIBC_OBJS)
	@# Process Manager Daemon
	@$(CXX) $(CXXFLAGS) -c $(SERVERS_DIR)/procmgr/main.cpp -o $(BUILD_DIR)/procmgr_main.o
	@$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(PROCMGR) \
		$(BUILD_DIR)/procmgr_main.o $(BUILD_DIR)/ipc.o $(LIBC_OBJS)

# Staging Limine Boot ISO directory
iso: all
	@mkdir -p $(ISO_DIR)/boot $(ISO_DIR)/EFI/BOOT
	@cp $(KERNEL_ELF) $(ISO_DIR)/boot/
	@cp $(INIT_SERVER) $(ISO_DIR)/boot/
	@cp $(UART_DRIVER) $(ISO_DIR)/boot/
	@cp $(SH_SERVER) $(ISO_DIR)/boot/
	@cp limine.conf $(ISO_DIR)/boot/limine.conf
	@cp limine.cfg $(ISO_DIR)/boot/limine.cfg
	@echo "[ISO] Staged boot files in $(ISO_DIR)/"

run: all
	@echo "[QEMU] Launching opencoreC in QEMU (SMP 4 Cores, Serial stdio)..."
	@$(QEMU) -M q35 -smp 4 -m 512M \
		-serial stdio \
		-display none \
		-no-reboot \
		-no-shutdown \
		-kernel $(KERNEL_ELF)

clean:
	@echo "[CLEAN] Removing build directory and cargo target..."
	@rm -rf $(BUILD_DIR) target

help:
	@echo "opencoreC Microkernel Build System"
	@echo "Targets:"
	@echo "  make all      - Build kernel, HAL, libc, and all user servers"
	@echo "  make run      - Launch QEMU with SMP 4 Cores & Serial output"
	@echo "  make clean    - Clean build artifacts"
