BUILD_DIR := build
.DEFAULT_GOAL := all
LOGS_DIR := $(BUILD_DIR)/LOGS
SCREENSHOTS_DIR := $(BUILD_DIR)/Screenshots
DATA_DIR := $(BUILD_DIR)/Data
REPORTS_DIR := $(BUILD_DIR)/Reports
GENERATED_DIR := $(BUILD_DIR)/generated
APPS_OUT_DIR  := $(BUILD_DIR)/Compiled_Apps
DESKTOP_ALIAS_DIR := $(BUILD_DIR)/Desktop_Aliases
COMPILED_ELF_DIR := $(BUILD_DIR)/compiled_elfs
DIAGNOSTICS_DIR := $(BUILD_DIR)/diagnostics
KERNEL_OUT_DIR := $(BUILD_DIR)/Kernel_Output
BOOT_OUT_DIR := $(BUILD_DIR)/Boot
TESTS_OUT_DIR := $(BUILD_DIR)/Tests
EXPERIMENTS_DIR := experiments
HAMNET_DIR ?= ../HamNet
HAMNET_CORE_DIR := $(HAMNET_DIR)/core
HAMNET_MONOCYPHER_DIR := $(HAMNET_DIR)/third_party/monocypher
HAMNET_PLATFORM_DIR := $(HAMNET_DIR)/platforms/hamsteros
HAMNET_APP_DIR := $(HAMNET_PLATFORM_DIR)/src
HAMNET_TEST_DIR := $(HAMNET_PLATFORM_DIR)/tests
HAMNET_CORE_INCLUDES := -I$(HAMNET_CORE_DIR)/include -I$(HAMNET_MONOCYPHER_DIR)
HAMNET_APP_INCLUDES := $(HAMNET_CORE_INCLUDES) -I$(HAMNET_APP_DIR)
HAMCHAT_DIR := $(HAMNET_DIR)/hamchat
HAMCHAT_CORE_DIR := $(HAMCHAT_DIR)/core
HAMCHAT_PLATFORM_DIR := $(HAMCHAT_DIR)/platforms/hamsteros
HAMCHAT_APP_DIR := $(HAMCHAT_PLATFORM_DIR)/src
HAMCHAT_CORE_INCLUDES := -I$(HAMCHAT_CORE_DIR)/include
HAMCHAT_APP_INCLUDES := $(HAMNET_CORE_INCLUDES) $(HAMCHAT_CORE_INCLUDES) -I$(HAMCHAT_APP_DIR)
KERNEL_ELF := $(COMPILED_ELF_DIR)/hamster.elf
FREEDOS_ZIP := $(BUILD_DIR)/freedos/FDT2607-FloppyEdition.zip
FREEDOS_IMG := $(BUILD_DIR)/hamster.img
INSTALL_TARGET_IMG := $(BUILD_DIR)/install-target-20mb.img
HAMLOAD_META := $(GENERATED_DIR)/hamster_kernel.inc
APP_SDK_SERVICES_H := $(GENERATED_DIR)/app_sdk_services.h
HAMLOAD_KERNEL_BIN := $(KERNEL_OUT_DIR)/hamster-dos.bin
HAMLOAD_ELF := $(COMPILED_ELF_DIR)/hamload.elf
HAMLOAD_BIN := $(BOOT_OUT_DIR)/hamload.bin
HAMLOAD_EXE := $(BOOT_OUT_DIR)/HAMLOAD.EXE
HAMLOAD_BUFFER_REL_PARAS := 0x0600
HAMLOAD_BUFFER_PARAS := 0x7100
HAMLOAD_MZ_MINALLOC_PARAS := 0x7400
HAMLOAD_PRELOAD_DRIVERS := \
	$(APPS_OUT_DIR)/PICOMEM.DRV \
	$(APPS_OUT_DIR)/MCAFD.DRV \
	$(APPS_OUT_DIR)/IBMSCSI.DRV
REBOOT_ELF := $(COMPILED_ELF_DIR)/reboot.elf
REBOOT_COM := $(BOOT_OUT_DIR)/REBOOT.COM
CHOICE_ELF := $(COMPILED_ELF_DIR)/choice.elf
CHOICE_COM := $(BOOT_OUT_DIR)/CHOICE.COM
IMLCHK_ELF := $(COMPILED_ELF_DIR)/imlchk.elf
IMLCHK_COM := $(BOOT_OUT_DIR)/IMLCHK.COM
SETBLUE_ELF := $(COMPILED_ELF_DIR)/setblue.elf
SETBLUE_COM := $(BOOT_OUT_DIR)/SETBLUE.COM
SETUPUI_ELF := $(COMPILED_ELF_DIR)/setupui.elf
SETUPUI_COM := $(BOOT_OUT_DIR)/SETUPUI.COM
VIDTEST_ELF := $(COMPILED_ELF_DIR)/vidtest.elf
VIDTEST_COM := $(DIAGNOSTICS_DIR)/VIDTEST.COM
HOST_CC ?= cc
HOST_TEST_CFLAGS := -std=c11 -Wall -Wextra -O2 -Ikernel -Idrivers -Iapps -Ifs -I$(GENERATED_DIR) $(HAMNET_CORE_INCLUDES)
FLOPPY_FORMAT_SMOKETEST_BIN := $(TESTS_OUT_DIR)/floppy_format_smoketest
PS2MOUSE_SMOKETEST_BIN := $(TESTS_OUT_DIR)/ps2mouse_decode_smoketest
USBMOUSE_SMOKETEST_BIN := $(TESTS_OUT_DIR)/usbmouse_smoketest
INPUT_ROUTER_SMOKETEST_BIN := $(TESTS_OUT_DIR)/input_router_smoketest
EVENT_SMOKETEST_BIN := $(TESTS_OUT_DIR)/event_smoketest
UI_CONTRACT_SMOKETEST_BIN := $(TESTS_OUT_DIR)/ui_contract_smoketest
FILE_MANAGER_COMMANDS_SMOKETEST_BIN := $(TESTS_OUT_DIR)/file_manager_commands_smoketest
FILE_ICONS_SMOKETEST_BIN := $(TESTS_OUT_DIR)/file_icons_smoketest
ZIP_CREATE_SMOKETEST_BIN := $(TESTS_OUT_DIR)/zip_create_smoketest
LAUNCH_CONTRACT_SMOKETEST_BIN := $(TESTS_OUT_DIR)/launch_contract_smoketest
DOS_SESSION_SMOKETEST_BIN := $(TESTS_OUT_DIR)/dos_session_smoketest
PATH_CONTRACT_SMOKETEST_BIN := $(TESTS_OUT_DIR)/path_contract_smoketest
FILE_CONTRACT_SMOKETEST_BIN := $(TESTS_OUT_DIR)/file_contract_smoketest
VOLUME_GENERATION_SMOKETEST_BIN := $(TESTS_OUT_DIR)/volume_generation_smoketest
DIRECTORY_CACHE_SMOKETEST_BIN := $(TESTS_OUT_DIR)/directory_cache_smoketest
VFAT_SMOKETEST_BIN := $(TESTS_OUT_DIR)/vfat_smoketest
BITMAP_SMOKETEST_BIN := $(TESTS_OUT_DIR)/bitmap_smoketest
VIDEO_PROFILE_SMOKETEST_BIN := $(TESTS_OUT_DIR)/video_profile_smoketest
XGA2_SMOKETEST_BIN := $(TESTS_OUT_DIR)/xga2_smoketest
SURFACE_SMOKETEST_BIN := $(TESTS_OUT_DIR)/surface_smoketest
VGA_PLANAR_PACK_SMOKETEST_BIN := $(TESTS_OUT_DIR)/vga_planar_pack_smoketest
VGA_PRIMITIVES_C_SMOKETEST_BIN := $(TESTS_OUT_DIR)/vga_primitives_c_smoketest
VGA_PRIMITIVES_REP_SMOKETEST_BIN := $(TESTS_OUT_DIR)/vga_primitives_rep_smoketest
VGA_SPRITE_ROWS_SMOKETEST_BIN := $(TESTS_OUT_DIR)/vga_sprite_rows_smoketest
AUDIO_MANAGER_SMOKETEST_BIN := $(TESTS_OUT_DIR)/audio_manager_smoketest
ADLIB_DRIVER_SMOKETEST_BIN := $(TESTS_OUT_DIR)/adlib_driver_smoketest
SB16_DRIVER_SMOKETEST_BIN := $(TESTS_OUT_DIR)/sb16_driver_smoketest
NE2000_DRIVER_SMOKETEST_BIN := $(TESTS_OUT_DIR)/ne2000_driver_smoketest
RTL8139_DRIVER_SMOKETEST_BIN := $(TESTS_OUT_DIR)/rtl8139_driver_smoketest
SBC82621_DRIVER_SMOKETEST_BIN := $(TESTS_OUT_DIR)/sbc82621_driver_smoketest
NETCORE_HTTP_SMOKETEST_BIN := $(TESTS_OUT_DIR)/netcore_http_smoketest
PICOMEM_DRIVER_SMOKETEST_BIN := $(TESTS_OUT_DIR)/picomem_driver_smoketest
CH375_DRIVER_SMOKETEST_BIN := $(TESTS_OUT_DIR)/ch375_driver_smoketest
CDPLAYER_SMOKETEST_BIN := $(TESTS_OUT_DIR)/cdplayer_smoketest
HAMSHARE_SMOKETEST_BIN := $(TESTS_OUT_DIR)/hamshare_smoketest
SPEAKER_SMOKETEST_BIN := $(TESTS_OUT_DIR)/speaker_smoketest
STORAGE_SMOKETEST_BIN := $(TESTS_OUT_DIR)/storage_smoketest
ATA_SMOKETEST_BIN := $(TESTS_OUT_DIR)/ata_smoketest
IBM_MCA_SCSI_SMOKETEST_BIN := $(TESTS_OUT_DIR)/ibm_mca_scsi_smoketest
ISO9660_MODULE_SMOKETEST_BIN := $(TESTS_OUT_DIR)/iso9660_module_smoketest
WAVEPLAYER_SMOKETEST_BIN := $(TESTS_OUT_DIR)/waveplayer_smoketest
MP3_BENCH_MINIMP3 := $(BUILD_DIR)/Bench/mp3bench-minimp3
MP3_BENCH_MPG123 := $(BUILD_DIR)/Bench/mp3bench-mpg123
MP3_BENCH_INPUT ?= $(BUILD_DIR)/Artifacts/ENYA.MP3
MP3_BENCH_OUTPUT_HZ ?= 12000
HAMSHEET_FORMULA_SMOKETEST_BIN := $(TESTS_OUT_DIR)/hamster_sheets_formula_smoketest
DRIVER_CONTRACT_SMOKETEST_BIN := $(TESTS_OUT_DIR)/driver_contract_smoketest
DRIVER_LOADER_RESOURCES_SMOKETEST_BIN := $(TESTS_OUT_DIR)/driver_loader_resources_smoketest
TASK_SMOKETEST_BIN := $(TESTS_OUT_DIR)/task_smoketest
APP_FAULT_PROBE_ELF := $(TESTS_OUT_DIR)/app_fault_probe.elf
APP_FAULT_PROBE_APP := $(TESTS_OUT_DIR)/FAULT.APP
PREEMPT_PROBE_ELF := $(TESTS_OUT_DIR)/preempt_probe.elf
PREEMPT_PROBE_APP := $(TESTS_OUT_DIR)/PREEMPT.APP
CRYPTO_PROBE_ELF := $(TESTS_OUT_DIR)/crypto_runtime_probe.elf
CRYPTO_PROBE_APP := $(TESTS_OUT_DIR)/CRYPTOT.APP
HTTP11_SMOKETEST_BIN := $(TESTS_OUT_DIR)/http11_smoketest
HAMNET_SCAN_SMOKETEST_BIN := $(TESTS_OUT_DIR)/hamnet_scan_smoketest
HAMNET_ONLINE_SMOKETEST_BIN := $(TESTS_OUT_DIR)/hamnet_online_smoketest
ENTROPY_SMOKETEST_BIN := $(TESTS_OUT_DIR)/entropy_smoketest
INFLATE_SMOKETEST_BIN := $(TESTS_OUT_DIR)/inflate_smoketest
PAYLOAD_EXPAND_SMOKETEST_BIN := $(TESTS_OUT_DIR)/payload_expand_smoketest
FAST_MEMORY_SMOKETEST_BIN := $(TESTS_OUT_DIR)/fast_memory_smoketest
UPDATE_SCAN_SMOKETEST_BIN := $(TESTS_OUT_DIR)/update_scan_smoketest
UPDATE_APP_SCAN_SMOKETEST_BIN := $(TESTS_OUT_DIR)/update_app_scan_smoketest
APP_HDD_PREPARE_SMOKETEST_BIN := $(TESTS_OUT_DIR)/app_hdd_prepare_smoketest
VM86_MODULE_TEST_OBJ := $(TESTS_OUT_DIR)/vm86_module_exit.o
VM86_MODULE_TEST_ELF := $(TESTS_OUT_DIR)/vm86_module_exit.elf
VM86_MODULE_TEST_COM := $(TESTS_OUT_DIR)/VM86T.COM
VM86_EXE_TEST_OBJ := $(TESTS_OUT_DIR)/vm86_module_exit_exe.o
VM86_EXE_TEST_ELF := $(TESTS_OUT_DIR)/vm86_module_exit_exe.elf
VM86_EXE_TEST_EXE := $(TESTS_OUT_DIR)/VM86E.EXE
VM86_HANG_TEST_OBJ := $(TESTS_OUT_DIR)/vm86_hang.o
VM86_HANG_TEST_ELF := $(TESTS_OUT_DIR)/vm86_hang.elf
VM86_HANG_TEST_COM := $(TESTS_OUT_DIR)/VM86H.COM
EXTRAS_INSTALL_ELF := $(COMPILED_ELF_DIR)/extras_install_app.elf
EXTRAS_INSTALL_APP := $(APPS_OUT_DIR)/EXSETUP.APP
HDMBR_ELF := $(COMPILED_ELF_DIR)/hdmbr.elf
HDMBR_BIN := $(BOOT_OUT_DIR)/HDMBR.BIN
HDBOOT_ELF := $(COMPILED_ELF_DIR)/hdboot.elf
HDBOOT_BIN := $(BOOT_OUT_DIR)/HDBOOT.BIN
HDSTAGE2_ELF := $(COMPILED_ELF_DIR)/hdstage2.elf
HDSTAGE2_BIN := $(BOOT_OUT_DIR)/HDSTAGE2.BIN
PMHELLO_ELF := $(COMPILED_ELF_DIR)/pmhello.elf
PMHELLO_BIN := $(DIAGNOSTICS_DIR)/pmhello.bin
PMHELLO_EXE := $(DIAGNOSTICS_DIR)/PMHELLO.EXE
NOTEPAD_ELF := $(COMPILED_ELF_DIR)/notepad_app.elf
NOTEPAD_APP := $(APPS_OUT_DIR)/NOTEPAD.APP
HAMWRITE_ELF := $(COMPILED_ELF_DIR)/hamwrite_app.elf
HAMWRITE_APP := $(APPS_OUT_DIR)/HAMWRITE.APP
HAMSHEET_ELF := $(COMPILED_ELF_DIR)/hamster_sheets_app.elf
HAMSHEET_APP := $(APPS_OUT_DIR)/HAMSHEET.APP
PIANO_ELF   := $(COMPILED_ELF_DIR)/piano_app.elf
PIANO_APP   := $(APPS_OUT_DIR)/PIANO.APP
CLOCK_ELF   := $(COMPILED_ELF_DIR)/clock_app.elf
CLOCK_APP   := $(APPS_OUT_DIR)/CLOCK.APP
CALC_ELF    := $(COMPILED_ELF_DIR)/calc_app.elf
CALC_APP    := $(APPS_OUT_DIR)/CALC.APP
PREFS_ELF   := $(COMPILED_ELF_DIR)/prefs_app.elf
PREFS_APP   := $(APPS_OUT_DIR)/PREFS.APP
FIND_ELF    := $(COMPILED_ELF_DIR)/find_app.elf
FIND_APP    := $(APPS_OUT_DIR)/FIND.APP
IMGVIEW_ELF := $(COMPILED_ELF_DIR)/imgview_app.elf
IMGVIEW_APP := $(APPS_OUT_DIR)/IMGVIEW.APP
IMGVIEW_ICO := $(APPS_OUT_DIR)/IMGVIEW.ICO
AUDPLAY_ELF := $(COMPILED_ELF_DIR)/audplay_app.elf
AUDPLAY_APP := $(APPS_OUT_DIR)/AUDPLAY.APP
AUDPLAY_ICO := $(APPS_OUT_DIR)/AUDPLAY.ICO
MPG123_DIR := third_party/mpg123
MPG123_BUILD_DIR := $(BUILD_DIR)/third_party/mpg123
MPG123_LIB := $(MPG123_BUILD_DIR)/libmpg123.a
MPG123_NAMES := parse frame format dct64 id3 optimize readers tabinit \
	libmpg123 index layer3 synth_8bit synth feature stringbuf dct64_i386
MPG123_OBJECTS := $(addprefix $(MPG123_BUILD_DIR)/,$(addsuffix .o,$(MPG123_NAMES)))
HAMNET_ELF  := $(COMPILED_ELF_DIR)/hamnet_app.elf
HAMNET_APP  := $(APPS_OUT_DIR)/HAMNET.APP
HAMNET_ICO  := $(APPS_OUT_DIR)/HAMNET.ICO
HAMNET_DESKTOP_ALIAS := $(DESKTOP_ALIAS_DIR)/HAMNET.APP
HAMCHAT_ELF := $(COMPILED_ELF_DIR)/hamchat_app.elf
HAMCHAT_APP := $(APPS_OUT_DIR)/HAMCHAT.APP
HAMCHAT_ICO := $(APPS_OUT_DIR)/HAMCHAT.ICO
IMAGEDEC_ELF := $(COMPILED_ELF_DIR)/imagedec_dll.elf
IMAGEDEC_DLL := $(APPS_OUT_DIR)/IMAGEDEC.DLL
MP3CODEC_ELF := $(COMPILED_ELF_DIR)/mp3_dll.elf
MP3CODEC_DLL := $(APPS_OUT_DIR)/MP3.DLL
AUDIOFORMAT_ELF := $(COMPILED_ELF_DIR)/audio_dll.elf
AUDIOFORMAT_DLL := $(APPS_OUT_DIR)/AUDIO.DLL
CRYPTO_DLL_ELF := $(COMPILED_ELF_DIR)/crypto_dll.elf
CRYPTO_DLL     := $(APPS_OUT_DIR)/CRYPTO.DLL
ZIP_DLL_ELF  := $(COMPILED_ELF_DIR)/zip_dll.elf
ZIP_DLL      := $(APPS_OUT_DIR)/ZIP.DLL
APPFAST_DLL_ELF := $(COMPILED_ELF_DIR)/appfast_dll.elf
APPFAST_DLL     := $(APPS_OUT_DIR)/APPFAST.DLL
FILEDLG_DLL_ELF := $(COMPILED_ELF_DIR)/filedlg_dll.elf
FILEDLG_DLL     := $(APPS_OUT_DIR)/FILEDLG.DLL
SAVER_DLL_ELF   := $(COMPILED_ELF_DIR)/saver_dll.elf
SAVER_DLL       := $(APPS_OUT_DIR)/SAVER.DLL
ATAPICD_ELF  := $(COMPILED_ELF_DIR)/atapicd_module.elf
ATAPICD_DRV  := $(APPS_OUT_DIR)/ATAPICD.DRV
DOSVM_ELF   := $(COMPILED_ELF_DIR)/dosvm_app.elf
DOSVM_APP   := $(APPS_OUT_DIR)/DOSVM.APP
CAL_ELF     := $(COMPILED_ELF_DIR)/cal_app.elf
CAL_APP     := $(APPS_OUT_DIR)/CAL.APP
SLOTS_ELF   := $(COMPILED_ELF_DIR)/slots_app.elf
SLOTS_APP   := $(APPS_OUT_DIR)/SLOTS.APP
BIOSTAR_ELF := $(COMPILED_ELF_DIR)/biostar_app.elf
BIOSTAR_APP := $(APPS_OUT_DIR)/BIORHYTH.APP
MANDEL_ELF  := $(COMPILED_ELF_DIR)/mandelbrot_app.elf
MANDEL_APP  := $(APPS_OUT_DIR)/MANDEL.APP
ZIPZORK_ELF := $(COMPILED_ELF_DIR)/zipzork_app.elf
ZIPZORK_APP := $(APPS_OUT_DIR)/ZIPZORK.APP
DESKHAM_ELF := $(COMPILED_ELF_DIR)/deskham_app.elf
DESKHAM_APP := $(APPS_OUT_DIR)/DESKHAM.APP
PAINT_ELF   := $(COMPILED_ELF_DIR)/paint_app.elf
PAINT_APP   := $(APPS_OUT_DIR)/PAINT.APP
SNAKE_APP   := $(APPS_OUT_DIR)/SNAKE.APP
MINES_APP   := $(APPS_OUT_DIR)/MINES.APP
PUZZLE_APP  := $(APPS_OUT_DIR)/PUZZLE.APP
LANDER_APP  := $(APPS_OUT_DIR)/LANDER.APP
FREECELL_APP := $(APPS_OUT_DIR)/FREECL.APP
POKER_APP    := $(APPS_OUT_DIR)/POKER.APP
GOLF_APP     := $(APPS_OUT_DIR)/GOLF.APP
HCOMMAND_APP := $(APPS_OUT_DIR)/HCOMMAND.APP
HCOMMAND_ART_INC := apps/hcommand_art.inc
HCOMMAND_ART_PREVIEW := assets/HCOMMAND_ART_PREVIEW.PNG
HCOMMAND_ART_ANIMATION := assets/HCOMMAND_ANIMATION_PREVIEW.GIF
HCOMMAND_SOUND_INC := apps/hcommand_sounds.inc
HCOMMAND_SOUND_DIR := contrib/extras/SOUNDS
HCOMMAND_SOUND_WAVS := $(sort $(wildcard $(HCOMMAND_SOUND_DIR)/HC*.WAV))
HCOMMAND_SOUND_SOURCES := tools/mkhcommand_sounds.py $(HCOMMAND_SOUND_DIR) $(HCOMMAND_SOUND_WAVS)
HCOMMAND_ART_SOURCES := \
	tools/mkhcommand_art.py \
	assets/hcommand_artist/units_infantry_habitat_alpha_v1.png \
	assets/hcommand_artist/units_vehicles_habitat_alpha_v1.png \
	assets/hcommand_artist/units_aircraft_habitat_alpha_v1.png \
	assets/hcommand_artist/buildings_habitat_alpha_v1.png \
	assets/hcommand_artist/unit_launcher_alpha_v1.png \
	assets/hcommand_artist/unit_medic_alpha_v1.png \
	assets/hcommand_artist/unit_scout_buggy_alpha_v1.png \
	assets/hcommand_artist/unit_skyguard_alpha_v1.png \
	assets/hcommand_artist/unit_field_artillery_alpha_v1.png \
	assets/hcommand_artist/unit_interceptor_alpha_v1.png \
	assets/hcommand_artist/unit_command_crawler_alpha_v1.png \
	assets/hcommand_artist/building_radar_alpha_v1.png \
	assets/hcommand_artist/building_repair_bay_alpha_v1.png \
	assets/hcommand_artist/building_aa_tower_alpha_v1.png \
	assets/hcommand_artist/repair_icon.png \
	assets/hcommand_artist/terrain_tiles.png \
	assets/hcommand_artist/terrain_mountains_v1.png \
	assets/hcommand_artist/command_deck.png \
	assets/hcommand_artist/command_deck_v2.png
DISKCOPY_ELF := $(COMPILED_ELF_DIR)/diskcopy_app.elf
DISKCOPY_APP := $(APPS_OUT_DIR)/DISKCOPY.APP
CDPLAY_ELF   := $(COMPILED_ELF_DIR)/cdplay_app.elf
CDPLAY_APP   := $(APPS_OUT_DIR)/CDPLAY.APP
FLOPDIAG_ELF := $(COMPILED_ELF_DIR)/flopdiag_app.elf
FLOPDIAG_APP := $(APPS_OUT_DIR)/FLOPDIAG.APP
CDDIAG_ELF   := $(COMPILED_ELF_DIR)/cddiag_app.elf
CDDIAG_APP   := $(APPS_OUT_DIR)/CDDIAG.APP
IDEDIAG_ELF  := $(COMPILED_ELF_DIR)/idediag_app.elf
IDEDIAG_APP  := $(APPS_OUT_DIR)/IDEDIAG.APP
USBDIAG_ELF  := $(COMPILED_ELF_DIR)/usbdiag_app.elf
USBDIAG_APP  := $(APPS_OUT_DIR)/USBDIAG.APP
SCSIDIAG_ELF := $(COMPILED_ELF_DIR)/scsidiag_app.elf
SCSIDIAG_APP := $(APPS_OUT_DIR)/SCSIDIAG.APP
NETDIAG_ELF  := $(COMPILED_ELF_DIR)/netdiag_app.elf
NETDIAG_APP  := $(APPS_OUT_DIR)/NETDIAG.APP
HAMSHARE_ELF := $(COMPILED_ELF_DIR)/hamshare_app.elf
HAMSHARE_APP := $(APPS_OUT_DIR)/HAMSHARE.APP
FORMAT_APP_ELF := $(COMPILED_ELF_DIR)/format_app.elf
FORMAT_APP   := $(APPS_OUT_DIR)/FORMAT.APP
GFXDIAG_ELF  := $(COMPILED_ELF_DIR)/gfxdiag_app.elf
GFXDIAG_APP  := $(APPS_OUT_DIR)/GFXDIAG.APP
DEVMGR_ELF   := $(COMPILED_ELF_DIR)/devmgr_app.elf
DEVMGR_APP   := $(APPS_OUT_DIR)/DEVMGR.APP
FONTS_ELF    := $(COMPILED_ELF_DIR)/fonts_app.elf
FONTS_APP    := $(APPS_OUT_DIR)/FONTS.APP
UPDATE_ELF   := $(COMPILED_ELF_DIR)/update_app.elf
UPDATE_APP   := $(APPS_OUT_DIR)/UPDATE.APP
UPDATE_PLUS_ELF := $(COMPILED_ELF_DIR)/update_plus_app.elf
UPDATE_PLUS_APP := $(APPS_OUT_DIR)/UPDATEP.APP
# .ICO files (256-byte raw palette icons, one per .APP)
DISKCOPY_ICO := $(APPS_OUT_DIR)/DISKCOPY.ICO
CDPLAY_ICO   := $(APPS_OUT_DIR)/CDPLAY.ICO
FLOPDIAG_ICO := $(APPS_OUT_DIR)/FLOPDIAG.ICO
CDDIAG_ICO   := $(APPS_OUT_DIR)/CDDIAG.ICO
IDEDIAG_ICO  := $(APPS_OUT_DIR)/IDEDIAG.ICO
USBDIAG_ICO  := $(APPS_OUT_DIR)/USBDIAG.ICO
SCSIDIAG_ICO := $(APPS_OUT_DIR)/SCSIDIAG.ICO
NETDIAG_ICO  := $(APPS_OUT_DIR)/NETDIAG.ICO
HAMSHARE_ICO := $(APPS_OUT_DIR)/HAMSHARE.ICO
FORMAT_ICO   := $(APPS_OUT_DIR)/FORMAT.ICO
GFXDIAG_ICO  := $(APPS_OUT_DIR)/GFXDIAG.ICO
DEVMGR_ICO   := $(APPS_OUT_DIR)/DEVMGR.ICO
FONTS_ICO    := $(APPS_OUT_DIR)/FONTS.ICO
EXTRAS_INSTALL_ICO := $(APPS_OUT_DIR)/SETUP.ICO
UPDATE_ICO   := $(APPS_OUT_DIR)/UPDATE.ICO
PREFS_ICO    := $(APPS_OUT_DIR)/PREFS.ICO
NOTEPAD_ICO  := $(APPS_OUT_DIR)/NOTEPAD.ICO
HAMWRITE_ICO := $(APPS_OUT_DIR)/HAMWRITE.ICO
HAMSTER_EXTRAS_IMG := $(BUILD_DIR)/HamsterExtras.img
HAMSTER_EXTRAS_ZIP := $(BUILD_DIR)/HamsterExtras.zip
HAMSTER_EXTRAS_LEGACY_IMG := $(BUILD_DIR)/Archive/HamsterExtrasLegacy.img
ZIPZORK_PACKAGE := $(BUILD_DIR)/zip-zork.zip
ZIPZORK_SOURCE_PACKAGE := $(BUILD_DIR)/zip-zork-source.zip
SPELL_DAT    := $(DATA_DIR)/SPELL.DAT
SPELL_DAT_SRC ?= contrib/extras/SPELL.DAT
EXTRAS_PAYLOAD_SRC := $(shell find contrib/extras -type f 2>/dev/null)
DOS_PAYLOAD_SRC := $(shell find dos -type f ! -path 'dos/freedos/*' ! -path 'dos/install/*' ! -name '*.S' ! -name '*.ASM' ! -name '*.INC' 2>/dev/null)
PAINT_ICO    := $(APPS_OUT_DIR)/PAINT.ICO
HAMNET_ICO   := $(APPS_OUT_DIR)/HAMNET.ICO
PIANO_ICO    := $(APPS_OUT_DIR)/PIANO.ICO
CLOCK_ICO    := $(APPS_OUT_DIR)/CLOCK.ICO
CALC_ICO     := $(APPS_OUT_DIR)/CALC.ICO
CAL_ICO      := $(APPS_OUT_DIR)/CAL.ICO
SLOTS_ICO    := $(APPS_OUT_DIR)/SLOTS.ICO
BIOSTAR_ICO  := $(APPS_OUT_DIR)/BIORHYTH.ICO
MANDEL_ICO   := $(APPS_OUT_DIR)/MANDEL.ICO
ZIPZORK_ICO  := $(APPS_OUT_DIR)/ZIPZORK.ICO
DESKHAM_ICO  := $(APPS_OUT_DIR)/DESKHAM.ICO
SNAKE_ICO    := $(APPS_OUT_DIR)/SNAKE.ICO
MINES_ICO    := $(APPS_OUT_DIR)/MINES.ICO
PUZZLE_ICO   := $(APPS_OUT_DIR)/PUZZLE.ICO
LANDER_ICO   := $(APPS_OUT_DIR)/LANDER.ICO
FREECELL_ICO := $(APPS_OUT_DIR)/FREECL.ICO
POKER_ICO    := $(APPS_OUT_DIR)/POKER.ICO
GOLF_ICO     := $(APPS_OUT_DIR)/GOLF.ICO
HCOMMAND_ICO := $(APPS_OUT_DIR)/HCOMMAND.ICO
FONT_ASSET_BIN := $(GENERATED_DIR)/fonts.dat
FONT_FACE_BINS := $(GENERATED_DIR)/fonts/ARIAL.HFF $(GENERATED_DIR)/fonts/COURIER.HFF $(GENERATED_DIR)/fonts/TIMES.HFF $(GENERATED_DIR)/fonts/FUTURE.HFF $(GENERATED_DIR)/fonts/GARAMOND.HFF $(GENERATED_DIR)/fonts/SCRIPT.HFF
HAMSTERS_SRC := assets/ui/hamsters.png
HAMSTERS_SHEET := $(GENERATED_DIR)/hamsters_sheet.png
HAMSTER_SPRITE_C := $(GENERATED_DIR)/hamster_sprite.c
HAMSTER_SPRITE_H := $(GENERATED_DIR)/hamster_sprite.h
HAMSTER_SPRITE_BIN := $(GENERATED_DIR)/hamsaver.bin
HAMSTER_SAVER_APP := $(GENERATED_DIR)/HAMSTER.APP
LOADING_WHEEL_SOURCE := assets/ui/loading-wheel/loading-wheel-sprite.png
LOADING_WHEEL_H := $(GENERATED_DIR)/loading_wheel_sprite.h
COURT_CARD_SOURCE := assets/cards/court-card-ai-source.png
COURT_CARD_ATLAS := $(GENERATED_DIR)/court_card_sprites.png
COURT_CARD_H := $(GENERATED_DIR)/court_card_sprites.h
FREECELL_COURT_SOURCE := assets/cards/freecell-court-ai-source.png
FREECELL_COURT_ATLAS := $(GENERATED_DIR)/freecell_court_sprites.png
FREECELL_COURT_H := $(GENERATED_DIR)/freecell_court_sprites.h
BOOT_LOGO_FALLBACK_C := $(GENERATED_DIR)/boot_logo.c
BOOT_LOGO_FALLBACK_H := $(GENERATED_DIR)/boot_logo.h

