# Project Name
#TARGET = elilong.efi
#INSTALLER_SRC = elilongsetup
VERSION = $(shell cat VERSION)
SBINDIR = /usr/sbin
STAGEDIR = /usr/share/elilong
MANDIR = /usr/man

#handle auto architecture detection
ifeq ($(ARCH),)
    UNAME_M := $(shell uname -m)
    ifeq ($(UNAME_M),x86_64)
        EFI_ARCH = x86_64
    else ifeq ($(patsubst i%86,i386,$(UNAME_M)),i386)
        EFI_ARCH = ia32
    else ifeq ($(UNAME_M),arm)
        EFI_ARCH = arm
    else
        EFI_ARCH = $(UNAME_M)
    endif
else
    # Maps Slackware native arch input flags down to standard gnu-efi names
    ifeq ($(ARCH),i586)
        EFI_ARCH = ia32
    else ifeq ($(ARCH),i686)
        EFI_ARCH = ia32
    else
        EFI_ARCH = $(ARCH)
    endif
endif

ifeq ($(EFI_ARCH),x86_64)
    TARGET          = elilongx64.efi
    OBJCOPY_FORMAT  = efi-app-x86_64
    FORMAT_LDS      = elf_x86_64_efi.lds
    CRT_OBJ         = crt0-efi-x86_64.o
    ARCH_CFLAGS     = -mno-red-zone -maccumulate-outgoing-args
else ifeq ($(EFI_ARCH),ia32)
    TARGET          = elilongia32.efi
    OBJCOPY_FORMAT  = efi-app-ia32
    FORMAT_LDS      = elf_ia32_efi.lds
    CRT_OBJ         = crt0-efi-ia32.o
    ARCH_CFLAGS     = -m32
else ifeq ($(EFI_ARCH),aarch64)
    TARGET          = elilongaa64.efi
    OBJCOPY_FORMAT  = efi-app-aarch64
    FORMAT_LDS      = elf_aarch64_efi.lds
    CRT_OBJ         = crt0-efi-aarch64.o
    ARCH_CFLAGS     =
else ifeq ($(EFI_ARCH),arm)
    TARGET          = elilongarm.efi
    OBJCOPY_FORMAT  = efi-app-arm
    FORMAT_LDS      = elf_arm_efi.lds
    CRT_OBJ         = crt0-efi-arm.o
    ARCH_CFLAGS     =
else ifeq ($(EFI_ARCH),riscv64)
    TARGET          = elilongrv64.efi
    OBJCOPY_FORMAT  = efi-app-riscv64
    FORMAT_LDS      = elf_riscv64_efi.lds
    CRT_OBJ         = crt0-efi-riscv64.o
    ARCH_CFLAGS     =
else ifeq ($(EFI_ARCH),riscv32)
    TARGET          = elilongrv32.efi
    OBJCOPY_FORMAT  = efi-app-riscv32
    FORMAT_LDS      = elf_riscv32_efi.lds
    CRT_OBJ         = crt0-efi-riscv32.o
    ARCH_CFLAGS     =
else
    $(error Unsupported native platform architecture configuration: $(EFI_ARCH))
endif

#detect distro
ifeq ($(shell [ -f /etc/slackware-version ] && echo 1),1)
    DISTRO    = Slackware
    SUBDIR    = Slackware
    DEF_MNT   = /boot/efi
else ifeq ($(shell [ -f /etc/arch-release ] && echo 1),1)
    DISTRO    = Arch
    SUBDIR    = arch
    DEF_MNT   = /boot
else
    DISTRO    = Generic
    SUBDIR    = elilong
    DEF_MNT   = /boot/efi
endif

#there should be a default message file for each detected distro
MSG_FILE := msgfiles/$(DISTRO).msg
ifeq ($(wildcard $(MSG_FILE)),)
    MSG_FILE := msgfiles/Generic.msg
endif

DATE := $(shell date +'%Y-%m-%d')

ifeq ($(shell pkg-config --exists gnu-efi && echo 0),0)
    EFIINC          = $(shell pkg-config --variable=includedir gnu-efi)
    EFILIB          = $(shell pkg-config --variable=libdir gnu-efi)
    CFLAGS_PKG      = $(shell pkg-config --cflags gnu-efi)
else
    EFIINC          = /usr/include/efi
    EFILIB          = /usr/lib$(LIBDIRSUFFIX)
    CFLAGS_PKG      =
