# DVX BASIC Makefile for DJGPP cross-compilation
#
# Builds:
#   basrt.lib    -- BASIC runtime library (VM + values + dlregsym init)
#   dvxbasic.app -- BASIC IDE (compiler + UI, links against basrt.lib)
#
# The runtime is a separate library so compiled BASIC apps can use
# it without including the compiler. The library's constructor calls
# dlregsym() to register its exports, making them available to DXEs
# loaded later (apps, widgets, etc.).

DJGPP_PREFIX  = $(HOME)/djgpp/djgpp
CC            = $(DJGPP_PREFIX)/bin/i586-pc-msdosdjgpp-gcc
DXE3GEN       = PATH=$(DJGPP_PREFIX)/bin:$(PATH) DJDIR=$(DJGPP_PREFIX)/i586-pc-msdosdjgpp $(DJGPP_PREFIX)/i586-pc-msdosdjgpp/bin/dxe3gen
CFLAGS        = -O2 -Wall -Wextra -Wno-type-limits -Wno-sign-compare -march=i486 -mtune=i586 -I../../core -I../../core/platform -I../../widgets -I../../shell -I../../tasks -I../../core/thirdparty -I.

OBJDIR  = ../../obj/dvxbasic
LIBSDIR = ../../bin/libs
APPDIR  = ../../bin/apps/dvxbasic
DVXRES  = ../../bin/dvxres
SAMPLES = samples/hello.bas samples/formtest.bas samples/clickme.bas samples/clickme.frm samples/input.bas

# Runtime library objects (VM + values)
RT_OBJS = $(OBJDIR)/vm.o $(OBJDIR)/values.o
RT_TARGET = $(LIBSDIR)/basrt.lib

# Compiler objects (only needed by the IDE)
COMP_OBJS = $(OBJDIR)/lexer.o $(OBJDIR)/parser.o $(OBJDIR)/codegen.o $(OBJDIR)/symtab.o

# Form runtime objects (bridge between BASIC and DVX widgets)
FORMRT_OBJS = $(OBJDIR)/formrt.o

# IDE app objects
IDE_OBJS = $(OBJDIR)/ideMain.o $(OBJDIR)/ideDesigner.o $(OBJDIR)/ideMenuEditor.o $(OBJDIR)/ideProject.o $(OBJDIR)/ideToolbox.o $(OBJDIR)/ideProperties.o
APP_OBJS = $(IDE_OBJS) $(FORMRT_OBJS)
APP_TARGET = $(APPDIR)/dvxbasic.app

# Native test programs (host gcc, not cross-compiled)
HOSTCC     = gcc
HOSTCFLAGS = -O2 -Wall -Wextra -Wno-type-limits -Wno-sign-compare -I. -I../../core
BINDIR     = ../../bin

TEST_COMPILER = $(BINDIR)/test_compiler
TEST_VM       = $(BINDIR)/test_vm
TEST_LEX      = $(BINDIR)/test_lex
TEST_QUICK    = $(BINDIR)/test_quick

STB_DS_IMPL        = ../../core/thirdparty/stb_ds_impl.c
TEST_COMPILER_SRCS = test_compiler.c compiler/lexer.c compiler/parser.c compiler/codegen.c compiler/symtab.c runtime/vm.c runtime/values.c $(STB_DS_IMPL)
TEST_VM_SRCS       = test_vm.c runtime/vm.c runtime/values.c $(STB_DS_IMPL)
TEST_LEX_SRCS      = test_lex.c compiler/lexer.c
TEST_QUICK_SRCS    = test_quick.c compiler/lexer.c compiler/parser.c compiler/codegen.c compiler/symtab.c runtime/vm.c runtime/values.c $(STB_DS_IMPL)

.PHONY: all clean tests

all: $(RT_TARGET) $(LIBSDIR)/basrt.dep $(APP_TARGET) install-samples

tests: $(TEST_COMPILER) $(TEST_VM) $(TEST_LEX) $(TEST_QUICK)

$(TEST_COMPILER): $(TEST_COMPILER_SRCS) | $(BINDIR)
	$(HOSTCC) $(HOSTCFLAGS) -o $@ $(TEST_COMPILER_SRCS) -lm

$(TEST_VM): $(TEST_VM_SRCS) | $(BINDIR)
	$(HOSTCC) $(HOSTCFLAGS) -o $@ $(TEST_VM_SRCS) -lm