CC ?= gcc
LD ?= ld
OBJCOPY ?= objcopy
QEMU ?= qemu-system-i386
BOOT_CHECK_TIMEOUT ?= 25s
GFX_BENCH_TAG ?= current

CFLAGS := -m32 -march=i386 -mtune=i386 -std=c11 -ffreestanding -fno-builtin -fno-pic -fno-pie \
	-fno-stack-protector -fno-asynchronous-unwind-tables -ffunction-sections -fdata-sections \
	-fomit-frame-pointer \
	-Ikernel -Idrivers -Iapps -Ifs -I$(GENERATED_DIR) $(HAMNET_CORE_INCLUDES) -Wall -Wextra -Os
HOT_CFLAGS := $(filter-out -Os,$(CFLAGS)) -O2
VGA_TUNE ?= i386
VGA_HOT_CFLAGS := $(filter-out -mtune=i386,$(HOT_CFLAGS)) -mtune=$(VGA_TUNE)
VGA_TUNE_STAMP := $(GENERATED_DIR)/vga-tune-$(VGA_TUNE).stamp
VGA_USE_REP_TRANSFERS ?= 1
VGA_TRANSFER_CFLAGS := -DVGA_USE_REP_TRANSFERS=$(VGA_USE_REP_TRANSFERS)
VGA_TRANSFER_STAMP := $(GENERATED_DIR)/vga-transfer-$(VGA_USE_REP_TRANSFERS).stamp
VGA_USE_ASM_SPRITE_ROWS ?= 0
VGA_SPRITE_CFLAGS := -DVGA_USE_ASM_SPRITE_ROWS=$(VGA_USE_ASM_SPRITE_ROWS)
VGA_SPRITE_STAMP := $(GENERATED_DIR)/vga-sprite-$(VGA_USE_ASM_SPRITE_ROWS).stamp
# FAT is predominantly device-I/O-bound; -Oz recovers 16 KB on the 2 MB build.
FAT_CFLAGS := $(filter-out -Os,$(CFLAGS)) -Oz
MAIN_CFLAGS := $(filter-out -Os,$(CFLAGS)) -Oz -fno-align-functions \
	-mpreferred-stack-boundary=2
ASFLAGS := -m32 -ffreestanding
LDFLAGS := -m elf_i386 -nostdlib -T linker.ld -Map $(KERNEL_OUT_DIR)/hamster.map --strip-debug --gc-sections

OBJS := \
	$(BUILD_DIR)/kernel/entry.o \
	$(BUILD_DIR)/kernel/event.o \
	$(BUILD_DIR)/kernel/entropy.o \
	$(BUILD_DIR)/kernel/heap.o \
	$(BUILD_DIR)/kernel/runtime_memory.o \
	$(BUILD_DIR)/kernel/ham_strings.o \
	$(BUILD_DIR)/kernel/lowmem.o \
	$(BUILD_DIR)/kernel/paging.o \
	$(BUILD_DIR)/kernel/workspace.o \
	$(BUILD_DIR)/kernel/clipboard.o \
	$(BUILD_DIR)/kernel/dos_session.o \
	$(BUILD_DIR)/kernel/panic.o \
	$(BUILD_DIR)/kernel/app_fault.o \
	$(BUILD_DIR)/kernel/app_fault_asm.o \
	$(BUILD_DIR)/kernel/app_protect.o \
	$(BUILD_DIR)/kernel/app_protect_asm.o \
	$(BUILD_DIR)/kernel/interrupts.o \
	$(BUILD_DIR)/kernel/interrupts_entry.o \
	$(BUILD_DIR)/kernel/vm86.o \
	$(BUILD_DIR)/kernel/zip_library.o \
	$(BUILD_DIR)/kernel/inflate.o \
	$(BUILD_DIR)/kernel/app_loader.o \
	$(BUILD_DIR)/kernel/app_hdd_prepare_proxy.o \
	$(BUILD_DIR)/kernel/driver_loader.o \
	$(BUILD_DIR)/kernel/input_router.o \
	$(BUILD_DIR)/kernel/service.o \
	$(BUILD_DIR)/kernel/task.o \
	$(BUILD_DIR)/kernel/task_switch.o \
	$(BUILD_DIR)/kernel/realmode_exit.o \
	$(BUILD_DIR)/kernel/realmode_exit_asm.o \
	$(BUILD_DIR)/kernel/main.o \
	$(BUILD_DIR)/apps/app_platform.o \
	$(BUILD_DIR)/apps/app_services.o \
	$(BUILD_DIR)/apps/print_service.o \
	$(BUILD_DIR)/apps/app_slots.o \
	$(BUILD_DIR)/apps/file_manager_commands.o \
	$(BUILD_DIR)/apps/file_icons.o \
	$(BUILD_DIR)/apps/file_dialog_proxy.o \
	$(BUILD_DIR)/apps/ext_loader.o \
	$(BUILD_DIR)/apps/launch_contract.o \
	$(BUILD_DIR)/apps/prefs_store.o \
	$(BUILD_DIR)/apps/shell.o \
	$(BUILD_DIR)/apps/ui_about.o \
	$(BUILD_DIR)/apps/ui_controls.o \
	$(BUILD_DIR)/apps/ui_edit.o \
	$(BUILD_DIR)/apps/ui_input_modal.o \
	$(BUILD_DIR)/apps/ui_layout.o \
	$(BUILD_DIR)/apps/ui_list_view.o \
	$(BUILD_DIR)/apps/ui_message_box.o \
	$(BUILD_DIR)/apps/ui_message.o \
	$(BUILD_DIR)/apps/ui_property_sheet.o \
	$(BUILD_DIR)/apps/ui_progress.o \
	$(BUILD_DIR)/apps/ui_wizard.o \
	$(BUILD_DIR)/apps/window.o \
	$(BUILD_DIR)/fs/directory_cache.o \
	$(BUILD_DIR)/fs/fat.o \
	$(BUILD_DIR)/fs/file_contract.o \
	$(BUILD_DIR)/fs/path_contract.o \
	$(BUILD_DIR)/fs/volume_generation.o \
	$(BUILD_DIR)/drivers/activity.o \
	$(BUILD_DIR)/drivers/audio_manager.o \
	$(BUILD_DIR)/drivers/ata.o \
	$(BUILD_DIR)/drivers/bitmap.o \
	$(BUILD_DIR)/drivers/bootlog.o \
	$(BUILD_DIR)/drivers/cdrom.o \
	$(BUILD_DIR)/drivers/cirrus_vga.o \
	$(BUILD_DIR)/drivers/driver_model.o \
	$(BUILD_DIR)/drivers/xga2.o \
	$(BUILD_DIR)/drivers/floppy.o \
	$(BUILD_DIR)/drivers/gameport.o \
	$(BUILD_DIR)/drivers/ide.o \
	$(BUILD_DIR)/drivers/keyboard.o \
	$(BUILD_DIR)/drivers/lpt.o \
	$(BUILD_DIR)/drivers/ne2k_net.o \
	$(BUILD_DIR)/drivers/pit.o \
	$(BUILD_DIR)/drivers/rtc.o \
	$(BUILD_DIR)/drivers/speaker.o \
	$(BUILD_DIR)/drivers/storage.o \
	$(BUILD_DIR)/drivers/surface.o \
	$(BUILD_DIR)/drivers/theme.o \
	$(BUILD_DIR)/drivers/video_profile.o \
	$(BUILD_DIR)/drivers/vga_primitives.o \
	$(BUILD_DIR)/drivers/vga_sprite_rows.o \
	$(BUILD_DIR)/drivers/vga_planar_pack.o \
	$(BUILD_DIR)/generated/boot_logo.o \
	$(BUILD_DIR)/drivers/vga.o \
	$(BUILD_DIR)/drivers/serial.o

.PHONY: all clean floppy floppy-2mb run run-2mb boot-check boot-check-2mb boot-check-4mb boot-check-8mb boot-check-crypto boot-check-vm86-module boot-check-adlib boot-check-ct1680 boot-check-sb16-resources boot-check-ne2000 gfx-benchmark gfx-benchmark-transfers mp3-decoder-benchmark install-target install-test-run docker-build docker-floppy docker-run docker-check freedos-fetch freedos-floppy freedos-run pmhello vidtest ram-report budget-report phase2-readiness-check app-services-check app-platform-check printer-check desktop-feature-check filesystem-regression smoketest-install smoketest-install-manifest smoketest-app-hdd-prepare smoketest-hardware-ui smoketest-desktop-layout smoketest-floppy-format smoketest-file-manager smoketest-waveplayer smoketest-hamsheet-formula smoketest-zip-create smoketest-launch smoketest-dos-session smoketest-path smoketest-file-contract smoketest-volume smoketest-directory-cache smoketest-vfat smoketest-input smoketest-event smoketest-entropy smoketest-payload-expand smoketest-fast-memory smoketest-extras smoketest-extras-hd smoketest-extras-legacy smoketest-bitmap smoketest-video smoketest-audio smoketest-network smoketest-board smoketest-picomem smoketest-ch375 smoketest-cdplayer smoketest-hamshare smoketest-speaker smoketest-storage smoketest-iso9660 smoketest-driver-contract smoketest-task smoketest-multitask smoketest-app-fault smoketest-http11 smoketest-hamnet-scan smoketest-hamnet-online smoketest-install-e2e smoketest-hamload-preloads dist-c dist-c-force extras-floppy extras-hd extras-legacy extras-package zipzork-package zipzork-source-package spell-dat ui-screenshots organize-build check-build-root-artifacts release-integrity-check

extras-floppy: $(HAMSTER_EXTRAS_IMG)
	python3 tools/organize_build.py --build-dir $(BUILD_DIR)

extras-hd: $(HAMSTER_EXTRAS_IMG)

extras-legacy: $(HAMSTER_EXTRAS_LEGACY_IMG)

extras-package: $(HAMSTER_EXTRAS_ZIP)

zipzork-package: $(ZIPZORK_PACKAGE) $(ZIPZORK_SOURCE_PACKAGE)
	python3 tools/test_zipzork_mouse_contract.py

zipzork-source-package: $(ZIPZORK_SOURCE_PACKAGE)

spell-dat: $(SPELL_DAT)

organize-build:
	python3 tools/organize_build.py --build-dir $(BUILD_DIR)

check-build-root-artifacts:
	@bad="$$(find $(BUILD_DIR) -maxdepth 1 -type f \( -name '*.log' -o -name '*.png' -o -name '*.ppm' \) -print)"; \
	if [ -n "$$bad" ]; then \
		echo "Build root contains logs/screenshots that belong in build/LOGS or build/Screenshots:"; \
		echo "$$bad"; \
		exit 1; \
	fi

all: freedos-floppy

ui-contracts: $(UI_CONTRACT_SMOKETEST_BIN) smoketest-desktop-layout desktop-feature-check
	python3 tools/check_ui_contracts.py
	python3 tools/test_hardware_ui_fixes.py
	./$(UI_CONTRACT_SMOKETEST_BIN)

desktop-feature-check:
	python3 tools/test_desktop_feature_contract.py

release-integrity-check: $(FREEDOS_IMG)
	python3 tools/test_update_network_dependencies.py
	python3 tools/check_release_integrity.py --image $(FREEDOS_IMG)

phase2-readiness-check:
	python3 tools/check_phase2_readiness.py

app-services-check: app-platform-check
	python3 tools/test_app_services_contract.py
	python3 tools/test_operation_contract.py
	python3 tools/test_dynamic_app_instances.py

app-platform-check:
	python3 tools/test_platform_services_contract.py

printer-check:
	python3 tools/test_printer_contract.py

ui-screenshots: $(FREEDOS_IMG) $(HAMSTER_EXTRAS_LEGACY_IMG)
	python3 tools/capture_ui_suite.py --image $(FREEDOS_IMG) --extras-image $(HAMSTER_EXTRAS_LEGACY_IMG)

gfx-benchmark: $(FREEDOS_IMG) | $(LOGS_DIR) $(SCREENSHOTS_DIR)
	rm -f $(LOGS_DIR)/gfxdiag-$(GFX_BENCH_TAG)-2mb.log $(LOGS_DIR)/gfxdiag-$(GFX_BENCH_TAG)-4mb.log
	python3 tools/capture_qemu_frame.py --image $(FREEDOS_IMG) --scenario gfxdiag-bench --memory 2M --serial file:$(LOGS_DIR)/gfxdiag-$(GFX_BENCH_TAG)-2mb.log --out $(SCREENSHOTS_DIR)/gfxdiag-$(GFX_BENCH_TAG)-2mb.png
	python3 tools/capture_qemu_frame.py --image $(FREEDOS_IMG) --scenario gfxdiag-bench --memory 4M --serial file:$(LOGS_DIR)/gfxdiag-$(GFX_BENCH_TAG)-4mb.log --out $(SCREENSHOTS_DIR)/gfxdiag-$(GFX_BENCH_TAG)-4mb.png
	grep -q "GFXBENCH PROFILE.*buffer=PACKED4" $(LOGS_DIR)/gfxdiag-$(GFX_BENCH_TAG)-2mb.log
	grep -q "GFXBENCH PROFILE.*buffer=FULL8" $(LOGS_DIR)/gfxdiag-$(GFX_BENCH_TAG)-4mb.log
	grep -q "GFXBENCH END" $(LOGS_DIR)/gfxdiag-$(GFX_BENCH_TAG)-2mb.log
	grep -q "GFXBENCH END" $(LOGS_DIR)/gfxdiag-$(GFX_BENCH_TAG)-4mb.log
	grep "GFXBENCH" $(LOGS_DIR)/gfxdiag-$(GFX_BENCH_TAG)-2mb.log
	grep "GFXBENCH" $(LOGS_DIR)/gfxdiag-$(GFX_BENCH_TAG)-4mb.log

gfx-benchmark-transfers:
	$(MAKE) freedos-floppy VGA_USE_REP_TRANSFERS=0
	$(MAKE) gfx-benchmark GFX_BENCH_TAG=transfer-c VGA_USE_REP_TRANSFERS=0
	grep -q "GFXBENCH PROFILE.*transfer=C" $(LOGS_DIR)/gfxdiag-transfer-c-2mb.log
	grep -q "GFXBENCH PROFILE.*transfer=C" $(LOGS_DIR)/gfxdiag-transfer-c-4mb.log
	$(MAKE) freedos-floppy VGA_USE_REP_TRANSFERS=1
	$(MAKE) gfx-benchmark GFX_BENCH_TAG=transfer-rep VGA_USE_REP_TRANSFERS=1
	grep -q "GFXBENCH PROFILE.*transfer=REP" $(LOGS_DIR)/gfxdiag-transfer-rep-2mb.log
	grep -q "GFXBENCH PROFILE.*transfer=REP" $(LOGS_DIR)/gfxdiag-transfer-rep-4mb.log
	python3 tools/compare_gfxbench.py --left-label C --right-label REP \
		--left-2mb $(LOGS_DIR)/gfxdiag-transfer-c-2mb.log \
		--right-2mb $(LOGS_DIR)/gfxdiag-transfer-rep-2mb.log \
		--left-4mb $(LOGS_DIR)/gfxdiag-transfer-c-4mb.log \
		--right-4mb $(LOGS_DIR)/gfxdiag-transfer-rep-4mb.log

filesystem-regression:
	python3 tools/test_filesystem_regression.py

smoketest-storage: $(STORAGE_SMOKETEST_BIN) $(ATA_SMOKETEST_BIN) $(IBM_MCA_SCSI_SMOKETEST_BIN) smoketest-floppy-format smoketest-install filesystem-regression
	./$(STORAGE_SMOKETEST_BIN)
	./$(ATA_SMOKETEST_BIN)
	./$(IBM_MCA_SCSI_SMOKETEST_BIN)

smoketest-iso9660: $(ISO9660_MODULE_SMOKETEST_BIN)
	./$(ISO9660_MODULE_SMOKETEST_BIN)

smoketest-waveplayer: $(WAVEPLAYER_SMOKETEST_BIN)
	./$(WAVEPLAYER_SMOKETEST_BIN)

$(MP3_BENCH_MINIMP3): tools/mp3_decoder_benchmark.c third_party/minimp3/minimp3.h
	mkdir -p $(dir $@)
	$(HOST_CC) -m32 -O3 -ffast-math -std=c11 \
	    -D_POSIX_C_SOURCE=200809L -DBENCH_MINIMP3 $< -o $@

$(MP3_BENCH_MPG123): tools/mp3_decoder_benchmark.c $(MPG123_LIB)
	mkdir -p $(dir $@)
	$(HOST_CC) -m32 -O2 -std=c11 -D_POSIX_C_SOURCE=200809L \
	    -ffunction-sections -fdata-sections -DBENCH_MPG123 \
	    -I$(MPG123_DIR)/include $< $(MPG123_LIB) \
	    -Wl,--gc-sections -lm -no-pie -o $@

mp3-decoder-benchmark: $(MP3_BENCH_MINIMP3) $(MP3_BENCH_MPG123)
	$(MP3_BENCH_MINIMP3) "$(MP3_BENCH_INPUT)" $(MP3_BENCH_OUTPUT_HZ)
	$(MP3_BENCH_MPG123) "$(MP3_BENCH_INPUT)" $(MP3_BENCH_OUTPUT_HZ)

smoketest-hamsheet-formula: $(HAMSHEET_FORMULA_SMOKETEST_BIN)
	./$(HAMSHEET_FORMULA_SMOKETEST_BIN)

smoketest-driver-contract: $(DRIVER_CONTRACT_SMOKETEST_BIN) $(DRIVER_LOADER_RESOURCES_SMOKETEST_BIN)
	./$(DRIVER_CONTRACT_SMOKETEST_BIN)
	./$(DRIVER_LOADER_RESOURCES_SMOKETEST_BIN)

smoketest-task: $(TASK_SMOKETEST_BIN)
	./$(TASK_SMOKETEST_BIN)

smoketest-multitask: smoketest-task app-services-check
	python3 tools/test_multitasking_contract.py

smoketest-app-fault: $(FREEDOS_IMG) $(APP_FAULT_PROBE_APP) | $(LOGS_DIR) $(SCREENSHOTS_DIR)
	python3 tools/capture_qemu_frame.py --image $(FREEDOS_IMG) \
	    --scenario app-fault-recovery --memory 8M --wait 25 \
	    --serial file:$(LOGS_DIR)/app-fault-recovery.log \
	    --out $(SCREENSHOTS_DIR)/app-fault-recovery.png
	grep -q "APPFAULT: protected FAULT.APP vector=14 error=00000007" $(LOGS_DIR)/app-fault-recovery.log
	grep -q "app_slot: quarantined FAULT" $(LOGS_DIR)/app-fault-recovery.log
	grep -q "APPFAULT: desktop resumed" $(LOGS_DIR)/app-fault-recovery.log
	! grep -q "PANIC:" $(LOGS_DIR)/app-fault-recovery.log

smoketest-http11: $(HTTP11_SMOKETEST_BIN)
	./$(HTTP11_SMOKETEST_BIN)

smoketest-hamnet-scan: $(HAMNET_SCAN_SMOKETEST_BIN)
	./$(HAMNET_SCAN_SMOKETEST_BIN)

smoketest-hamnet-online: $(HAMNET_ONLINE_SMOKETEST_BIN)
	./$(HAMNET_ONLINE_SMOKETEST_BIN)

smoketest-entropy: $(ENTROPY_SMOKETEST_BIN)
	./$(ENTROPY_SMOKETEST_BIN)

smoketest-payload-expand: $(INFLATE_SMOKETEST_BIN) $(PAYLOAD_EXPAND_SMOKETEST_BIN)
	python3 tools/test_hama_format.py
	./$(INFLATE_SMOKETEST_BIN)
	./$(PAYLOAD_EXPAND_SMOKETEST_BIN)

smoketest-fast-memory: $(FAST_MEMORY_SMOKETEST_BIN)
	./$(FAST_MEMORY_SMOKETEST_BIN)

smoketest-update-scan: $(UPDATE_SCAN_SMOKETEST_BIN) $(UPDATE_APP_SCAN_SMOKETEST_BIN)
	./$(UPDATE_SCAN_SMOKETEST_BIN)
	./$(UPDATE_APP_SCAN_SMOKETEST_BIN)

smoketest-extras: $(FREEDOS_IMG) $(HAMSTER_EXTRAS_IMG) $(UPDATE_APP)
	python3 tools/test_update_editions.py --checker $(UPDATE_APP) --full $(UPDATE_PLUS_APP)
	python3 tools/test_extras_manifest.py --image $(HAMSTER_EXTRAS_IMG)
	python3 tools/test_extras_e2e.py --memory-mb 2 --extras-image $(HAMSTER_EXTRAS_IMG)
	python3 tools/test_extras_install_performance.py

smoketest-extras-hd: smoketest-extras

smoketest-extras-legacy: $(HAMSTER_EXTRAS_LEGACY_IMG)
	python3 tools/test_extras_payloads.py --image $(HAMSTER_EXTRAS_LEGACY_IMG)

smoketest-input: $(PS2MOUSE_SMOKETEST_BIN) $(USBMOUSE_SMOKETEST_BIN) $(INPUT_ROUTER_SMOKETEST_BIN) $(UI_CONTRACT_SMOKETEST_BIN) smoketest-event
	./$(PS2MOUSE_SMOKETEST_BIN)
	./$(USBMOUSE_SMOKETEST_BIN)
	./$(INPUT_ROUTER_SMOKETEST_BIN)
	./$(UI_CONTRACT_SMOKETEST_BIN)

smoketest-event: $(EVENT_SMOKETEST_BIN)
	./$(EVENT_SMOKETEST_BIN)

smoketest-bitmap: $(BITMAP_SMOKETEST_BIN)
	./$(BITMAP_SMOKETEST_BIN)

smoketest-file-manager: $(FILE_MANAGER_COMMANDS_SMOKETEST_BIN) $(FILE_ICONS_SMOKETEST_BIN) smoketest-zip-create
	./$(FILE_MANAGER_COMMANDS_SMOKETEST_BIN)
	./$(FILE_ICONS_SMOKETEST_BIN)
	python3 tools/test_file_manager_menu_clicks.py

smoketest-zip-create: $(ZIP_CREATE_SMOKETEST_BIN)
	./$(ZIP_CREATE_SMOKETEST_BIN)

smoketest-launch: $(LAUNCH_CONTRACT_SMOKETEST_BIN)
	./$(LAUNCH_CONTRACT_SMOKETEST_BIN)

smoketest-dos-session: $(DOS_SESSION_SMOKETEST_BIN)
	./$(DOS_SESSION_SMOKETEST_BIN)

smoketest-path: $(PATH_CONTRACT_SMOKETEST_BIN)
	./$(PATH_CONTRACT_SMOKETEST_BIN)

smoketest-file-contract: $(FILE_CONTRACT_SMOKETEST_BIN)
	./$(FILE_CONTRACT_SMOKETEST_BIN)

smoketest-volume: $(VOLUME_GENERATION_SMOKETEST_BIN)
	./$(VOLUME_GENERATION_SMOKETEST_BIN)

smoketest-directory-cache: $(DIRECTORY_CACHE_SMOKETEST_BIN)
	./$(DIRECTORY_CACHE_SMOKETEST_BIN)

smoketest-vfat: $(VFAT_SMOKETEST_BIN)
	./$(VFAT_SMOKETEST_BIN)

smoketest-video: $(VIDEO_PROFILE_SMOKETEST_BIN) $(SURFACE_SMOKETEST_BIN) $(VGA_PLANAR_PACK_SMOKETEST_BIN) $(VGA_PRIMITIVES_C_SMOKETEST_BIN) $(VGA_PRIMITIVES_REP_SMOKETEST_BIN) $(VGA_SPRITE_ROWS_SMOKETEST_BIN)
	./$(VIDEO_PROFILE_SMOKETEST_BIN)
	./$(SURFACE_SMOKETEST_BIN)
	./$(VGA_PLANAR_PACK_SMOKETEST_BIN)
	./$(VGA_PRIMITIVES_C_SMOKETEST_BIN)
	./$(VGA_PRIMITIVES_REP_SMOKETEST_BIN)
	./$(VGA_SPRITE_ROWS_SMOKETEST_BIN)

smoketest-xga2: $(XGA2_SMOKETEST_BIN)
	./$(XGA2_SMOKETEST_BIN)

smoketest-audio: $(AUDIO_MANAGER_SMOKETEST_BIN) $(ADLIB_DRIVER_SMOKETEST_BIN) $(SB16_DRIVER_SMOKETEST_BIN)
	./$(AUDIO_MANAGER_SMOKETEST_BIN)
	./$(ADLIB_DRIVER_SMOKETEST_BIN)
	./$(SB16_DRIVER_SMOKETEST_BIN)

