PROJECT_ROOT := $(abspath ../..)
override TOOLCHAIN_DIR := $(PROJECT_ROOT)/toolchain
override CROSS := $(TOOLCHAIN_DIR)/cross/bin/ia16-elf-
BUILD ?= $(PROJECT_ROOT)/build/userland/libc
USERLAND_MEMMODEL ?= small

IA16_MEMMODELS := tiny small medium compact large huge
ifeq ($(filter $(USERLAND_MEMMODEL),$(IA16_MEMMODELS)),)
$(error unsupported USERLAND_MEMMODEL=$(USERLAND_MEMMODEL); use tiny, small, medium, compact, large, or huge)
endif

CC := $(CROSS)gcc
AR := $(CROSS)ar
GCC_INCLUDE_DIR := $(shell $(CC) -print-file-name=include)

CPPFLAGS := -I$(CURDIR)/include -I. -I$(PROJECT_ROOT)/kern
# libc consumes a few stable cross-boundary server ABI headers (e.g.
# <storage/core/block_abi.h>, <nativesys/service/system_native_abi.h>).  Add the
# service root so they resolve by their short name, matching every other build
# unit (the kernel build and the userland base both carry this root).
CPPFLAGS += -I$(PROJECT_ROOT)/kern/system/service
CPPFLAGS += -I$(PROJECT_ROOT)
CPPFLAGS += -nostdinc -isystem $(GCC_INCLUDE_DIR)
CPPFLAGS += -D__LIBC__ -D__HAS_NO_FLOATS__ -D__HAS_NO_LONGLONG__
CFLAGS := $(CPPFLAGS) -std=gnu99 -Os -Wall -Wextra
CFLAGS += -DANTLER_USERLAND_16BIT_ONLY=1 -D__HAS_NO_LONGLONG__ -Dlong=short
CFLAGS += -Wno-unused-parameter -Wno-sign-compare -Wno-old-style-definition
CFLAGS += -ffreestanding -fno-builtin -fno-pic -fno-stack-protector
CFLAGS += -fno-jump-tables -ffunction-sections -fdata-sections
CFLAGS += -march=i8086 -mtune=i8086 -mno-protected-mode
CFLAGS += -mcmodel=$(USERLAND_MEMMODEL) -msegelf
ifneq ($(filter $(USERLAND_MEMMODEL),tiny small),)
CFLAGS += -mno-segment-relocation-stuff
endif

LIBC := $(BUILD)/libc.a
ARCH_HEADERS := $(wildcard $(PROJECT_ROOT)/arch/i8086/*.h)

LIBC_C_DIRS := ctype error getent malloc misc regex stdio string termcap termios time
LIBC_C_SRCS := $(shell find $(LIBC_C_DIRS) -name '*.c' | sort)
LIBC_C_SRCS := $(filter-out \
	malloc/brk.c \
	malloc/sbrk.c \
	misc/hexdump.c \
	misc/lltostr.c \
	misc/qsort-bsd.c \
	misc/qsort-gnu.c \
	misc/ulltostr.c, \
	$(LIBC_C_SRCS))
LIBC_C_SRCS += syscalls.c
LIBC_C_SRCS += \
	system/abort.c \
	system/closedir.c \
	system/execl.c \
	system/execvp.c \
	system/execvpe.c \
	system/opendir.c \
	system/readdir.c \
	system/rewinddir.c \
	system/seekdir.c \
	system/sigaction.c \
	system/signal.c \
	system/sleep.c \
	system/telldir.c \
	system/usleep.c
LIBC_ASM_SRCS := \
	asm/divmod.S \
	asm/memcpy-s.S \
	asm/memset-s.S \
	asm/strcpy-s.S \
	asm/strlen-s.S \
	misc/antler_login_far.S \
	system/setjmp.S \
	system/signalcb.S
CRT0 := $(BUILD)/crt0.o
LIBC_OBJS := $(patsubst %.c,$(BUILD)/%.o,$(LIBC_C_SRCS))
LIBC_OBJS += $(patsubst %.S,$(BUILD)/%.o,$(LIBC_ASM_SRCS))

.PHONY: all clean check-toolchain

all: $(LIBC) $(CRT0)

check-toolchain:
	@if ! command -v "$(CC)" >/dev/null 2>&1; then \
		echo "missing IA-16 compiler: $(CC)" >&2; \
		exit 1; \
	fi
	@if ! command -v "$(AR)" >/dev/null 2>&1; then \
		echo "missing IA-16 archiver: $(AR)" >&2; \
		exit 1; \
	fi

$(BUILD)/%.o: %.c Makefile $(ARCH_HEADERS) | check-toolchain
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD)/%.o: %.S Makefile $(ARCH_HEADERS) | check-toolchain
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) -c $< -o $@

$(LIBC): $(LIBC_OBJS)
	@mkdir -p $(dir $@)
	rm -f $@
	$(AR) rcs $@ $(LIBC_OBJS)

clean:
	rm -rf $(BUILD)