$(TEST_LEX): $(TEST_LEX_SRCS) | $(BINDIR)
	$(HOSTCC) $(HOSTCFLAGS) -w -o $@ $(TEST_LEX_SRCS) -lm

$(TEST_QUICK): $(TEST_QUICK_SRCS) | $(BINDIR)
	$(HOSTCC) $(HOSTCFLAGS) -o $@ $(TEST_QUICK_SRCS) -lm

# Runtime library DXE (exports symbols via dlregsym constructor)
$(RT_TARGET): $(RT_OBJS) | $(LIBSDIR)
	$(DXE3GEN) -o $(LIBSDIR)/basrt.dxe \
		-E _bas -E _BAS \
		-U $(RT_OBJS)
	mv $(LIBSDIR)/basrt.dxe $@

$(LIBSDIR)/basrt.dep: ../../config/basrt.dep | $(LIBSDIR)
	sed 's/$$/\r/' $< > $@

# IDE app DXE (compiler linked in, runtime from basrt.lib)
$(APP_TARGET): $(COMP_OBJS) $(APP_OBJS) dvxbasic.res | $(APPDIR)
	$(DXE3GEN) -o $@ -E _appDescriptor -E _appMain -U $(COMP_OBJS) $(APP_OBJS)
	$(DVXRES) build $@ dvxbasic.res

install-samples: $(SAMPLES) | $(APPDIR)
	cp $(SAMPLES) $(APPDIR)/

# Object files
$(OBJDIR)/codegen.o: compiler/codegen.c compiler/codegen.h compiler/symtab.h compiler/opcodes.h runtime/values.h | $(OBJDIR)
	$(CC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/formrt.o: formrt/formrt.c formrt/formrt.h compiler/codegen.h runtime/vm.h | $(OBJDIR)
	$(CC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/ideDesigner.o: ide/ideDesigner.c ide/ideDesigner.h | $(OBJDIR)
	$(CC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/ideMenuEditor.o: ide/ideMenuEditor.c ide/ideMenuEditor.h ide/ideDesigner.h | $(OBJDIR)
	$(CC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/ideMain.o: ide/ideMain.c ide/ideDesigner.h ide/ideMenuEditor.h ide/ideProject.h ide/ideToolbox.h ide/ideProperties.h compiler/parser.h runtime/vm.h | $(OBJDIR)
	$(CC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/ideProject.o: ide/ideProject.c ide/ideProject.h | $(OBJDIR)
	$(CC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/ideProperties.o: ide/ideProperties.c ide/ideProperties.h ide/ideDesigner.h | $(OBJDIR)
	$(CC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/ideToolbox.o: ide/ideToolbox.c ide/ideToolbox.h ide/ideDesigner.h | $(OBJDIR)
	$(CC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/lexer.o: compiler/lexer.c compiler/lexer.h | $(OBJDIR)
	$(CC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/parser.o: compiler/parser.c compiler/parser.h compiler/lexer.h compiler/codegen.h compiler/symtab.h compiler/opcodes.h | $(OBJDIR)
	$(CC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/symtab.o: compiler/symtab.c compiler/symtab.h compiler/opcodes.h | $(OBJDIR)
	$(CC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/values.o: runtime/values.c runtime/values.h compiler/opcodes.h | $(OBJDIR)
	$(CC) $(CFLAGS) -c -o $@ $<

$(OBJDIR)/vm.o: runtime/vm.c runtime/vm.h runtime/values.h compiler/opcodes.h | $(OBJDIR)
	$(CC) $(CFLAGS) -c -o $@ $<

# Directories
$(OBJDIR):
	mkdir -p $(OBJDIR)

$(LIBSDIR):
	mkdir -p $(LIBSDIR)

$(APPDIR):
	mkdir -p $(APPDIR)

$(BINDIR):
	mkdir -p $(BINDIR)

clean:
	rm -f $(RT_OBJS) $(COMP_OBJS) $(FORMRT_OBJS) $(IDE_OBJS) $(RT_TARGET) $(APP_TARGET) $(LIBSDIR)/basrt.dep $(OBJDIR)/basrt_init.o
	rm -f $(TEST_COMPILER) $(TEST_VM) $(TEST_LEX) $(TEST_QUICK)