smoketest-network: $(NE2000_DRIVER_SMOKETEST_BIN) $(RTL8139_DRIVER_SMOKETEST_BIN) $(NETCORE_HTTP_SMOKETEST_BIN)
	./$(NE2000_DRIVER_SMOKETEST_BIN)
	./$(RTL8139_DRIVER_SMOKETEST_BIN)
	./$(NETCORE_HTTP_SMOKETEST_BIN)

smoketest-board: $(SBC82621_DRIVER_SMOKETEST_BIN)
	./$(SBC82621_DRIVER_SMOKETEST_BIN)

smoketest-picomem: $(PICOMEM_DRIVER_SMOKETEST_BIN)
	./$(PICOMEM_DRIVER_SMOKETEST_BIN)

smoketest-hamload-preloads:
	python3 tools/test_hamload_preloads.py

smoketest-ch375: $(CH375_DRIVER_SMOKETEST_BIN)
	./$(CH375_DRIVER_SMOKETEST_BIN)

smoketest-cdplayer: $(CDPLAYER_SMOKETEST_BIN)
	./$(CDPLAYER_SMOKETEST_BIN)

smoketest-hamshare: $(HAMSHARE_SMOKETEST_BIN)
	./$(HAMSHARE_SMOKETEST_BIN)

smoketest-speaker: $(SPEAKER_SMOKETEST_BIN)
	./$(SPEAKER_SMOKETEST_BIN)

smoketest-floppy-format: $(FLOPPY_FORMAT_SMOKETEST_BIN)
	./$(FLOPPY_FORMAT_SMOKETEST_BIN)

smoketest-install: smoketest-install-manifest smoketest-app-hdd-prepare smoketest-install-e2e

smoketest-install-manifest:
	python3 tools/test_install_manifest.py

smoketest-app-hdd-prepare: $(APP_HDD_PREPARE_SMOKETEST_BIN)
	./$(APP_HDD_PREPARE_SMOKETEST_BIN)

smoketest-hardware-ui: smoketest-desktop-layout
	python3 tools/test_hardware_ui_fixes.py

smoketest-desktop-layout:
	python3 tools/test_desktop_drive_layout.py

smoketest-install-e2e:
	python3 tools/test_install_e2e.py

ram-report: $(KERNEL_ELF)
	python3 tools/ram_report.py

budget-report: $(FREEDOS_IMG)
	python3 tools/build_budget_report.py

$(BUILD_DIR):
	mkdir -p $(BUILD_DIR)

$(LOGS_DIR) $(SCREENSHOTS_DIR) $(DATA_DIR) $(REPORTS_DIR) $(BUILD_DIR)/Archive: | $(BUILD_DIR)
	mkdir -p $@

$(FLOPPY_FORMAT_SMOKETEST_BIN): tests/floppy_format_smoketest.c apps/format.c | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/floppy_format_smoketest.c apps/format.c -o $@

$(PS2MOUSE_SMOKETEST_BIN): tests/ps2mouse_decode_smoketest.c apps/ps2_mouse_driver/ps2mouse_drv.c kernel/app_abi.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/ps2mouse_decode_smoketest.c -o $@

$(USBMOUSE_SMOKETEST_BIN): tests/usbmouse_smoketest.c apps/usb_mouse_driver/usbmouse_drv.c apps/usb_mouse_driver/usbmouse_diag.h kernel/app_abi.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/usbmouse_smoketest.c -o $@

$(INPUT_ROUTER_SMOKETEST_BIN): tests/input_router_smoketest.c kernel/input_router.c kernel/input_router.h drivers/keyboard.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/input_router_smoketest.c kernel/input_router.c -o $@

$(UI_CONTRACT_SMOKETEST_BIN): tests/ui_contract_smoketest.c apps/ui_controls.c apps/ui_message.c drivers/theme.c apps/ui_controls.h apps/ui_message.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/ui_contract_smoketest.c apps/ui_controls.c apps/ui_message.c drivers/theme.c -o $@

$(EVENT_SMOKETEST_BIN): tests/event_smoketest.c kernel/event.c kernel/event.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/event_smoketest.c kernel/event.c -o $@

$(BITMAP_SMOKETEST_BIN): tests/bitmap_smoketest.c drivers/bitmap.c drivers/bitmap.h $(HAMNET_CORE_DIR)/src/hamnet_image_decode.c $(HAMNET_CORE_DIR)/include/hamnet_image_decode.h apps/image_decode.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) $(HAMNET_CORE_INCLUDES) tests/bitmap_smoketest.c drivers/bitmap.c $(HAMNET_CORE_DIR)/src/hamnet_image_decode.c -o $@

$(FILE_MANAGER_COMMANDS_SMOKETEST_BIN): tests/file_manager_commands_smoketest.c apps/file_manager_commands.c apps/file_manager_commands.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/file_manager_commands_smoketest.c apps/file_manager_commands.c -o $@

$(FILE_ICONS_SMOKETEST_BIN): tests/file_icons_smoketest.c apps/file_icons.c apps/file_icons.h fs/fat.h drivers/vga.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/file_icons_smoketest.c apps/file_icons.c -o $@

$(ZIP_CREATE_SMOKETEST_BIN): tests/zip_create_smoketest.c apps/zip_create.c apps/zip_create.h apps/payload_expand.c apps/payload_expand.h kernel/inflate.c kernel/inflate.h kernel/crc32.c kernel/crc32.h kernel/fast_memory.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/zip_create_smoketest.c apps/zip_create.c apps/payload_expand.c kernel/inflate.c kernel/crc32.c -o $@

$(LAUNCH_CONTRACT_SMOKETEST_BIN): tests/launch_contract_smoketest.c apps/launch_contract.c apps/launch_contract.h fs/fat.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/launch_contract_smoketest.c apps/launch_contract.c -o $@

$(DOS_SESSION_SMOKETEST_BIN): tests/dos_session_smoketest.c kernel/dos_session.c kernel/dos_session.h apps/launch_contract.c apps/launch_contract.h fs/fat.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) -DHAMSTEROS_DOS_SESSION_NO_EXEC tests/dos_session_smoketest.c kernel/dos_session.c apps/launch_contract.c -o $@

$(PATH_CONTRACT_SMOKETEST_BIN): tests/path_contract_smoketest.c fs/path_contract.c fs/path_contract.h fs/fat.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/path_contract_smoketest.c fs/path_contract.c -o $@

$(FILE_CONTRACT_SMOKETEST_BIN): tests/file_contract_smoketest.c fs/file_contract.c fs/file_contract.h fs/directory_cache.c fs/directory_cache.h fs/path_contract.c fs/path_contract.h fs/fat.h fs/volume_generation.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/file_contract_smoketest.c fs/file_contract.c fs/directory_cache.c fs/path_contract.c -o $@

$(VOLUME_GENERATION_SMOKETEST_BIN): tests/volume_generation_smoketest.c fs/volume_generation.c fs/volume_generation.h fs/fat.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/volume_generation_smoketest.c fs/volume_generation.c -o $@

$(DIRECTORY_CACHE_SMOKETEST_BIN): tests/directory_cache_smoketest.c fs/directory_cache.c fs/directory_cache.h fs/fat.h fs/volume_generation.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/directory_cache_smoketest.c fs/directory_cache.c -o $@

$(VFAT_SMOKETEST_BIN): tests/vfat_smoketest.c fs/fat.c fs/fat.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) -ffunction-sections -fdata-sections \
		tests/vfat_smoketest.c -Wl,--gc-sections -o $@

$(VIDEO_PROFILE_SMOKETEST_BIN): tests/video_profile_smoketest.c drivers/video_profile.c drivers/video_profile.h drivers/vga.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/video_profile_smoketest.c drivers/video_profile.c -o $@

$(XGA2_SMOKETEST_BIN): tests/xga2_smoketest.c drivers/xga2.c drivers/xga2.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/xga2_smoketest.c -o $@

$(SURFACE_SMOKETEST_BIN): tests/surface_smoketest.c drivers/surface.c drivers/surface.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/surface_smoketest.c drivers/surface.c -o $@

$(VGA_PLANAR_PACK_SMOKETEST_BIN): tests/vga_planar_pack_smoketest.c drivers/vga_planar_pack.c drivers/vga_planar_pack.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/vga_planar_pack_smoketest.c drivers/vga_planar_pack.c -o $@

$(VGA_PRIMITIVES_C_SMOKETEST_BIN): tests/vga_primitives_smoketest.c drivers/vga_primitives.c drivers/vga_primitives.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) -DVGA_USE_REP_TRANSFERS=0 tests/vga_primitives_smoketest.c drivers/vga_primitives.c -o $@

$(VGA_PRIMITIVES_REP_SMOKETEST_BIN): tests/vga_primitives_smoketest.c drivers/vga_primitives.c drivers/vga_primitives.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) -DVGA_USE_REP_TRANSFERS=1 tests/vga_primitives_smoketest.c drivers/vga_primitives.c -o $@

$(VGA_SPRITE_ROWS_SMOKETEST_BIN): tests/vga_sprite_rows_smoketest.c drivers/vga_sprite_rows.c drivers/vga_sprite_rows.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) -m32 -march=i386 -mtune=i486 \
		-DVGA_USE_ASM_SPRITE_ROWS=1 tests/vga_sprite_rows_smoketest.c \
		drivers/vga_sprite_rows.c -o $@

$(AUDIO_MANAGER_SMOKETEST_BIN): tests/audio_manager_smoketest.c drivers/audio_manager.c drivers/audio_manager.h kernel/driver_loader.h kernel/app_abi.h drivers/driver_model.h drivers/speaker.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/audio_manager_smoketest.c drivers/audio_manager.c -o $@

$(ADLIB_DRIVER_SMOKETEST_BIN): tests/adlib_driver_smoketest.c apps/adlib_driver/adlib_drv.c apps/adlib_driver/adlib_drv_entry.c kernel/app_abi.h drivers/driver_model.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/adlib_driver_smoketest.c -o $@

$(SB16_DRIVER_SMOKETEST_BIN): tests/sb16_driver_smoketest.c apps/sb16_driver/sb16_drv.c apps/sb16_driver/sb16_drv_entry.c kernel/app_abi.h kernel/fast_memory.h drivers/driver_model.h drivers/sb16_volume.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/sb16_driver_smoketest.c -o $@

$(NE2000_DRIVER_SMOKETEST_BIN): tests/ne2000_driver_smoketest.c apps/ne2000_driver/ne2000_drv.c apps/ne2000_driver/ne2000_drv_entry.c kernel/app_abi.h drivers/ne2k_net.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/ne2000_driver_smoketest.c -o $@

$(RTL8139_DRIVER_SMOKETEST_BIN): tests/rtl8139_driver_smoketest.c apps/rtl8139_driver/rtl8139_drv.c kernel/app_abi.h drivers/ne2k_net.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/rtl8139_driver_smoketest.c -o $@

$(SBC82621_DRIVER_SMOKETEST_BIN): tests/sbc82621_driver_smoketest.c apps/sbc82621_driver/sbc82621_drv.c kernel/app_abi.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/sbc82621_driver_smoketest.c -o $@

$(NETCORE_HTTP_SMOKETEST_BIN): tests/netcore_http_smoketest.c apps/netcore_driver/netcore_drv.c kernel/app_abi.h $(HAMNET_CORE_DIR)/include/hamnet_http11.h $(HAMNET_CORE_DIR)/src/hamnet_resource_policy.c $(HAMNET_CORE_DIR)/include/hamnet_resource_policy.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) $(HAMNET_CORE_INCLUDES) -DHAMSTEROS_NETCORE_HOST_TEST \
	    -ffunction-sections -fdata-sections tests/netcore_http_smoketest.c \
	    apps/netcore_driver/netcore_drv.c $(HAMNET_CORE_DIR)/src/hamnet_resource_policy.c \
	    -Wl,--gc-sections -o $@

$(PICOMEM_DRIVER_SMOKETEST_BIN): tests/picomem_driver_smoketest.c apps/picomem_driver/picomem_drv.c apps/picomem_driver/picomem_drv_entry.c kernel/app_abi.h drivers/driver_model.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/picomem_driver_smoketest.c -o $@

$(CH375_DRIVER_SMOKETEST_BIN): tests/ch375_driver_smoketest.c apps/ch375_driver/ch375_drv.c apps/ch375_driver/ch375_drv_entry.c kernel/app_abi.h drivers/storage.h drivers/driver_model.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/ch375_driver_smoketest.c -o $@

$(CDPLAYER_SMOKETEST_BIN): tests/cdplayer_smoketest.c apps/cdplayer.c apps/cdplayer.h apps/cdplayer_tool_entry.c apps/cdplayer_tool_stubs.c kernel/app_abi.h $(APP_SDK_SERVICES_H) | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/cdplayer_smoketest.c apps/cdplayer.c apps/cdplayer_tool_entry.c apps/cdplayer_tool_stubs.c -o $@

$(HAMSHARE_SMOKETEST_BIN): tests/hamshare_smoketest.c apps/hamshare.c apps/hamshare.h apps/window.h drivers/vga.h fs/fat.h fs/file_contract.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) -DHAMSHARE_TEST tests/hamshare_smoketest.c apps/hamshare.c -o $@

$(SPEAKER_SMOKETEST_BIN): tests/speaker_smoketest.c drivers/speaker.c drivers/speaker.h drivers/pit.h kernel/io.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) -DHAMSTEROS_SPEAKER_HOST_TEST tests/speaker_smoketest.c drivers/speaker.c -o $@

$(STORAGE_SMOKETEST_BIN): tests/storage_smoketest.c drivers/storage.c drivers/storage.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/storage_smoketest.c drivers/storage.c -o $@

$(ATA_SMOKETEST_BIN): tests/ata_smoketest.c drivers/ata.c drivers/ata.h kernel/io.h drivers/pit.h drivers/serial.h kernel/service.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/ata_smoketest.c -o $@

$(IBM_MCA_SCSI_SMOKETEST_BIN): tests/ibm_mca_scsi_smoketest.c apps/ibm_mca_scsi_driver/ibm_mca_scsi_drv.c kernel/app_abi.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/ibm_mca_scsi_smoketest.c -o $@

$(ISO9660_MODULE_SMOKETEST_BIN): tests/iso9660_module_smoketest.c drivers/iso9660_module.c drivers/iso9660_module.h drivers/cdrom.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/iso9660_module_smoketest.c drivers/iso9660_module.c -o $@

$(WAVEPLAYER_SMOKETEST_BIN): tests/waveplayer_smoketest.c apps/waveplayer.c apps/waveplayer_mpg123.c apps/waveplayer_mpg123.h apps/waveplayer_formats.c apps/waveplayer_formats.h $(MPG123_LIB) kernel/app_abi.h apps/file_dialog.h apps/window.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) -m32 -DWAVEPLAYER_SPECTRUM_TEST \
	    -DWAVEPLAYER_USE_MPG123 -I$(MPG123_DIR)/include \
	    -ffunction-sections -fdata-sections tests/waveplayer_smoketest.c \
	    apps/waveplayer.c apps/waveplayer_mpg123.c \
	    apps/waveplayer_formats.c $(MPG123_LIB) \
	    -Wl,--gc-sections -lm -no-pie -o $@

$(HAMSHEET_FORMULA_SMOKETEST_BIN): tests/hamster_sheets_formula_smoketest.c apps/hamster_sheets.c apps/hamster_sheets.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) -ffunction-sections -fdata-sections -DHAMSTER_SHEETS_FORMULA_TEST \
	    tests/hamster_sheets_formula_smoketest.c apps/hamster_sheets.c \
	    -Wl,--gc-sections -o $@

$(DRIVER_CONTRACT_SMOKETEST_BIN): tests/driver_contract_smoketest.c kernel/app_abi.h drivers/driver_model.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/driver_contract_smoketest.c -o $@

$(DRIVER_LOADER_RESOURCES_SMOKETEST_BIN): tests/driver_loader_resources_smoketest.c kernel/driver_loader.c kernel/driver_loader.h kernel/app_abi.h drivers/driver_model.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) -ffunction-sections -fdata-sections \
		tests/driver_loader_resources_smoketest.c -Wl,--gc-sections -o $@

$(TASK_SMOKETEST_BIN): tests/task_smoketest.c kernel/task.c kernel/task.h apps/ui_message.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/task_smoketest.c kernel/task.c -o $@