endif
EFI_LDS      := $(shell find $(EFILIB) -name $(FORMAT_LDS) 2>/dev/null | head -n 1)
EFI_CRT_OBJS := $(shell find $(EFILIB) -name $(CRT_OBJ) 2>/dev/null | head -n 1)

ifeq ($(EFI_LDS),)
    EFI_LDS := $(EFILIB)/gnuefi/$(FORMAT_LDS)
endif
ifeq ($(EFI_CRT_OBJS),)
    EFI_CRT_OBJS := $(EFILIB)/gnuefi/$(CRT_OBJ)
endif

CC              = gcc
LD              = ld
OBJCOPY         = objcopy

DEFS            = -DGNU_EFI_USE_MS_ABI \
                  -DVERSION='"$(VERSION)"' \
                  -DDISTRO='L"$(DISTRO)"' \
                  -DSUBDIR='L"$(SUBDIR)"'

# Compile Flags
CFLAGS          = -I. -Isrc -I$(EFIINC) -I$(EFIINC)/$(EFI_ARCH) -I$(EFIINC)/protocol \
                  -fpic -ffreestanding -fno-stack-protector -fno-stack-check \
                  -fshort-wchar -Wall $(ARCH_CFLAGS) $(CFLAGS_PKG) $(DEFS)

# Linker Flags
LDFLAGS         = -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic \
                  -L$(EFILIB) --entry=_start --stats
LIBS            = -lefi -lgnuefi
OBJS            = src/main.o src/loader.o src/config.o


all: $(TARGET) elilongsetup elilong.8

src/%.o: src/%.c
	$(CC) $(CFLAGS) -c $< -o $@

elilong.so: $(OBJS)
	$(LD) $(LDFLAGS) $(EFI_CRT_OBJS) $(OBJS) -o $@ $(LIBS)

$(TARGET): elilong.so
	$(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym \
	           -j .rel -j .rela -j .reloc -j .rodata -j .rdata --target=$(OBJCOPY_FORMAT) $< $@

# inject relevant content into elilongsetup
elilongsetup: src/elilongsetup $(MSG_FILE)
	@echo "Injecting $(DISTRO) message box and parameters into elilongsetup..."
	@sed -e '/@@DISTMESS@@/r $(MSG_FILE)' -e '/@@DISTMESS@@/d' \
	     -e "s/@@VERSION@@/$(VERSION)/g" \
	     -e "s|@@SUBDIR@@|$(SUBDIR)|g" \
	     -e "s|@@DISTRO@@|$(DISTRO)|g" \
	     -e "s|@@STAGEDIR@@|$(STAGEDIR)|g" \
	     -e "s|@@DEF_MNT@@|$(DEF_MNT)|g" src/elilongsetup > elilongsetup
	@chmod 755 elilongsetup

# inject relevant content into man page
elilong.8: src/elilong.8
	@echo "Generating man page for $(DISTRO) (v$(VERSION))..."
	@sed -e "s/@@VERSION@@/$(VERSION)/g" \
	     -e "s|@@SUBDIR@@|$(SUBDIR)|g" \
	     -e "s|@@DISTRO@@|$(DISTRO)|g" \
	     -e "s|@@DEF_MNT@@|$(DEF_MNT)|g" \
	     -e "s|@@STAGEDIR@@|$(STAGEDIR)|g" \
	     -e "s|@@SBINDIR@@|$(SBINDIR)|g" \
	     -e "s|@@DATE@@|$(DATE)|g" src/elilong.8 > elilong.8


install: all
	# Create directories using DESTDIR if provided
	install -d $(DESTDIR)$(SBINDIR)
	install -d $(DESTDIR)$(STAGEDIR)
	install -d $(DESTDIR)$(MANDIR)/man8

	# Install the EFI binary to staging directory ready to be "installed" by elilongsetup
	install -m 644 $(TARGET) $(DESTDIR)$(STAGEDIR)/elilong.efi
	install -m 755 elilongsetup $(DESTDIR)$(SBINDIR)/elilongsetup
	gzip -9c elilong.8 > $(DESTDIR)$(MANDIR)/man8/elilong.8.gz

clean:
	rm -f src/*.o *.so elilong*.efi elilongsetup elilong.8

.PHONY: all clean install

