# DESCRIP.MMS - DOSBox 0.72 Build Description for OpenVMS
# Generated for OpenVMS 8.4 AXP
# Use with: MMK or MMS

.IFDEF __VAX__
ARCH = VAX
.ENDIF

.IFDEF __ALPHA__
ARCH = ALPHA
.ENDIF

.IFDEF __IA64__
ARCH = IA64
.ENDIF

# Compiler and flags
CXX = CXX
#
# ---------------------------------------------------------------------------
# GLOBAL OPTIMIZATION LEVEL
#
# Every source file in the tree is now compiled with this. Previously a number
# of files were built /NOOPTIMIZE because the DEC C++ compiler ACCVIOed on
# them; this build is a deliberate test of full optimization on real Alpha
# hardware, so all of them are back on $(OPT).
#
# To back off globally, change this ONE macro, e.g.
#     OPT = /OPTIMIZE=LEVEL=3
#     OPT = /OPTIMIZE=LEVEL=2/NOINLINE
#     OPT = /NOOPTIMIZE
# The per-file /NOOPTIMIZE fallbacks are kept as commented-out rules below, in
# case an individual file still crashes the compiler at LEVEL=4.
OPT = /OPTIMIZE=LEVEL=4
# ---------------------------------------------------------------------------
#
# ---------------------------------------------------------------------------
# INCLUDE PATHS  ($ MMK CHECK  will tell you which of these actually resolve)
#
# ONE list, $(INCDIRS), is used by EVERY compile in this file. Do not create
# per-directory variants - that duplication is what produced the invalid
# [-.-.INCLUDE] spelling and the "cannot find dosbox.h" failure.
#
# The list is a deliberate SUPERSET, so it works no matter where the headers
# live relative to the sources and no matter what the default directory is
# when the compiler runs. Both of these layouts are supported:
#
#   LAYOUT A - include as a SIBLING of the source dir (upstream layout)
#     DQB1:[000000.SRC.DOSBOX_0_72]        <- project root, holds CONFIG.H
#            +-- [.INCLUDE]                <- DOSBOX.H, CPU.H, MEM.H, ...
#            +-- [.DOSBOX_SRC]             <- this DESCRIP.MMS, DOSBOX.CPP
#                      +-- [.CPU] [.DOS] [.GUI] [.HARDWARE] [.INTS] ...
#
#   LAYOUT B - include COPIED INSIDE the source dir. This is what the
#   AlphaServer actually has, confirmed from a build log:
#     DQB1:[000000.SRC.DOSBOX_0_72.SRC]
#            +-- [.INCLUDE]                <- DOSBOX.H, CONFIG.H, CPU.H, ...
#            +-- [.CPU] [.DOS] [.GUI] ...
#   Note [-.INCLUDE] does NOT exist there, which is why the list must carry
#   [.INCLUDE] as well - the original flags only had the [-.INCLUDE] form.
#
# What each entry resolves to, with default = the source dir (DOSBOX_SRC):
#   [.INCLUDE]   -> DOSBOX_SRC.INCLUDE      (layout B)
#   [-.INCLUDE]  -> DOSBOX_0_72.INCLUDE     (layout A)
#   [--.INCLUDE] -> SRC.INCLUDE             (harmless, normally absent)
#   []           -> DOSBOX_SRC              (per-module local headers)
#   [-]          -> DOSBOX_0_72             (CONFIG.H in layout A)
#   [--]         -> SRC
#
# The [.CPU] rules SET DEFAULT [.CPU] first, which shifts everything down one
# level - [-.INCLUDE] then means DOSBOX_SRC.INCLUDE (layout B) and
# [--.INCLUDE] means DOSBOX_0_72.INCLUDE (layout A). Because both spellings
# are in the list, the SAME flags work from [.CPU] and from the source root,
# including after a failed build leaves SET DEFAULT in the wrong place.
#
# VMS SYNTAX NOTE: hyphens meaning "up a level" must be CONSECUTIVE.
# Two levels up is [--.INCLUDE]. [-.-.INCLUDE] is INVALID and will never
# find anything - do not reintroduce it.
#
# Search paths that do not exist are skipped silently by the compiler, so
# listing all of them costs nothing.
#
# ESCAPE HATCH: DOSBOX_INCLUDE is searched FIRST and is a logical name, so any
# layout can be fixed from DCL without editing this file. If MMK still cannot
# find DOSBOX.H, point it at the include directory by absolute path:
#   $ DEFINE DOSBOX_INCLUDE DQB1:[000000.SRC.DOSBOX_0_72.INCLUDE]
# An undefined logical simply fails to translate and is skipped, so leaving it
# undefined costs nothing.
#
# SDL is likewise a LOGICAL NAME, not a subdirectory - it must point at the
# SDL headers:
#   $ DEFINE SDL device:[path.SDL-1_2_14.include]
INCDIRS = (DOSBOX_INCLUDE,[.INCLUDE],[-.INCLUDE],[--.INCLUDE],[],[-],[--],SDL)
# ---------------------------------------------------------------------------
#
# Common flag groups - see the per-file rules below for which files need which.
# DECLSPEC= fixes SDL headers, SDLCALL= fixes SDL calling convention
# /name=(as_is,shortened) preserves extern "C" case to match SDL library (compiled with as_is)
DEFS = /DEFINE=(OPENVMS,__USE_STD_IOSTREAM,"DECLSPEC=","SDLCALL=")
# These warning disables prevent compiler crashes on certain constructs - but
# on a handful of files they CAUSE an ACCVIO, hence the _NOWARN variants.
WARNOFF = /WARNINGS=(DISABLE=(INTOVERFLOW,SHIFTCNTBIG,CODEUNREACHABLE))
#
# ---------------------------------------------------------------------------
# TARGET CPU ARCHITECTURE - the biggest compiler-side lever for emulator speed.
#
# WHY: the default is /ARCHITECTURE=GENERIC, which emits code that still runs
# on an EV4, and therefore MUST NOT USE the Byte/Word Extensions (BWX). Without
# BWX every single byte or word load/store becomes an LDQ_U + EXTBL (or
# LDQ_U + INSBL + MSKBL + STQ_U) sequence instead of one LDBU/STB.
#
# That matters enormously here: with C_UNALIGNED_MEMORY undefined (it must be,
# unaligned access traps on Alpha), include/mem.h implements EVERY emulated
# 16/32-bit memory access as individual byte accesses plus shifts - see
# host_readw/host_readd. Opcode fetch, memory operands and VGA writes are all
# byte traffic, so the interpreter's inner loop is dominated by exactly the
# operation GENERIC pessimises. A DS10 is an EV6/EV67 and has BWX.
#
# HOST = whatever CPU you are compiling on. The resulting binary will NOT run
# on pre-EV56 Alphas, which is fine for a DS10-targeted build. Use EV6
# explicitly if you ever cross-build.
#
# SMOKE-TEST THIS FIRST - it costs one file instead of a full rebuild:
#     $ SET DEFAULT [.SRC]
#     $ DELETE [.CPU]FLAGS.OBJ;*
#     $ MMK [.CPU]FLAGS.OBJ
# If CXX rejects the qualifier, blank the macro out and you are back to the
# previous known-good build:
#     ARCHOPT =
ARCHOPT = /ARCHITECTURE=HOST
# Further experiments, one at a time (see PERFORMANCE_TUNING_ALPHA.txt):
#     ARCHOPT = /ARCHITECTURE=HOST/OPTIMIZE=TUNE=HOST
#     OPT     = /OPTIMIZE=LEVEL=5      (adds software pipelining + unrolling)
# ---------------------------------------------------------------------------
CXXBASE = /name=(as_is,shortened)/float=ieee$(ARCHOPT)/INCLUDE=$(INCDIRS)$(DEFS)

