# The MIT License (MIT) # # Copyright (C) 2026 Scott Duensing # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # DVX BASIC Makefile # # Builds: # basrt.lib -- BASIC runtime library (VM + values + form # runtime + dlregsym init) # dvxbasic.app -- BASIC IDE (compiler + UI, links against # basrt.lib, standalone stub embedded) # basstub.app -- standalone app stub (obj/dvxbasic, embedded # into the IDE and bascomp) # bin/system/BASCOMP.EXE-- DOS command-line compiler # bin/host/bascomp -- host command-line compiler # bin/host/basrun -- host headless runner # test_compiler, test_compact, test_suite -- host test harnesses # ("make tests" builds and runs them) # obj/host/basrt.a -- host compiler + runtime + form runtime for the # src/test/formrt suite ("make host-basrt") # # 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.). include ../../../common.mk LIBDVX = ../../../libs/kpunch/libdvx TOOLSDIR = ../../../tools DVX_INCLUDES = -I$(LIBDVX) -I$(LIBDVX)/platform -I$(LIBDVX)/thirdparty -I. CFLAGS = $(DOS_CFLAGS) $(DVX_INCLUDES) -I../../../widgets/kpunch -I../../../libs/kpunch/dvxshell -I../../../libs/kpunch/libtasks OBJDIR = ../../../../obj/dvxbasic LIBSDIR = ../../../../bin/libs APPDIR = ../../../../bin/apps/kpunch/dvxbasic HOSTDIR = ../../../../bin/host DVXRES = $(HOSTDIR)/dvxres SYSTEMDIR = ../../../../bin/system # Sources every command-line build (bascomp, basrun, test_suite) links: # the build pipeline, the full compiler and the runtime without forms. COMP_SRCS = compiler/lexer.c compiler/parser.c compiler/codegen.c compiler/symtab.c compiler/strip.c compiler/obfuscate.c compiler/compact.c VM_SRCS = runtime/vm.c runtime/values.c runtime/serialize.c # Standalone programs that link the VM also need what libdvx provides it # at run time on the target (INI access through dvxPrefs). VM_LINK_SRCS = $(VM_SRCS) $(LIBDVX)/dvxPrefs.c SUPPORT_SRCS = $(LIBDVX)/platform/dvxPlatformUtil.c $(LIBDVX)/thirdparty/stb_ds_impl.c RES_SRCS = $(LIBDVX)/dvxResource.c $(TOOLSDIR)/dvxResWrite.c CLI_SRCS = basBuild.c $(COMP_SRCS) $(VM_LINK_SRCS) $(RES_SRCS) $(SUPPORT_SRCS) # Runtime library objects (VM + values + form runtime + serialization) RT_OBJS = $(OBJDIR)/vm.o $(OBJDIR)/values.o $(OBJDIR)/formrt.o $(OBJDIR)/frmParser.o $(OBJDIR)/basNativeDos.o $(OBJDIR)/serialize.o RT_TARGETDIR = $(LIBSDIR)/kpunch/basrt RT_TARGET = $(RT_TARGETDIR)/basrt.lib # Compiler objects (only needed by the IDE) COMP_OBJS = $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(COMP_SRCS))) $(OBJDIR)/basBuild.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_TARGET = $(APPDIR)/dvxbasic.app # Standalone stub (embedded as IDE resource) STUB_OBJS = $(OBJDIR)/basstub.o $(OBJDIR)/basModuleRes.o STUB_TARGET = $(OBJDIR)/basstub.app # DOS command-line compiler: the same DOS objects the IDE uses plus the # resource and support code the loader normally provides. DOS_BASCOMP_OBJS = $(patsubst %.c,$(OBJDIR)/%.o,$(notdir stub/bascomp.c $(CLI_SRCS))) # ---- Native host tools and harnesses (host gcc, not cross-compiled) ---- # # TESTSAN=1 rebuilds the harnesses, bascomp and basrun under ASan/UBSan # (make tests TESTSAN=1). Objects live in one directory per mode; the # binaries share bin/host and depend on a mode stamp so switching TESTSAN # relinks them instead of running a stale binary. HOSTCFLAGS = $(HOST_TOOL_CFLAGS) -Wno-stringop-truncation -D_GNU_SOURCE $(DVX_INCLUDES) HOSTLDFLAGS = HOSTTOOL_OBJDIR = $(OBJDIR)/host-$(if $(filter 1,$(TESTSAN)),san,plain) ifeq ($(TESTSAN),1) HOSTCFLAGS += -g $(SAN_FLAGS) HOSTLDFLAGS += $(SAN_FLAGS) endif # COV=1 (make coverage): every host build (harnesses, bascomp, basrun, # basrt.a) gets gcov instrumentation and lands under obj/hostcov so it # never mixes with the sanitized or release host binaries. dvxres is # still the release tool from bin/host. Must precede the rules below # because target names expand when they are read. ifeq ($(COV),1) HOSTDIR = ../../../../obj/hostcov/basic DVXRES = ../../../../bin/host/dvxres HOSTTOOL_OBJDIR = $(HOSTDIR)/obj HOSTCFLAGS += -g --coverage HOSTLDFLAGS += --coverage endif TESTSAN_STAMP = $(HOSTDIR)/.testsan-$(if $(filter 1,$(TESTSAN)),on,off) # hostObjs SRCS -> the host tool objects for SRCS hostObjs = $(patsubst %.c,$(HOSTTOOL_OBJDIR)/%.o,$(notdir $1)) TEST_COMPILER = $(HOSTDIR)/test_compiler TEST_COMPACT = $(HOSTDIR)/test_compact TEST_SUITE = $(HOSTDIR)/test_suite BASCOMP_TARGET = $(HOSTDIR)/bascomp BASRUN_TARGET = $(HOSTDIR)/basrun TEST_COMPILER_OBJS = $(call hostObjs,test_compiler.c $(COMP_SRCS) $(VM_LINK_SRCS) $(SUPPORT_SRCS)) TEST_COMPACT_OBJS = $(call hostObjs,test_compact.c $(COMP_SRCS) $(VM_LINK_SRCS) $(SUPPORT_SRCS)) TEST_SUITE_OBJS = $(call hostObjs,test_suite.c $(CLI_SRCS)) BASCOMP_OBJS = $(call hostObjs,stub/bascomp.c $(CLI_SRCS)) BASRUN_OBJS = $(call hostObjs,stub/basrun.c stub/basModuleRes.c $(CLI_SRCS)) HOSTTOOL_OBJS = $(sort $(TEST_COMPILER_OBJS) $(TEST_COMPACT_OBJS) $(TEST_SUITE_OBJS) $(BASCOMP_OBJS) $(BASRUN_OBJS)) # Extra per-object host flags HOSTFLAGS_test_suite = -DBAS_TEST_SRC_DIR='"$(abspath .)"' # Host-side BASIC test directory (basrun fixtures, fuzzers, compaction # diff) and the scratch directory the harnesses run in (they write files # into the working directory). BASIC_TESTDIR = ../../../test/basic HARNESS_WORK = ../../../../obj/test/harness .PHONY: all clean tests all: $(RT_TARGET) $(RT_TARGETDIR)/basrt.dep $(STUB_TARGET) $(APP_TARGET) $(BASCOMP_TARGET) $(BASRUN_TARGET) $(SYSTEMDIR)/BASCOMP.EXE # Run every built harness and fail the build if any returns non-zero. # test_compiler, test_compact and test_suite each report a failure count # and return non-zero on failure. make stops at the first one that fails. # The src/test/basic suite (sample runs, fixtures, fuzzers, compaction # differential) needs bascomp and basrun; it inherits TESTSAN. tests: $(TEST_COMPILER) $(TEST_COMPACT) $(TEST_SUITE) $(BASCOMP_TARGET) $(BASRUN_TARGET) mkdir -p $(HARNESS_WORK) cd $(HARNESS_WORK) && $(abspath $(TEST_COMPILER)) cd $(HARNESS_WORK) && $(abspath $(TEST_COMPACT)) cd $(HARNESS_WORK) && $(abspath $(TEST_SUITE)) $(MAKE) -C $(BASIC_TESTDIR) test TESTSAN=$(TESTSAN) $(TEST_COMPILER): $(TEST_COMPILER_OBJS) $(TESTSAN_STAMP) | $(HOSTDIR) $(HOSTCC) $(HOSTLDFLAGS) -o $@ $(TEST_COMPILER_OBJS) -lm $(TEST_COMPACT): $(TEST_COMPACT_OBJS) $(TESTSAN_STAMP) | $(HOSTDIR) $(HOSTCC) $(HOSTLDFLAGS) -o $@ $(TEST_COMPACT_OBJS) -lm $(TEST_SUITE): $(TEST_SUITE_OBJS) $(TESTSAN_STAMP) | $(HOSTDIR) $(HOSTCC) $(HOSTLDFLAGS) -o $@ $(TEST_SUITE_OBJS) -lm $(BASRUN_TARGET): $(BASRUN_OBJS) $(TESTSAN_STAMP) | $(HOSTDIR) $(HOSTCC) $(HOSTLDFLAGS) -o $@ $(BASRUN_OBJS) -lm # Host command-line compiler -- basstub.app is appended as a STUB # resource so bascomp is self-contained (no BASSTUB.APP companion file), # and noicon.bmp as the ICON32 fallback for projects without an icon. $(BASCOMP_TARGET): $(BASCOMP_OBJS) $(TESTSAN_STAMP) $(STUB_TARGET) noicon.bmp $(DVXRES) | $(HOSTDIR) $(HOSTCC) $(HOSTLDFLAGS) -o $@ $(BASCOMP_OBJS) -lm $(DVXRES) add $@ STUB binary @$(STUB_TARGET) $(DVXRES) add $@ noicon icon @noicon.bmp $(TESTSAN_STAMP): | $(HOSTDIR) rm -f $(HOSTDIR)/.testsan-on $(HOSTDIR)/.testsan-off touch $@ # One host object rule per source (the sources live in several dirs). define HOST_OBJ_RULE $(call hostObjs,$1): $1 $$(DVX_MAKEFILES) | $$(HOSTTOOL_OBJDIR) $$(HOSTCC) $$(HOSTCFLAGS) $$(HOSTFLAGS_$(basename $(notdir $1))) -c -o $$@ $$< endef $(foreach src,$(sort test_compiler.c test_compact.c test_suite.c stub/bascomp.c stub/basrun.c stub/basModuleRes.c $(CLI_SRCS)),$(eval $(call HOST_OBJ_RULE,$(src)))) # DOS command-line compiler (same STUB / noicon embed as the host build) $(SYSTEMDIR)/BASCOMP.EXE: $(DOS_BASCOMP_OBJS) $(STUB_TARGET) noicon.bmp $(DVXRES) | $(SYSTEMDIR) $(CC) -o $(SYSTEMDIR)/bascomp.exe $(DOS_BASCOMP_OBJS) -lm $(EXE2COFF) $(SYSTEMDIR)/bascomp.exe cat $(CWSDSTUB) $(SYSTEMDIR)/bascomp > $@ rm -f $(SYSTEMDIR)/bascomp $(SYSTEMDIR)/bascomp.exe $(DVXRES) add $@ STUB binary @$(STUB_TARGET) $(DVXRES) add $@ noicon icon @noicon.bmp $(HOSTDIR) $(HOSTTOOL_OBJDIR) $(SYSTEMDIR): mkdir -p $@ # Runtime library DXE (exports symbols via dlregsym constructor) $(RT_TARGET): $(RT_OBJS) | $(RT_TARGETDIR) $(DXE3GEN) -o $(RT_TARGETDIR)/basrt.dxe -U $(RT_OBJS) mv $(RT_TARGETDIR)/basrt.dxe $@ $(RT_TARGETDIR)/basrt.dep: basrt.dep | $(RT_TARGETDIR) sed 's/$$/\r/' $< > $@ # Standalone stub DXE (embedded as resource in IDE app) $(STUB_TARGET): $(STUB_OBJS) | $(OBJDIR) $(DXE3GEN) -o $@ -U $(STUB_OBJS) # IDE app DXE (compiler linked in, runtime from basrt.lib, stub embedded) $(APP_TARGET): $(COMP_OBJS) $(IDE_OBJS) $(STUB_TARGET) dvxbasic.res | $(APPDIR) $(DXE3GEN) -o $@ -U $(COMP_OBJS) $(IDE_OBJS) $(DVXRES) build $@ dvxbasic.res $(DVXRES) add $@ STUB binary @$(STUB_TARGET) # DOS object files. One pattern rule per source directory; header # dependencies come from the compiler (DEPFLAGS writes a .d next to each # object) so no hand-written list can drift out of date. $(OBJDIR)/%.o: compiler/%.c $(DVX_MAKEFILES) | $(OBJDIR) $(CC) $(CFLAGS) -c -o $@ $< $(OBJDIR)/%.o: runtime/%.c $(DVX_MAKEFILES) | $(OBJDIR) $(CC) $(CFLAGS) -c -o $@ $< $(OBJDIR)/%.o: formrt/%.c $(DVX_MAKEFILES) | $(OBJDIR) $(CC) $(CFLAGS) -c -o $@ $< $(OBJDIR)/%.o: ide/%.c $(DVX_MAKEFILES) | $(OBJDIR) $(CC) $(CFLAGS) -c -o $@ $< $(OBJDIR)/%.o: stub/%.c $(DVX_MAKEFILES) | $(OBJDIR) $(CC) $(CFLAGS) -c -o $@ $< $(OBJDIR)/%.o: $(LIBDVX)/%.c $(DVX_MAKEFILES) | $(OBJDIR) $(CC) $(CFLAGS) -c -o $@ $< $(OBJDIR)/%.o: $(LIBDVX)/platform/%.c $(DVX_MAKEFILES) | $(OBJDIR) $(CC) $(CFLAGS) -c -o $@ $< $(OBJDIR)/%.o: $(LIBDVX)/thirdparty/%.c $(DVX_MAKEFILES) | $(OBJDIR) $(CC) $(CFLAGS) -c -o $@ $< $(OBJDIR)/%.o: $(TOOLSDIR)/%.c $(DVX_MAKEFILES) | $(OBJDIR) $(CC) $(CFLAGS) -c -o $@ $< $(OBJDIR)/%.o: %.c $(DVX_MAKEFILES) | $(OBJDIR) $(CC) $(CFLAGS) -c -o $@ $< # Directories $(OBJDIR): mkdir -p $(OBJDIR) $(RT_TARGETDIR): mkdir -p $(RT_TARGETDIR) $(APPDIR): mkdir -p $(APPDIR) clean: host-basrt-clean rm -rf $(RT_OBJS) $(COMP_OBJS) $(IDE_OBJS) $(STUB_OBJS) $(DOS_BASCOMP_OBJS) $(OBJDIR)/*.d $(RT_TARGET) $(APP_TARGET) $(STUB_TARGET) $(BASCOMP_TARGET) $(SYSTEMDIR)/BASCOMP.EXE $(RT_TARGETDIR)/basrt.dep $(RT_TARGETDIR) rm -rf $(OBJDIR)/host-plain $(OBJDIR)/host-san $(HARNESS_WORK) rm -f $(TEST_COMPILER) $(TEST_COMPACT) $(TEST_SUITE) $(BASRUN_TARGET) $(HOSTDIR)/.testsan-on $(HOSTDIR)/.testsan-off $(MAKE) -C $(BASIC_TESTDIR) clean # ============================================================ # Host basrt archive (src/test/formrt suite) # ============================================================ # # Compiler + runtime + form runtime built with the native toolchain into # obj/host/basrt.a, linked by the form-runtime test suite against the # host libdvx.a and the widget .so files. basNativeHost.c stands in for # the i386 basNativeDos.c trampoline (Makefile object-list selection, no # preprocessor conditionals). SAN/COV per common.mk; must match the rest # of the host build. HOSTRT_DIR = $(HOST_OBJROOT)/basrt HOSTRT_TARGET = $(HOST_OBJROOT)/basrt.a HOSTRT_SRCS = $(COMP_SRCS) $(VM_SRCS) formrt/formrt.c formrt/frmParser.c formrt/basNativeHost.c HOSTRT_OBJS = $(patsubst %.c,$(HOSTRT_DIR)/%.o,$(notdir $(HOSTRT_SRCS))) HOSTRT_CFLAGS = $(HOST_CFLAGS) -Wno-stringop-truncation $(DVX_INCLUDES) -I../../../widgets/kpunch -I../../../libs/kpunch/dvxshell -I../../../libs/kpunch/libtasks .PHONY: host-basrt host-basrt-clean host-basrt: $(HOSTRT_TARGET) $(HOSTRT_TARGET): $(HOSTRT_OBJS) rm -f $@ ar rcs $@ $(HOSTRT_OBJS) $(HOSTRT_DIR)/%.o: compiler/%.c $(DVX_MAKEFILES) @mkdir -p $(HOSTRT_DIR) $(HOSTCC) $(HOSTRT_CFLAGS) -c -o $@ $< $(HOSTRT_DIR)/%.o: runtime/%.c $(DVX_MAKEFILES) @mkdir -p $(HOSTRT_DIR) $(HOSTCC) $(HOSTRT_CFLAGS) -c -o $@ $< $(HOSTRT_DIR)/%.o: formrt/%.c $(DVX_MAKEFILES) @mkdir -p $(HOSTRT_DIR) $(HOSTCC) $(HOSTRT_CFLAGS) -c -o $@ $< host-basrt-clean: rm -rf $(HOSTRT_DIR) $(HOSTRT_TARGET) -include $(wildcard $(OBJDIR)/*.d) $(HOSTTOOL_OBJS:.o=.d) $(HOSTRT_OBJS:.o=.d)