$(TESTS_OUT_DIR)/app_fault_probe.o: tests/app_fault_probe.c kernel/app_abi.h | $(TESTS_OUT_DIR)
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(APP_FAULT_PROBE_ELF): $(TESTS_OUT_DIR)/app_fault_probe.o tools/app.ld | $(TESTS_OUT_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< -o $@

$(APP_FAULT_PROBE_APP): $(APP_FAULT_PROBE_ELF) tools/mkapp.py | $(TESTS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name FAULT --output $@

$(TESTS_OUT_DIR)/preempt_probe.o: tests/preempt_probe.c kernel/app_abi.h | $(TESTS_OUT_DIR)
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(PREEMPT_PROBE_ELF): $(TESTS_OUT_DIR)/preempt_probe.o tools/app.ld | $(TESTS_OUT_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< -o $@

$(PREEMPT_PROBE_APP): $(PREEMPT_PROBE_ELF) tools/mkapp.py | $(TESTS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name PREEMPT --output $@

$(TESTS_OUT_DIR)/crypto_runtime_probe.o: tests/crypto_runtime_probe.c kernel/app_abi.h apps/crypto_library.h $(HAMNET_MONOCYPHER_DIR)/monocypher.h | $(TESTS_OUT_DIR)
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@

$(CRYPTO_PROBE_ELF): $(TESTS_OUT_DIR)/crypto_runtime_probe.o $(BUILD_DIR)/apps/crypto_client.o tools/app.ld | $(TESTS_OUT_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs --gc-sections -nostdlib \
	    $(TESTS_OUT_DIR)/crypto_runtime_probe.o \
	    $(BUILD_DIR)/apps/crypto_client.o \
	    -o $@

$(CRYPTO_PROBE_APP): $(CRYPTO_PROBE_ELF) tools/mkapp.py | $(TESTS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name CRYPTOT --output $@

$(HTTP11_SMOKETEST_BIN): tests/http11_smoketest.c $(HAMNET_CORE_DIR)/src/hamnet_http11.c $(HAMNET_CORE_DIR)/include/hamnet_http11.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) $(HAMNET_CORE_INCLUDES) tests/http11_smoketest.c $(HAMNET_CORE_DIR)/src/hamnet_http11.c -o $@

$(HAMNET_SCAN_SMOKETEST_BIN): $(HAMNET_TEST_DIR)/hamnet_scan_smoketest.c $(HAMNET_APP_DIR)/hamnet.c $(HAMNET_CORE_DIR)/src/hamnet_classic.c $(HAMNET_CORE_DIR)/include/hamnet_classic.h $(HAMNET_CORE_DIR)/src/hamnet_resource_policy.c $(HAMNET_CORE_DIR)/include/hamnet_resource_policy.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) $(HAMNET_APP_INCLUDES) -DHAMSTEROS_HAMNET_SCAN_HOST_TEST \
	    -DHAMNET_ONLINE_ENABLED=1 \
	    -ffunction-sections -fdata-sections $(HAMNET_TEST_DIR)/hamnet_scan_smoketest.c $(HAMNET_APP_DIR)/hamnet.c \
	    $(HAMNET_CORE_DIR)/src/hamnet_classic.c \
	    $(HAMNET_CORE_DIR)/src/hamnet_resource_policy.c \
	    -Wl,--gc-sections -o $@

$(HAMNET_ONLINE_SMOKETEST_BIN): $(HAMNET_TEST_DIR)/hamnet_online_smoketest.c $(HAMNET_CORE_DIR)/src/hamnet_online.c $(HAMNET_CORE_DIR)/include/hamnet_online.h $(HAMNET_CORE_DIR)/src/hamnet_transport.c $(HAMNET_CORE_DIR)/include/hamnet_transport.h $(HAMNET_MONOCYPHER_DIR)/monocypher.c $(HAMNET_MONOCYPHER_DIR)/monocypher.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) -DHAMNET_ONLINE_ENABLED=1 -DHAMNET_ONLINE_TEST_KEY \
	    $(HAMNET_CORE_INCLUDES) $(HAMNET_TEST_DIR)/hamnet_online_smoketest.c \
	    $(HAMNET_CORE_DIR)/src/hamnet_online.c \
	    $(HAMNET_CORE_DIR)/src/hamnet_transport.c \
	    $(HAMNET_MONOCYPHER_DIR)/monocypher.c -o $@

$(ENTROPY_SMOKETEST_BIN): tests/entropy_smoketest.c kernel/entropy.c kernel/entropy.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/entropy_smoketest.c kernel/entropy.c -o $@

$(INFLATE_SMOKETEST_BIN): tests/inflate_smoketest.c kernel/inflate.c kernel/inflate.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/inflate_smoketest.c kernel/inflate.c -o $@

$(PAYLOAD_EXPAND_SMOKETEST_BIN): tests/payload_expand_smoketest.c apps/payload_expand.c apps/payload_expand.h kernel/inflate.c kernel/inflate.h kernel/app_abi.h kernel/crc32.c kernel/crc32.h kernel/fast_memory.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/payload_expand_smoketest.c apps/payload_expand.c kernel/inflate.c kernel/crc32.c -o $@

$(FAST_MEMORY_SMOKETEST_BIN): tests/fast_memory_smoketest.c kernel/fast_memory.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/fast_memory_smoketest.c -o $@

$(UPDATE_SCAN_SMOKETEST_BIN): tests/update_scan_smoketest.c apps/update_scan.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/update_scan_smoketest.c -o $@

$(UPDATE_APP_SCAN_SMOKETEST_BIN): tests/update_app_scan_smoketest.c apps/update.c apps/update_scan.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) -ffunction-sections -fdata-sections \
		tests/update_app_scan_smoketest.c -Wl,--gc-sections -o $@

$(APP_HDD_PREPARE_SMOKETEST_BIN): tests/app_hdd_prepare_smoketest.c kernel/app_hdd_prepare.c kernel/app_hdd_prepare.h kernel/app_loader.h kernel/app_abi.h kernel/heap.h drivers/serial.h fs/fat.h | $(TESTS_OUT_DIR)
	$(HOST_CC) $(HOST_TEST_CFLAGS) tests/app_hdd_prepare_smoketest.c \
		kernel/app_hdd_prepare.c -o $@

$(VM86_MODULE_TEST_OBJ): tests/vm86_module_exit.S | $(TESTS_OUT_DIR)
	$(CC) $(ASFLAGS) -c $< -o $@

$(VM86_MODULE_TEST_ELF): $(VM86_MODULE_TEST_OBJ) | $(TESTS_OUT_DIR)
	$(LD) -m elf_i386 -nostdlib -N -Ttext 0 $< -o $@

$(VM86_MODULE_TEST_COM): $(VM86_MODULE_TEST_ELF) | $(TESTS_OUT_DIR)
	$(OBJCOPY) -O binary $< $@

$(VM86_EXE_TEST_OBJ): tests/vm86_module_exit_exe.S | $(TESTS_OUT_DIR)
	$(CC) $(ASFLAGS) -c $< -o $@

$(VM86_EXE_TEST_ELF): $(VM86_EXE_TEST_OBJ) | $(TESTS_OUT_DIR)
	$(LD) -m elf_i386 -nostdlib -N -Ttext 0 $< -o $@

$(VM86_EXE_TEST_EXE): $(VM86_EXE_TEST_ELF) | $(TESTS_OUT_DIR)
	$(OBJCOPY) -O binary $< $@

$(VM86_HANG_TEST_OBJ): tests/vm86_hang.S | $(TESTS_OUT_DIR)
	$(CC) $(ASFLAGS) -c $< -o $@

$(VM86_HANG_TEST_ELF): $(VM86_HANG_TEST_OBJ) | $(TESTS_OUT_DIR)
	$(LD) -m elf_i386 -nostdlib -N -Ttext 0 $< -o $@

$(VM86_HANG_TEST_COM): $(VM86_HANG_TEST_ELF) | $(TESTS_OUT_DIR)
	$(OBJCOPY) -O binary $< $@

$(APPS_OUT_DIR): | $(BUILD_DIR)
	mkdir -p $(APPS_OUT_DIR)

$(DESKTOP_ALIAS_DIR): | $(BUILD_DIR)
	mkdir -p $(DESKTOP_ALIAS_DIR)

$(BUILD_DIR)/kernel $(BUILD_DIR)/drivers $(BUILD_DIR)/generated $(BUILD_DIR)/apps $(BUILD_DIR)/fs $(COMPILED_ELF_DIR) $(DIAGNOSTICS_DIR) $(KERNEL_OUT_DIR) $(BOOT_OUT_DIR) $(TESTS_OUT_DIR): | $(BUILD_DIR)
	mkdir -p $@

$(BUILD_DIR)/dos: | $(BUILD_DIR)
	mkdir -p $@

drivers/vga_fonts.inc $(FONT_ASSET_BIN) $(FONT_FACE_BINS): tools/mkvga_fonts.py $(wildcard assets/fonts/*.ttf) | $(BUILD_DIR)/generated
	python3 tools/mkvga_fonts.py

$(HAMSTERS_SHEET): $(HAMSTERS_SRC) tools/slice_hamsters.py | $(BUILD_DIR)/generated
	python3 tools/slice_hamsters.py --input $(HAMSTERS_SRC) --output $(HAMSTERS_SHEET)

$(HAMSTER_SPRITE_C) $(HAMSTER_SPRITE_H) $(HAMSTER_SPRITE_BIN) $(HAMSTER_SAVER_APP): $(HAMSTERS_SHEET) tools/mkhamsters.py | $(BUILD_DIR)/generated
	python3 tools/mkhamsters.py --input $(HAMSTERS_SHEET) --c-output $(HAMSTER_SPRITE_C) --h-output $(HAMSTER_SPRITE_H) --bin-output $(HAMSTER_SPRITE_BIN) --saver-output $(HAMSTER_SAVER_APP)

$(LOADING_WHEEL_H): $(LOADING_WHEEL_SOURCE) tools/mkloadingwheel.py | $(BUILD_DIR)/generated
	python3 tools/mkloadingwheel.py --sprite-input $(LOADING_WHEEL_SOURCE) --header-output $@

$(BUILD_DIR)/kernel/entry.o: kernel/entry.s | $(BUILD_DIR)/kernel
	$(CC) $(ASFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/event.o: kernel/event.c kernel/event.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/entropy.o: kernel/entropy.c kernel/entropy.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/heap.o: kernel/heap.c kernel/heap.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/runtime_memory.o: kernel/runtime_memory.c kernel/runtime_memory.h kernel/heap.h kernel/app_loader.h kernel/ham_strings.h apps/shell.h drivers/vga.h fs/directory_cache.h fs/fat.h $(HAMNET_CORE_DIR)/include/hamnet_image_decode.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/ham_strings.o: kernel/ham_strings.c kernel/ham_strings.h fs/fat.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/lowmem.o: kernel/lowmem.c kernel/lowmem.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/paging.o: kernel/paging.c kernel/paging.h kernel/heap.h kernel/panic.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/workspace.o: kernel/workspace.c kernel/workspace.h kernel/heap.h drivers/serial.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/clipboard.o: kernel/clipboard.c kernel/clipboard.h kernel/heap.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/dos_session.o: kernel/dos_session.c kernel/dos_session.h apps/launch_contract.h kernel/vm86.h kernel/service.h drivers/vga.h fs/fat.h fs/file_contract.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/panic.o: kernel/panic.c kernel/panic.h drivers/serial.h drivers/vga.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/app_fault.o: kernel/app_fault.c kernel/app_fault.h drivers/serial.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/app_fault_asm.o: kernel/app_fault_asm.S | $(BUILD_DIR)/kernel
	$(CC) $(ASFLAGS) -c $< -o $@

$(GENERATED_DIR)/app_protect_abi.inc: kernel/app_abi.h tools/gen_app_protect_abi.py | $(GENERATED_DIR)
	python3 tools/gen_app_protect_abi.py --header kernel/app_abi.h --output $@

$(BUILD_DIR)/kernel/app_protect.o: kernel/app_protect.c kernel/app_protect.h kernel/app_abi.h kernel/heap.h kernel/interrupts.h kernel/paging.h kernel/task.h kernel/workspace.h $(GENERATED_DIR)/app_protect_abi.inc | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -I$(GENERATED_DIR) -c $< -o $@

$(BUILD_DIR)/kernel/app_protect_asm.o: kernel/app_protect_asm.S | $(BUILD_DIR)/kernel
	$(CC) $(ASFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/interrupts.o: kernel/interrupts.c kernel/interrupts.h kernel/app_fault.h kernel/app_protect.h kernel/entropy.h kernel/panic.h drivers/keyboard.h drivers/serial.h kernel/io.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/interrupts_entry.o: kernel/interrupts.s | $(BUILD_DIR)/kernel
	$(CC) $(ASFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/vm86.o: kernel/vm86.c kernel/vm86.h kernel/vm86_module.h kernel/app_fault.h kernel/app_protect.h kernel/app_loader.h kernel/panic.h drivers/serial.h | $(BUILD_DIR)/kernel
	$(CC) $(HOT_CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/inflate.o: kernel/inflate.c kernel/inflate.h | $(BUILD_DIR)/kernel
	$(CC) $(HOT_CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/app_loader.o: kernel/app_loader.c kernel/app_loader.h kernel/app_abi.h kernel/app_fault.h kernel/app_protect.h kernel/entropy.h kernel/heap.h kernel/inflate.h kernel/lowmem.h kernel/task.h kernel/workspace.h kernel/clipboard.h kernel/version.h fs/fat.h fs/file_contract.h drivers/audio_manager.h drivers/serial.h apps/window.h apps/file_dialog.h apps/crypto_library.h drivers/vga.h apps/prefs.h apps/shell.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/app_hdd_prepare_proxy.o: kernel/app_hdd_prepare_proxy.c kernel/app_hdd_prepare.h kernel/app_loader.h kernel/app_abi.h apps/appfast_library.h drivers/serial.h fs/fat.h | $(BUILD_DIR)/kernel
	$(CC) $(filter-out -Os,$(CFLAGS)) -Oz -fno-align-functions \
		-mpreferred-stack-boundary=2 -c $< -o $@

$(BUILD_DIR)/kernel/driver_loader.o: kernel/driver_loader.c kernel/driver_loader.h kernel/app_abi.h kernel/app_loader.h kernel/heap.h kernel/io.h drivers/pit.h fs/fat.h drivers/driver_model.h drivers/serial.h drivers/storage.h apps/prefs.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/input_router.o: kernel/input_router.c kernel/input_router.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/service.o: kernel/service.c kernel/service.h kernel/driver_loader.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/task.o: kernel/task.c kernel/task.h kernel/heap.h apps/ui_message.h apps/window.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/task_switch.o: kernel/task_switch.S | $(BUILD_DIR)/kernel
	$(CC) $(ASFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/realmode_exit.o: kernel/realmode_exit.c kernel/service.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/realmode_exit_asm.o: kernel/realmode_exit.S | $(BUILD_DIR)/kernel
	$(CC) $(ASFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/main.o: kernel/main.c kernel/app_hdd_prepare.h kernel/app_protect.h kernel/event.h kernel/heap.h kernel/input_router.h kernel/lowmem.h kernel/paging.h kernel/panic.h kernel/driver_loader.h kernel/interrupts.h kernel/service.h kernel/task.h drivers/activity.h drivers/audio_manager.h drivers/ata.h drivers/bootlog.h drivers/cdrom.h drivers/cirrus_vga.h drivers/driver_model.h drivers/floppy.h drivers/keyboard.h drivers/serial.h drivers/storage.h drivers/theme.h drivers/vga.h drivers/xga2.h fs/fat.h apps/calculator.h apps/calendar.h apps/clock.h apps/file_dialog.h apps/mines.h apps/moonlander.h apps/notepad.h apps/paint.h apps/prefs.h apps/puzzle.h apps/shell.h apps/snake.h apps/hamwrite_loader.h | $(BUILD_DIR)/kernel $(HAMSTER_SPRITE_H)
	$(CC) $(MAIN_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/calculator.o: apps/calculator.c apps/calculator.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/calendar.o: apps/calendar.c apps/calendar.h apps/window.h drivers/rtc.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/clock.o: apps/clock.c apps/clock.h apps/window.h drivers/rtc.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/file_dialog.o: apps/file_dialog.c apps/file_dialog.h apps/ui_controls.h apps/ui_edit.h apps/window.h drivers/vga.h drivers/pit.h fs/directory_cache.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/format.o: apps/format.c apps/format.h apps/window.h drivers/floppy.h drivers/vga.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/gfxdiag.o: apps/gfxdiag.c apps/gfxdiag.h apps/window.h kernel/heap.h drivers/pit.h drivers/serial.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/cdplayer.o: apps/cdplayer.c apps/cdplayer.h apps/window.h drivers/cdrom.h drivers/atapi.h drivers/pit.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/cdromdiag.o: apps/cdromdiag.c apps/cdromdiag.h apps/window.h drivers/cdrom.h drivers/atapi.h drivers/vga.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/diskcopier.o: apps/diskcopier.c apps/diskcopier.h apps/window.h apps/shell.h drivers/floppy.h drivers/serial.h drivers/vga.h fs/fat.h kernel/service.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/floppydiag.o: apps/floppydiag.c apps/floppydiag.h apps/window.h drivers/floppy.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/idediag.o: apps/idediag.c apps/idediag.h apps/window.h drivers/ide.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/notepad_loader.o: apps/notepad_loader.c apps/notepad.h apps/ext_loader.h kernel/app_loader.h kernel/app_abi.h drivers/serial.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/ext_loader.o: apps/ext_loader.c apps/ext_loader.h kernel/app_loader.h kernel/app_protect.h kernel/app_abi.h fs/fat.h drivers/serial.h drivers/vga.h drivers/pit.h $(LOADING_WHEEL_H) | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/app_slots.o: apps/app_slots.c apps/ext_loader.h apps/notepad.h apps/paint.h apps/clock.h apps/calculator.h apps/calendar.h apps/hamwrite_loader.h apps/deskham.h apps/window.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/prefs.o: apps/prefs.c apps/prefs.h apps/shell.h apps/window.h drivers/bootlog.h drivers/vga.h drivers/sb16.h kernel/heap.h kernel/workspace.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/prefs_store.o: apps/prefs_store.c apps/prefs.h apps/window.h drivers/audio_manager.h drivers/bootlog.h drivers/gameport.h drivers/lpt.h drivers/vga.h drivers/sb16.h kernel/heap.h kernel/workspace.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/shell.o: apps/shell.c apps/shell.h apps/calculator.h apps/calendar.h apps/clock.h apps/file_manager_commands.h apps/file_icons.h apps/launch_contract.h apps/zip_create.h apps/zip_extract.h apps/mines.h apps/notepad.h apps/paint.h apps/prefs.h kernel/app_loader.h kernel/version.h apps/puzzle.h apps/snake.h apps/window.h apps/ui_controls.h apps/ui_edit.h apps/ui_layout.h apps/ui_message.h drivers/activity.h drivers/audio_manager.h drivers/floppy.h drivers/rtc.h drivers/theme.h drivers/vga.h fs/directory_cache.h fs/fat.h kernel/heap.h kernel/lowmem.h kernel/workspace.h apps/hamwrite.h apps/hamwrite_loader.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/zip_create.o: apps/zip_create.c apps/zip_create.h kernel/heap.h kernel/lowmem.h kernel/service.h kernel/crc32.h kernel/fast_memory.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/zip_extract.o: apps/zip_extract.c apps/zip_extract.h kernel/app_loader.h kernel/heap.h kernel/lowmem.h kernel/service.h kernel/crc32.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/kernel/zip_library.o: kernel/zip_library.c apps/zip_library.h apps/zip_create.h apps/zip_extract.h kernel/app_loader.h drivers/serial.h | $(BUILD_DIR)/kernel
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/file_manager_commands.o: apps/file_manager_commands.c apps/file_manager_commands.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/file_icons.o: apps/file_icons.c apps/file_icons.h fs/fat.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/file_dialog_proxy.o: apps/file_dialog_proxy.c apps/file_dialog.h apps/file_dialog_library.h apps/ui_edit.h kernel/app_loader.h drivers/serial.h | $(BUILD_DIR)/apps
	$(CC) $(filter-out -Os,$(CFLAGS)) -Oz -fno-align-functions -c $< -o $@

$(BUILD_DIR)/apps/launch_contract.o: apps/launch_contract.c apps/launch_contract.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/activity.o: drivers/activity.c drivers/activity.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/audio_manager.o: drivers/audio_manager.c drivers/audio_manager.h drivers/speaker.h kernel/driver_loader.h kernel/app_abi.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/window.o: apps/window.c apps/window.h drivers/theme.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/ui_message.o: apps/ui_message.c apps/ui_message.h apps/window.h drivers/theme.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/ui_controls.o: apps/ui_controls.c apps/ui_controls.h apps/ui_message.h apps/window.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/ui_about.o: apps/ui_about.c apps/ui_about.h apps/ui_controls.h apps/ui_layout.h apps/window.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/app_platform.o: apps/app_platform.c apps/app_platform.h apps/app_services.h apps/print_service.h kernel/app_abi.h apps/ui_message.h fs/file_contract.h | $(BUILD_DIR)/apps
	$(CC) $(filter-out -Os,$(CFLAGS)) -Oz -fno-align-functions -c $< -o $@

$(BUILD_DIR)/apps/app_services.o: apps/app_services.c apps/app_services.h kernel/app_abi.h apps/ui_message.h apps/ui_progress.h drivers/theme.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/print_service.o: apps/print_service.c apps/print_service.h apps/app_services.h apps/prefs.h drivers/lpt.h kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/ui_edit.o: apps/ui_edit.c apps/ui_edit.h apps/ui_message.h kernel/clipboard.h drivers/theme.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/ui_input_modal.o: apps/ui_input_modal.c apps/ui_input_modal.h apps/ui_controls.h apps/ui_edit.h apps/ui_layout.h apps/window.h drivers/theme.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/ui_layout.o: apps/ui_layout.c apps/ui_layout.h apps/ui_controls.h apps/ui_message.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/ui_list_view.o: apps/ui_list_view.c apps/ui_list_view.h apps/ui_message.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/ui_message_box.o: apps/ui_message_box.c apps/ui_message_box.h apps/ui_controls.h apps/ui_layout.h apps/window.h drivers/theme.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/ui_property_sheet.o: apps/ui_property_sheet.c apps/ui_property_sheet.h apps/ui_controls.h apps/ui_layout.h apps/window.h drivers/theme.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/ui_progress.o: apps/ui_progress.c apps/ui_progress.h apps/ui_controls.h apps/ui_layout.h apps/ui_message.h apps/window.h drivers/theme.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/ui_wizard.o: apps/ui_wizard.c apps/ui_wizard.h apps/ui_controls.h apps/ui_layout.h apps/window.h drivers/theme.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/fs/directory_cache.o: fs/directory_cache.c fs/directory_cache.h fs/fat.h fs/volume_generation.h | $(BUILD_DIR)/fs
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/fs/file_contract.o: fs/file_contract.c fs/file_contract.h fs/directory_cache.h fs/fat.h fs/path_contract.h | $(BUILD_DIR)/fs
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/fs/fat.o: fs/fat.c fs/fat.h fs/volume_generation.h kernel/fast_memory.h drivers/activity.h drivers/ata.h drivers/cdrom.h drivers/floppy.h drivers/storage.h | $(BUILD_DIR)/fs
	$(CC) $(FAT_CFLAGS) -c $< -o $@

$(BUILD_DIR)/fs/path_contract.o: fs/path_contract.c fs/path_contract.h fs/fat.h | $(BUILD_DIR)/fs
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/fs/volume_generation.o: fs/volume_generation.c fs/volume_generation.h fs/fat.h | $(BUILD_DIR)/fs
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/atapi.o: drivers/atapi.c drivers/atapi.h drivers/activity.h drivers/ata.h kernel/io.h kernel/service.h drivers/serial.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/bitmap.o: drivers/bitmap.c drivers/bitmap.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/cirrus_vga.o: drivers/cirrus_vga.c drivers/cirrus_vga.h kernel/io.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/xga2.o: drivers/xga2.c drivers/xga2.h kernel/io.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/driver_model.o: drivers/driver_model.c drivers/driver_model.h drivers/audio_manager.h drivers/ata.h drivers/cdrom.h drivers/floppy.h drivers/gameport.h drivers/lpt.h drivers/pit.h drivers/rtc.h drivers/vga.h drivers/xga2.h kernel/driver_loader.h kernel/app_abi.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/gameport.o: drivers/gameport.c drivers/gameport.h drivers/pit.h kernel/io.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/lpt.o: drivers/lpt.c drivers/lpt.h drivers/pit.h kernel/io.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/cdrom.o: drivers/cdrom.c drivers/cdrom.h drivers/cd_module.h kernel/app_loader.h drivers/serial.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/ata.o: drivers/ata.c drivers/ata.h kernel/io.h kernel/service.h drivers/pit.h drivers/serial.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/bootlog.o: drivers/bootlog.c drivers/bootlog.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/floppy.o: drivers/floppy.c drivers/floppy.h kernel/io.h kernel/service.h kernel/driver_loader.h kernel/app_abi.h drivers/serial.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/ide.o: drivers/ide.c drivers/ide.h kernel/io.h kernel/service.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/rtc.o: drivers/rtc.c drivers/rtc.h drivers/pit.h kernel/io.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/pit.o: drivers/pit.c drivers/pit.h kernel/io.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/speaker.o: drivers/speaker.c drivers/speaker.h drivers/pit.h kernel/io.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/sb16.o: drivers/sb16.c drivers/sb16.h drivers/sb16_volume.h drivers/pit.h drivers/serial.h kernel/fast_memory.h kernel/heap.h kernel/io.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

# ---- External kernel drivers (.DRV) ----------------------------------------
PICOMEM_DRV_ELF := $(COMPILED_ELF_DIR)/picomem_drv.elf
PICOMEM_DRV     := $(APPS_OUT_DIR)/PICOMEM.DRV
SB16_DRV_ELF   := $(COMPILED_ELF_DIR)/sb16_drv.elf
SB16_DRV       := $(APPS_OUT_DIR)/SB16.DRV
ADLIB_DRV_ELF  := $(COMPILED_ELF_DIR)/adlib_drv.elf
ADLIB_DRV      := $(APPS_OUT_DIR)/ADLIB.DRV
NCR400_DRV_ELF := $(COMPILED_ELF_DIR)/ncr400_drv.elf
NCR400_DRV     := $(APPS_OUT_DIR)/NCR400.DRV
AHA154X_DRV_ELF := $(COMPILED_ELF_DIR)/aha154x_drv.elf
AHA154X_DRV     := $(APPS_OUT_DIR)/AHA154X.DRV
CH375_DRV_ELF   := $(COMPILED_ELF_DIR)/ch375_drv.elf
CH375_DRV       := $(APPS_OUT_DIR)/CH375.DRV
USBMOUSE_DRV_ELF := $(COMPILED_ELF_DIR)/usbmouse_drv.elf
USBMOUSE_DRV     := $(APPS_OUT_DIR)/USBMOUSE.DRV
RTL8139_DRV_ELF  := $(COMPILED_ELF_DIR)/rtl8139_drv.elf
RTL8139_DRV      := $(APPS_OUT_DIR)/RTL8139.DRV
SBC82621_DRV_ELF := $(COMPILED_ELF_DIR)/sbc82621_drv.elf
SBC82621_DRV     := $(APPS_OUT_DIR)/SBC82621.DRV
PS2MOUSE_DRV_ELF := $(COMPILED_ELF_DIR)/ps2mouse_drv.elf
PS2MOUSE_DRV     := $(APPS_OUT_DIR)/PS2MOUSE.DRV
SERMOUSE_DRV_ELF := $(COMPILED_ELF_DIR)/sermouse_drv.elf
SERMOUSE_DRV     := $(APPS_OUT_DIR)/SERMOUSE.DRV
NE2000_DRV_ELF   := $(COMPILED_ELF_DIR)/ne2000_drv.elf
NE2000_DRV       := $(APPS_OUT_DIR)/NE2000.DRV
NETCORE_DRV_ELF  := $(COMPILED_ELF_DIR)/netcore_drv.elf
NETCORE_DRV      := $(APPS_OUT_DIR)/NETCORE.DRV
THREEC509_DRV_ELF := $(COMPILED_ELF_DIR)/3c509_drv.elf
THREEC509_DRV     := $(APPS_OUT_DIR)/3C509.DRV
MCAFD_DRV_ELF    := $(COMPILED_ELF_DIR)/mcafd_drv.elf
MCAFD_DRV        := $(APPS_OUT_DIR)/MCAFD.DRV
IBMSCSI_DRV_ELF  := $(COMPILED_ELF_DIR)/ibmscsi_drv.elf
IBMSCSI_DRV      := $(APPS_OUT_DIR)/IBMSCSI.DRV

$(BUILD_DIR)/apps/picomem_drv_main.o: apps/picomem_driver/picomem_drv.c kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/picomem_drv_entry.o: apps/picomem_driver/picomem_drv_entry.c kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(PICOMEM_DRV_ELF): $(BUILD_DIR)/apps/picomem_drv_entry.o $(BUILD_DIR)/apps/picomem_drv_main.o tools/driver.ld | $(COMPILED_ELF_DIR)
	ld -T tools/driver.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/picomem_drv_entry.o \
	    $(BUILD_DIR)/apps/picomem_drv_main.o -o $@
	@echo "ld: $@ built"

$(PICOMEM_DRV): $(PICOMEM_DRV_ELF) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --driver --no-compress --elf $< --name PICOMEM --output $@

$(BUILD_DIR)/apps/sb16_drv_main.o: apps/sb16_driver/sb16_drv.c kernel/app_abi.h kernel/fast_memory.h drivers/sb16_volume.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/sb16_drv_entry.o: apps/sb16_driver/sb16_drv_entry.c kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(SB16_DRV_ELF): $(BUILD_DIR)/apps/sb16_drv_entry.o $(BUILD_DIR)/apps/sb16_drv_main.o tools/driver.ld | $(COMPILED_ELF_DIR)
	ld -T tools/driver.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/sb16_drv_entry.o \
	    $(BUILD_DIR)/apps/sb16_drv_main.o -o $@
	@echo "ld: $@ built"

$(SB16_DRV): $(SB16_DRV_ELF) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --driver --elf $< --name SB16 --output $@

$(BUILD_DIR)/apps/adlib_drv_main.o: apps/adlib_driver/adlib_drv.c kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/adlib_drv_entry.o: apps/adlib_driver/adlib_drv_entry.c kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(ADLIB_DRV_ELF): $(BUILD_DIR)/apps/adlib_drv_entry.o $(BUILD_DIR)/apps/adlib_drv_main.o tools/driver.ld | $(COMPILED_ELF_DIR)
	ld -T tools/driver.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/adlib_drv_entry.o \
	    $(BUILD_DIR)/apps/adlib_drv_main.o -o $@
	@echo "ld: $@ built"

$(ADLIB_DRV): $(ADLIB_DRV_ELF) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --driver --elf $< --name ADLIB --output $@

$(BUILD_DIR)/apps/ncr400_drv_main.o: apps/ncr53c400_driver/ncr53c400_drv.c kernel/app_abi.h drivers/storage.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/ncr400_drv_entry.o: apps/ncr53c400_driver/ncr53c400_drv_entry.c kernel/app_abi.h drivers/storage.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(NCR400_DRV_ELF): $(BUILD_DIR)/apps/ncr400_drv_entry.o $(BUILD_DIR)/apps/ncr400_drv_main.o tools/driver.ld | $(COMPILED_ELF_DIR)
	ld -T tools/driver.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/ncr400_drv_entry.o \
	    $(BUILD_DIR)/apps/ncr400_drv_main.o -o $@
	@echo "ld: $@ built"

$(NCR400_DRV): $(NCR400_DRV_ELF) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --driver --elf $< --name NCR400 --output $@

$(BUILD_DIR)/apps/aha154x_drv_main.o: apps/aha154x_driver/aha154x_drv.c kernel/app_abi.h drivers/storage.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/aha154x_drv_entry.o: apps/aha154x_driver/aha154x_drv_entry.c kernel/app_abi.h drivers/storage.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(AHA154X_DRV_ELF): $(BUILD_DIR)/apps/aha154x_drv_entry.o $(BUILD_DIR)/apps/aha154x_drv_main.o tools/driver.ld | $(COMPILED_ELF_DIR)
	ld -T tools/driver.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/aha154x_drv_entry.o \
	    $(BUILD_DIR)/apps/aha154x_drv_main.o -o $@
	@echo "ld: $@ built"

$(AHA154X_DRV): $(AHA154X_DRV_ELF) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --driver --elf $< --name AHA154X --output $@

$(BUILD_DIR)/apps/ch375_drv_main.o: apps/ch375_driver/ch375_drv.c kernel/app_abi.h drivers/storage.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/ch375_drv_entry.o: apps/ch375_driver/ch375_drv_entry.c kernel/app_abi.h drivers/storage.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(CH375_DRV_ELF): $(BUILD_DIR)/apps/ch375_drv_entry.o $(BUILD_DIR)/apps/ch375_drv_main.o tools/driver.ld | $(COMPILED_ELF_DIR)
	ld -T tools/driver.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/ch375_drv_entry.o \
	    $(BUILD_DIR)/apps/ch375_drv_main.o -o $@
	@echo "ld: $@ built"

$(CH375_DRV): $(CH375_DRV_ELF) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --driver --elf $< --name CH375 --output $@

$(BUILD_DIR)/apps/ps2mouse_drv_main.o: apps/ps2_mouse_driver/ps2mouse_drv.c kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/ps2mouse_drv_entry.o: apps/ps2_mouse_driver/ps2mouse_drv_entry.c kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(PS2MOUSE_DRV_ELF): $(BUILD_DIR)/apps/ps2mouse_drv_entry.o $(BUILD_DIR)/apps/ps2mouse_drv_main.o tools/driver.ld | $(COMPILED_ELF_DIR)
	ld -T tools/driver.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/ps2mouse_drv_entry.o \
	    $(BUILD_DIR)/apps/ps2mouse_drv_main.o -o $@
	@echo "ld: $@ built"

$(PS2MOUSE_DRV): $(PS2MOUSE_DRV_ELF) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --driver --elf $< --name PS2MOUSE --output $@

$(BUILD_DIR)/apps/usbmouse_drv_main.o: apps/usb_mouse_driver/usbmouse_drv.c apps/usb_mouse_driver/usbmouse_diag.h kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/usbmouse_drv_entry.o: apps/usb_mouse_driver/usbmouse_drv_entry.c kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(USBMOUSE_DRV_ELF): $(BUILD_DIR)/apps/usbmouse_drv_entry.o $(BUILD_DIR)/apps/usbmouse_drv_main.o tools/driver.ld | $(COMPILED_ELF_DIR)
	ld -T tools/driver.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/usbmouse_drv_entry.o \
	    $(BUILD_DIR)/apps/usbmouse_drv_main.o -o $@
	@echo "ld: $@ built"

$(USBMOUSE_DRV): $(USBMOUSE_DRV_ELF) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --driver --no-compress --elf $< --name USBMOUSE --output $@

$(BUILD_DIR)/apps/rtl8139_drv_main.o: apps/rtl8139_driver/rtl8139_drv.c kernel/app_abi.h drivers/ne2k_net.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/rtl8139_drv_entry.o: apps/rtl8139_driver/rtl8139_drv_entry.c kernel/app_abi.h drivers/ne2k_net.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(RTL8139_DRV_ELF): $(BUILD_DIR)/apps/rtl8139_drv_entry.o $(BUILD_DIR)/apps/rtl8139_drv_main.o tools/driver.ld | $(COMPILED_ELF_DIR)
	ld -T tools/driver.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/rtl8139_drv_entry.o \
	    $(BUILD_DIR)/apps/rtl8139_drv_main.o -o $@
	@echo "ld: $@ built"

$(RTL8139_DRV): $(RTL8139_DRV_ELF) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --driver --elf $< --name RTL8139 --output $@

$(BUILD_DIR)/apps/sbc82621_drv_main.o: apps/sbc82621_driver/sbc82621_drv.c kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/sbc82621_drv_entry.o: apps/sbc82621_driver/sbc82621_drv_entry.c kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(SBC82621_DRV_ELF): $(BUILD_DIR)/apps/sbc82621_drv_entry.o $(BUILD_DIR)/apps/sbc82621_drv_main.o tools/driver.ld | $(COMPILED_ELF_DIR)
	ld -T tools/driver.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/sbc82621_drv_entry.o \
	    $(BUILD_DIR)/apps/sbc82621_drv_main.o -o $@
	@echo "ld: $@ built"

$(SBC82621_DRV): $(SBC82621_DRV_ELF) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --driver --elf $< --name SBC82621 --output $@

$(BUILD_DIR)/apps/sermouse_drv_main.o: apps/serial_mouse_driver/sermouse_drv.c kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/sermouse_drv_entry.o: apps/serial_mouse_driver/sermouse_drv_entry.c kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(SERMOUSE_DRV_ELF): $(BUILD_DIR)/apps/sermouse_drv_entry.o $(BUILD_DIR)/apps/sermouse_drv_main.o tools/driver.ld | $(COMPILED_ELF_DIR)
	ld -T tools/driver.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/sermouse_drv_entry.o \
	    $(BUILD_DIR)/apps/sermouse_drv_main.o -o $@
	@echo "ld: $@ built"

$(SERMOUSE_DRV): $(SERMOUSE_DRV_ELF) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --driver --elf $< --name SERMOUSE --output $@

$(BUILD_DIR)/apps/ne2000_drv_main.o: apps/ne2000_driver/ne2000_drv.c kernel/app_abi.h drivers/ne2k_net.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/http11.o: $(HAMNET_CORE_DIR)/src/hamnet_http11.c $(HAMNET_CORE_DIR)/include/hamnet_http11.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@

$(BUILD_DIR)/drivers/hamnet_resource_policy.o: $(HAMNET_CORE_DIR)/src/hamnet_resource_policy.c $(HAMNET_CORE_DIR)/include/hamnet_resource_policy.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@

$(BUILD_DIR)/apps/ne2000_drv_entry.o: apps/ne2000_driver/ne2000_drv_entry.c kernel/app_abi.h drivers/ne2k_net.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(NE2000_DRV_ELF): $(BUILD_DIR)/apps/ne2000_drv_entry.o $(BUILD_DIR)/apps/ne2000_drv_main.o tools/driver.ld | $(COMPILED_ELF_DIR)
	ld -T tools/driver.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/ne2000_drv_entry.o \
	    $(BUILD_DIR)/apps/ne2000_drv_main.o -o $@
	@echo "ld: $@ built"

$(NE2000_DRV): $(NE2000_DRV_ELF) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --driver --elf $< --name NE2000 --output $@

$(BUILD_DIR)/apps/netcore_drv_main.o: apps/netcore_driver/netcore_drv.c kernel/app_abi.h drivers/ne2k_net.h $(HAMNET_CORE_DIR)/include/hamnet_http11.h $(HAMNET_CORE_DIR)/include/hamnet_resource_policy.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@

$(BUILD_DIR)/apps/netcore_drv_entry.o: apps/netcore_driver/netcore_drv_entry.c kernel/app_abi.h drivers/ne2k_net.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(NETCORE_DRV_ELF): $(BUILD_DIR)/apps/netcore_drv_entry.o $(BUILD_DIR)/apps/netcore_drv_main.o $(BUILD_DIR)/drivers/http11.o $(BUILD_DIR)/drivers/hamnet_resource_policy.o tools/driver.ld | $(COMPILED_ELF_DIR)
	ld -T tools/driver.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/netcore_drv_entry.o \
	    $(BUILD_DIR)/apps/netcore_drv_main.o \
	    $(BUILD_DIR)/drivers/http11.o \
	    $(BUILD_DIR)/drivers/hamnet_resource_policy.o -o $@
	@echo "ld: $@ built"

$(NETCORE_DRV): $(NETCORE_DRV_ELF) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --driver --elf $< --name NETCORE --output $@

$(BUILD_DIR)/apps/3c509_drv_main.o: apps/3c509_driver/3c509_drv.c kernel/app_abi.h drivers/ne2k_net.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/3c509_drv_entry.o: apps/3c509_driver/3c509_drv_entry.c kernel/app_abi.h drivers/ne2k_net.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(THREEC509_DRV_ELF): $(BUILD_DIR)/apps/3c509_drv_entry.o $(BUILD_DIR)/apps/3c509_drv_main.o tools/driver.ld | $(COMPILED_ELF_DIR)
	ld -T tools/driver.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/3c509_drv_entry.o \
	    $(BUILD_DIR)/apps/3c509_drv_main.o -o $@
	@echo "ld: $@ built"

$(THREEC509_DRV): $(THREEC509_DRV_ELF) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --driver --elf $< --name 3C509 --output $@

$(BUILD_DIR)/apps/mcafd_drv_main.o: apps/mca_floppy_driver/mca_floppy_drv.c kernel/app_abi.h drivers/storage.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/mcafd_drv_entry.o: apps/mca_floppy_driver/mca_floppy_drv_entry.c kernel/app_abi.h drivers/storage.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(MCAFD_DRV_ELF): $(BUILD_DIR)/apps/mcafd_drv_entry.o $(BUILD_DIR)/apps/mcafd_drv_main.o tools/driver.ld | $(COMPILED_ELF_DIR)
	ld -T tools/driver.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/mcafd_drv_entry.o \
	    $(BUILD_DIR)/apps/mcafd_drv_main.o -o $@
	@echo "ld: $@ built"

$(MCAFD_DRV): $(MCAFD_DRV_ELF) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --driver --no-compress --elf $< --name MCAFD --output $@

$(BUILD_DIR)/apps/ibmscsi_drv_main.o: apps/ibm_mca_scsi_driver/ibm_mca_scsi_drv.c kernel/app_abi.h drivers/storage.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/ibmscsi_drv_entry.o: apps/ibm_mca_scsi_driver/ibm_mca_scsi_drv_entry.c kernel/app_abi.h drivers/storage.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

$(IBMSCSI_DRV_ELF): $(BUILD_DIR)/apps/ibmscsi_drv_entry.o $(BUILD_DIR)/apps/ibmscsi_drv_main.o tools/driver.ld | $(COMPILED_ELF_DIR)
	ld -T tools/driver.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/ibmscsi_drv_entry.o \
	    $(BUILD_DIR)/apps/ibmscsi_drv_main.o -o $@
	@echo "ld: $@ built"

$(IBMSCSI_DRV): $(IBMSCSI_DRV_ELF) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --driver --no-compress --elf $< --name IBMSCSI --output $@

$(BUILD_DIR)/drivers/storage.o: drivers/storage.c drivers/storage.h drivers/ata.h drivers/atapi.h drivers/cdrom.h drivers/floppy.h kernel/driver_loader.h kernel/app_abi.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/surface.o: drivers/surface.c drivers/surface.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/theme.o: drivers/theme.c drivers/theme.h drivers/vga.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/video_profile.o: drivers/video_profile.c drivers/video_profile.h drivers/vga.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/keyboard.o: drivers/keyboard.c drivers/keyboard.h kernel/io.h drivers/serial.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/ne2k_net.o: drivers/ne2k_net.c drivers/ne2k_net.h kernel/app_abi.h kernel/driver_loader.h kernel/io.h kernel/service.h drivers/pit.h apps/prefs.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/ps2_mouse.o: drivers/ps2_mouse.c drivers/ps2_mouse.h kernel/io.h drivers/serial.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/serial_mouse.o: drivers/serial_mouse.c drivers/serial_mouse.h drivers/ps2_mouse.h drivers/serial.h kernel/io.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/drivers/serial.o: drivers/serial.c drivers/serial.h kernel/io.h | $(BUILD_DIR)/drivers
	$(CC) $(CFLAGS) -c $< -o $@

$(GENERATED_DIR)/vga-tune-%.stamp: | $(GENERATED_DIR)
	rm -f $(GENERATED_DIR)/vga-tune-*.stamp
	touch $@

$(BUILD_DIR)/drivers/vga_planar_pack.o: drivers/vga_planar_pack.c drivers/vga_planar_pack.h $(VGA_TUNE_STAMP) | $(BUILD_DIR)/drivers
	$(CC) $(VGA_HOT_CFLAGS) -c $< -o $@

$(GENERATED_DIR)/vga-transfer-%.stamp: | $(GENERATED_DIR)
	rm -f $(GENERATED_DIR)/vga-transfer-*.stamp
	touch $@

$(BUILD_DIR)/drivers/vga_primitives.o: drivers/vga_primitives.c drivers/vga_primitives.h $(VGA_TUNE_STAMP) $(VGA_TRANSFER_STAMP) | $(BUILD_DIR)/drivers
	$(CC) $(VGA_HOT_CFLAGS) $(VGA_TRANSFER_CFLAGS) -c $< -o $@

$(GENERATED_DIR)/vga-sprite-%.stamp: | $(GENERATED_DIR)
	rm -f $(GENERATED_DIR)/vga-sprite-*.stamp
	touch $@

$(BUILD_DIR)/drivers/vga_sprite_rows.o: drivers/vga_sprite_rows.c drivers/vga_sprite_rows.h $(VGA_TUNE_STAMP) $(VGA_SPRITE_STAMP) | $(BUILD_DIR)/drivers
	$(CC) $(VGA_HOT_CFLAGS) $(VGA_SPRITE_CFLAGS) -c $< -o $@

$(BOOT_LOGO_FALLBACK_C) $(BOOT_LOGO_FALLBACK_H) &: Backdrop/MHS.BMP tools/mkasset.py | $(GENERATED_DIR)
	python3 tools/mkasset.py --input Backdrop/MHS.BMP --c-output $(BOOT_LOGO_FALLBACK_C) --h-output $(BOOT_LOGO_FALLBACK_H)

$(BUILD_DIR)/generated/boot_logo.o: $(BOOT_LOGO_FALLBACK_C) $(BOOT_LOGO_FALLBACK_H) | $(GENERATED_DIR)
	$(CC) $(CFLAGS) -c $(BOOT_LOGO_FALLBACK_C) -o $@

$(BUILD_DIR)/drivers/vga.o: drivers/vga.c drivers/vga.h drivers/vga_primitives.h drivers/vga_sprite_rows.h drivers/vga_planar_pack.h drivers/bitmap.h drivers/cirrus_vga.h drivers/theme.h kernel/io.h kernel/version.h drivers/vga_fonts.inc $(VGA_TUNE_STAMP) | $(BUILD_DIR)/drivers
	$(CC) $(VGA_HOT_CFLAGS) -c $< -o $@


$(KERNEL_ELF): $(OBJS) linker.ld | $(COMPILED_ELF_DIR) $(KERNEL_OUT_DIR)
	$(LD) $(LDFLAGS) $(OBJS) -o $@

$(HAMLOAD_META) $(HAMLOAD_KERNEL_BIN): $(KERNEL_ELF) $(HAMLOAD_PRELOAD_DRIVERS) tools/mkhamload_meta.py | $(BUILD_DIR)/generated $(KERNEL_OUT_DIR)
	python3 tools/mkhamload_meta.py --kernel-elf $(KERNEL_ELF) --kernel-bin $(HAMLOAD_KERNEL_BIN) --include-out $(HAMLOAD_META) \
		--buffer-rel-paras $(HAMLOAD_BUFFER_REL_PARAS) --buffer-paras $(HAMLOAD_BUFFER_PARAS) \
		$(foreach driver,$(HAMLOAD_PRELOAD_DRIVERS),--preload-driver $(driver))

$(BUILD_DIR)/dos/hamload.o: dos/hamload.S $(HAMLOAD_META) | $(BUILD_DIR)/dos
	$(CC) $(ASFLAGS) -I$(GENERATED_DIR) -c $< -o $@

$(HAMLOAD_ELF): $(BUILD_DIR)/dos/hamload.o | $(COMPILED_ELF_DIR)
	$(LD) -m elf_i386 -nostdlib -Ttext 0x0 $< -o $@

$(HAMLOAD_BIN): $(HAMLOAD_ELF) | $(BOOT_OUT_DIR)
	$(OBJCOPY) -O binary $< $@

$(HAMLOAD_EXE): $(HAMLOAD_BIN) tools/mkmz.py | $(BOOT_OUT_DIR)
	python3 tools/mkmz.py --input $< --output $@ \
		--minalloc-paras $(HAMLOAD_MZ_MINALLOC_PARAS) \
		--maxalloc-paras $(HAMLOAD_MZ_MINALLOC_PARAS) \
		--staging-rel-paras $(HAMLOAD_BUFFER_REL_PARAS) \
		--staging-paras $(HAMLOAD_BUFFER_PARAS)

$(BUILD_DIR)/dos/reboot.o: dos/reboot.S | $(BUILD_DIR)/dos
	$(CC) $(ASFLAGS) -c $< -o $@

$(REBOOT_ELF): $(BUILD_DIR)/dos/reboot.o | $(COMPILED_ELF_DIR)
	$(LD) -m elf_i386 -nostdlib -Ttext 0x100 $< -o $@

$(REBOOT_COM): $(REBOOT_ELF) | $(BOOT_OUT_DIR)
	$(OBJCOPY) -O binary $< $@

$(BUILD_DIR)/dos/choice.o: dos/choice.S | $(BUILD_DIR)/dos
	$(CC) $(ASFLAGS) -c $< -o $@

$(CHOICE_ELF): $(BUILD_DIR)/dos/choice.o | $(COMPILED_ELF_DIR)
	$(LD) -m elf_i386 -nostdlib -Ttext 0x100 $< -o $@

$(CHOICE_COM): $(CHOICE_ELF) | $(BOOT_OUT_DIR)
	$(OBJCOPY) -O binary $< $@

$(BUILD_DIR)/dos/imlchk.o: dos/imlchk.S | $(BUILD_DIR)/dos
	$(CC) $(ASFLAGS) -c $< -o $@

$(IMLCHK_ELF): $(BUILD_DIR)/dos/imlchk.o | $(COMPILED_ELF_DIR)
	$(LD) -m elf_i386 -nostdlib -Ttext 0x100 $< -o $@

$(IMLCHK_COM): $(IMLCHK_ELF) | $(BOOT_OUT_DIR)
	$(OBJCOPY) -O binary $< $@

$(BUILD_DIR)/dos/setblue.o: dos/setblue.S | $(BUILD_DIR)/dos
	$(CC) $(ASFLAGS) -c $< -o $@

$(SETBLUE_ELF): $(BUILD_DIR)/dos/setblue.o | $(COMPILED_ELF_DIR)
	$(LD) -m elf_i386 -nostdlib -Ttext 0x100 $< -o $@

$(SETBLUE_COM): $(SETBLUE_ELF) | $(BOOT_OUT_DIR)
	$(OBJCOPY) -O binary $< $@

$(BUILD_DIR)/dos/setupui.o: dos/setupui.S | $(BUILD_DIR)/dos
	$(CC) $(ASFLAGS) -c $< -o $@

$(SETUPUI_ELF): $(BUILD_DIR)/dos/setupui.o | $(COMPILED_ELF_DIR)
	$(LD) -m elf_i386 -nostdlib -Ttext 0x100 $< -o $@

$(SETUPUI_COM): $(SETUPUI_ELF) | $(BOOT_OUT_DIR)
	$(OBJCOPY) -O binary $< $@

$(BUILD_DIR)/dos/vidtest.o: dos/vidtest.S | $(BUILD_DIR)/dos
	$(CC) $(ASFLAGS) -c $< -o $@

$(VIDTEST_ELF): $(BUILD_DIR)/dos/vidtest.o | $(COMPILED_ELF_DIR)
	$(LD) -m elf_i386 -nostdlib -Ttext 0x100 $< -o $@

$(VIDTEST_COM): $(VIDTEST_ELF) | $(DIAGNOSTICS_DIR)
	$(OBJCOPY) -O binary $< $@

vidtest: $(VIDTEST_COM)

$(BUILD_DIR)/dos/hdmbr.o: boot/hdmbr.S | $(BUILD_DIR)/dos
	$(CC) $(ASFLAGS) -c $< -o $@

$(HDMBR_ELF): $(BUILD_DIR)/dos/hdmbr.o | $(COMPILED_ELF_DIR)
	$(LD) -m elf_i386 -nostdlib -Ttext 0x0 $< -o $@

$(HDMBR_BIN): $(HDMBR_ELF) | $(BOOT_OUT_DIR)
	$(OBJCOPY) -O binary $< $@

$(BUILD_DIR)/dos/hdboot.o: boot/hdboot.S | $(BUILD_DIR)/dos
	$(CC) $(ASFLAGS) -c $< -o $@

$(HDBOOT_ELF): $(BUILD_DIR)/dos/hdboot.o | $(COMPILED_ELF_DIR)
	$(LD) -m elf_i386 -nostdlib -Ttext 0x0 $< -o $@

$(HDBOOT_BIN): $(HDBOOT_ELF) | $(BOOT_OUT_DIR)
	$(OBJCOPY) -O binary $< $@

$(BUILD_DIR)/dos/hdstage2.o: boot/hdstage2.S $(HAMLOAD_META) | $(BUILD_DIR)/dos
	$(CC) $(ASFLAGS) -I$(GENERATED_DIR) -c $< -o $@

$(HDSTAGE2_ELF): $(BUILD_DIR)/dos/hdstage2.o | $(COMPILED_ELF_DIR)
	$(LD) -m elf_i386 -nostdlib -Ttext 0x0 $< -o $@

$(HDSTAGE2_BIN): $(HDSTAGE2_ELF) | $(BOOT_OUT_DIR)
	$(OBJCOPY) -O binary $< $@

$(BUILD_DIR)/dos/pmhello.o: dos/pmhello.S | $(BUILD_DIR)/dos
	$(CC) $(ASFLAGS) -c $< -o $@

$(PMHELLO_ELF): $(BUILD_DIR)/dos/pmhello.o | $(COMPILED_ELF_DIR)
	$(LD) -m elf_i386 -nostdlib -Ttext 0x0 $< -o $@

$(PMHELLO_BIN): $(PMHELLO_ELF) | $(DIAGNOSTICS_DIR)
	$(OBJCOPY) -O binary $< $@

$(PMHELLO_EXE): $(PMHELLO_BIN) tools/mkmz.py
	python3 tools/mkmz.py --input $< --output $@ --minalloc-paras 0x20 --maxalloc-paras 0x20

pmhello: $(PMHELLO_EXE)

floppy: $(FREEDOS_IMG)

floppy-2mb: $(FREEDOS_IMG)

install-target: $(INSTALL_TARGET_IMG)

freedos-fetch: $(FREEDOS_ZIP)

freedos-floppy: $(FREEDOS_IMG)
	python3 tools/organize_build.py --build-dir $(BUILD_DIR)

$(INSTALL_TARGET_IMG): tools/mkfatdisk.py | $(BUILD_DIR)
	python3 tools/mkfatdisk.py --output $@ --size-bytes 20971520 --fat-format 16 --label HAMTEST

run: $(FREEDOS_IMG)
	$(QEMU) -machine pc -m 32M -boot a -vga std -drive file=$(FREEDOS_IMG),format=raw,if=floppy -serial stdio -display none -no-reboot

run-2mb: $(FREEDOS_IMG)
	$(QEMU) -machine pc -m 2M -boot a -vga std -drive file=$(FREEDOS_IMG),format=raw,if=floppy -serial stdio -display none -no-reboot

freedos-run: $(FREEDOS_IMG)
	$(QEMU) -machine pc -m 16M -boot a -vga std -drive file=$(FREEDOS_IMG),format=raw,if=floppy

install-test-run: $(FREEDOS_IMG) $(INSTALL_TARGET_IMG)
	$(QEMU) -machine pc -m 16M -boot a -vga std -drive file=$(FREEDOS_IMG),format=raw,if=floppy -drive file=$(INSTALL_TARGET_IMG),format=raw,if=ide,index=1,media=disk

dist-c: $(FREEDOS_IMG) | $(BUILD_DIR)
	@if [ "$(ALLOW_HD_REFRESH)" != "1" ]; then \
		echo "dist-c is blocked so build/hamster-c.img is not silently refreshed."; \
		echo "Run 'make dist-c-force' or 'make dist-c ALLOW_HD_REFRESH=1' when you really want to rebuild it."; \
		exit 1; \
	fi
	python3 tools/mkinstalled.py --floppy $(FREEDOS_IMG) --hd $(BUILD_DIR)/hamster-c.img --create-fresh

dist-c-force: $(FREEDOS_IMG) | $(BUILD_DIR)
	python3 tools/mkinstalled.py --floppy $(FREEDOS_IMG) --hd $(BUILD_DIR)/hamster-c.img --create-fresh

boot-check: $(FREEDOS_IMG) | $(LOGS_DIR)
	rm -f $(LOGS_DIR)/boot-check.log
	timeout $(BOOT_CHECK_TIMEOUT) $(QEMU) -machine pc -m 32M -boot a -vga std -drive file=$(FREEDOS_IMG),format=raw,if=floppy -serial file:$(LOGS_DIR)/boot-check.log -display none -no-reboot; test $$? -eq 124
	grep -q "Input loop ready" $(LOGS_DIR)/boot-check.log

boot-check-2mb: $(FREEDOS_IMG) | $(LOGS_DIR)
	rm -f $(LOGS_DIR)/boot-check-2mb.log
	timeout $(BOOT_CHECK_TIMEOUT) $(QEMU) -machine pc -m 2M -boot a -vga std -drive file=$(FREEDOS_IMG),format=raw,if=floppy -serial file:$(LOGS_DIR)/boot-check-2mb.log -display none -no-reboot; test $$? -eq 124
	grep -q "Multitasking: classic cooperative" $(LOGS_DIR)/boot-check-2mb.log
	grep -q "IDT/PIC ready; IRQs: KBD MOUSE EDGE 18HZ" $(LOGS_DIR)/boot-check-2mb.log
	grep -q "Input loop ready" $(LOGS_DIR)/boot-check-2mb.log

boot-check-4mb: $(FREEDOS_IMG) | $(LOGS_DIR)
	rm -f $(LOGS_DIR)/boot-check-4mb.log
	timeout $(BOOT_CHECK_TIMEOUT) $(QEMU) -machine pc -m 4M -boot a -vga std -drive file=$(FREEDOS_IMG),format=raw,if=floppy -serial file:$(LOGS_DIR)/boot-check-4mb.log -display none -no-reboot; test $$? -eq 124
	grep -q "Multitasking: enhanced cooperative (4 MB+)" $(LOGS_DIR)/boot-check-4mb.log
	grep -q "IDT/PIC ready; IRQs: KBD MOUSE EDGE 50HZ" $(LOGS_DIR)/boot-check-4mb.log
	grep -q "Input loop ready" $(LOGS_DIR)/boot-check-4mb.log

boot-check-8mb: $(FREEDOS_IMG) | $(LOGS_DIR)
	rm -f $(LOGS_DIR)/boot-check-8mb.log
	timeout $(BOOT_CHECK_TIMEOUT) $(QEMU) -machine pc -m 8M -boot a -vga std -drive file=$(FREEDOS_IMG),format=raw,if=floppy -serial file:$(LOGS_DIR)/boot-check-8mb.log -display none -no-reboot; test $$? -eq 124
	grep -q "Multitasking: Hybrid Preemptive (8 MB class)" $(LOGS_DIR)/boot-check-8mb.log
	grep -q "App protection: Ring 3 private address spaces" $(LOGS_DIR)/boot-check-8mb.log
	grep -q "IDT/PIC ready; IRQs: KBD MOUSE EDGE 50HZ" $(LOGS_DIR)/boot-check-8mb.log
	grep -q "Input loop ready" $(LOGS_DIR)/boot-check-8mb.log

boot-check-crypto: $(FREEDOS_IMG) $(CRYPTO_PROBE_APP) | $(LOGS_DIR)
	cp $(FREEDOS_IMG) $(TESTS_OUT_DIR)/crypto-runtime.img
	mcopy -o -i $(TESTS_OUT_DIR)/crypto-runtime.img $(CRYPTO_PROBE_APP) ::/PROGRAMS/STARTUP/CRYPTOT.APP
	rm -f $(LOGS_DIR)/boot-check-crypto.log $(LOGS_DIR)/boot-check-crypto-8mb.log
	timeout 20s $(QEMU) -machine pc -m 2M -boot a -vga std -drive file=$(TESTS_OUT_DIR)/crypto-runtime.img,format=raw,if=floppy -serial file:$(LOGS_DIR)/boot-check-crypto.log -display none -no-reboot; test $$? -eq 124
	grep -q "CRYPTO PROBE: PASS" $(LOGS_DIR)/boot-check-crypto.log
	! grep -q "crypto: load failed" $(LOGS_DIR)/boot-check-crypto.log
	! grep -q "crypto: invalid descriptor" $(LOGS_DIR)/boot-check-crypto.log
	! grep -q "PANIC:" $(LOGS_DIR)/boot-check-crypto.log
	timeout 20s $(QEMU) -machine pc -m 8M -boot a -vga std -drive file=$(TESTS_OUT_DIR)/crypto-runtime.img,format=raw,if=floppy -serial file:$(LOGS_DIR)/boot-check-crypto-8mb.log -display none -no-reboot; test $$? -eq 124
	grep -q "CRYPTO PROBE: PASS" $(LOGS_DIR)/boot-check-crypto-8mb.log
	! grep -q "APPFAULT:" $(LOGS_DIR)/boot-check-crypto-8mb.log
	! grep -q "PANIC:" $(LOGS_DIR)/boot-check-crypto-8mb.log

boot-check-vm86-module: $(FREEDOS_IMG) $(VM86_MODULE_TEST_COM) $(VM86_EXE_TEST_EXE) $(VM86_HANG_TEST_COM) dos/Boulder.exe | $(LOGS_DIR)
	cp $(FREEDOS_IMG) $(TESTS_OUT_DIR)/vm86-module.img
	mcopy -o -i $(TESTS_OUT_DIR)/vm86-module.img $(VM86_MODULE_TEST_COM) ::/VM86T.COM
	mcopy -o -i $(TESTS_OUT_DIR)/vm86-module.img $(VM86_HANG_TEST_COM) ::/VM86H.COM
	mcopy -o -i $(TESTS_OUT_DIR)/vm86-module.img $(VM86_EXE_TEST_EXE) ::/VM86E.EXE
	mcopy -o -i $(TESTS_OUT_DIR)/vm86-module.img dos/Boulder.exe ::/DOS/BOULDER.COM
	mcopy -o -i $(TESTS_OUT_DIR)/vm86-module.img $(VM86_MODULE_TEST_COM) ::/VM86TEST.FLG
	mcopy -o -i $(TESTS_OUT_DIR)/vm86-module.img $(VM86_MODULE_TEST_COM) ::/BOULDER.FLG
	rm -f $(LOGS_DIR)/boot-check-vm86-module.log
	timeout 45s $(QEMU) -machine pc -m 2M -boot a -vga std -drive file=$(TESTS_OUT_DIR)/vm86-module.img,format=raw,if=floppy -serial file:$(LOGS_DIR)/boot-check-vm86-module.log -display none -no-reboot; test $$? -eq 124
	grep -q "VM86: DOSVM.APP loaded" $(LOGS_DIR)/boot-check-vm86-module.log
	grep -q "VM86: self-test rc 42" $(LOGS_DIR)/boot-check-vm86-module.log
	grep -q "VM86: EXE startup rc 43" $(LOGS_DIR)/boot-check-vm86-module.log
	grep -q "VM86: hard-abort rc 254" $(LOGS_DIR)/boot-check-vm86-module.log
	grep -q "VM86STAT: Boulder profile rc 254" $(LOGS_DIR)/boot-check-vm86-module.log
	grep -q "VM86: DOSVM.APP unloaded" $(LOGS_DIR)/boot-check-vm86-module.log
	grep -q "Input loop ready" $(LOGS_DIR)/boot-check-vm86-module.log
	! grep -q "PANIC:" $(LOGS_DIR)/boot-check-vm86-module.log

boot-check-adlib: $(FREEDOS_IMG) | $(LOGS_DIR)
	rm -f $(LOGS_DIR)/boot-check-adlib.log
	timeout $(BOOT_CHECK_TIMEOUT) $(QEMU) -machine pc -m 32M -boot a -vga std -audiodev driver=none,id=audio -device adlib,audiodev=audio -drive file=$(FREEDOS_IMG),format=raw,if=floppy -serial file:$(LOGS_DIR)/boot-check-adlib.log -display none -no-reboot; test $$? -eq 124
	grep -q "ADLIB.DRV: OPL2 detected at 0x388" $(LOGS_DIR)/boot-check-adlib.log
	grep -q "Input loop ready" $(LOGS_DIR)/boot-check-adlib.log

boot-check-ct1680: $(FREEDOS_IMG) | $(LOGS_DIR)
	rm -f $(LOGS_DIR)/boot-check-ct1680-220.log $(LOGS_DIR)/boot-check-ct1680-240.log
	timeout $(BOOT_CHECK_TIMEOUT) $(QEMU) -machine pc -m 32M -boot a -vga std -audiodev driver=none,id=audio -device sb16,audiodev=audio,version=0x0302,iobase=0x220,irq=5,dma=1 -device adlib,audiodev=audio -drive file=$(FREEDOS_IMG),format=raw,if=floppy -serial file:$(LOGS_DIR)/boot-check-ct1680-220.log -display none -no-reboot; test $$? -eq 124
	grep -q "SB16.DRV: detected at 0x00000220" $(LOGS_DIR)/boot-check-ct1680-220.log
	! grep -q "ADLIB.DRV: OPL2 detected" $(LOGS_DIR)/boot-check-ct1680-220.log
	grep -q "Input loop ready" $(LOGS_DIR)/boot-check-ct1680-220.log
	timeout $(BOOT_CHECK_TIMEOUT) $(QEMU) -machine pc -m 32M -boot a -vga std -audiodev driver=none,id=audio -device sb16,audiodev=audio,version=0x0302,iobase=0x240,irq=5,dma=1 -device adlib,audiodev=audio -drive file=$(FREEDOS_IMG),format=raw,if=floppy -serial file:$(LOGS_DIR)/boot-check-ct1680-240.log -display none -no-reboot; test $$? -eq 124
	grep -q "SB16.DRV: detected at 0x00000240" $(LOGS_DIR)/boot-check-ct1680-240.log
	! grep -q "ADLIB.DRV: OPL2 detected" $(LOGS_DIR)/boot-check-ct1680-240.log
	grep -q "Input loop ready" $(LOGS_DIR)/boot-check-ct1680-240.log

boot-check-sb16-resources: $(FREEDOS_IMG) | $(LOGS_DIR)
	rm -f $(LOGS_DIR)/boot-check-sb16-irq10.log $(LOGS_DIR)/boot-check-sb16-irq2.log
	timeout $(BOOT_CHECK_TIMEOUT) $(QEMU) -machine pc -m 32M -boot a -vga std -audiodev driver=none,id=audio -device sb16,audiodev=audio,version=0x0405,iobase=0x260,irq=10,dma=3 -drive file=$(FREEDOS_IMG),format=raw,if=floppy -serial file:$(LOGS_DIR)/boot-check-sb16-irq10.log -display none -no-reboot; test $$? -eq 124
	grep -q "SB16.DRV: detected at 0x00000260 IRQ 0000000A DMA 00000003" $(LOGS_DIR)/boot-check-sb16-irq10.log
	grep -q "Input loop ready" $(LOGS_DIR)/boot-check-sb16-irq10.log
	timeout $(BOOT_CHECK_TIMEOUT) $(QEMU) -machine pc -m 32M -boot a -vga std -audiodev driver=none,id=audio -device sb16,audiodev=audio,version=0x0405,iobase=0x280,irq=9,dma=0 -drive file=$(FREEDOS_IMG),format=raw,if=floppy -serial file:$(LOGS_DIR)/boot-check-sb16-irq2.log -display none -no-reboot; test $$? -eq 124
	grep -q "SB16.DRV: detected at 0x00000280 IRQ 00000002 DMA 00000000" $(LOGS_DIR)/boot-check-sb16-irq2.log
	grep -q "Input loop ready" $(LOGS_DIR)/boot-check-sb16-irq2.log

boot-check-ne2000: $(FREEDOS_IMG) | $(LOGS_DIR)
	rm -f $(LOGS_DIR)/boot-check-ne2000-300.log $(LOGS_DIR)/boot-check-ne2000-320.log
	python3 tools/capture_qemu_frame.py --image $(FREEDOS_IMG) --scenario netdiag --wait 15 --ne2k-iobase 0x300 --ne2k-irq 9 --serial file:$(LOGS_DIR)/boot-check-ne2000-300.log --out $(BUILD_DIR)/Screenshots/boot-check-ne2000-300.png
	grep -q "NE2000.DRV: detected at 0x00000300" $(LOGS_DIR)/boot-check-ne2000-300.log
	grep -q "DRIVER: loaded NE2000.DRV" $(LOGS_DIR)/boot-check-ne2000-300.log
	grep -q "DRIVER: loaded NETCORE.DRV" $(LOGS_DIR)/boot-check-ne2000-300.log
	grep -q "Input loop ready" $(LOGS_DIR)/boot-check-ne2000-300.log
	python3 tools/capture_qemu_frame.py --image $(FREEDOS_IMG) --scenario netdiag --wait 15 --ne2k-iobase 0x320 --ne2k-irq 5 --serial file:$(LOGS_DIR)/boot-check-ne2000-320.log --out $(BUILD_DIR)/Screenshots/boot-check-ne2000-320.png
	grep -q "NE2000.DRV: detected at 0x00000320" $(LOGS_DIR)/boot-check-ne2000-320.log
	grep -q "DRIVER: loaded NE2000.DRV" $(LOGS_DIR)/boot-check-ne2000-320.log
	grep -q "DRIVER: loaded NETCORE.DRV" $(LOGS_DIR)/boot-check-ne2000-320.log
	grep -q "Input loop ready" $(LOGS_DIR)/boot-check-ne2000-320.log

docker-build:
	docker compose run --rm builder make

docker-floppy:
	docker compose run --rm builder make freedos-floppy

docker-run:
	docker compose run --rm builder make run

docker-check:
	docker compose run --rm builder make boot-check

$(FREEDOS_ZIP): tools/fetch_freedos.py | $(BUILD_DIR)
	python3 tools/fetch_freedos.py --output $@

$(FREEDOS_IMG): $(HAMNET_DESKTOP_ALIAS)

$(FREEDOS_IMG): $(KERNEL_ELF) $(HAMLOAD_META) $(HAMLOAD_KERNEL_BIN) $(HAMLOAD_EXE) $(REBOOT_COM) $(CHOICE_COM) $(IMLCHK_COM) $(SETBLUE_COM) $(SETUPUI_COM) $(HDMBR_BIN) $(HDBOOT_BIN) $(HDSTAGE2_BIN) $(IMAGEDEC_DLL) $(DOSVM_APP) $(NOTEPAD_APP) $(HAMNET_APP) $(HAMCHAT_APP) $(PIANO_APP) $(CLOCK_APP) $(CALC_APP) $(PREFS_APP) $(FIND_APP) $(IMGVIEW_APP) $(AUDPLAY_APP) $(CAL_APP) $(SLOTS_APP) $(PAINT_APP) $(SNAKE_APP) $(MINES_APP) $(PUZZLE_APP) $(LANDER_APP) $(FREECELL_APP) $(POKER_APP) $(DISKCOPY_APP) $(CDDIAG_APP) $(IDEDIAG_APP) $(USBDIAG_APP) $(SCSIDIAG_APP) $(NETDIAG_APP) $(HAMSHARE_APP) $(FORMAT_APP) $(GFXDIAG_APP) $(DEVMGR_APP) $(FONTS_APP) $(UPDATE_APP) $(DISKCOPY_ICO) $(CDDIAG_ICO) $(IDEDIAG_ICO) $(USBDIAG_ICO) $(SCSIDIAG_ICO) $(NETDIAG_ICO) $(HAMSHARE_ICO) $(FORMAT_ICO) $(GFXDIAG_ICO) $(DEVMGR_ICO) $(FONTS_ICO) $(UPDATE_ICO) $(PREFS_ICO) $(NOTEPAD_ICO) $(HAMNET_ICO) $(HAMCHAT_ICO) $(PAINT_ICO) $(PIANO_ICO) $(CLOCK_ICO) $(CALC_ICO) $(CAL_ICO) $(SLOTS_ICO) $(SNAKE_ICO) $(MINES_ICO) $(PUZZLE_ICO) $(POKER_ICO) $(IMGVIEW_ICO) $(AUDPLAY_ICO) $(PICOMEM_DRV) $(SB16_DRV) $(ADLIB_DRV) $(NCR400_DRV) $(AHA154X_DRV) $(CH375_DRV) $(PS2MOUSE_DRV) $(SERMOUSE_DRV) $(NE2000_DRV) $(NETCORE_DRV) $(THREEC509_DRV) $(FONT_FACE_BINS) $(FREEDOS_ZIP) tools/mkfreedosfloppy.py tools/install_manifest.py lang/ham_strings.tsv $(wildcard Backdrop/*.BMP) boot/WELCOME.TXT boot/HELP.HTM boot/HAMNET/TESTPAGE.HTM boot/README.TXT boot/NOTICE.TXT boot/STARTUP.WAV boot/DOOT.WAV dos/freedos/FDAUTO.BAT dos/freedos/FDCONFIG.SYS dos/freedos/AUTOEXEC.BAT dos/freedos/CONFIG.SYS dos/freedos/HAMSTER.BAT dos/install/INSTALL.BAT
	python3 tools/mkfreedosfloppy.py --source-zip $(FREEDOS_ZIP) --output $@ --hamster-kernel $(HAMLOAD_KERNEL_BIN) --hamload-exe $(HAMLOAD_EXE) --payload-dir $(BUILD_DIR) --apps-dir $(APPS_OUT_DIR) --choice-com $(CHOICE_COM) --imlchk-com $(IMLCHK_COM) --setblue-com $(SETBLUE_COM) --setupui-com $(SETUPUI_COM) --hd-mbr-bin $(HDMBR_BIN) --hd-boot-bin $(HDBOOT_BIN) --hd-stage2-bin $(HDSTAGE2_BIN)

$(HAMSTER_EXTRAS_LEGACY_IMG): $(HAMWRITE_APP) $(HAMWRITE_ICO) $(HAMSHEET_APP) $(UPDATE_PLUS_APP) $(UPDATE_ICO) $(GOLF_APP) $(GOLF_ICO) $(HCOMMAND_APP) $(HCOMMAND_ICO) $(SLOTS_APP) $(SLOTS_ICO) $(BIOSTAR_APP) $(BIOSTAR_ICO) $(MANDEL_APP) $(MANDEL_ICO) $(ZIPZORK_APP) $(ZIPZORK_ICO) $(DESKHAM_APP) $(DESKHAM_ICO) $(SPELL_DAT) $(FONT_FACE_BINS) $(HAMSTER_SAVER_APP) $(EXTRAS_INSTALL_APP) $(EXTRAS_INSTALL_ICO) Backdrop/MHS.BMP tools/mkextras_legacy.py lang/extras_en.tsv third_party/esdb/COPYRIGHT.txt $(DOS_PAYLOAD_SRC) $(EXTRAS_PAYLOAD_SRC) boot/GOLFPUTT.WAV boot/GOLFSINK.WAV boot/GOLFERR.WAV boot/GOLFJNG.WAV | $(BUILD_DIR)/Archive
	python3 tools/mkextras_legacy.py --output $@ --apps-dir $(APPS_OUT_DIR) --update-app $(UPDATE_PLUS_APP) --update-icon $(UPDATE_ICO) --spell-dat $(SPELL_DAT) --fonts-dir $(GENERATED_DIR)/fonts --hamster-saver $(HAMSTER_SAVER_APP) --installer $(EXTRAS_INSTALL_APP) --installer-icon $(EXTRAS_INSTALL_ICO) --logo Backdrop/MHS.BMP

$(HAMSTER_EXTRAS_IMG): $(HAMSTER_EXTRAS_LEGACY_IMG) $(EXTRAS_INSTALL_APP) tools/mkextras.py tools/extras_components.py
	python3 tools/mkextras.py --source-image $(HAMSTER_EXTRAS_LEGACY_IMG) --installer $(EXTRAS_INSTALL_APP) --output $@

$(HAMSTER_EXTRAS_ZIP): $(HAMSTER_EXTRAS_IMG) tools/package_hamster_extras.py kernel/version.h | $(BUILD_DIR)
	python3 tools/package_hamster_extras.py --image $(HAMSTER_EXTRAS_IMG) --output $@ --version-header kernel/version.h

$(ZIPZORK_PACKAGE): $(ZIPZORK_APP) $(ZIPZORK_ICO) contrib/extras/GAMES/ZORK/ZORK1.Z3 contrib/extras/LICENSES/FROTZ.TXT contrib/extras/LICENSES/ZORK1.TXT tools/package_zipzork_addon.py kernel/version.h apps/zipzork.h | $(BUILD_DIR)
	python3 tools/package_zipzork_addon.py --app $(ZIPZORK_APP) --icon $(ZIPZORK_ICO) --output $@

$(ZIPZORK_SOURCE_PACKAGE): tools/package_zipzork_source.py tools/package_zipzork_addon.py tools/test_zipzork_addon_e2e.py tools/verify_zipzork_mg1_capture.py tools/gen_app_sdk.py tools/Dockerfile Makefile compose.yaml README.md contrib/extras/LICENSES/FONTS.TXT Archive/WIN16/resources/fonts/COPYING.LIB $(shell find apps kernel drivers fs assets/fonts third_party/windows-frotz -type f 2>/dev/null) | $(BUILD_DIR)
	python3 tools/package_zipzork_source.py --output $@

$(SPELL_DAT): $(SPELL_DAT_SRC) | $(DATA_DIR)
	cp $< $@

clean:
	@if [ -d "$(BUILD_DIR)" ]; then \
		find "$(BUILD_DIR)" -mindepth 1 -maxdepth 1 ! -name hamster-c.img \
			-exec rm -rf -- {} +; \
	fi

# ---- External app: NOTEPAD.APP ------------------------------------------------
# Compiled from the SAME notepad.c that the built-in uses, linked with stub
# wrappers (notepad_stubs.c) that route kernel API calls through HamsterHostAPI.
# The entry point (notepad_ext_entry.c) returns a populated AppDescriptor.

APP_CFLAGS := $(CFLAGS) -Ikernel
HCOMMAND_CFLAGS := $(filter-out -Os -march=i386 -mtune=i386,$(APP_CFLAGS)) \
	-O2 -march=i486 -mtune=i486
AUDPLAY_MP3_OPT ?= -O3 -ffast-math -Wno-stringop-overflow
AUDPLAY_PROFILE_CFLAGS ?=
# MP3 playback officially targets a 486DX2/66 or faster. Keep the rest of
# HamsterOS i386-compatible, but allow the codec's hot path to use 486
# instructions. mpg123's historical OPT_I486 path only accelerates full-rate
# 16-bit stereo; OPT_I386 is the correct synthesis path for our native
# quarter-rate mono output.
MPG123_CFLAGS = $(APP_CFLAGS) -O2 -march=i486 -mtune=i486 \
	-fomit-frame-pointer \
	-funroll-all-loops -finline-functions -ffast-math -w -DHAVE_CONFIG_H \
	-DOPT_I386 -DREAL_IS_FLOAT -DHAMSTEROS_RUNTIME_ISPOW \
	-I$(MPG123_DIR)/config \
	-I$(MPG123_DIR)/include -I$(MPG123_DIR)/src/libmpg123 \
	-I$(MPG123_DIR)/src/common -I$(MPG123_DIR)/src/compat
MPG123_WRAPPER_CFLAGS = $(APP_CFLAGS) -O2 -march=i486 -mtune=i486 \
	-mfpmath=387

# ---- DOSVM.APP on-demand VM86 backend ---------------------------------------

$(BUILD_DIR)/apps/dosvm_ext.o: apps/dosvm_ext_entry.c kernel/app_abi.h kernel/vm86.h kernel/vm86_module.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/dosvm_app.o: apps/dosvm_vm86.c kernel/vm86.h kernel/vm86_module.h kernel/interrupts.h kernel/panic.h kernel/paging.h drivers/vga.h fs/fat.h fs/file_contract.h fs/directory_cache.h drivers/serial.h kernel/io.h | $(BUILD_DIR)/apps
	$(CC) $(HOT_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/dosvm_stubs.o: apps/dosvm_stubs.c kernel/app_abi.h kernel/vm86_module.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/dosvm_asm.o: apps/dosvm_vm86_asm.S | $(BUILD_DIR)/apps
	$(CC) $(ASFLAGS) -c $< -o $@

$(DOSVM_ELF): $(BUILD_DIR)/apps/dosvm_ext.o $(BUILD_DIR)/apps/dosvm_app.o $(BUILD_DIR)/apps/dosvm_stubs.o $(BUILD_DIR)/apps/dosvm_asm.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/dosvm_ext.o \
	    $(BUILD_DIR)/apps/dosvm_app.o \
	    $(BUILD_DIR)/apps/dosvm_stubs.o \
	    $(BUILD_DIR)/apps/dosvm_asm.o \
	    -o $@

$(DOSVM_APP): $(DOSVM_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name DOSVM --output $@

$(BUILD_DIR)/apps/notepad_ext.o: apps/notepad_ext_entry.c kernel/app_abi.h apps/notepad.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/notepad_app.o: apps/notepad.c apps/notepad.h apps/app_about_modal.h apps/file_dialog.h apps/prefs.h apps/window.h kernel/ham_strings.h kernel/heap.h kernel/clipboard.h drivers/vga.h fs/fat.h drivers/serial.h apps/shell.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/notepad_stubs.o: apps/notepad_stubs.c kernel/app_abi.h kernel/ham_strings.h kernel/heap.h kernel/clipboard.h apps/file_dialog.h apps/window.h drivers/vga.h fs/fat.h drivers/serial.h apps/prefs.h apps/shell.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(NOTEPAD_ELF): $(BUILD_DIR)/apps/notepad_ext.o $(BUILD_DIR)/apps/notepad_app.o $(BUILD_DIR)/apps/notepad_stubs.o $(BUILD_DIR)/apps/app_about_modal.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/notepad_ext.o \
	    $(BUILD_DIR)/apps/notepad_app.o \
	    $(BUILD_DIR)/apps/notepad_stubs.o \
	    $(BUILD_DIR)/apps/app_about_modal.o \
	    -o $@

$(NOTEPAD_APP): $(NOTEPAD_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name NOTEPAD --app-menus --output $@

# ---- External app: HAMWRITE.APP ---------------------------------------------

$(BUILD_DIR)/apps/hamwrite_ext.o: apps/hamwrite_ext_entry.c kernel/app_abi.h apps/hamwrite.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/hamwrite_app.o: apps/hamwrite.c apps/hamwrite.h apps/hamwrite_icons.h apps/app_about_modal.h apps/image_decode.h apps/file_dialog.h apps/prefs.h apps/window.h kernel/ham_strings.h kernel/heap.h kernel/clipboard.h drivers/vga.h drivers/rtc.h fs/fat.h apps/shell.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@

$(BUILD_DIR)/apps/hamwrite_stubs.o: apps/hamwrite_stubs.c kernel/app_abi.h kernel/ham_strings.h drivers/vga.h drivers/rtc.h apps/window.h apps/file_dialog.h fs/fat.h apps/prefs.h apps/shell.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(HAMWRITE_ELF): $(BUILD_DIR)/apps/hamwrite_ext.o $(BUILD_DIR)/apps/hamwrite_app.o $(BUILD_DIR)/apps/hamwrite_stubs.o $(BUILD_DIR)/apps/image_decode_client.o $(BUILD_DIR)/apps/app_about_modal.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/hamwrite_ext.o \
	    $(BUILD_DIR)/apps/hamwrite_app.o \
	    $(BUILD_DIR)/apps/hamwrite_stubs.o \
	    $(BUILD_DIR)/apps/image_decode_client.o \
	    $(BUILD_DIR)/apps/app_about_modal.o \
	    -o $@

$(HAMWRITE_APP): $(HAMWRITE_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name HAMWRITE --app-menus --right-click --output $@

# ---- Shared image decoder DLL ----------------------------------------------

$(BUILD_DIR)/apps/image_decode_client.o: apps/image_decode_client.c apps/image_decode.h kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@

$(BUILD_DIR)/apps/image_decode_dll_entry.o: apps/image_decode_dll_entry.c apps/image_decode.h kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@

$(BUILD_DIR)/apps/image_decode_dll.o: $(HAMNET_CORE_DIR)/src/hamnet_image_decode.c $(HAMNET_CORE_DIR)/include/hamnet_image_decode.h apps/image_decode.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@

$(IMAGEDEC_ELF): $(BUILD_DIR)/apps/image_decode_dll_entry.o $(BUILD_DIR)/apps/image_decode_dll.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/image_decode_dll_entry.o \
	    $(BUILD_DIR)/apps/image_decode_dll.o \
	    -o $@

$(IMAGEDEC_DLL): $(IMAGEDEC_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name IMAGEDEC --output $@

# ---- Shared audio libraries ------------------------------------------------

$(BUILD_DIR)/apps/mp3_dll_entry.o: apps/audio_codec_dll_entry.c apps/audio_codec.h apps/waveplayer_mpg123.h kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/mp3_dll_stubs.o: apps/audio_codec_runtime_stubs.c kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/mp3_dll_codec.o: apps/waveplayer_mpg123.c apps/waveplayer_mpg123.h $(MPG123_DIR)/include/mpg123.h | $(BUILD_DIR)/apps
	$(CC) $(MPG123_WRAPPER_CFLAGS) $(AUDPLAY_PROFILE_CFLAGS) \
	    -I$(MPG123_DIR)/include -c $< -o $@

$(MP3CODEC_ELF): $(BUILD_DIR)/apps/mp3_dll_entry.o $(BUILD_DIR)/apps/mp3_dll_stubs.o $(BUILD_DIR)/apps/mp3_dll_codec.o $(MPG123_LIB) tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs --gc-sections -nostdlib \
	    $(BUILD_DIR)/apps/mp3_dll_entry.o \
	    $(BUILD_DIR)/apps/mp3_dll_stubs.o \
	    $(BUILD_DIR)/apps/mp3_dll_codec.o \
	    $(MPG123_LIB) \
	    $$(gcc -m32 -print-libgcc-file-name) \
	    -o $@

$(MP3CODEC_DLL): $(MP3CODEC_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name MP3 --output $@

$(BUILD_DIR)/apps/audio_dll_entry.o: apps/audio_format_dll_entry.c apps/audio_format_library.h apps/waveplayer_formats.h kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/audio_dll_formats.o: apps/waveplayer_formats.c apps/waveplayer_formats.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(AUDIOFORMAT_ELF): $(BUILD_DIR)/apps/audio_dll_entry.o $(BUILD_DIR)/apps/audio_dll_formats.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs --gc-sections -nostdlib \
	    $(BUILD_DIR)/apps/audio_dll_entry.o \
	    $(BUILD_DIR)/apps/audio_dll_formats.o \
	    -o $@

$(AUDIOFORMAT_DLL): $(AUDIOFORMAT_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name AUDIO --output $@

# ---- Shared cryptography runtime -------------------------------------------

$(BUILD_DIR)/apps/crypto_dll_entry.o: apps/crypto_dll_entry.c apps/crypto_library.h kernel/app_abi.h $(HAMNET_MONOCYPHER_DIR)/monocypher.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@

$(BUILD_DIR)/apps/crypto_client.o: apps/crypto_client.c apps/crypto_library.h kernel/app_abi.h $(HAMNET_MONOCYPHER_DIR)/monocypher.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@

$(CRYPTO_DLL_ELF): $(BUILD_DIR)/apps/crypto_dll_entry.o $(BUILD_DIR)/apps/monocypher.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs --gc-sections -nostdlib \
	    $(BUILD_DIR)/apps/crypto_dll_entry.o \
	    $(BUILD_DIR)/apps/monocypher.o \
	    -o $@

$(CRYPTO_DLL): $(CRYPTO_DLL_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name CRYPTO --output $@

# ---- On-demand ZIP library -------------------------------------------------

$(BUILD_DIR)/apps/zip_dll_entry.o: apps/zip_dll_entry.c apps/zip_library.h kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/zip_dll_stubs.o: apps/zip_dll_stubs.c kernel/app_abi.h kernel/app_loader.h kernel/heap.h kernel/lowmem.h kernel/service.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/zip_create_dll.o: apps/zip_create.c apps/zip_create.h kernel/heap.h kernel/lowmem.h kernel/service.h kernel/crc32.h kernel/fast_memory.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/zip_extract_dll.o: apps/zip_extract.c apps/zip_extract.h kernel/app_loader.h kernel/heap.h kernel/lowmem.h kernel/service.h kernel/crc32.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/crc32.o: kernel/crc32.c kernel/crc32.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(ZIP_DLL_ELF): $(BUILD_DIR)/apps/zip_dll_entry.o $(BUILD_DIR)/apps/zip_dll_stubs.o $(BUILD_DIR)/apps/zip_create_dll.o $(BUILD_DIR)/apps/zip_extract_dll.o $(BUILD_DIR)/apps/crc32.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/zip_dll_entry.o \
	    $(BUILD_DIR)/apps/zip_dll_stubs.o \
	    $(BUILD_DIR)/apps/zip_create_dll.o \
	    $(BUILD_DIR)/apps/zip_extract_dll.o \
	    $(BUILD_DIR)/apps/crc32.o \
	    -o $@

$(ZIP_DLL): $(ZIP_DLL_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name ZIP --output $@

# ---- One-shot installed-app expansion library ------------------------------

$(BUILD_DIR)/apps/appfast_dll_entry.o: apps/appfast_dll_entry.c apps/appfast_library.h kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/appfast_dll_stubs.o: apps/appfast_stubs.c apps/appfast_library.h kernel/app_abi.h kernel/app_loader.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/appfast_dll_core.o: kernel/app_hdd_prepare.c kernel/app_hdd_prepare.h kernel/app_loader.h kernel/app_abi.h kernel/heap.h drivers/serial.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(filter-out -Os,$(APP_CFLAGS)) -Oz -fno-align-functions \
		-mpreferred-stack-boundary=2 -c $< -o $@

$(APPFAST_DLL_ELF): $(BUILD_DIR)/apps/appfast_dll_entry.o $(BUILD_DIR)/apps/appfast_dll_stubs.o $(BUILD_DIR)/apps/appfast_dll_core.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs --gc-sections -nostdlib \
	    $(BUILD_DIR)/apps/appfast_dll_entry.o \
	    $(BUILD_DIR)/apps/appfast_dll_core.o \
	    $(BUILD_DIR)/apps/appfast_dll_stubs.o \
	    -o $@

$(APPFAST_DLL): $(APPFAST_DLL_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name APPFAST --output $@

# ---- Unloadable common File Dialog library ---------------------------------

$(BUILD_DIR)/apps/filedlg_dll_entry.o: apps/file_dialog_dll_entry.c apps/file_dialog_library.h kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/filedlg_dll_stubs.o: apps/file_dialog_dll_stubs.c apps/file_dialog_library.h kernel/app_abi.h apps/ui_controls.h apps/ui_edit.h drivers/theme.h drivers/vga.h fs/directory_cache.h kernel/clipboard.h kernel/heap.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/filedlg_dll_core.o: apps/file_dialog.c apps/file_dialog.h apps/ui_controls.h apps/ui_edit.h fs/directory_cache.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/filedlg_dll_controls.o: apps/ui_controls.c apps/ui_controls.h apps/ui_message.h apps/window.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/filedlg_dll_edit.o: apps/ui_edit.c apps/ui_edit.h apps/ui_message.h kernel/clipboard.h drivers/theme.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/filedlg_dll_message.o: apps/ui_message.c apps/ui_message.h apps/window.h drivers/theme.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/filedlg_dll_window.o: apps/window.c apps/window.h drivers/theme.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(FILEDLG_DLL_ELF): $(BUILD_DIR)/apps/filedlg_dll_entry.o $(BUILD_DIR)/apps/filedlg_dll_stubs.o $(BUILD_DIR)/apps/filedlg_dll_core.o $(BUILD_DIR)/apps/filedlg_dll_controls.o $(BUILD_DIR)/apps/filedlg_dll_edit.o $(BUILD_DIR)/apps/filedlg_dll_message.o $(BUILD_DIR)/apps/filedlg_dll_window.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs --gc-sections -nostdlib \
	    $(BUILD_DIR)/apps/filedlg_dll_entry.o \
	    $(BUILD_DIR)/apps/filedlg_dll_core.o \
	    $(BUILD_DIR)/apps/filedlg_dll_controls.o \
	    $(BUILD_DIR)/apps/filedlg_dll_edit.o \
	    $(BUILD_DIR)/apps/filedlg_dll_message.o \
	    $(BUILD_DIR)/apps/filedlg_dll_window.o \
	    $(BUILD_DIR)/apps/filedlg_dll_stubs.o \
	    -o $@

$(FILEDLG_DLL): $(FILEDLG_DLL_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name FILEDLG --output $@

# ---- Unloadable screen-saver engine ---------------------------------------

$(BUILD_DIR)/apps/saver_dll.o: apps/screensaver_dll.c apps/screensaver_library.h apps/prefs.h kernel/app_abi.h drivers/vga.h drivers/theme.h $(HAMSTER_SPRITE_H) | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(SAVER_DLL_ELF): $(BUILD_DIR)/apps/saver_dll.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs --gc-sections -nostdlib \
	    $(BUILD_DIR)/apps/saver_dll.o -o $@

$(SAVER_DLL): $(SAVER_DLL_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name SAVER --output $@

$(FREEDOS_IMG): $(ZIP_DLL)
$(FREEDOS_IMG): $(APPFAST_DLL)
$(FREEDOS_IMG): $(FILEDLG_DLL)
$(FREEDOS_IMG): $(SAVER_DLL)
$(FREEDOS_IMG): $(CRYPTO_DLL)
$(FREEDOS_IMG): $(MP3CODEC_DLL) $(AUDIOFORMAT_DLL)
$(FREEDOS_IMG): $(MCAFD_DRV) $(IBMSCSI_DRV)
$(FREEDOS_IMG): $(USBMOUSE_DRV) $(RTL8139_DRV) $(SBC82621_DRV)

# ---- On-demand ATAPI CD-ROM module ----------------------------------------

$(BUILD_DIR)/apps/cd_module_entry.o: apps/cd_module_entry.c drivers/cd_module.h drivers/cdrom.h drivers/iso9660_module.h drivers/atapi.h kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/cd_module_stubs.o: apps/cd_module_stubs.c kernel/app_abi.h drivers/activity.h drivers/ata.h kernel/heap.h drivers/serial.h kernel/service.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/atapi_module.o: drivers/atapi.c drivers/atapi.h drivers/activity.h drivers/ata.h kernel/heap.h kernel/service.h drivers/serial.h kernel/io.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/cdrom_module_impl.o: drivers/cdrom_module_impl.c drivers/cdrom.h drivers/atapi.h drivers/serial.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/iso9660_module.o: drivers/iso9660_module.c drivers/iso9660_module.h drivers/cdrom.h drivers/atapi.h kernel/service.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(ATAPICD_ELF): $(BUILD_DIR)/apps/cd_module_entry.o $(BUILD_DIR)/apps/cd_module_stubs.o $(BUILD_DIR)/apps/atapi_module.o $(BUILD_DIR)/apps/cdrom_module_impl.o $(BUILD_DIR)/apps/iso9660_module.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/cd_module_entry.o \
	    $(BUILD_DIR)/apps/cd_module_stubs.o \
	    $(BUILD_DIR)/apps/atapi_module.o \
	    $(BUILD_DIR)/apps/cdrom_module_impl.o \
	    $(BUILD_DIR)/apps/iso9660_module.o \
	    -o $@

$(ATAPICD_DRV): $(ATAPICD_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name ATAPICD --output $@

$(FREEDOS_IMG): $(ATAPICD_DRV)

# ---- External app: HAMSHEET.APP (standalone, Hamster Extras disk) -----------

$(BUILD_DIR)/apps/hamster_sheets_ext.o: apps/hamster_sheets_ext_entry.c kernel/app_abi.h apps/hamster_sheets.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/hamster_sheets_app.o: apps/hamster_sheets.c apps/hamster_sheets.h apps/hamster_sheets_icons.h apps/app_about_modal.h apps/file_dialog.h kernel/ham_strings.h apps/window.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/hamster_sheets_stubs.o: apps/hamster_sheets_stubs.c kernel/app_abi.h $(APP_SDK_SERVICES_H) kernel/ham_strings.h apps/file_dialog.h apps/window.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(HAMSHEET_ELF): $(BUILD_DIR)/apps/hamster_sheets_ext.o $(BUILD_DIR)/apps/hamster_sheets_app.o $(BUILD_DIR)/apps/hamster_sheets_stubs.o $(BUILD_DIR)/apps/app_about_modal.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/hamster_sheets_ext.o \
	    $(BUILD_DIR)/apps/hamster_sheets_app.o \
	    $(BUILD_DIR)/apps/hamster_sheets_stubs.o \
	    $(BUILD_DIR)/apps/app_about_modal.o \
	    -o $@

$(HAMSHEET_APP): $(HAMSHEET_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name HAMSHEET --app-menus --right-click --output $@

# ---- External app: HAMNET.APP -----------------------------------------------

$(BUILD_DIR)/apps/hamnet_ext.o: $(HAMNET_APP_DIR)/hamnet_ext_entry.c kernel/app_abi.h apps/crypto_library.h $(HAMNET_APP_DIR)/hamnet.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_APP_INCLUDES) -c $< -o $@

$(BUILD_DIR)/apps/hamnet_app.o: $(HAMNET_APP_DIR)/hamnet.c $(HAMNET_APP_DIR)/hamnet.h $(HAMNET_CORE_DIR)/include/hamnet_classic.h $(HAMNET_CORE_DIR)/include/hamnet_online.h $(HAMNET_CORE_DIR)/include/hamnet_logo.h $(HAMNET_CORE_DIR)/include/hamnet_resource_policy.h apps/image_decode.h apps/window.h drivers/vga.h fs/fat.h kernel/app_abi.h kernel/entropy.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_APP_INCLUDES) -DHAMNET_ONLINE_ENABLED=0 -c $< -o $@

$(BUILD_DIR)/apps/hamnet_app_plus.o: $(HAMNET_APP_DIR)/hamnet.c $(HAMNET_APP_DIR)/hamnet.h $(HAMNET_CORE_DIR)/include/hamnet_classic.h $(HAMNET_CORE_DIR)/include/hamnet_account_sync.h $(HAMNET_CORE_DIR)/include/hamnet_online.h $(HAMNET_CORE_DIR)/include/hamnet_logo.h $(HAMNET_CORE_DIR)/include/hamnet_resource_policy.h apps/image_decode.h apps/window.h drivers/vga.h fs/fat.h kernel/app_abi.h kernel/entropy.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_APP_INCLUDES) -DHAMNET_ONLINE_ENABLED=1 -c $< -o $@

$(BUILD_DIR)/apps/hamnet_stubs.o: $(HAMNET_APP_DIR)/hamnet_stubs.c kernel/app_abi.h kernel/entropy.h apps/window.h drivers/vga.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_APP_INCLUDES) -c $< -o $@

$(BUILD_DIR)/apps/hamnet_online.o: $(HAMNET_CORE_DIR)/src/hamnet_online.c $(HAMNET_CORE_DIR)/include/hamnet_online.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -DHAMNET_ONLINE_ENABLED=0 -c $< -o $@

$(BUILD_DIR)/apps/hamnet_online_plus.o: $(HAMNET_CORE_DIR)/src/hamnet_online.c $(HAMNET_CORE_DIR)/include/hamnet_online.h $(HAMNET_CORE_DIR)/include/hamnet_transport.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -DHAMNET_ONLINE_ENABLED=1 -c $< -o $@

$(BUILD_DIR)/apps/hamnet_transport.o: $(HAMNET_CORE_DIR)/src/hamnet_transport.c $(HAMNET_CORE_DIR)/include/hamnet_transport.h $(HAMNET_MONOCYPHER_DIR)/monocypher.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@

$(BUILD_DIR)/apps/hamnet_logo.o: $(HAMNET_CORE_DIR)/src/hamnet_logo.c $(HAMNET_CORE_DIR)/include/hamnet_logo.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@

$(BUILD_DIR)/apps/hamnet_resource_policy.o: $(HAMNET_CORE_DIR)/src/hamnet_resource_policy.c $(HAMNET_CORE_DIR)/include/hamnet_resource_policy.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@

$(BUILD_DIR)/apps/hamnet_classic.o: $(HAMNET_CORE_DIR)/src/hamnet_classic.c $(HAMNET_CORE_DIR)/include/hamnet_classic.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@

$(BUILD_DIR)/apps/hamnet_account_sync.o: $(HAMNET_CORE_DIR)/src/hamnet_account_sync.c $(HAMNET_CORE_DIR)/include/hamnet_account_sync.h $(HAMNET_CORE_DIR)/include/hamnet_online.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -DHAMNET_ONLINE_ENABLED=1 -c $< -o $@

$(BUILD_DIR)/apps/monocypher.o: $(HAMNET_MONOCYPHER_DIR)/monocypher.c $(HAMNET_MONOCYPHER_DIR)/monocypher.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -Wno-unused-function -c $< -o $@

$(HAMNET_ELF): $(BUILD_DIR)/apps/hamnet_ext.o $(BUILD_DIR)/apps/hamnet_app_plus.o $(BUILD_DIR)/apps/hamnet_stubs.o $(BUILD_DIR)/apps/hamnet_classic.o $(BUILD_DIR)/apps/hamnet_account_sync.o $(BUILD_DIR)/apps/hamnet_online_plus.o $(BUILD_DIR)/apps/hamnet_transport.o $(BUILD_DIR)/apps/hamnet_logo.o $(BUILD_DIR)/apps/hamnet_resource_policy.o $(BUILD_DIR)/apps/crypto_client.o $(BUILD_DIR)/apps/image_decode_client.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs --gc-sections -nostdlib \
	    $(BUILD_DIR)/apps/hamnet_ext.o \
	    $(BUILD_DIR)/apps/hamnet_app_plus.o \
	    $(BUILD_DIR)/apps/hamnet_stubs.o \
	    $(BUILD_DIR)/apps/hamnet_classic.o \
	    $(BUILD_DIR)/apps/hamnet_account_sync.o \
	    $(BUILD_DIR)/apps/hamnet_online_plus.o \
	    $(BUILD_DIR)/apps/hamnet_transport.o \
	    $(BUILD_DIR)/apps/hamnet_logo.o \
	    $(BUILD_DIR)/apps/hamnet_resource_policy.o \
	    $(BUILD_DIR)/apps/crypto_client.o \
	    $(BUILD_DIR)/apps/image_decode_client.o \
	    -o $@

$(HAMNET_APP): $(HAMNET_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name HAMNET --app-menus --output $@

$(HAMNET_DESKTOP_ALIAS): $(HAMNET_ICO) tools/mkapp.py | $(DESKTOP_ALIAS_DIR)
	python3 tools/mkapp.py --alias-target /PROGRAMS/HAMNET.APP --name HAMNET --icon $(HAMNET_ICO) --output $@

$(BUILD_DIR)/apps/hamchat_ext.o: $(HAMCHAT_APP_DIR)/hamchat_ext_entry.c kernel/app_abi.h apps/crypto_library.h $(HAMCHAT_APP_DIR)/hamchat.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMCHAT_APP_INCLUDES) -c $< -o $@

$(BUILD_DIR)/apps/hamchat_app.o: $(HAMCHAT_APP_DIR)/hamchat.c $(HAMCHAT_APP_DIR)/hamchat.h $(HAMCHAT_APP_DIR)/hamchat_hamsteros_art.h $(HAMCHAT_CORE_DIR)/include/hamchat_protocol.h $(HAMCHAT_CORE_DIR)/include/hamchat_rich.h $(HAMNET_CORE_DIR)/include/hamnet_online.h $(HAMNET_CORE_DIR)/include/hamnet_transport.h apps/window.h drivers/vga.h fs/fat.h kernel/app_abi.h kernel/entropy.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMCHAT_APP_INCLUDES) -DHAMNET_ONLINE_ENABLED=1 -c $< -o $@

$(BUILD_DIR)/apps/hamchat_rich.o: $(HAMCHAT_CORE_DIR)/src/hamchat_rich.c $(HAMCHAT_CORE_DIR)/include/hamchat_rich.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMCHAT_CORE_INCLUDES) -c $< -o $@

$(BUILD_DIR)/apps/hamchat_stubs.o: $(HAMCHAT_APP_DIR)/hamchat_stubs.c kernel/app_abi.h $(APP_SDK_SERVICES_H) apps/window.h drivers/vga.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMCHAT_APP_INCLUDES) -c $< -o $@

$(HAMCHAT_ELF): $(BUILD_DIR)/apps/hamchat_ext.o $(BUILD_DIR)/apps/hamchat_app.o $(BUILD_DIR)/apps/hamchat_rich.o $(BUILD_DIR)/apps/hamchat_stubs.o $(BUILD_DIR)/apps/hamnet_online_plus.o $(BUILD_DIR)/apps/hamnet_transport.o $(BUILD_DIR)/apps/crypto_client.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs --gc-sections -nostdlib \
	    $(BUILD_DIR)/apps/hamchat_ext.o \
	    $(BUILD_DIR)/apps/hamchat_app.o \
	    $(BUILD_DIR)/apps/hamchat_rich.o \
	    $(BUILD_DIR)/apps/hamchat_stubs.o \
	    $(BUILD_DIR)/apps/hamnet_online_plus.o \
	    $(BUILD_DIR)/apps/hamnet_transport.o \
	    $(BUILD_DIR)/apps/crypto_client.o \
	    -o $@

$(HAMCHAT_APP): $(HAMCHAT_ELF) tools/mkapp.py $(HAMCHAT_ICO) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name HAMCHAT --icon $(HAMCHAT_ICO) --app-menus --output $@

# ---- .ICO files (256-byte raw palette icons, one per .APP) ------------------

# Tool app icons: generated from mkicon.py (mirrors vga.c draw_*_icon bitmaps)
$(DISKCOPY_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py DISKCOPY $@
$(CDPLAY_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py CDPLAY $@
$(FLOPDIAG_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py FLOPDIAG $@
$(CDDIAG_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py CDDIAG $@
$(IDEDIAG_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py IDEDIAG $@
$(USBDIAG_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py USBDIAG $@
$(SCSIDIAG_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py SCSIDIAG $@
$(NETDIAG_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py NETDIAG $@
$(HAMSHARE_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py HAMSHARE $@
$(FORMAT_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py FORMAT $@
$(GFXDIAG_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py GFXDIAG $@
$(DEVMGR_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py DEVMGR $@
$(FONTS_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py FONTS $@
$(EXTRAS_INSTALL_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py INSTALL $@
$(UPDATE_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py UPDATE $@
$(PREFS_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py PREFS $@
$(NOTEPAD_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py NOTEPAD $@
$(HAMWRITE_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py HAMWRITE $@
$(HAMNET_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py HAMNET $@
$(HAMCHAT_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py HAMCHAT $@
$(PAINT_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py PAINT $@
$(PIANO_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py PIANO $@
$(CLOCK_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py CLOCK $@
$(CALC_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py CALC $@
$(CAL_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py CAL $@
$(SLOTS_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py SLOTS $@
$(DESKHAM_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py DESKHAM $@
# Game icons: use existing bundled icon assets (already 256-byte palette format)
$(SNAKE_ICO): assets/snake_icon.bin | $(APPS_OUT_DIR)
	cp assets/snake_icon.bin $@
$(MINES_ICO): assets/mines_icon.bin | $(APPS_OUT_DIR)
	cp assets/mines_icon.bin $@
$(PUZZLE_ICO): assets/puzzle_icon.bin | $(APPS_OUT_DIR)
	cp assets/puzzle_icon.bin $@
$(LANDER_ICO): assets/moonlander_icon.bin | $(APPS_OUT_DIR)
	cp assets/moonlander_icon.bin $@
$(FREECELL_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py FREECELL $@
$(POKER_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py POKER $@

# ---- PIANO.APP external app -------------------------------------------------

$(BUILD_DIR)/apps/piano_ext.o: apps/piano_ext_entry.c kernel/app_abi.h apps/piano.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/piano_app.o: apps/piano.c apps/piano.h apps/window.h drivers/vga.h drivers/speaker.h drivers/pit.h drivers/serial.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/piano_stubs.o: apps/piano_stubs.c kernel/app_abi.h apps/window.h drivers/vga.h drivers/speaker.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(PIANO_ELF): $(BUILD_DIR)/apps/piano_ext.o $(BUILD_DIR)/apps/piano_app.o $(BUILD_DIR)/apps/piano_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/piano_ext.o \
	    $(BUILD_DIR)/apps/piano_app.o \
	    $(BUILD_DIR)/apps/piano_stubs.o \
	    -o $@

$(PIANO_APP): $(PIANO_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name PIANO --app-menus --output $@

# ---- CLOCK.APP external app -------------------------------------------------

$(BUILD_DIR)/apps/clock_ext.o: apps/clock_ext_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/clock.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/clock_app.o: apps/clock.c apps/clock.h apps/app_about_modal.h apps/prefs.h apps/window.h drivers/vga.h drivers/rtc.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/clock_stubs.o: apps/clock_stubs.c kernel/app_abi.h apps/window.h drivers/vga.h drivers/rtc.h apps/prefs.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/app_about_modal.o: apps/app_about_modal.c apps/app_about_modal.h apps/window.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(CLOCK_ELF): $(BUILD_DIR)/apps/clock_ext.o $(BUILD_DIR)/apps/clock_app.o $(BUILD_DIR)/apps/clock_stubs.o $(BUILD_DIR)/apps/app_about_modal.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/clock_ext.o \
	    $(BUILD_DIR)/apps/clock_app.o \
	    $(BUILD_DIR)/apps/clock_stubs.o \
	    $(BUILD_DIR)/apps/app_about_modal.o \
	    -o $@

$(CLOCK_APP): $(CLOCK_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name CLOCK --app-menus --output $@

# ---- CALC.APP external app --------------------------------------------------

$(BUILD_DIR)/apps/calc_ext.o: apps/calculator_ext_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/calculator.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/calc_app.o: apps/calculator.c apps/calculator.h apps/app_about_modal.h apps/window.h drivers/vga.h apps/prefs.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/calc_stubs.o: apps/calculator_stubs.c kernel/app_abi.h apps/window.h drivers/vga.h apps/prefs.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(CALC_ELF): $(BUILD_DIR)/apps/calc_ext.o $(BUILD_DIR)/apps/calc_app.o $(BUILD_DIR)/apps/calc_stubs.o $(BUILD_DIR)/apps/app_about_modal.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/calc_ext.o \
	    $(BUILD_DIR)/apps/calc_app.o \
	    $(BUILD_DIR)/apps/calc_stubs.o \
	    $(BUILD_DIR)/apps/app_about_modal.o \
	    -o $@

$(CALC_APP): $(CALC_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name CALC --app-menus --output $@

# ---- PREFS.APP external app -------------------------------------------------

$(BUILD_DIR)/apps/prefs_ext.o: apps/prefs_ext_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/prefs.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/prefs_app.o: apps/prefs.c apps/prefs.h apps/shell.h apps/window.h drivers/bootlog.h drivers/vga.h drivers/sb16.h kernel/heap.h kernel/workspace.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -DPREFS_EXTERNAL_APP -c $< -o $@

$(BUILD_DIR)/apps/prefs_stubs.o: apps/prefs_stubs.c kernel/app_abi.h apps/window.h drivers/vga.h apps/prefs.h fs/fat.h drivers/rtc.h drivers/bootlog.h drivers/serial.h kernel/heap.h kernel/workspace.h drivers/sb16.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(PREFS_ELF): $(BUILD_DIR)/apps/prefs_ext.o $(BUILD_DIR)/apps/prefs_app.o $(BUILD_DIR)/apps/prefs_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs --gc-sections -nostdlib \
	    $(BUILD_DIR)/apps/prefs_ext.o \
	    $(BUILD_DIR)/apps/prefs_app.o \
	    $(BUILD_DIR)/apps/prefs_stubs.o \
	    -o $@

$(PREFS_APP): $(PREFS_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name PREFS --output $@

# ---- FIND.APP external app --------------------------------------------------

$(BUILD_DIR)/apps/find_ext.o: apps/find_app_ext_entry.c apps/app_standard_menu.h apps/find_app.h kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/find_app.o: apps/find_app.c apps/find_app.h apps/window.h drivers/vga.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/find_stubs.o: apps/find_app_stubs.c kernel/app_abi.h $(APP_SDK_SERVICES_H) apps/window.h drivers/vga.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(FIND_ELF): $(BUILD_DIR)/apps/find_ext.o $(BUILD_DIR)/apps/find_app.o $(BUILD_DIR)/apps/find_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/find_ext.o \
	    $(BUILD_DIR)/apps/find_app.o \
	    $(BUILD_DIR)/apps/find_stubs.o \
	    -o $@

$(FIND_APP): $(FIND_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name FIND --app-menus --output $@

# ---- IMGVIEW.APP external app -----------------------------------------------

$(BUILD_DIR)/apps/imgview_ext.o: apps/imgview_ext_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/window.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/imgview_app.o: apps/imgview.c apps/image_decode.h apps/file_dialog.h apps/window.h drivers/vga.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@

$(BUILD_DIR)/apps/imgview_stubs.o: apps/imgview_stubs.c kernel/app_abi.h $(APP_SDK_SERVICES_H) apps/file_dialog.h apps/window.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(IMGVIEW_ELF): $(BUILD_DIR)/apps/imgview_ext.o $(BUILD_DIR)/apps/imgview_app.o $(BUILD_DIR)/apps/imgview_stubs.o $(BUILD_DIR)/apps/image_decode_client.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/imgview_ext.o \
	    $(BUILD_DIR)/apps/imgview_app.o \
	    $(BUILD_DIR)/apps/imgview_stubs.o \
	    $(BUILD_DIR)/apps/image_decode_client.o \
	    -o $@

$(IMGVIEW_APP): $(IMGVIEW_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name IMGVIEW --app-menus --output $@

$(IMGVIEW_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py IMGVIEW $@

# ---- AUDPLAY.APP external app -----------------------------------------------

$(BUILD_DIR)/apps/audplay_ext.o: apps/waveplayer_ext_entry.c kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(MPG123_BUILD_DIR):
	mkdir -p $@

$(MPG123_BUILD_DIR)/%.o: $(MPG123_DIR)/src/libmpg123/%.c $(MPG123_DIR)/config/config.h $(MPG123_DIR)/include/mpg123.h | $(MPG123_BUILD_DIR)
	$(CC) $(MPG123_CFLAGS) -c $< -o $@

$(MPG123_LIB): $(MPG123_OBJECTS)
	ar rcs $@ $^

$(BUILD_DIR)/apps/audplay_app.o: apps/waveplayer.c apps/waveplayer_mpg123.h apps/cdplayer.h kernel/app_abi.h apps/file_dialog.h apps/window.h drivers/audio_manager.h drivers/vga.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(AUDPLAY_PROFILE_CFLAGS) -DWAVEPLAYER_USE_MPG123 -mfpmath=387 -c $< -o $@

$(BUILD_DIR)/apps/audplay_mpg123.o: apps/waveplayer_mpg123_client.c apps/waveplayer_mpg123.h kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/audplay_mp3.o: apps/waveplayer_mp3.c third_party/minimp3/minimp3.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(AUDPLAY_MP3_OPT) -mfpmath=387 -c $< -o $@

$(BUILD_DIR)/apps/audplay_formats.o: apps/waveplayer_formats_client.c apps/waveplayer_formats.h kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/audplay_stubs.o: apps/waveplayer_stubs.c kernel/app_abi.h $(APP_SDK_SERVICES_H) apps/file_dialog.h apps/window.h drivers/audio_manager.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(AUDPLAY_ELF): $(BUILD_DIR)/apps/audplay_ext.o $(BUILD_DIR)/apps/audplay_app.o $(BUILD_DIR)/apps/audplay_mpg123.o $(BUILD_DIR)/apps/audplay_formats.o $(BUILD_DIR)/apps/audplay_stubs.o $(BUILD_DIR)/apps/cdplay_app.o $(BUILD_DIR)/apps/cdplay_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs --gc-sections -nostdlib \
	    $(BUILD_DIR)/apps/audplay_ext.o \
	    $(BUILD_DIR)/apps/audplay_app.o \
	    $(BUILD_DIR)/apps/audplay_mpg123.o \
	    $(BUILD_DIR)/apps/audplay_formats.o \
	    $(BUILD_DIR)/apps/audplay_stubs.o \
	    $(BUILD_DIR)/apps/cdplay_app.o \
	    $(BUILD_DIR)/apps/cdplay_stubs.o \
	    -o $@

$(AUDPLAY_APP): $(AUDPLAY_ELF) $(AUDPLAY_ICO) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name AUDPLAY --icon $(AUDPLAY_ICO) --app-menus --output $@

$(AUDPLAY_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py AUDPLAY $@

# ---- CAL.APP external app ---------------------------------------------------

$(BUILD_DIR)/apps/cal_ext.o: apps/calendar_ext_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/calendar.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/cal_app.o: apps/calendar.c apps/calendar.h apps/app_about_modal.h apps/window.h drivers/vga.h drivers/rtc.h apps/prefs.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/cal_stubs.o: apps/calendar_stubs.c kernel/app_abi.h apps/window.h drivers/vga.h drivers/rtc.h apps/prefs.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(CAL_ELF): $(BUILD_DIR)/apps/cal_ext.o $(BUILD_DIR)/apps/cal_app.o $(BUILD_DIR)/apps/cal_stubs.o $(BUILD_DIR)/apps/app_about_modal.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/cal_ext.o \
	    $(BUILD_DIR)/apps/cal_app.o \
	    $(BUILD_DIR)/apps/cal_stubs.o \
	    $(BUILD_DIR)/apps/app_about_modal.o \
	    -o $@

$(CAL_APP): $(CAL_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name CAL --app-menus --output $@

# ---- SLOTS.APP external app -------------------------------------------------

$(BUILD_DIR)/apps/slot_ext.o: apps/slot_ext_entry.c kernel/app_abi.h apps/slot_machine.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/slot_app.o: apps/slot_machine.c apps/slot_machine.h apps/window.h drivers/vga.h drivers/pit.h fs/file_contract.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/slot_stubs.o: apps/slot_stubs.c kernel/app_abi.h apps/window.h drivers/vga.h fs/file_contract.h fs/fat.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(SLOTS_ELF): $(BUILD_DIR)/apps/slot_ext.o $(BUILD_DIR)/apps/slot_app.o $(BUILD_DIR)/apps/slot_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/slot_ext.o \
	    $(BUILD_DIR)/apps/slot_app.o \
	    $(BUILD_DIR)/apps/slot_stubs.o \
	    -o $@

$(SLOTS_APP): $(SLOTS_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name SLOTS --app-menus --output $@

# ---- BIORHYTH.APP external app ---------------------------------------------

$(BUILD_DIR)/apps/biostar_ext.o: apps/biostar_ext_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/biostar.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/biostar_app.o: apps/biostar.c apps/biostar.h apps/app_about_modal.h apps/window.h drivers/vga.h drivers/rtc.h | $(BUILD_DIR)/apps
	$(CC) $(filter-out -Os,$(APP_CFLAGS)) -Oz -c $< -o $@

$(BUILD_DIR)/apps/biostar_stubs.o: apps/biostar_stubs.c kernel/app_abi.h apps/window.h drivers/vga.h drivers/rtc.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BIOSTAR_ELF): $(BUILD_DIR)/apps/biostar_ext.o $(BUILD_DIR)/apps/biostar_app.o $(BUILD_DIR)/apps/biostar_stubs.o $(BUILD_DIR)/apps/app_about_modal.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs --gc-sections -nostdlib \
	    $(BUILD_DIR)/apps/biostar_ext.o \
	    $(BUILD_DIR)/apps/biostar_app.o \
	    $(BUILD_DIR)/apps/biostar_stubs.o \
	    $(BUILD_DIR)/apps/app_about_modal.o \
	    -o $@

$(BIOSTAR_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py BIORHYTH $@

$(BIOSTAR_APP): $(BIOSTAR_ELF) tools/mkapp.py $(BIOSTAR_ICO) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name BIORHYTH --icon $(BIOSTAR_ICO) --app-menus --output $@

# ---- MANDEL.APP Mandelbrot explorer ---------------------------------------

$(BUILD_DIR)/apps/mandelbrot_ext.o: apps/mandelbrot_entry.c kernel/app_abi.h apps/mandelbrot.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/mandelbrot_app.o: apps/mandelbrot.c apps/mandelbrot.h apps/app_about_modal.h apps/window.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(filter-out -Os,$(APP_CFLAGS)) -Oz -c $< -o $@

$(BUILD_DIR)/apps/mandelbrot_stubs.o: apps/mandelbrot_stubs.c kernel/app_abi.h apps/window.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(MANDEL_ELF): $(BUILD_DIR)/apps/mandelbrot_ext.o $(BUILD_DIR)/apps/mandelbrot_app.o $(BUILD_DIR)/apps/mandelbrot_stubs.o $(BUILD_DIR)/apps/app_about_modal.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs --gc-sections -nostdlib \
	    $(BUILD_DIR)/apps/mandelbrot_ext.o \
	    $(BUILD_DIR)/apps/mandelbrot_app.o \
	    $(BUILD_DIR)/apps/mandelbrot_stubs.o \
	    $(BUILD_DIR)/apps/app_about_modal.o \
	    -o $@

$(MANDEL_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py MANDEL $@

$(MANDEL_APP): $(MANDEL_ELF) tools/mkapp.py $(MANDEL_ICO) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name MANDEL --icon $(MANDEL_ICO) --app-menus --output $@

# ---- ZIPZORK.APP Z-machine V1-V6 interpreter ------------------------------

FROTZ_DIR := third_party/windows-frotz/Generic
FROTZ_NAMES := buffer err fastmem files hotkey input main math object process \
	quetzal random redirect screen sound stream table text variable
FROTZ_OBJECTS := $(addprefix $(BUILD_DIR)/apps/frotz_,$(addsuffix .o,$(FROTZ_NAMES)))
ZIPZORK_CFLAGS := $(filter-out -Os,$(APP_CFLAGS)) -Oz -D__UNIX_PORT_FILE \
	-DTRUE=1 -DFALSE=0 -Dmain=frotz_unused_main -include stdbool.h -include string.h \
	-Iapps/zipzork_compat -I$(FROTZ_DIR)

$(BUILD_DIR)/apps/zipzork_ext.o: apps/zipzork_entry.c apps/zipzork.h kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/zipzork_app.o: apps/zipzork.c apps/zipzork.h apps/app_about_modal.h apps/window.h | $(BUILD_DIR)/apps
	$(CC) $(filter-out -Os,$(APP_CFLAGS)) -Oz -c $< -o $@

$(BUILD_DIR)/apps/zipzork_stubs.o: apps/zipzork_stubs.c apps/zipzork.h kernel/app_abi.h $(APP_SDK_SERVICES_H) apps/window.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/zipzork_port.o: apps/zipzork_port.c apps/zipzork.h apps/zipzork_font8x8.inc apps/zipzork_compat/stdio.h apps/zipzork_compat/stdlib.h apps/zipzork_compat/string.h $(FROTZ_DIR)/frotz.h drivers/vga_fonts.inc | $(BUILD_DIR)/apps
	$(CC) $(ZIPZORK_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/frotz_%.o: $(FROTZ_DIR)/%.c $(FROTZ_DIR)/frotz.h apps/zipzork_compat/stdio.h apps/zipzork_compat/stdlib.h apps/zipzork_compat/string.h apps/zipzork_compat/signal.h | $(BUILD_DIR)/apps
	$(CC) $(ZIPZORK_CFLAGS) -c $< -o $@

$(ZIPZORK_ELF): $(BUILD_DIR)/apps/zipzork_ext.o $(BUILD_DIR)/apps/zipzork_app.o $(BUILD_DIR)/apps/zipzork_stubs.o $(BUILD_DIR)/apps/zipzork_port.o $(FROTZ_OBJECTS) $(BUILD_DIR)/apps/app_about_modal.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs --gc-sections -nostdlib \
	    $(BUILD_DIR)/apps/zipzork_ext.o $(BUILD_DIR)/apps/zipzork_app.o \
	    $(BUILD_DIR)/apps/zipzork_stubs.o $(BUILD_DIR)/apps/zipzork_port.o \
	    $(FROTZ_OBJECTS) $(BUILD_DIR)/apps/app_about_modal.o -o $@

$(ZIPZORK_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py HELP $@

$(ZIPZORK_APP): $(ZIPZORK_ELF) tools/mkapp.py $(ZIPZORK_ICO) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name ZIPZORK --icon $(ZIPZORK_ICO) \
	    --high-memory --open-launch-at --app-menus --output $@

# ---- DESKHAM.APP optional desktop companion -------------------------------

$(BUILD_DIR)/apps/deskham_ext.o: apps/deskham_entry.c apps/deskham.h kernel/app_abi.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/deskham_app.o: apps/deskham.c apps/deskham.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/deskham_stubs.o: apps/deskham_stubs.c kernel/app_abi.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(DESKHAM_ELF): $(BUILD_DIR)/apps/deskham_ext.o $(BUILD_DIR)/apps/deskham_app.o $(BUILD_DIR)/apps/deskham_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $(BUILD_DIR)/apps/deskham_ext.o $(BUILD_DIR)/apps/deskham_app.o $(BUILD_DIR)/apps/deskham_stubs.o -o $@

$(DESKHAM_APP): $(DESKHAM_ELF) tools/mkapp.py $(DESKHAM_ICO) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name DESKHAM --icon $(DESKHAM_ICO) --right-click --output $@

# ---- paint_loader.o (kernel side dispatch) ----------------------------------

$(BUILD_DIR)/apps/paint_loader.o: apps/paint_loader.c apps/paint.h kernel/app_loader.h kernel/app_abi.h kernel/heap.h drivers/serial.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(CFLAGS) -c $< -o $@

# ---- PAINT.APP external app -------------------------------------------------

$(BUILD_DIR)/apps/paint_ext.o: apps/paint_ext_entry.c kernel/app_abi.h apps/paint.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/paint_app.o: apps/paint.c apps/paint.h apps/app_about_modal.h apps/image_decode.h apps/file_dialog.h apps/prefs.h apps/window.h drivers/vga.h fs/fat.h apps/shell.h kernel/workspace.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@

$(BUILD_DIR)/apps/paint_stubs.o: apps/paint_stubs.c kernel/app_abi.h kernel/workspace.h apps/file_dialog.h apps/window.h drivers/vga.h fs/fat.h apps/prefs.h apps/shell.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@

$(PAINT_ELF): $(BUILD_DIR)/apps/paint_ext.o $(BUILD_DIR)/apps/paint_app.o $(BUILD_DIR)/apps/paint_stubs.o $(BUILD_DIR)/apps/image_decode_client.o $(BUILD_DIR)/apps/app_about_modal.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/paint_ext.o \
	    $(BUILD_DIR)/apps/paint_app.o \
	    $(BUILD_DIR)/apps/paint_stubs.o \
	    $(BUILD_DIR)/apps/image_decode_client.o \
	    $(BUILD_DIR)/apps/app_about_modal.o \
	    -o $@

$(PAINT_APP): $(PAINT_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name PAINT --app-menus --output $@

# ---- Tool .APP files (/TOOLS/ directory) ------------------------------------

$(BUILD_DIR)/apps/diskcopy_ext.o: apps/diskcopier_tool_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/diskcopier.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/diskcopy_app.o: apps/diskcopier.c apps/diskcopier.h apps/window.h drivers/vga.h drivers/floppy.h fs/fat.h apps/shell.h drivers/serial.h kernel/service.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/diskcopy_stubs.o: apps/diskcopier_tool_stubs.c kernel/app_abi.h $(APP_SDK_SERVICES_H) apps/window.h drivers/vga.h drivers/floppy.h fs/fat.h apps/shell.h drivers/serial.h kernel/service.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(DISKCOPY_ELF): $(BUILD_DIR)/apps/diskcopy_ext.o $(BUILD_DIR)/apps/diskcopy_app.o $(BUILD_DIR)/apps/diskcopy_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< $(BUILD_DIR)/apps/diskcopy_app.o $(BUILD_DIR)/apps/diskcopy_stubs.o -o $@
$(DISKCOPY_APP): $(DISKCOPY_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name DISKCOPY --app-menus --output $@

$(BUILD_DIR)/apps/cdplay_ext.o: apps/cdplayer_tool_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/cdplayer.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/cdplay_app.o: apps/cdplayer.c apps/cdplayer.h apps/window.h drivers/vga.h drivers/cdrom.h drivers/pit.h drivers/serial.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/cdplay_stubs.o: apps/cdplayer_tool_stubs.c kernel/app_abi.h $(APP_SDK_SERVICES_H) apps/window.h drivers/vga.h drivers/cdrom.h drivers/pit.h drivers/serial.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(CDPLAY_ELF): $(BUILD_DIR)/apps/cdplay_ext.o $(BUILD_DIR)/apps/cdplay_app.o $(BUILD_DIR)/apps/cdplay_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< $(BUILD_DIR)/apps/cdplay_app.o $(BUILD_DIR)/apps/cdplay_stubs.o -o $@
$(CDPLAY_APP): $(CDPLAY_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name CDPLAY --app-menus --output $@

$(BUILD_DIR)/apps/flopdiag_ext.o: apps/floppydiag_tool_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/floppydiag.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/flopdiag_app.o: apps/floppydiag.c apps/floppydiag.h apps/window.h drivers/vga.h drivers/floppy.h fs/fat.h drivers/pit.h apps/shell.h drivers/serial.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/flopdiag_stubs.o: apps/floppydiag_tool_stubs.c kernel/app_abi.h apps/window.h drivers/vga.h drivers/floppy.h fs/fat.h drivers/pit.h apps/shell.h drivers/serial.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(FLOPDIAG_ELF): $(BUILD_DIR)/apps/flopdiag_ext.o $(BUILD_DIR)/apps/flopdiag_app.o $(BUILD_DIR)/apps/flopdiag_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< $(BUILD_DIR)/apps/flopdiag_app.o $(BUILD_DIR)/apps/flopdiag_stubs.o -o $@
$(FLOPDIAG_APP): $(FLOPDIAG_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name FLOPDIAG --app-menus --output $@

$(BUILD_DIR)/apps/cddiag_ext.o: apps/cdromdiag_tool_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/cdromdiag.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/cddiag_app.o: apps/cdromdiag.c apps/cdromdiag.h apps/window.h drivers/vga.h drivers/cdrom.h fs/fat.h apps/shell.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/cddiag_stubs.o: apps/cdromdiag_tool_stubs.c kernel/app_abi.h $(APP_SDK_SERVICES_H) apps/window.h drivers/vga.h drivers/cdrom.h fs/fat.h apps/shell.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(CDDIAG_ELF): $(BUILD_DIR)/apps/cddiag_ext.o $(BUILD_DIR)/apps/cddiag_app.o $(BUILD_DIR)/apps/cddiag_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< $(BUILD_DIR)/apps/cddiag_app.o $(BUILD_DIR)/apps/cddiag_stubs.o -o $@
$(CDDIAG_APP): $(CDDIAG_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name CDDIAG --app-menus --output $@

$(BUILD_DIR)/apps/idediag_ext.o: apps/idediag_tool_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/idediag.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/idediag_app.o: apps/idediag.c apps/idediag.h apps/window.h drivers/vga.h drivers/ide.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/idediag_stubs.o: apps/idediag_tool_stubs.c kernel/app_abi.h $(APP_SDK_SERVICES_H) apps/window.h drivers/vga.h drivers/ide.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(IDEDIAG_ELF): $(BUILD_DIR)/apps/idediag_ext.o $(BUILD_DIR)/apps/idediag_app.o $(BUILD_DIR)/apps/idediag_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< $(BUILD_DIR)/apps/idediag_app.o $(BUILD_DIR)/apps/idediag_stubs.o -o $@
$(IDEDIAG_APP): $(IDEDIAG_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name IDEDIAG --app-menus --output $@

$(BUILD_DIR)/apps/usbdiag_ext.o: apps/usbdiag_tool_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/usbdiag.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/usbdiag_app.o: apps/usbdiag.c apps/usbdiag.h apps/usb_mouse_driver/usbmouse_diag.h kernel/app_abi.h apps/window.h drivers/vga.h drivers/storage.h drivers/driver_model.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/usbdiag_stubs.o: apps/usbdiag_tool_stubs.c kernel/app_abi.h apps/window.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(USBDIAG_ELF): $(BUILD_DIR)/apps/usbdiag_ext.o $(BUILD_DIR)/apps/usbdiag_app.o $(BUILD_DIR)/apps/usbdiag_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< $(BUILD_DIR)/apps/usbdiag_app.o $(BUILD_DIR)/apps/usbdiag_stubs.o -o $@
$(USBDIAG_APP): $(USBDIAG_ELF) tools/mkapp.py $(USBDIAG_ICO) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name USBDIAG --icon $(USBDIAG_ICO) --app-menus --output $@

$(BUILD_DIR)/apps/scsidiag_ext.o: apps/scsidiag_tool_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/scsidiag.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/scsidiag_app.o: apps/scsidiag.c apps/scsidiag.h apps/window.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/scsidiag_stubs.o: apps/scsidiag_tool_stubs.c kernel/app_abi.h apps/window.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(SCSIDIAG_ELF): $(BUILD_DIR)/apps/scsidiag_ext.o $(BUILD_DIR)/apps/scsidiag_app.o $(BUILD_DIR)/apps/scsidiag_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< $(BUILD_DIR)/apps/scsidiag_app.o $(BUILD_DIR)/apps/scsidiag_stubs.o -o $@
$(SCSIDIAG_APP): $(SCSIDIAG_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name SCSIDIAG --app-menus --output $@

$(BUILD_DIR)/apps/netdiag_ext.o: apps/netdiag_tool_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/netdiag.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/netdiag_app.o: apps/netdiag.c apps/netdiag.h apps/netdiag_version.h apps/window.h drivers/vga.h drivers/ne2k_net.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/netdiag_stubs.o: apps/netdiag_tool_stubs.c kernel/app_abi.h $(APP_SDK_SERVICES_H) apps/window.h drivers/vga.h drivers/ne2k_net.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(NETDIAG_ELF): $(BUILD_DIR)/apps/netdiag_ext.o $(BUILD_DIR)/apps/netdiag_app.o $(BUILD_DIR)/apps/netdiag_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< $(BUILD_DIR)/apps/netdiag_app.o $(BUILD_DIR)/apps/netdiag_stubs.o -o $@
$(NETDIAG_APP): $(NETDIAG_ELF) tools/mkapp.py $(NETDIAG_ICO) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name NETDIAG --icon $(NETDIAG_ICO) --no-compress --app-menus --output $@

$(BUILD_DIR)/apps/hamshare_ext.o: apps/hamshare_tool_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/hamshare.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/hamshare_app.o: apps/hamshare.c apps/hamshare.h apps/window.h drivers/vga.h fs/fat.h fs/file_contract.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/hamshare_stubs.o: apps/hamshare_tool_stubs.c kernel/app_abi.h $(APP_SDK_SERVICES_H) apps/window.h drivers/vga.h fs/fat.h fs/file_contract.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(HAMSHARE_ELF): $(BUILD_DIR)/apps/hamshare_ext.o $(BUILD_DIR)/apps/hamshare_app.o $(BUILD_DIR)/apps/hamshare_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< $(BUILD_DIR)/apps/hamshare_app.o $(BUILD_DIR)/apps/hamshare_stubs.o -o $@
$(HAMSHARE_APP): $(HAMSHARE_ELF) tools/mkapp.py $(HAMSHARE_ICO) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name HAMSHARE --icon $(HAMSHARE_ICO) --open-launch-at --app-menus --output $@

$(BUILD_DIR)/apps/format_ext.o: apps/format_tool_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/format.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/format_app.o: apps/format.c apps/format.h apps/window.h drivers/vga.h drivers/floppy.h fs/fat.h apps/shell.h drivers/serial.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/format_stubs.o: apps/format_tool_stubs.c kernel/app_abi.h $(APP_SDK_SERVICES_H) apps/window.h drivers/vga.h drivers/floppy.h fs/fat.h apps/shell.h drivers/serial.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(FORMAT_APP_ELF): $(BUILD_DIR)/apps/format_ext.o $(BUILD_DIR)/apps/format_app.o $(BUILD_DIR)/apps/format_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< $(BUILD_DIR)/apps/format_app.o $(BUILD_DIR)/apps/format_stubs.o -o $@
$(FORMAT_APP): $(FORMAT_APP_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name FORMAT --app-menus --output $@

$(BUILD_DIR)/apps/gfxdiag_ext.o: apps/gfxdiag_tool_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/gfxdiag.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/gfxdiag_app.o: apps/gfxdiag.c apps/gfxdiag.h apps/window.h kernel/heap.h drivers/vga.h drivers/pit.h drivers/serial.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/gfxdiag_stubs.o: apps/gfxdiag_tool_stubs.c kernel/app_abi.h apps/window.h drivers/vga.h drivers/pit.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(GFXDIAG_ELF): $(BUILD_DIR)/apps/gfxdiag_ext.o $(BUILD_DIR)/apps/gfxdiag_app.o $(BUILD_DIR)/apps/gfxdiag_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< $(BUILD_DIR)/apps/gfxdiag_app.o $(BUILD_DIR)/apps/gfxdiag_stubs.o -o $@
$(GFXDIAG_APP): $(GFXDIAG_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name GFXDIAG --app-menus --output $@

$(BUILD_DIR)/apps/devmgr_ext.o: apps/devmgr_tool_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/devmgr.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/devmgr_app.o: apps/devmgr.c apps/devmgr.h kernel/app_abi.h apps/window.h drivers/vga.h drivers/driver_model.h kernel/driver_loader.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/devmgr_stubs.o: apps/devmgr_tool_stubs.c kernel/app_abi.h apps/window.h drivers/vga.h drivers/driver_model.h kernel/driver_loader.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(DEVMGR_ELF): $(BUILD_DIR)/apps/devmgr_ext.o $(BUILD_DIR)/apps/devmgr_app.o $(BUILD_DIR)/apps/devmgr_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< $(BUILD_DIR)/apps/devmgr_app.o $(BUILD_DIR)/apps/devmgr_stubs.o -o $@
$(DEVMGR_APP): $(DEVMGR_ELF) tools/mkapp.py | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name DEVMGR --app-menus --output $@

$(BUILD_DIR)/apps/fonts_ext.o: apps/fonts_tool_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/fonts.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/fonts_app.o: apps/fonts.c apps/fonts.h apps/window.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/fonts_stubs.o: apps/fonts_tool_stubs.c kernel/app_abi.h apps/window.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(FONTS_ELF): $(BUILD_DIR)/apps/fonts_ext.o $(BUILD_DIR)/apps/fonts_app.o $(BUILD_DIR)/apps/fonts_stubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< $(BUILD_DIR)/apps/fonts_app.o $(BUILD_DIR)/apps/fonts_stubs.o -o $@
$(FONTS_APP): $(FONTS_ELF) tools/mkapp.py $(FONTS_ICO) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name FONTS --icon $(FONTS_ICO) --app-menus --output $@

$(BUILD_DIR)/apps/extras_install_ext.o: apps/extras_install_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/extras_install.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/extras_install_app.o: apps/extras_install.c apps/extras_install.h apps/payload_expand.h apps/zip_extract.h apps/window.h apps/image_decode.h drivers/vga.h fs/fat.h fs/file_contract.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) $(HAMNET_CORE_INCLUDES) -c $< -o $@
$(APP_SDK_SERVICES_H): tools/gen_app_sdk.py kernel/app_abi.h | $(GENERATED_DIR)
	python3 tools/gen_app_sdk.py --abi kernel/app_abi.h --output $@

$(BUILD_DIR)/apps/extras_install_stubs.o: apps/extras_install_stubs.c kernel/app_abi.h kernel/inflate.h $(APP_SDK_SERVICES_H) apps/window.h drivers/vga.h fs/fat.h fs/file_contract.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/payload_expand.o: apps/payload_expand.c apps/payload_expand.h kernel/app_abi.h kernel/inflate.h kernel/crc32.h kernel/fast_memory.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/inflate.o: kernel/inflate.c kernel/inflate.h | $(BUILD_DIR)/apps
	$(CC) $(filter-out -Os,$(APP_CFLAGS)) -O2 -c $< -o $@
$(EXTRAS_INSTALL_ELF): $(BUILD_DIR)/apps/extras_install_ext.o $(BUILD_DIR)/apps/extras_install_app.o $(BUILD_DIR)/apps/extras_install_stubs.o $(BUILD_DIR)/apps/image_decode_client.o $(BUILD_DIR)/apps/payload_expand.o $(BUILD_DIR)/apps/zip_extract_dll.o $(BUILD_DIR)/apps/inflate.o $(BUILD_DIR)/apps/crc32.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< $(BUILD_DIR)/apps/extras_install_app.o $(BUILD_DIR)/apps/extras_install_stubs.o $(BUILD_DIR)/apps/image_decode_client.o $(BUILD_DIR)/apps/payload_expand.o $(BUILD_DIR)/apps/zip_extract_dll.o $(BUILD_DIR)/apps/inflate.o $(BUILD_DIR)/apps/crc32.o -o $@
$(EXTRAS_INSTALL_APP): $(EXTRAS_INSTALL_ELF) tools/mkapp.py $(EXTRAS_INSTALL_ICO) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name SETUP --icon $(EXTRAS_INSTALL_ICO) --no-compress --open-launch-at --app-menus --output $@

$(BUILD_DIR)/apps/update_ext.o: apps/update_tool_entry.c apps/app_standard_menu.h kernel/app_abi.h apps/update.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(BUILD_DIR)/apps/update_app.o: apps/update.c apps/update.h apps/payload_expand.h apps/update_scan.h apps/window.h drivers/vga.h fs/fat.h fs/file_contract.h kernel/ham_strings.h kernel/version.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -DUPDATE_DOWNLOAD_ENABLED=0 -c $< -o $@
$(BUILD_DIR)/apps/update_app_plus.o: apps/update.c apps/update.h apps/payload_expand.h apps/update_scan.h apps/window.h drivers/vga.h fs/fat.h fs/file_contract.h kernel/ham_strings.h kernel/version.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -DUPDATE_DOWNLOAD_ENABLED=1 -c $< -o $@
$(BUILD_DIR)/apps/update_stubs.o: apps/update_tool_stubs.c kernel/app_abi.h $(APP_SDK_SERVICES_H) kernel/ham_strings.h apps/window.h drivers/vga.h fs/fat.h fs/file_contract.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $< -o $@
$(UPDATE_ELF): $(BUILD_DIR)/apps/update_ext.o $(BUILD_DIR)/apps/update_app.o $(BUILD_DIR)/apps/update_stubs.o $(BUILD_DIR)/apps/payload_expand.o $(BUILD_DIR)/apps/inflate.o $(BUILD_DIR)/apps/crc32.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< $(BUILD_DIR)/apps/update_app.o $(BUILD_DIR)/apps/update_stubs.o $(BUILD_DIR)/apps/payload_expand.o $(BUILD_DIR)/apps/inflate.o $(BUILD_DIR)/apps/crc32.o -o $@
$(UPDATE_APP): $(UPDATE_ELF) tools/mkapp.py $(UPDATE_ICO) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name UPDATE --icon $(UPDATE_ICO) --open-launch-at --app-menus --output $@

$(UPDATE_PLUS_ELF): $(BUILD_DIR)/apps/update_ext.o $(BUILD_DIR)/apps/update_app_plus.o $(BUILD_DIR)/apps/update_stubs.o $(BUILD_DIR)/apps/payload_expand.o $(BUILD_DIR)/apps/inflate.o $(BUILD_DIR)/apps/crc32.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $< $(BUILD_DIR)/apps/update_app_plus.o $(BUILD_DIR)/apps/update_stubs.o $(BUILD_DIR)/apps/payload_expand.o $(BUILD_DIR)/apps/inflate.o $(BUILD_DIR)/apps/crc32.o -o $@
$(UPDATE_PLUS_APP): $(UPDATE_PLUS_ELF) tools/mkapp.py $(UPDATE_ICO) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name UPDATE --icon $(UPDATE_ICO) --open-launch-at --app-menus --output $@


# ---- Game .APP files (bundled with 16x16 icons) -----------------------------

define GAME_APP_RULES
$(BUILD_DIR)/apps/$(1)_gentry.o: apps/$(1)_gentry.c kernel/app_abi.h apps/$(1).h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $$< -o $$@

$(BUILD_DIR)/apps/$(1)_gstubs.o: apps/$(1)_gstubs.c apps/games_stubs_base.h kernel/app_abi.h apps/window.h drivers/vga.h | $(BUILD_DIR)/apps
	$(CC) $(APP_CFLAGS) -c $$< -o $$@

$(BUILD_DIR)/apps/$(1)_gapp.o: apps/$(1).c apps/$(1).h apps/window.h drivers/vga.h drivers/pit.h | $(BUILD_DIR)/apps
	$(CC) $(if $(filter tankbattle,$(1)),$(HCOMMAND_CFLAGS),$(APP_CFLAGS)) $(HAMNET_CORE_INCLUDES) -c $$< -o $$@
endef

$(eval $(call GAME_APP_RULES,snake))
$(eval $(call GAME_APP_RULES,mines))
$(eval $(call GAME_APP_RULES,puzzle))
$(eval $(call GAME_APP_RULES,moonlander))
$(eval $(call GAME_APP_RULES,freecell))
$(eval $(call GAME_APP_RULES,golf))
$(eval $(call GAME_APP_RULES,tankbattle))

$(FREECELL_COURT_ATLAS) $(FREECELL_COURT_H) &: $(FREECELL_COURT_SOURCE) tools/mkcourtcard_sprites.py | $(GENERATED_DIR)
	python3 tools/mkcourtcard_sprites.py --profile freecell --input $(FREECELL_COURT_SOURCE) --atlas-output $(FREECELL_COURT_ATLAS) --header-output $(FREECELL_COURT_H)

$(BUILD_DIR)/apps/freecell_gapp.o: apps/card_art.h $(FREECELL_COURT_H)

# snake
$(COMPILED_ELF_DIR)/snake_app.elf: $(BUILD_DIR)/apps/snake_gentry.o $(BUILD_DIR)/apps/snake_gapp.o $(BUILD_DIR)/apps/snake_gstubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $(BUILD_DIR)/apps/snake_gentry.o $(BUILD_DIR)/apps/snake_gapp.o $(BUILD_DIR)/apps/snake_gstubs.o -o $@

$(SNAKE_APP): $(COMPILED_ELF_DIR)/snake_app.elf tools/mkapp.py assets/snake_icon.bin | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name SNAKE --icon assets/snake_icon.bin --app-menus --output $@

# mines
$(COMPILED_ELF_DIR)/mines_app.elf: $(BUILD_DIR)/apps/mines_gentry.o $(BUILD_DIR)/apps/mines_gapp.o $(BUILD_DIR)/apps/mines_gstubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $(BUILD_DIR)/apps/mines_gentry.o $(BUILD_DIR)/apps/mines_gapp.o $(BUILD_DIR)/apps/mines_gstubs.o -o $@

$(MINES_APP): $(COMPILED_ELF_DIR)/mines_app.elf tools/mkapp.py assets/mines_icon.bin | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name MINES --icon assets/mines_icon.bin --app-menus --output $@

# puzzle
$(COMPILED_ELF_DIR)/puzzle_app.elf: $(BUILD_DIR)/apps/puzzle_gentry.o $(BUILD_DIR)/apps/puzzle_gapp.o $(BUILD_DIR)/apps/puzzle_gstubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $(BUILD_DIR)/apps/puzzle_gentry.o $(BUILD_DIR)/apps/puzzle_gapp.o $(BUILD_DIR)/apps/puzzle_gstubs.o -o $@

$(PUZZLE_APP): $(COMPILED_ELF_DIR)/puzzle_app.elf tools/mkapp.py assets/puzzle_icon.bin | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name PUZZLE --icon assets/puzzle_icon.bin --app-menus --output $@

# moonlander (lander)
$(COMPILED_ELF_DIR)/lander_app.elf: $(BUILD_DIR)/apps/moonlander_gentry.o $(BUILD_DIR)/apps/moonlander_gapp.o $(BUILD_DIR)/apps/moonlander_gstubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $(BUILD_DIR)/apps/moonlander_gentry.o $(BUILD_DIR)/apps/moonlander_gapp.o $(BUILD_DIR)/apps/moonlander_gstubs.o -o $@

$(LANDER_APP): $(COMPILED_ELF_DIR)/lander_app.elf tools/mkapp.py assets/moonlander_icon.bin | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name LANDER --icon assets/moonlander_icon.bin --app-menus --output $@

# freecell
$(COMPILED_ELF_DIR)/freecell_app.elf: $(BUILD_DIR)/apps/freecell_gentry.o $(BUILD_DIR)/apps/freecell_gapp.o $(BUILD_DIR)/apps/freecell_gstubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $(BUILD_DIR)/apps/freecell_gentry.o $(BUILD_DIR)/apps/freecell_gapp.o $(BUILD_DIR)/apps/freecell_gstubs.o -o $@

$(FREECELL_APP): $(COMPILED_ELF_DIR)/freecell_app.elf tools/mkapp.py $(FREECELL_ICO) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name FREECL --icon $(FREECELL_ICO) --app-menus --output $@

# poker
$(eval $(call GAME_APP_RULES,poker))
$(COURT_CARD_ATLAS) $(COURT_CARD_H) &: $(COURT_CARD_SOURCE) tools/mkcourtcard_sprites.py | $(GENERATED_DIR)
	python3 tools/mkcourtcard_sprites.py --input $(COURT_CARD_SOURCE) --atlas-output $(COURT_CARD_ATLAS) --header-output $(COURT_CARD_H)

$(BUILD_DIR)/apps/poker_gapp.o: apps/card_art.h $(COURT_CARD_H)
$(COMPILED_ELF_DIR)/poker_app.elf: $(BUILD_DIR)/apps/poker_gentry.o $(BUILD_DIR)/apps/poker_gapp.o $(BUILD_DIR)/apps/poker_gstubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $(BUILD_DIR)/apps/poker_gentry.o $(BUILD_DIR)/apps/poker_gapp.o $(BUILD_DIR)/apps/poker_gstubs.o -o $@

$(POKER_APP): $(COMPILED_ELF_DIR)/poker_app.elf tools/mkapp.py $(POKER_ICO) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name POKER --icon $(POKER_ICO) --app-menus --output $@

# golf
$(COMPILED_ELF_DIR)/golf_app.elf: $(BUILD_DIR)/apps/golf_gentry.o $(BUILD_DIR)/apps/golf_gapp.o $(BUILD_DIR)/apps/golf_gstubs.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib $(BUILD_DIR)/apps/golf_gentry.o $(BUILD_DIR)/apps/golf_gapp.o $(BUILD_DIR)/apps/golf_gstubs.o -o $@

$(GOLF_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py GOLF $@

$(GOLF_APP): $(COMPILED_ELF_DIR)/golf_app.elf tools/mkapp.py $(GOLF_ICO) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name GOLF --icon $(GOLF_ICO) --output $@

# Hamster Command (Extras LAN RTS)
$(HCOMMAND_ART_INC) $(HCOMMAND_ART_PREVIEW) $(HCOMMAND_ART_ANIMATION) &: $(HCOMMAND_ART_SOURCES)
	python3 tools/mkhcommand_art.py --include $(HCOMMAND_ART_INC) --preview $(HCOMMAND_ART_PREVIEW) --animation-preview $(HCOMMAND_ART_ANIMATION)

$(HCOMMAND_SOUND_INC): $(HCOMMAND_SOUND_SOURCES)
	python3 tools/mkhcommand_sounds.py --source-dir $(HCOMMAND_SOUND_DIR) --include $(HCOMMAND_SOUND_INC)

$(BUILD_DIR)/apps/tankbattle_gapp.o: apps/hamster_command_title.inc $(HCOMMAND_ART_INC) $(HCOMMAND_SOUND_INC) ports/hcommand/core/hcommand_game.h ports/hcommand/core/hcommand_ui.h $(HAMNET_CORE_DIR)/include/hamnet_online.h $(HAMNET_CORE_DIR)/include/hamnet_transport.h

$(BUILD_DIR)/apps/hcommand_wire.o: ports/hcommand/core/hcommand_wire.c ports/hcommand/core/hcommand_wire.h | $(BUILD_DIR)/apps
	$(CC) $(HCOMMAND_CFLAGS) -c $< -o $@

$(BUILD_DIR)/apps/hcommand_game.o: ports/hcommand/core/hcommand_game.c ports/hcommand/core/hcommand_game.h ports/hcommand/core/hcommand_wire.h | $(BUILD_DIR)/apps
	$(CC) $(HCOMMAND_CFLAGS) -c $< -o $@

$(COMPILED_ELF_DIR)/tankbattle_app.elf: $(BUILD_DIR)/apps/tankbattle_gentry.o $(BUILD_DIR)/apps/tankbattle_gapp.o $(BUILD_DIR)/apps/tankbattle_gstubs.o $(BUILD_DIR)/apps/hamnet_online_plus.o $(BUILD_DIR)/apps/hamnet_transport.o $(BUILD_DIR)/apps/crypto_client.o $(BUILD_DIR)/apps/hcommand_wire.o $(BUILD_DIR)/apps/hcommand_game.o tools/app.ld | $(COMPILED_ELF_DIR)
	$(LD) -T tools/app.ld -melf_i386 --emit-relocs -nostdlib \
	    $(BUILD_DIR)/apps/tankbattle_gentry.o \
	    $(BUILD_DIR)/apps/tankbattle_gapp.o \
	    $(BUILD_DIR)/apps/tankbattle_gstubs.o \
	    $(BUILD_DIR)/apps/hamnet_online_plus.o \
	    $(BUILD_DIR)/apps/hamnet_transport.o \
	    $(BUILD_DIR)/apps/crypto_client.o \
	    $(BUILD_DIR)/apps/hcommand_wire.o \
	    $(BUILD_DIR)/apps/hcommand_game.o \
	    -o $@

$(HCOMMAND_ICO): tools/mkicon.py | $(APPS_OUT_DIR)
	python3 tools/mkicon.py HCOMMAND $@

$(HCOMMAND_APP): $(COMPILED_ELF_DIR)/tankbattle_app.elf tools/mkapp.py $(HCOMMAND_ICO) | $(APPS_OUT_DIR)
	python3 tools/mkapp.py --elf $< --name HCommand --icon $(HCOMMAND_ICO) --app-menus --right-click --high-memory --output $@