# Standard flags - used by the .CPP.OBJ suffix rule, so every file that has no
# explicit rule below gets these.
CXXFLAGS = $(CXXBASE)$(OPT)$(WARNOFF)
# Without the /WARNINGS disables, for files where those disables (not the
# optimizer) were implicated in earlier compiler ACCVIOs.
CXXFLAGS_NOWARN = $(CXXBASE)$(OPT)
# adlib.cpp additionally needs INTSIGNCHANGE suppressed.
CXXFLAGS_ADLIB = $(CXXBASE)$(OPT)/WARNINGS=(DISABLE=INTSIGNCHANGE)
# [.CPU] files - same flags now that $(INCDIRS) covers both default dirs.
# Kept as separate macro names so the CPU tree can be tuned independently.
CXXFLAGS_CPU = $(CXXBASE)$(OPT)$(WARNOFF)
CXXFLAGS_CPU_NOWARN = $(CXXBASE)$(OPT)

# ---------------------------------------------------------------------------
# HOT PATHS - core_normal.cpp is the CPU interpreter that runs EVERY emulated
# instruction (core=normal is the default, and core=auto also resolves to
# Normal on Alpha since the dynamic cores are x86-only). render*.cpp run the
# per-frame pixel scalers. These now build at the global $(OPT) like everything
# else; the macros are kept so the hot files can be tuned independently if
# LEVEL=4 turns out to be a problem for them specifically.
HOTOPT = $(OPT)
CXXFLAGS_CPU_HOT = $(CXXBASE)$(HOTOPT)$(WARNOFF)
# render*.cpp historically omit the /WARNINGS disables (they were implicated in
# earlier ACCVIOs on these files).
CXXFLAGS_HOT = $(CXXBASE)$(HOTOPT)

# Linker and flags
# Use CXXLINK (C++ aware linker)
LINK = CXXLINK
LINKFLAGS =
# Optional: Enable map file for detailed debugging/crash analysis (slower linking)
# LINKFLAGS = /MAP=DOSBOX.MAP
# LINKFLAGS = /MAP=DOSBOX.MAP/FULL  # Most detailed but very slow
# SDL library - use local options file with all SDL libs + X11 shareables
# LIBSDL logical must be defined: DEFINE LIBSDL SYS$SYSROOT:[SYSMGR.BUILD.SDL-1_2_14.SRC]
LIBS = SDL_LINK.OPT

# Object files by module
CPU_OBJS = [.cpu]callback.obj,[.cpu]core_full.obj,[.cpu]core_normal.obj,-
[.cpu]core_simple.obj,[.cpu]cpu.obj,[.cpu]flags.obj,[.cpu]modrm.obj,-
[.cpu]paging.obj

