-
-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathMakefile
More file actions
345 lines (306 loc) · 17.2 KB
/
Copy pathMakefile
File metadata and controls
345 lines (306 loc) · 17.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
# Makefile — builds the reconstructed Wacki engine + tools.
#
# Per-target config is chopped out into mk/<target>.mk — one file per platform,
# mirroring src/platform/<family>/. This top file holds only what's COMMON
# (toolchain, base flags, the platform-agnostic source lists, the generic
# recipes); it then `include`s exactly one mk/<target>.mk based on $(TARGET),
# which sets that platform's CFLAGS / BIN_NAME / size opts / PLATFORM_SRCS.
#
# Adding a platform = a new src/platform/<plat>/ dir + a new mk/<plat>.mk; no
# edits to this file. Build a non-default target with `make TARGET=<plat>`
# (in practice via the tools/build-<plat>.sh Docker wrappers).
CC ?= cc
SDL2_CFG ?= sdl2-config
# ---- cross-compile toolchain --------------------------------------------- *
# A CROSS_COMPILE prefix retargets the engine compiler (e.g. arm-linux-
# gnueabihf- for Miyoo). HOSTCC stays native — it builds the embed-pe-data code
# generator, which MUST run on the build machine, not the target.
TARGET ?=
CROSS_COMPILE ?=
HOSTCC ?= cc
ifneq ($(CROSS_COMPILE),)
CC := $(CROSS_COMPILE)gcc
endif
# Base CFLAGS: release-ish with all warnings. -Wpedantic stays on — the two GNU
# extensions we use intentionally (typeof, statement-exprs) are suppressed via
# -Wno-language-extension-token so any NEW warning still surfaces. mk/<target>.mk
# appends its arch + -D switches on top.
#
# -fno-strict-aliasing is REQUIRED, not cosmetic: the Entity struct is accessed
# through multiple type-punned aliases — script writes `*(int32_t *)(eb + 0x48)`
# and the same memory is read as `*(int16_t *)(eb + 0x4A)` (upper 16 bits).
# Under strict-aliasing the compiler may reorder these → the walker step loop
# misses the target-reached comparison and overshoots 1px/tick → cascading
# "actor walks past target" bugs (Fjej weź-kwiatka, Ebek climb glitches).
CFLAGS ?= -O2 -Wall -Wextra -Wpedantic \
-Wno-unused-parameter -Wno-pointer-sign \
-Wno-language-extension-token \
-fno-strict-aliasing \
-std=gnu99 -I include
# Version string baked into the startup banner. Defaults to git describe so dev
# builds carry "<last-tag>-<n>-g<sha>[-dirty]" (users paste it into bug reports);
# falls back to "unknown" outside a git checkout (extracted release tarball).
WACKI_VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo unknown)
CFLAGS += -DWACKI_VERSION='"$(WACKI_VERSION)"'
# All built binaries land in $(DIST) — gitignored, so artefacts never sit at the
# repo root or next to the sources they're built from.
DIST := dist
$(DIST):
@mkdir -p $@
# Windows (MSYS2/mingw) binaries need a `.exe` suffix. `OS` is "Windows_NT"
# under both mingw-make and MSYS2 GNU make; POSIX hosts leave it empty.
ifeq ($(OS),Windows_NT)
EXE := .exe
else
EXE :=
endif
# SDL2 link flags. SDL_CFG (--cflags) + SDL_LIB_DYN (--libs) are the dynamic
# defaults shared by every SDL-family target; SDL_LIB tracks them by default and
# is overridden by mk/desktop.mk for STATIC_SDL2 release builds. TARGET=ps2
# brings its own SDL2-PS2 and overrides SDL_CFG/SDL_LIB from tools/build-ps2.sh,
# so these shell-outs (empty when sdl2-config is absent) don't matter there.
STATIC_SDL2 ?= 0
SDL_CFG := $(shell $(SDL2_CFG) --cflags 2>/dev/null)
SDL_LIB_DYN := $(shell $(SDL2_CFG) --libs 2>/dev/null)
SDL_LIB := $(SDL_LIB_DYN)
# Knobs mk/<target>.mk may set; default them empty here so a target that doesn't
# care leaves them blank rather than referencing an undefined var.
CFLAGS_SIZE :=
LDFLAGS_SIZE :=
LDFLAGS_STATIC :=
MACOS_FRAMEWORKS :=
WACKI_RES :=
# ---- platform-agnostic engine sources --------------------------------------
# The core engine — everything that is NOT platform-specific. mk/<target>.mk
# appends its PLATFORM_SRCS (HAL impls + hooks provider) to this list.
ENGINE_SRCS = \
$(EMBEDDED_PE_SRC) \
$(EMBEDDED_ICON_SRC) \
src/main.c src/data_root.c src/config.c \
src/game.c src/graphics.c src/audio.c \
src/archive.c src/depack.c src/assets.c src/vm/main.c \
src/actor/intern.c src/actor/registration.c \
src/actor/list.c src/actor/vm.c \
src/actor/render.c src/actor/alloc.c \
src/actor/walker.c \
src/save.c src/font.c src/flic.c src/flic/decoder.c \
src/heap.c src/timer.c src/stubs.c \
src/binary_data.c src/pe_loader.c src/log.c \
src/platform/sdl/platform_sdl.c src/vm/script_obj.c src/vm/parser.c \
src/util/rng.c \
src/hud/panel.c src/hud/inventory.c src/hud/items.c \
src/scene/click_queue.c src/scene/hit_test.c src/scene/mask_list.c \
src/scene/navigation.c src/scene/actor_walk.c src/scene/stage.c \
src/scene/bg_mask.c src/scene/spawn.c src/scene/komnata.c \
src/scene/preload.c src/scene/hud_paint.c src/scene/frame_tick.c \
src/scene/dispatch.c src/hud/cursor.c \
src/scene/walkability.c src/scene/scene_input.c \
src/scene/play_loop.c src/scene/komnata_scene.c \
src/audio/sound_queue.c src/audio/cutscene.c \
src/audio/sfx.c src/audio/music_stream.c \
src/script_bridge/palette.c src/script_bridge/entity.c \
src/text/balloon.c src/text/dialog.c \
src/anim/resolver.c src/util/screenshot.c \
src/anim/paint_primitives.c src/anim/alpha_blit.c \
src/menu/chapter_select.c src/menu/slot_picker.c \
src/menu/options.c src/menu/menu_loop.c \
src/menu/main_menu.c src/menu/port_attribution.c
# Shared platform building blocks referenced by mk/{desktop,miyoo,portmaster}.mk
# (see docs/platform-hal.md). SDL_PLATFORM_SRCS = the SDL2/stdio HAL impls
# shared by desktop + the handhelds: storage (save + file I/O), audio, video,
# system, and the SDL_GameController glue. data-root discovery differs
# desktop-vs-handheld (external-media scanners + folder picker vs a fixed
# SD-card list), so each target links its own data_root_* rather than one
# #ifdef'd file. PS2 brings its own equivalents and pulls none of these.
SDL_PLATFORM_SRCS = src/platform/sdl/save_host.c \
src/platform/sdl/file_host.c src/platform/sdl/audio_sdl.c \
src/platform/sdl/flic_host.c src/platform/sdl/video_sdl.c \
src/platform/sdl/system_sdl.c src/platform/sdl/gamepad_sdl.c
SDL_DATAROOT_DESKTOP = src/platform/sdl/data_root_desktop.c
SDL_DATAROOT_HANDHELD = src/platform/sdl/data_root_handheld.c
# Select the active platform: include exactly one mk/<target>.mk. TARGET empty
# → desktop. An unknown TARGET fails fast here with a clear message rather than
# a confusing "missing symbol" link error later.
TGT := $(or $(strip $(TARGET)),desktop)
ifeq ($(wildcard mk/$(TGT).mk),)
$(error Unknown TARGET '$(TARGET)' — no mk/$(TGT).mk (valid: desktop, miyoo, portmaster, ps2))
endif
include mk/$(TGT).mk
# ---- debug build (sanitizers) ----------------------------------------------
# `make debug` rebuilds desktop with ASan + UBSan + frame pointers + no opt for
# actionable backtraces; -DWACKI_VERBOSE turns on LOG_TRACE/LOG_DEBUG (compiled
# out of release). Separate binary; always dynamic SDL2 (ASan + static SDL2
# don't mix).
DEBUG_CFLAGS = -O0 -g -fno-omit-frame-pointer \
-fsanitize=address -fsanitize=undefined \
-fno-strict-aliasing \
-Wall -Wextra -Wno-unused-parameter -Wno-pointer-sign \
-Wno-language-extension-token \
-DWACKI_VERBOSE \
-std=gnu99 -I include
DEBUG_LDFLAGS = -fsanitize=address -fsanitize=undefined
# ---- embedded WACKI.EXE data sections --------------------------------------
# tools/embed-pe-data reads WACKI.EXE and emits a generated C source with the
# .rdata + .data raw bytes as a const slice table + blob. The PE-loader resolves
# original VAs against it at runtime — no PE parsing, no file I/O after build.
# Build-time dep: data/WACKI.EXE must exist; the generated file is gitignored.
EMBEDDED_PE_SRC = src/embedded_wacki_pe.c
EMBEDDED_PE_BIN = data/WACKI.EXE
EMBED_PE_TOOL = $(DIST)/embed-pe-data$(EXE)
# Built with HOSTCC: this tool runs at build time on the build machine; cross-
# compiling it would mean qemu-ing it every time the embedded PE source needs
# regenerating.
$(EMBED_PE_TOOL): tools/embed-pe-data.c | $(DIST)
$(HOSTCC) -O2 -Wall -I include -o $@ $<
$(EMBEDDED_PE_SRC): $(EMBEDDED_PE_BIN) $(EMBED_PE_TOOL)
$(EMBED_PE_TOOL) $(EMBEDDED_PE_BIN) $(EMBEDDED_PE_SRC)
# Window icon: embed the 64×64 BMP from assets/icons/ as a C byte array so
# SDL_SetWindowIcon can hand it to the window system (Dock / taskbar / titlebar).
# Generated with `xxd -i` + a hand-written SPDX header; checked into git so
# contributors without xxd can still build. Regenerate via this target after
# changing the BMP.
EMBEDDED_ICON_SRC = src/embedded_icon.c
EMBEDDED_ICON_BIN = assets/icons/wacki-window.bmp
$(EMBEDDED_ICON_SRC): $(EMBEDDED_ICON_BIN)
@which xxd >/dev/null || { echo "xxd missing — install vim-common"; exit 1; }
@(printf '/* SPDX-License-Identifier: GPL-3.0-or-later\n * Copyright (C) 2026 Mateusz Szu\xc5\x82\x61\n *\n * src/embedded_icon.c — GENERATED from %s.\n * Loaded as an SDL_Surface via SDL_LoadBMP_RW and handed to\n * SDL_SetWindowIcon in PlatformInit so the engine'\''s window /\n * taskbar / dock entry carry the game artwork.\n */\n\n#include <stddef.h>\n\n' "$(EMBEDDED_ICON_BIN)"; xxd -i -n wacki_icon_bmp $(EMBEDDED_ICON_BIN)) > $@
# ---- tools + tests (host-side, desktop config) -----------------------------
TOOL_SRCS_EXTRACT = tools/dta-extract.c src/depack.c src/archive.c \
src/platform/sdl/file_host.c src/heap.c src/log.c
TOOL_SRCS_PKV2 = tools/pkv2-depack.c src/depack.c src/log.c
# Unit tests link only the SDL-free subset of the engine + small mocks for
# symbols normally defined in stubs.c (which #includes SDL). Coverage map + how
# to add a suite: tests/README.md.
TEST_SRCS = \
tests/test_main.c tests/test_entity_layout.c \
tests/test_rng.c tests/test_pkv2.c \
tests/test_archive.c tests/test_save.c \
tests/test_save_io.c tests/test_assets.c \
tests/test_font.c tests/test_walker.c \
tests/test_graphics.c tests/test_pe_loader.c \
tests/test_binary_data.c tests/test_timer.c \
tests/test_script_vm.c tests/test_real_vm.c \
tests/test_vm_control_flow.c \
tests/test_vm_script_parser.c tests/test_vm_call_stack.c \
tests/test_vm_more_ops.c tests/test_heap_cygio.c \
tests/test_vm_walk_anim.c tests/test_vm_dialog.c \
tests/test_vm_misc_ops.c tests/test_vm_safety.c \
tests/test_vm_game_over.c tests/test_per_entity_vm.c \
tests/test_archive_extended.c tests/test_pe_loader_malformed.c \
tests/test_assets_rle.c tests/test_font_color.c \
tests/test_save_slot.c tests/test_vm_with_pe.c \
tests/test_vm_show_text_bind.c tests/test_graphics_alpha.c \
tests/test_vm_wait_break.c tests/test_archive_lifecycle.c \
tests/test_pe_loader_lifecycle.c tests/test_vm_corner_cases.c \
tests/test_save_io_extended.c \
tests/test_inventory.c tests/test_sound_queue.c \
tests/test_panel_hit_test.c tests/test_click_hit_test.c \
tests/test_per_entity_vm_real.c \
tests/test_click_queue.c tests/test_update_registration.c \
tests/test_ent_ptr_intern.c tests/test_sampl_parser.c \
tests/test_komnata_load.c tests/test_flic_decoder.c \
tests/test_engine_stubs.c
TEST_ENGINE_SRCS = \
tests/embedded_wacki_pe_stub.c \
src/depack.c src/archive.c src/graphics.c \
src/pe_loader.c src/heap.c src/platform/sdl/file_host.c \
src/assets.c src/font.c src/save.c \
src/platform/sdl/save_host.c \
src/binary_data.c src/timer.c src/vm/main.c src/log.c \
src/vm/script_obj.c src/vm/parser.c \
src/util/rng.c \
src/hud/panel.c src/hud/inventory.c src/hud/items.c \
src/scene/click_queue.c src/scene/hit_test.c src/scene/mask_list.c \
src/scene/navigation.c src/scene/actor_walk.c src/scene/stage.c \
src/scene/bg_mask.c src/scene/spawn.c src/scene/komnata.c \
src/audio/sound_queue.c src/audio/sfx.c \
src/script_bridge/palette.c src/script_bridge/entity.c \
src/text/balloon.c src/text/dialog.c \
src/anim/resolver.c \
src/stubs.c src/actor/intern.c src/actor/registration.c \
src/actor/list.c src/actor/vm.c \
src/actor/render.c src/actor/alloc.c \
src/actor/walker.c src/anim/alpha_blit.c \
src/flic/decoder.c
# Tests reuse the engine's warnings but use a stub SDL.h (tests/sdl_stub) instead
# of the system SDL2 headers; -I tests/sdl_stub MUST come first so the stub wins
# script.c's `#include <SDL.h>`. gnu11 makes _Static_assert first-class.
TEST_CFLAGS = -O2 -Wall -Wextra -Wpedantic \
-Wno-unused-parameter -Wno-pointer-sign \
-Wno-language-extension-token \
-fno-strict-aliasing \
-std=gnu11 -I tests/sdl_stub -I include -I tests
# ---- targets ----------------------------------------------------------------
.PHONY: all engine tools viewer clean run debug test test-asan miyoo ps2 ps2-iso
all: engine tools
engine: $(DIST)/$(BIN_NAME)$(EXE)
$(DIST)/$(BIN_NAME)$(EXE): $(ENGINE_SRCS) $(WACKI_RES) | $(DIST)
$(CC) $(CFLAGS) $(CFLAGS_SIZE) $(SDL_CFG) -o $@ $(ENGINE_SRCS) $(WACKI_RES) $(SDL_LIB) $(LDFLAGS_STATIC) $(LDFLAGS_SIZE) $(MACOS_FRAMEWORKS)
ifeq ($(OS),Windows_NT)
$(WACKI_RES): assets/icons/wacki.rc assets/icons/wacki.ico | $(DIST)
$(WINDRES) --include-dir=assets/icons -i $< -o $@
endif
# Cross-target convenience wrappers — build through the per-platform Docker
# image so callers don't need a host-installed cross toolchain. Each script
# invokes `make TARGET=<plat> ...` (with the right sdl2-config / SDL overrides)
# inside its container.
miyoo:
./tools/build-miyoo.sh
ps2:
./tools/build-ps2.sh
# Bootable PS2 ISO (SYSTEM.CNF + ELF + game data) so PCSX2 runs it via "Boot
# ISO" with no HostFS config. Builds the ELF first if needed.
ps2-iso:
./tools/build-ps2-iso.sh
debug: $(DIST)/wacki-debug$(EXE)
$(DIST)/wacki-debug$(EXE): $(ENGINE_SRCS) | $(DIST)
$(CC) $(DEBUG_CFLAGS) $(SDL_CFG) -o $@ $(ENGINE_SRCS) $(SDL_LIB_DYN) $(DEBUG_LDFLAGS) $(MACOS_FRAMEWORKS)
tools: $(DIST)/dta-extract$(EXE) $(DIST)/pkv2-depack$(EXE)
$(DIST)/dta-extract$(EXE): $(TOOL_SRCS_EXTRACT) | $(DIST)
$(CC) $(CFLAGS) -o $@ $(TOOL_SRCS_EXTRACT)
$(DIST)/pkv2-depack$(EXE): $(TOOL_SRCS_PKV2) | $(DIST)
$(CC) $(CFLAGS) -o $@ $(TOOL_SRCS_PKV2)
# ---- asset explorer (wacki-viewer) -----------------------------------------
# The standalone Nuklear + SDL2 asset browser lives in its OWN self-contained
# subproject under assets-explorer/ — it has its own Makefile, vendored
# third_party/ single-header libs, and UI sources (assets-explorer/src/). It
# still compiles a small SDL-free subset of THIS engine's sources in-place
# (../src/{depack,archive,...}) so it always reflects real engine behaviour.
#
# This target just delegates, so `make viewer` from the repo root keeps
# working; CC / SDL2_CFG are forwarded so a custom toolchain carries through.
# The built binary lands in assets-explorer/dist/wacki-viewer.
viewer:
$(MAKE) -C assets-explorer CC='$(CC)' SDL2_CFG='$(SDL2_CFG)'
run: $(DIST)/$(BIN_NAME)$(EXE)
$(DIST)/$(BIN_NAME)$(EXE)
# Build + run unit tests. Exit non-zero if any test fails.
test: $(DIST)/run-tests$(EXE)
$(DIST)/run-tests$(EXE)
$(DIST)/run-tests$(EXE): $(TEST_SRCS) $(TEST_ENGINE_SRCS) | $(DIST)
$(CC) $(TEST_CFLAGS) -o $@ $(TEST_SRCS) $(TEST_ENGINE_SRCS)
# Sanitizer test leg — same sources as `test`, built with ASan + UBSan so
# the file-format parsers (depack / flic / RLE / archive) and the raw-byte
# entity paths are exercised with memory checking on. Alignment checking is
# OFF: the suite deliberately does unaligned byte access mirroring the
# Entity layout (the packed-struct EOFF accessor handles it safely in
# production, and tests run only on permissive hosts) — same rationale as
# the engine's -fno-strict-aliasing. Leak detection is off to match
# tools/smoke-runner.sh (the port isn't leak-free yet). This is the leg to
# wire into CI; it needs neither SDL2 nor WACKI.EXE.
TEST_ASAN_CFLAGS = -O1 -g -fno-omit-frame-pointer \
-fsanitize=address -fsanitize=undefined \
-fno-sanitize=alignment -fno-strict-aliasing \
-Wall -Wextra -Wno-unused-parameter -Wno-pointer-sign \
-Wno-language-extension-token \
-std=gnu11 -I tests/sdl_stub -I include -I tests
test-asan: $(DIST)/run-tests-asan$(EXE)
ASAN_OPTIONS=detect_leaks=0 $(DIST)/run-tests-asan$(EXE)
$(DIST)/run-tests-asan$(EXE): $(TEST_SRCS) $(TEST_ENGINE_SRCS) | $(DIST)
$(CC) $(TEST_ASAN_CFLAGS) -o $@ $(TEST_SRCS) $(TEST_ENGINE_SRCS)
# `clean` blows away the whole $(DIST) tree (every built artefact lives there),
# the generated embed source, and stray .o files from ad-hoc compiles.
clean:
rm -rf $(DIST)
rm -f $(EMBEDDED_PE_SRC)
rm -f *.o src/*.o tools/*.o tests/*.o