joeylib2/make/dvx.mk
2026-10-05 16:47:00 -05:00

268 lines
12 KiB
Makefile

# DVX build rules: every example as a DVX program (.app).
#
# A JoeyLib program on DVX runs in a window of the DVX desktop, or on the
# whole screen (src/dvx). The library, libjoey.a, is built here with
# JoeyLib's own DJGPP (DVX is built with the same gcc 12.2.0) against the SDK
# the installer unpacked from a DVX tree's dist/sdk.zip into
# toolchains/opt/dvx/sdk (DVX_SDK); the stage and the graphics are the DOS
# port's (src/x86, the chunky generics). Each example is then a DVX SDK
# project in build/dvx/apps/<name>/ -- symlinks to its sources and to the
# port's entry (src/dvx/dvxApp.c), a generated one-topic help file and
# resource list -- built and packaged by the SDK's own sdk.mk (KIND = app,
# LIBS = libjoey.a, DATA = its data files) and copied into build/dvx/bin/
# laid out as it goes into DVX: apps/joeylib/<name>/<name>.app, <name>.hlp
# and DATA/. The gates and joey-run copy that tree into a DVX installation.
include $(dir $(lastword $(MAKEFILE_LIST)))/common.mk
# The asset rules below define real targets before `all`, which would
# otherwise become make's default goal.
.DEFAULT_GOAL := all
$(call requireTool,$(DOS_CC),toolchain:dos)
$(call requireTool,$(DVX_SDK)/sdk.mk,toolchain:dvx)
PLATFORM := dvx
BUILD := $(REPO_DIR)/build/$(PLATFORM)
LIBDIR := $(BUILD)/lib
BINDIR := $(BUILD)/bin
APPSDIR := $(BUILD)/apps
DATADIR := $(BUILD)/data
# Where a program installs in DVX: apps/<vendor>/<name>/.
VENDOR := joeylib
PORT_DIR := $(SRC_DIR)/dvx
# sdk.mk's code generation, so the library matches the programs it links
# into; -fomit-frame-pointer as on DOS.
DVX_ARCH := -march=i486 -mtune=i586 -fomit-frame-pointer
# The SDK's header folders (sdk.mk's list: all but the BASIC and socket ones),
# for the port's own files only -- the core never sees a DVX header.
DVX_SDK_INCS := $(addprefix -I,$(filter-out %/basic %/net,$(patsubst %/,%,$(wildcard $(DVX_SDK)/include/*/))))
# A program's exit() and atexit() are the port's (src/dvx/program.c): the
# handlers run, and JoeyLib shuts down, when the program ends rather than
# when DVX does. Applied to the library and the programs, never to the port.
PROGRAM_RENAMES := -Dexit=dvxPortExit -Datexit=dvxPortAtExit
CFLAGS := $(COMMON_CFLAGS) $(DVX_ARCH) -DJOEYLIB_PLATFORM_DVX -I$(SRC_X86) -I$(SRC_CG) -MMD -MP
LIB_CFLAGS := $(CFLAGS) $(PROGRAM_RENAMES)
PORT_CFLAGS := $(CFLAGS) -I$(PORT_DIR) $(DVX_SDK_INCS)
# The flags every program adds to sdk.mk's (which bring the SDK headers and
# -Werror), with the include folders every port gives its examples: the
# program's main becomes jlGameMain, which the port calls.
APP_CFLAGS := -DJOEYLIB_PLATFORM_DVX -Dmain=jlGameMain $(PROGRAM_RENAMES) -fomit-frame-pointer -I$(INCLUDE_DIR) -I$(SRC_CORE) -I$(PORT_DIR)
# dvxApp.c is compiled into each program (it names it), not the library.
PORT_ENTRY := $(PORT_DIR)/dvxApp.c
PORT_C_SRCS := $(filter-out $(PORT_ENTRY),$(wildcard $(PORT_DIR)/*.c))
X86_C_SRCS := $(wildcard $(SRC_X86)/*.c)
LIB_OBJS := \
$(patsubst $(SRC_CORE)/%.c,$(BUILD)/obj/core/%.o,$(CORE_C_SRCS)) \
$(patsubst $(SRC_DIR)/generic/%.c,$(BUILD)/obj/generic/%.o,$(GENERIC_C_SRCS)) \
$(patsubst $(PORT_DIR)/%.c,$(BUILD)/obj/port/%.o,$(PORT_C_SRCS)) \
$(patsubst $(SRC_X86)/%.c,$(BUILD)/obj/x86/%.o,$(X86_C_SRCS)) \
$(BUILD)/obj/codegen/spriteCompile.o \
$(BUILD)/obj/codegen/spriteStage.o
LIB := $(LIBDIR)/libjoey.a
# The examples: for each, its sources, its window title and a line of help
# (no apostrophes: the help lines are written through the shell in quotes).
# Worth knowing which ones the gates use:
# UBER the golden-hash vehicle: a hash per public op, which must equal
# the DOS port's (tests/goldens/uber/dos.txt): the same stage.
# TILEBANK the tile-bank gate's program: the DOS bake loaded both ways and
# pixel-checked, every other target's bake refused.
# KEYS the input gate's program: typed characters to jlInputGetChar.
hello_SRCS := $(EXAMPLES)/hello/hello.c
hello_TITLE := Hello
hello_HELP := The smallest JoeyLib program: it clears the screen and waits for a key.
pattern_SRCS := $(EXAMPLES)/pattern/pattern.c
pattern_TITLE := Pattern
pattern_HELP := Eight bands of gradient palettes, one per band of scan lines.
draw_SRCS := $(EXAMPLES)/draw/draw.c
draw_TITLE := Draw
draw_HELP := The drawing primitives: pixels, lines, circles, rectangles and flood fills.
keys_SRCS := $(EXAMPLES)/keys/keys.c
keys_TITLE := Keys
keys_HELP := Keyboard, typed characters and mouse: held keys light up and typed text appears. Escape ends it.
serial_SRCS := $(EXAMPLES)/serial/serial.c
serial_TITLE := Serial
serial_HELP := A serial terminal on COM1.
sertest_SRCS := $(EXAMPLES)/sertest/sertest.c
sertest_TITLE := SerTest
sertest_HELP := The serial port test program.
save_SRCS := $(EXAMPLES)/save/save.c
save_TITLE := Save
save_HELP := Saved files: counts its runs in a file in its settings folder.
tilebank_SRCS := $(EXAMPLES)/tilebank/tilebank.c
tilebank_TITLE := TileBank
tilebank_HELP := The tile bank check: loads a baked tile bank two ways and checks every pixel.
joy_SRCS := $(EXAMPLES)/joy/joy.c
joy_TITLE := Joy
joy_HELP := Joysticks: shows the position and buttons of each joystick.
sprite_SRCS := $(EXAMPLES)/sprite/sprite.c
sprite_TITLE := Sprite
sprite_HELP := Compiled sprites moving over a background.
audio_SRCS := $(EXAMPLES)/audio/audio.c
audio_TITLE := Audio
audio_HELP := Sound: music, sound effects and tones.
uber_SRCS := $(EXAMPLES)/uber/uber.c
uber_TITLE := Uber
uber_HELP := The JoeyLib conformance and speed test: every drawing call, timed and checked. Its results go to joeylog.txt in its settings folder.
adv_SRCS := $(EXAMPLES)/adventure/adventure.c
adv_TITLE := Adventure
adv_HELP := A small adventure game.
adv2_SRCS := $(EXAMPLES)/adventure2/adventure2.c
adv2_TITLE := Adventure 2
adv2_HELP := A second small adventure game.
agi_SRCS := $(EXAMPLES)/agi/agi.c $(EXAMPLES)/agi/agiRes.c $(EXAMPLES)/agi/agiPic.c $(EXAMPLES)/agi/agiView.c $(EXAMPLES)/agi/agiVm.c $(EXAMPLES)/agi/agiObj.c $(EXAMPLES)/agi/agiText.c
agi_TITLE := AGI
agi_HELP := A Sierra AGI interpreter. The files of the game it plays go in its DATA folder.
staxi_SRCS := $(EXAMPLES)/spacetaxi/spacetaxi.c $(EXAMPLES)/spacetaxi/stLevel.c $(EXAMPLES)/spacetaxi/stLevelFile.c $(EXAMPLES)/spacetaxi/stRender.c $(EXAMPLES)/spacetaxi/stSim.c $(EXAMPLES)/spacetaxi/stFare.c $(EXAMPLES)/spacetaxi/stHooks.c $(EXAMPLES)/spacetaxi/stTitle.c $(EXAMPLES)/spacetaxi/stC64Data.c $(EXAMPLES)/spacetaxi/stCels.c $(EXAMPLES)/spacetaxi/stAudio.c $(EXAMPLES)/spacetaxi/stLevelCels.c
staxi_TITLE := Space Taxi
staxi_HELP := Space Taxi: fly the taxi, pick up the fares, take them where they ask to go.
APPS := hello pattern draw keys serial sertest save tilebank joy sprite audio uber adv adv2 agi staxi
# UBER's probe build (part of all; scripts/verify-dvx-display.sh): UBER
# with its UBER_PROBE rows, the display parity row among them, as a program
# of its own packaged apart in build/dvx/probe, so neither bin/ (joey-run's
# tree) nor the goldened UBER changes. -DUBER_FRAMES=1 as the IIgs probe
# build: the run is wanted for its probe rows, not its timings.
# (Its name, like every program's, is a DOS 8.3 name: DVX runs on DOS.)
uberprob_SRCS := $(uber_SRCS)
uberprob_TITLE := Uber Probe
uberprob_HELP := UBER with its probe rows: the present checked against the stage on screen. Its results go to joeylog.txt in its settings folder.
uberprob_CFLAGS := -DUBER_PROBE -DUBER_FRAMES=1
uberprob_BIN := $(BUILD)/probe
PROBE_APPS := uberprob
# Data the examples read from DATA/ beside the program: AUDIO its music and
# sound effect; TILEBANK the DOS bake of the tile-bank fixture (the DOS
# target byte: DVX shows the DOS stage), every other target's bake it must
# refuse, and the expected pixels (common.mk); Space Taxi the DOS bake of
# its levels, compiled cel banks (x86 code, the DOS target byte) and speech,
# made by make/dos.mk -- only when the C64 image it comes from is present.
audio_DATA := $(DATADIR)/audio/DATA
tilebank_DATA := $(DATADIR)/tilebank/DATA
staxi_DATA := $(if $(HAVE_STAXI_DATA),$(DATADIR)/staxi/DATA)
AUDIO_DATA_FILES := $(audio_DATA)/test.mod $(audio_DATA)/test.sfx
TILEBANK_OWN := $(tilebank_DATA)/tilebank/own.tbk
DOS_STAXI_DATA := $(REPO_DIR)/build/dos/bin/STAXI/DATA
.PHONY: all dvx dvx-lib dvx-apps dvx-probe clean-dvx clean $(addprefix app-,$(APPS) $(PROBE_APPS))
all dvx: dvx-lib dvx-apps dvx-probe
dvx-lib: $(LIB)
dvx-apps: $(addprefix app-,$(APPS))
dvx-probe: $(addprefix app-,$(PROBE_APPS))
$(BUILD)/obj/core/%.o: $(SRC_CORE)/%.c
@mkdir -p $(dir $@)
$(DOS_CC) $(LIB_CFLAGS) -c $< -o $@
$(BUILD)/obj/generic/%.o: $(SRC_DIR)/generic/%.c
@mkdir -p $(dir $@)
$(DOS_CC) $(LIB_CFLAGS) -c $< -o $@
$(BUILD)/obj/x86/%.o: $(SRC_X86)/%.c
@mkdir -p $(dir $@)
$(DOS_CC) $(LIB_CFLAGS) -c $< -o $@
$(BUILD)/obj/codegen/%.o: $(SRC_CG)/%.c
@mkdir -p $(dir $@)
$(DOS_CC) $(LIB_CFLAGS) -c $< -o $@
$(BUILD)/obj/port/%.o: $(PORT_DIR)/%.c
@mkdir -p $(dir $@)
$(DOS_CC) $(PORT_CFLAGS) -c $< -o $@
$(LIB): $(LIB_OBJS)
@mkdir -p $(dir $@)
rm -f $@
$(DOS_AR) rcs $@ $^
# One program: (re)write its SDK project -- the Makefile, symlinks to its
# sources and the port's entry, the help source and the resource list --
# then let sdk.mk build and package it, and copy the package into bin/.
# sdk.mk rebuilds only what changed; the project files are rewritten only
# when their contents change, so an unchanged program is not relinked.
# $(1) = the program's name; $(1)_CFLAGS, if any, are added to its flags,
# and $(1)_BIN, if set, is where it goes instead of bin/.
define appRule
app-$(1): $(LIB) $$($(1)_SRCS) $(PORT_ENTRY) $$(if $$($(1)_DATA),$(1)-data)
@mkdir -p $(APPSDIR)/$(1)
@for src in $$($(1)_SRCS) $(PORT_ENTRY); do ln -sfn $$$$src $(APPSDIR)/$(1)/$$$$(basename $$$$src); done
@printf '%s\n' \
'# Generated by make/dvx.mk: the DVX SDK project of the JoeyLib example $(1).' \
'SDK_DIR = $(DVX_SDK)' \
'KIND = app' \
'NAME = $(1)' \
'VENDOR = $(VENDOR)' \
'LIBS = $(LIB)' \
'DATA = $$($(1)_DATA)' \
"CFLAGS = $(APP_CFLAGS) $$($(1)_CFLAGS) -I$$(dir $$(firstword $$($(1)_SRCS))) -DDVX_PORT_APP_NAME='\"$$($(1)_TITLE)\"'" \
'include $$$$(SDK_DIR)/sdk.mk' | $(REPO_DIR)/make/support/dvx/writeIfChanged.sh $(APPSDIR)/$(1)/Makefile
@printf '%s\n' \
'.topic $(1).overview' \
'.title $$($(1)_TITLE)' \
'.toc 0 $$($(1)_TITLE)' \
'.default' \
'.index $$($(1)_TITLE)' \
'' \
'.h1 $$($(1)_TITLE)' \
'' \
'$$($(1)_HELP)' \
'' \
'$$($(1)_TITLE) is a JoeyLib example program. It runs in its own window at a virtual 70 frames a second; while the window is active every key goes to it except Alt+Tab (switch programs), Ctrl+Esc (Task Manager) and Alt+F4 (close it). Game > Exit also closes it.' \
'' \
'Game > Full Screen, or Alt+Enter, puts it on the whole screen at 320x200 in 256 colours, and back in its window. It starts the way it was left. Alt+Tab or Ctrl+Esc brings the desktop back while it runs on; coming back to it gives it the whole screen again.' \
| $(REPO_DIR)/make/support/dvx/writeIfChanged.sh $(APPSDIR)/$(1)/$(1).dhs
@printf '%s\n' \
'name text "$$($(1)_TITLE)"' \
'author text "JoeyLib"' \
'description text "JoeyLib example: $$($(1)_TITLE)"' \
| $(REPO_DIR)/make/support/dvx/writeIfChanged.sh $(APPSDIR)/$(1)/$(1).res
$$(MAKE) -C $(APPSDIR)/$(1) DJGPP_PREFIX=$(DOS_PREFIX) package
@mkdir -p $$(or $$($(1)_BIN),$(BINDIR))
rm -rf $$(or $$($(1)_BIN),$(BINDIR))/apps/$(VENDOR)/$(1)
cp -R $(APPSDIR)/$(1)/pkg/apps $$(or $$($(1)_BIN),$(BINDIR))/
endef
$(foreach a,$(APPS) $(PROBE_APPS),$(eval $(call appRule,$(a))))
.PHONY: audio-data tilebank-data staxi-data
audio-data: $(AUDIO_DATA_FILES)
tilebank-data: $(TILEBANK_OWN)
staxi-data:
$(MAKE) -f $(REPO_DIR)/make/dos.mk dos-staxi-data
rm -rf $(staxi_DATA)
@mkdir -p $(dir $(staxi_DATA))
cp -R $(DOS_STAXI_DATA) $(staxi_DATA)
$(audio_DATA)/%: $(REPO_DIR)/assets/%
@mkdir -p $(dir $@)
cp $< $@
$(TILEBANK_OWN): $(TILEBANK_BAKE_DEPS)
python3 $(TILEBANK_STAGE) dos $(TILEBANK_PNG) $(dir $@)
clean-dvx:
rm -rf $(BUILD)
# `clean` as an alias for `clean-dvx`. Without it a bare
# `make -f make/dvx.mk clean` FAILS -- and with stderr discarded that
# looks like success while leaving stale objects the next build links.
clean: clean-dvx
# Pull in per-object header-dependency files generated by gcc -MMD/-MP.
-include $(LIB_OBJS:.o=.d)