DOS_OBJS = [.dos]cdrom.obj,[.dos]cdrom_image.obj,[.dos]dos_classes.obj,-
[.dos]dos.obj,[.dos]dos_devices.obj,[.dos]dos_execute.obj,-
[.dos]dos_files.obj,[.dos]dos_ioctl.obj,[.dos]dos_keyboard_layout.obj,-
[.dos]dos_memory.obj,[.dos]dos_misc.obj,[.dos]dos_mscdex.obj,-
[.dos]dos_programs.obj,[.dos]dos_tables.obj,[.dos]drive_cache.obj,-
[.dos]drive_fat.obj,[.dos]drive_iso.obj,[.dos]drive_local.obj,-
[.dos]drives.obj,[.dos]drive_virtual.obj,[.dos]vms_filesystem.obj

FPU_OBJS = [.fpu]fpu.obj

GUI_OBJS = [.gui]midi.obj,[.gui]render.obj,[.gui]render_scalers.obj,-
[.gui]sdlmain.obj,[.gui]sdl_mapper.obj

HARDWARE_OBJS = [.hardware]adlib.obj,[.hardware]cmos.obj,[.hardware]disney.obj,-
[.hardware]dma.obj,[.hardware]gameblaster.obj,[.hardware]gus.obj,-
[.hardware]hardware.obj,[.hardware]iohandler.obj,-
[.hardware]joystick.obj,[.hardware]keyboard.obj,-
[.hardware]memory.obj,[.hardware]mixer.obj,[.hardware]mpu401.obj,-
[.hardware]pcspeaker.obj,[.hardware]pic.obj,[.hardware]sblaster.obj,-
[.hardware]tandy_sound.obj,[.hardware]timer.obj,[.hardware]vga_attr.obj,-
[.hardware]vga.obj,[.hardware]vga_crtc.obj,[.hardware]vga_dac.obj,-
[.hardware]vga_draw.obj,[.hardware]vga_gfx.obj,[.hardware]vga_memory.obj,-
[.hardware]vga_misc.obj,[.hardware]vga_other.obj,[.hardware]vga_s3.obj,-
[.hardware]vga_seq.obj,[.hardware]vga_xga.obj

SERIAL_OBJS = [.hardware.serialport]misc_util.obj,-
[.hardware.serialport]serialdummy.obj,-
[.hardware.serialport]serialport.obj

INTS_OBJS = [.ints]bios.obj,[.ints]bios_disk.obj,[.ints]bios_keyboard.obj,-
[.ints]ems.obj,[.ints]int10_char.obj,[.ints]int10.obj,-
[.ints]int10_memory.obj,[.ints]int10_misc.obj,[.ints]int10_modes.obj,-
[.ints]int10_pal.obj,[.ints]int10_put_pixel.obj,[.ints]int10_vesa.obj,-
[.ints]mouse.obj,[.ints]xms.obj

# LIBS_OBJS = [.libs.zmbv]zmbv.obj
# ZMBV disabled - requires zlib which is not available
LIBS_OBJS =

MISC_OBJS = [.misc]messages.obj,[.misc]programs.obj,[.misc]setup.obj,-
[.misc]support.obj

SHELL_OBJS = [.shell]shell_batch.obj,[.shell]shell_cmds.obj,-
[.shell]shell.obj,[.shell]shell_misc.obj

MAIN_OBJS = []dosbox.obj

ALL_OBJS = $(CPU_OBJS),$(DOS_OBJS),$(FPU_OBJS),$(GUI_OBJS),$(HARDWARE_OBJS),-
$(SERIAL_OBJS),$(INTS_OBJS),$(MISC_OBJS),$(SHELL_OBJS),$(MAIN_OBJS)

# Main targets
all : setup_config dosbox.exe
	@ write sys$output "Build complete!"

# ---------------------------------------------------------------------------
# SETUP_CONFIG - stage CONFIG.H into the include directory, next to DOSBOX.H.
#
# WHY THIS EXISTS: include/dosbox.h does "#include ""config.h""" and is pulled
# in by essentially every source file, but CONFIG.H ships at the PROJECT ROOT
# (beside CONFIGURE.COM), not in the include directory. Nothing generates it -
# CONFIGURE.COM does not write CONFIG.H - so it must simply be in a directory
# the compiler searches. On OpenVMS the default /NESTED_INCLUDE_DIRECTORY is
# PRIMARY_FILE, meaning the quoted include inside DOSBOX.H is resolved relative
# to the .CPP being compiled (e.g. [.CPU]) and NOT relative to DOSBOX.H - so
# "it sits next to dosbox.h" is not by itself enough; the directory has to be
# in $(INCDIRS). Copying it next to DOSBOX.H puts it in a directory that is
# already proven reachable, which is why this is the reliable fix.
#
# The project root stays AUTHORITATIVE: the copy is refreshed on every build,
# so editing [-]CONFIG.H (e.g. toggling C_CORE_INLINE while performance
# testing) always takes effect and the staged copy can never go stale.
#
# DO NOT use CONFIG_VMS.H - it is stale and enables C_IPX and C_MODEM, whose
# objects (IPX.OBJ, IPXSERVER.OBJ, NULLMODEM.OBJ, SOFTMODEM.OBJ) are
# deliberately NOT in $(ALL_OBJS), so the link would fail on missing symbols.
setup_config :
	@ write sys$output "Staging CONFIG.H into the include directory..."
	- if (f$search("[-]CONFIG.H") .nes. "") .and. (f$search("[.INCLUDE]DOSBOX.H") .nes. "") then copy [-]CONFIG.H [.INCLUDE]CONFIG.H
	- if (f$search("[-]CONFIG.H") .nes. "") .and. (f$search("[-.INCLUDE]DOSBOX.H") .nes. "") then copy [-]CONFIG.H [-.INCLUDE]CONFIG.H
	- if (f$search("[-]CONFIG.H") .eqs. "") .and. (f$search("[]CONFIG.H") .nes. "") .and. (f$search("[.INCLUDE]DOSBOX.H") .nes. "") then copy []CONFIG.H [.INCLUDE]CONFIG.H
	- if f$search("[.INCLUDE]CONFIG.H") .nes. "" then purge/nolog/keep=1 [.INCLUDE]CONFIG.H
	- if f$search("[-.INCLUDE]CONFIG.H") .nes. "" then purge/nolog/keep=1 [-.INCLUDE]CONFIG.H
	@ if f$search("[.INCLUDE]CONFIG.H") .nes. "" then write sys$output "  ok: [.INCLUDE]CONFIG.H"
	@ if f$search("[-.INCLUDE]CONFIG.H") .nes. "" then write sys$output "  ok: [-.INCLUDE]CONFIG.H"
	@ if (f$search("[.INCLUDE]CONFIG.H") .eqs. "") .and. (f$search("[-.INCLUDE]CONFIG.H") .eqs. "") then write sys$output "  WARNING: no CONFIG.H staged - run MMK CHECK"

# ---------------------------------------------------------------------------
# $ MMK CHECK - diagnose "cannot find dosbox.h" WITHOUT running a compile.
# Run it from the source directory, exactly where you run MMK. Every FOUND
# line is a path the compiler will also find; if DOSBOX.H shows "missing" on
# all three, the headers are not where any relative path can reach them and
# you need to fix the layout (or add an entry to $(INCDIRS) above).
check :
	@ write sys$output ""
	@ write sys$output "=== DOSBox / OpenVMS build environment check ==="
	@ show default
	@ write sys$output ""
	@ write sys$output "--- DOSBOX.H (needs at least one FOUND) ---"
	@ if f$search("DOSBOX_INCLUDE:DOSBOX.H") .nes. "" then write sys$output "  FOUND    DOSBOX_INCLUDE:DOSBOX.H  (logical override in use)"
	@ if f$search("DOSBOX_INCLUDE:DOSBOX.H") .eqs. "" then write sys$output "  missing  DOSBOX_INCLUDE:DOSBOX.H  (logical not defined - optional)"
	@ if f$search("[.INCLUDE]DOSBOX.H") .nes. "" then write sys$output "  FOUND    [.INCLUDE]DOSBOX.H      (layout B: include inside src)"
	@ if f$search("[.INCLUDE]DOSBOX.H") .eqs. "" then write sys$output "  missing  [.INCLUDE]DOSBOX.H"
	@ if f$search("[-.INCLUDE]DOSBOX.H") .nes. "" then write sys$output "  FOUND    [-.INCLUDE]DOSBOX.H     (layout A: include beside src)"
	@ if f$search("[-.INCLUDE]DOSBOX.H") .eqs. "" then write sys$output "  missing  [-.INCLUDE]DOSBOX.H"
	@ if f$search("[--.INCLUDE]DOSBOX.H") .nes. "" then write sys$output "  FOUND    [--.INCLUDE]DOSBOX.H"
	@ if f$search("[--.INCLUDE]DOSBOX.H") .eqs. "" then write sys$output "  missing  [--.INCLUDE]DOSBOX.H"
	@ write sys$output ""
	@ write sys$output "--- CONFIG.H (needs at least one FOUND - see the SETUP_CONFIG target) ---"
	@ if f$search("[.INCLUDE]CONFIG.H") .nes. "" then write sys$output "  FOUND    [.INCLUDE]CONFIG.H     (staged beside DOSBOX.H)"
	@ if f$search("[.INCLUDE]CONFIG.H") .eqs. "" then write sys$output "  missing  [.INCLUDE]CONFIG.H"
	@ if f$search("[-.INCLUDE]CONFIG.H") .nes. "" then write sys$output "  FOUND    [-.INCLUDE]CONFIG.H    (staged beside DOSBOX.H)"
	@ if f$search("[-.INCLUDE]CONFIG.H") .eqs. "" then write sys$output "  missing  [-.INCLUDE]CONFIG.H"
	@ if f$search("[]CONFIG.H") .nes. "" then write sys$output "  FOUND    []CONFIG.H"
	@ if f$search("[]CONFIG.H") .eqs. "" then write sys$output "  missing  []CONFIG.H"
	@ if f$search("[-]CONFIG.H") .nes. "" then write sys$output "  FOUND    [-]CONFIG.H            (project root - AUTHORITATIVE copy)"
	@ if f$search("[-]CONFIG.H") .eqs. "" then write sys$output "  missing  [-]CONFIG.H            (project root - upload it there)"
	@ if f$search("[--]CONFIG.H") .nes. "" then write sys$output "  FOUND    [--]CONFIG.H"
	@ if f$search("[--]CONFIG.H") .eqs. "" then write sys$output "  missing  [--]CONFIG.H"
	@ if (f$search("[.INCLUDE]CONFIG.H") .eqs. "") .and. (f$search("[-.INCLUDE]CONFIG.H") .eqs. "") .and. (f$search("[]CONFIG.H") .eqs. "") .and. (f$search("[-]CONFIG.H") .eqs. "") then write sys$output "  *** CONFIG.H IS NOWHERE - upload it to the project root, then MMK SETUP_CONFIG"
	@ write sys$output "  NOTE: do NOT rename CONFIG_VMS.H to CONFIG.H - it is stale (C_IPX/C_MODEM)"
	@ write sys$output ""
	@ write sys$output "--- [.CPU] compiles (they SET DEFAULT [.CPU] first) ---"
	@ write sys$output "  From [.CPU], [-.INCLUDE] is this dir's [.INCLUDE] and"
	@ write sys$output "  [--.INCLUDE] is this dir's [-.INCLUDE] - both are in INCDIRS,"
	@ write sys$output "  so any FOUND above also covers the CPU files."
	@ if f$search("[.CPU]CPU.CPP") .nes. "" then write sys$output "  FOUND    [.CPU]CPU.CPP  (source tree looks right)"
	@ if f$search("[.CPU]CPU.CPP") .eqs. "" then write sys$output "  missing  [.CPU]CPU.CPP  -> wrong default directory for MMK"
	@ write sys$output ""
	@ write sys$output "--- SDL headers (logical name, must be defined) ---"
	- show logical SDL
	- show logical LIBSDL
	@ if f$search("SDL:SDL.H") .nes. "" then write sys$output "  FOUND    SDL:SDL.H"
	@ if f$search("SDL:SDL.H") .eqs. "" then write sys$output "  missing  SDL:SDL.H  -> DEFINE SDL dev:[path.SDL-1_2_14.include]"
	@ write sys$output ""
	@ write sys$output "=== end of check ==="

dosbox.exe : $(ALL_OBJS) x11_link.opt
	@ write sys$output "Linking DOSBOX.EXE..."
	$(LINK)$(LINKFLAGS) /EXE=dosbox.exe $(ALL_OBJS),-
	LIBSDL:LIBSDLMAIN/LIB,-
	LIBSDL:LIBVIDEO/LIB,-
	LIBSDL:LIBVIDEO_X11/LIB,-
	LIBSDL:LIBJOYSTICK/LIB,-
	LIBSDL:LIBEVENTS/LIB,-
	LIBSDL:LIBFILE/LIB,-
	LIBSDL:LIBAUDIO/LIB,-
	LIBSDL:LIBCDROM/LIB,-
	LIBSDL:LIBTIMER/LIB,-
	LIBSDL:LIBCPUINFO/LIB,-
	LIBSDL:LIBTHREAD/LIB,-
	LIBSDL:LIBTHREAD_GENERIC/LIB,-
	LIBSDL:LIBLOADSO/LIB,-
	LIBSDL:STDLIB/LIB,-
	LIBSDL:LIBSDL/LIB,-
	[]x11_link.opt/OPTIONS

x11_link.opt :
	@ open/write optfile x11_link.opt
	@ write optfile "SYS$SHARE:DECW$XLIBSHR.EXE/SHARE"
	@ write optfile "SYS$SHARE:DECW$XTLIBSHRR5.EXE/SHARE"
	@ write optfile "SYS$SHARE:DECW$XMULIBSHRR5.EXE/SHARE"
	@ write optfile "SYS$SHARE:DECW$XEXTLIBSHR.EXE/SHARE"
	@ write optfile "SYS$SHARE:DECW$XMLIBSHR12.EXE/SHARE"
	@ close optfile

DOSBOX_LINK.OPT :
	@ open/write optfile DOSBOX_LINK.OPT
	@ write optfile "! Link options for DOSBox"
	@ write optfile "[.cpu]callback.obj,[.cpu]core_full.obj,[.cpu]core_normal.obj,[.cpu]core_simple.obj"
	@ write optfile "[.cpu]cpu.obj,[.cpu]flags.obj,[.cpu]modrm.obj,[.cpu]paging.obj"
	@ write optfile "[.dos]cdrom.obj,[.dos]cdrom_image.obj,[.dos]dos_classes.obj,[.dos]dos.obj"
	@ write optfile "[.dos]dos_devices.obj,[.dos]dos_execute.obj,[.dos]dos_files.obj,[.dos]dos_ioctl.obj"
	@ write optfile "[.dos]dos_keyboard_layout.obj,[.dos]dos_memory.obj,[.dos]dos_misc.obj"
	@ write optfile "[.dos]dos_mscdex.obj,[.dos]dos_programs.obj,[.dos]dos_tables.obj"
	@ write optfile "[.dos]drive_cache.obj,[.dos]drive_fat.obj,[.dos]drive_iso.obj,[.dos]drive_local.obj"
	@ write optfile "[.dos]drives.obj,[.dos]drive_virtual.obj,[.fpu]fpu.obj"
	@ write optfile "[.gui]midi.obj,[.gui]render.obj,[.gui]render_scalers.obj,[.gui]sdlmain.obj,[.gui]sdl_mapper.obj"
	@ write optfile "[.hardware]adlib.obj,[.hardware]cmos.obj,[.hardware]disney.obj,[.hardware]dma.obj"
	@ write optfile "[.hardware]gameblaster.obj,[.hardware]gus.obj,[.hardware]hardware.obj"
	@ write optfile "[.hardware]iohandler.obj,[.hardware]joystick.obj,[.hardware]keyboard.obj"
	@ write optfile "[.hardware]memory.obj,[.hardware]mixer.obj,[.hardware]mpu401.obj"
	@ write optfile "[.hardware]pcspeaker.obj,[.hardware]pic.obj,[.hardware]sblaster.obj"
	@ write optfile "[.hardware]tandy_sound.obj,[.hardware]timer.obj"
	@ write optfile "[.hardware]vga_attr.obj,[.hardware]vga.obj,[.hardware]vga_crtc.obj,[.hardware]vga_dac.obj"
	@ write optfile "[.hardware]vga_draw.obj,[.hardware]vga_gfx.obj,[.hardware]vga_memory.obj"
	@ write optfile "[.hardware]vga_misc.obj,[.hardware]vga_other.obj,[.hardware]vga_s3.obj"
	@ write optfile "[.hardware]vga_seq.obj,[.hardware]vga_xga.obj"
	@ write optfile "[.hardware.serialport]misc_util.obj,[.hardware.serialport]serialdummy.obj"
	@ write optfile "[.hardware.serialport]serialport.obj"
	@ write optfile "[.ints]bios.obj,[.ints]bios_disk.obj,[.ints]bios_keyboard.obj,[.ints]ems.obj"
	@ write optfile "[.ints]int10_char.obj,[.ints]int10.obj,[.ints]int10_memory.obj"
	@ write optfile "[.ints]int10_misc.obj,[.ints]int10_modes.obj,[.ints]int10_pal.obj"
	@ write optfile "[.ints]int10_put_pixel.obj,[.ints]int10_vesa.obj,[.ints]mouse.obj,[.ints]xms.obj"
	@ write optfile "[.misc]messages.obj,[.misc]programs.obj,[.misc]setup.obj,[.misc]support.obj"
	@ write optfile "[.shell]shell_batch.obj,[.shell]shell_cmds.obj,[.shell]shell.obj,[.shell]shell_misc.obj"
	@ write optfile "[]dosbox.obj"
	@ write optfile "LIBSDL:LIBSDL/LIB"
	@ write optfile "LIBSDL:LIBSDLMAIN/LIB"
	@ write optfile "LIBSDL:LIBVIDEO/LIB"
	@ write optfile "LIBSDL:LIBVIDEO_X11/LIB"
	@ write optfile "LIBSDL:LIBJOYSTICK/LIB"
	@ write optfile "LIBSDL:LIBEVENTS/LIB"
	@ write optfile "LIBSDL:LIBFILE/LIB"
	@ write optfile "LIBSDL:LIBAUDIO/LIB"
	@ write optfile "LIBSDL:LIBCDROM/LIB"
	@ write optfile "LIBSDL:LIBTIMER/LIB"
	@ write optfile "LIBSDL:LIBCPUINFO/LIB"
	@ write optfile "LIBSDL:LIBTHREAD/LIB"
	@ write optfile "LIBSDL:LIBTHREAD_GENERIC/LIB"
	@ write optfile "LIBSDL:LIBLOADSO/LIB"
	@ write optfile "LIBSDL:STDLIB/LIB"
	@ close optfile

dosbox.olb : $(ALL_OBJS)
	@ write sys$output "Creating DOSBOX.OLB..."
	@ if f$search("dosbox.olb") .nes. "" then library /delete dosbox.olb *
	@ if f$search("dosbox.olb") .nes. "" then delete dosbox.olb;*
	library /create dosbox.olb $(ALL_OBJS)

clean :
	@ write sys$output "Cleaning object files..."
	- delete [.cpu]*.obj;*
	- delete [.dos]*.obj;*
	- delete [.fpu]*.obj;*
	- delete [.gui]*.obj;*
	- delete [.hardware]*.obj;*
	- delete [.hardware.serialport]*.obj;*
	- delete [.ints]*.obj;*
	- delete [.libs.zmbv]*.obj;*
	- delete [.misc]*.obj;*
	- delete [.shell]*.obj;*
	- delete dosbox.obj;*
	- delete dosbox.exe;*
	- delete dosbox.olb;*
	@ write sys$output "Clean complete!"

# Suffix rules for C++ compilation
.SUFFIXES
.SUFFIXES .OBJ .CPP

.CPP.OBJ :
	$(CXX) $(CXXFLAGS) /OBJECT=$(MMS$TARGET) $(MMS$SOURCE)

# Explicit dependencies - tell MMS where source files are
# CPU files with special handling for local includes
[.cpu]callback.obj : [.cpu]callback.cpp
	SET DEFAULT [.CPU]
	$(CXX) $(CXXFLAGS_CPU) /OBJECT=callback.obj callback.cpp
	SET DEFAULT [-]

[.cpu]core_full.obj : [.cpu]core_full.cpp
	SET DEFAULT [.CPU]
	$(CXX) $(CXXFLAGS_CPU) /OBJECT=core_full.obj core_full.cpp
	SET DEFAULT [-]

# HOT PATH: CPU interpreter, runs every emulated instruction. See HOTOPT above.
[.cpu]core_normal.obj : [.cpu]core_normal.cpp
	SET DEFAULT [.CPU]
	$(CXX) $(CXXFLAGS_CPU_HOT) /OBJECT=core_normal.obj core_normal.cpp
	SET DEFAULT [-]

# core_simple.cpp was /NOOPTIMIZE (compiler ACCVIO); now built at $(OPT).
# Fallback if it still crashes:
#	$(CXX) $(CXXFLAGS_CPU_NOWARN)/NOOPTIMIZE /OBJECT=core_simple.obj core_simple.cpp
[.cpu]core_simple.obj : [.cpu]core_simple.cpp
	SET DEFAULT [.CPU]
	$(CXX) $(CXXFLAGS_CPU) /OBJECT=core_simple.obj core_simple.cpp
	SET DEFAULT [-]

[.cpu]cpu.obj : [.cpu]cpu.cpp
	SET DEFAULT [.CPU]
	$(CXX) $(CXXFLAGS_CPU) /OBJECT=cpu.obj cpu.cpp
	SET DEFAULT [-]

[.cpu]flags.obj : [.cpu]flags.cpp
	SET DEFAULT [.CPU]
	$(CXX) $(CXXFLAGS_CPU) /OBJECT=flags.obj flags.cpp
	SET DEFAULT [-]

[.cpu]modrm.obj : [.cpu]modrm.cpp
	SET DEFAULT [.CPU]
	$(CXX) $(CXXFLAGS_CPU) /OBJECT=modrm.obj modrm.cpp
	SET DEFAULT [-]

[.cpu]paging.obj : [.cpu]paging.cpp
	SET DEFAULT [.CPU]
	$(CXX) $(CXXFLAGS_CPU) /OBJECT=paging.obj paging.cpp
	SET DEFAULT [-]

[.dos]cdrom.obj : [.dos]cdrom.cpp

# cdrom_image.cpp - omit warning disables (they were implicated in the ACCVIO).
# Now optimized at $(OPT). Fallback: append /NOOPTIMIZE to the command below.
[.dos]cdrom_image.obj : [.dos]cdrom_image.cpp
	$(CXX) $(CXXFLAGS_NOWARN) /OBJECT=$(MMS$TARGET) $(MMS$SOURCE)
[.dos]dos_classes.obj : [.dos]dos_classes.cpp
[.dos]dos.obj : [.dos]dos.cpp
[.dos]dos_devices.obj : [.dos]dos_devices.cpp
[.dos]dos_execute.obj : [.dos]dos_execute.cpp
[.dos]dos_files.obj : [.dos]dos_files.cpp
[.dos]dos_ioctl.obj : [.dos]dos_ioctl.cpp
[.dos]dos_keyboard_layout.obj : [.dos]dos_keyboard_layout.cpp
[.dos]dos_memory.obj : [.dos]dos_memory.cpp
[.dos]dos_misc.obj : [.dos]dos_misc.cpp
[.dos]dos_mscdex.obj : [.dos]dos_mscdex.cpp

# dos_programs.cpp - WARNING disables cause ACCVIO, omit them for this file only.
# Now optimized at $(OPT). Fallback: append /NOOPTIMIZE to the command below.
[.dos]dos_programs.obj : [.dos]dos_programs.cpp
	$(CXX) $(CXXFLAGS_NOWARN) /OBJECT=$(MMS$TARGET) $(MMS$SOURCE)

[.dos]dos_tables.obj : [.dos]dos_tables.cpp
[.dos]drive_cache.obj : [.dos]drive_cache.cpp
[.dos]drive_fat.obj : [.dos]drive_fat.cpp
[.dos]drive_iso.obj : [.dos]drive_iso.cpp
[.dos]drive_local.obj : [.dos]drive_local.cpp
[.dos]drives.obj : [.dos]drives.cpp
[.dos]drive_virtual.obj : [.dos]drive_virtual.cpp
[.dos]vms_filesystem.obj : [.dos]vms_filesystem.cpp

[.fpu]fpu.obj : [.fpu]fpu.cpp

[.gui]midi.obj : [.gui]midi.cpp

# HOT PATH: per-frame render pipeline. Built at $(HOTOPT) = $(OPT); lower
# HOTOPT above if the compiler ACCVIOs on the render files specifically.
[.gui]render.obj : [.gui]render.cpp
	$(CXX) $(CXXFLAGS_HOT) /OBJECT=$(MMS$TARGET) $(MMS$SOURCE)

# HOT PATH: pixel scalers, run for every output pixel. See HOTOPT above.
[.gui]render_scalers.obj : [.gui]render_scalers.cpp
	$(CXX) $(CXXFLAGS_HOT) /OBJECT=$(MMS$TARGET) $(MMS$SOURCE)

# sdlmain.cpp - omit warning disables (implicated in earlier ACCVIO).
# Now optimized at $(OPT). Fallback: append /NOOPTIMIZE to the command below.
[.gui]sdlmain.obj : [.gui]sdlmain.cpp
	$(CXX) $(CXXFLAGS_NOWARN) /OBJECT=$(MMS$TARGET) $(MMS$SOURCE)

# sdl_mapper.cpp - omit warning disables (implicated in earlier ACCVIO).
# Now optimized at $(OPT). Fallback: append /NOOPTIMIZE to the command below.
[.gui]sdl_mapper.obj : [.gui]sdl_mapper.cpp
	$(CXX) $(CXXFLAGS_NOWARN) /OBJECT=$(MMS$TARGET) $(MMS$SOURCE)

# adlib.cpp - omit warning disables, suppress sign change warnings.
# Now optimized at $(OPT). Fallback: append /NOOPTIMIZE to the command below.
[.hardware]adlib.obj : [.hardware]adlib.cpp
	$(CXX) $(CXXFLAGS_ADLIB) /OBJECT=$(MMS$TARGET) $(MMS$SOURCE)
[.hardware]cmos.obj : [.hardware]cmos.cpp
[.hardware]disney.obj : [.hardware]disney.cpp
[.hardware]dma.obj : [.hardware]dma.cpp
[.hardware]gameblaster.obj : [.hardware]gameblaster.cpp
[.hardware]gus.obj : [.hardware]gus.cpp
[.hardware]hardware.obj : [.hardware]hardware.cpp
[.hardware]iohandler.obj : [.hardware]iohandler.cpp
[.hardware]ipx.obj : [.hardware]ipx.cpp
[.hardware]ipxserver.obj : [.hardware]ipxserver.cpp
[.hardware]joystick.obj : [.hardware]joystick.cpp
[.hardware]keyboard.obj : [.hardware]keyboard.cpp
[.hardware]memory.obj : [.hardware]memory.cpp
[.hardware]mixer.obj : [.hardware]mixer.cpp
[.hardware]mpu401.obj : [.hardware]mpu401.cpp
[.hardware]pcspeaker.obj : [.hardware]pcspeaker.cpp
[.hardware]pic.obj : [.hardware]pic.cpp
[.hardware]sblaster.obj : [.hardware]sblaster.cpp
[.hardware]tandy_sound.obj : [.hardware]tandy_sound.cpp
[.hardware]timer.obj : [.hardware]timer.cpp
[.hardware]vga_attr.obj : [.hardware]vga_attr.cpp
[.hardware]vga.obj : [.hardware]vga.cpp
[.hardware]vga_crtc.obj : [.hardware]vga_crtc.cpp
[.hardware]vga_dac.obj : [.hardware]vga_dac.cpp
[.hardware]vga_draw.obj : [.hardware]vga_draw.cpp
[.hardware]vga_gfx.obj : [.hardware]vga_gfx.cpp
[.hardware]vga_memory.obj : [.hardware]vga_memory.cpp
[.hardware]vga_misc.obj : [.hardware]vga_misc.cpp
[.hardware]vga_other.obj : [.hardware]vga_other.cpp
[.hardware]vga_s3.obj : [.hardware]vga_s3.cpp
[.hardware]vga_seq.obj : [.hardware]vga_seq.cpp
[.hardware]vga_xga.obj : [.hardware]vga_xga.cpp

[.hardware.serialport]misc_util.obj : [.hardware.serialport]misc_util.cpp
[.hardware.serialport]nullmodem.obj : [.hardware.serialport]nullmodem.cpp
[.hardware.serialport]serialdummy.obj : [.hardware.serialport]serialdummy.cpp
[.hardware.serialport]serialport.obj : [.hardware.serialport]serialport.cpp
[.hardware.serialport]softmodem.obj : [.hardware.serialport]softmodem.cpp

[.ints]bios.obj : [.ints]bios.cpp
[.ints]bios_disk.obj : [.ints]bios_disk.cpp
[.ints]bios_keyboard.obj : [.ints]bios_keyboard.cpp
[.ints]ems.obj : [.ints]ems.cpp
[.ints]int10_char.obj : [.ints]int10_char.cpp
[.ints]int10.obj : [.ints]int10.cpp
[.ints]int10_memory.obj : [.ints]int10_memory.cpp
[.ints]int10_misc.obj : [.ints]int10_misc.cpp
[.ints]int10_modes.obj : [.ints]int10_modes.cpp
[.ints]int10_pal.obj : [.ints]int10_pal.cpp
[.ints]int10_put_pixel.obj : [.ints]int10_put_pixel.cpp
[.ints]int10_vesa.obj : [.ints]int10_vesa.cpp
[.ints]mouse.obj : [.ints]mouse.cpp
[.ints]xms.obj : [.ints]xms.cpp

[.libs.zmbv]zmbv.obj : [.libs.zmbv]zmbv.cpp

[.misc]messages.obj : [.misc]messages.cpp
[.misc]programs.obj : [.misc]programs.cpp
[.misc]setup.obj : [.misc]setup.cpp
[.misc]support.obj : [.misc]support.cpp

[.shell]shell_batch.obj : [.shell]shell_batch.cpp
[.shell]shell_cmds.obj : [.shell]shell_cmds.cpp
[.shell]shell.obj : [.shell]shell.cpp
[.shell]shell_misc.obj : [.shell]shell_misc.cpp

# dosbox.cpp - main entry point
[]dosbox.obj : dosbox.cpp
	$(CXX) $(CXXFLAGS) /OBJECT=$(MMS$TARGET) $(MMS$SOURCE)
