Builder Manual Play
Builder Manual / Build System

BUILD / Build System

Build System

Make targets, compiler flags, platform prerequisites, and WebAssembly build flow.

Build System


Makefile Overview

The project uses a GNU Makefile with explicit per-directory wildcards. New .c files in recognized source directories are compiled automatically; new source directories need matching SRCS and pattern-rule entries.

CC      ?= clang
CFLAGS  = -std=c11 -Wall -Wextra -Wpedantic $(shell sdl2-config --cflags)
LIBS    = $(shell sdl2-config --libs) -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lm
OUTDIR  = out
OBJDIR  = $(OUTDIR)/obj
TARGET  = $(OUTDIR)/super-mango
SRCDIR  = src
SRCS    = $(wildcard $(SRCDIR)/*.c) \
          $(wildcard $(SRCDIR)/collectibles/*.c) \
          $(wildcard $(SRCDIR)/collision/*.c) \
          $(wildcard $(SRCDIR)/core/*.c) \
          $(wildcard $(SRCDIR)/effects/*.c) \
          $(wildcard $(SRCDIR)/entities/*.c) \
          $(wildcard $(SRCDIR)/hazards/*.c) \
          $(wildcard $(SRCDIR)/input/*.c) \
          $(wildcard $(SRCDIR)/levels/*.c) \
          $(wildcard $(SRCDIR)/player/*.c) \
          $(wildcard $(SRCDIR)/render/*.c) \
          $(wildcard $(SRCDIR)/screens/*.c) \
          $(wildcard $(SRCDIR)/surfaces/*.c) \
          $(SRCDIR)/editor/serializer.c \
          $(SRCDIR)/editor/serializer_emit.c \
          $(SRCDIR)/editor/serializer_io.c \
          $(SRCDIR)/editor/serializer_load.c \
          $(SRCDIR)/editor/serializer_load_climbables.c \
          $(SRCDIR)/editor/serializer_load_collectibles.c \
          $(SRCDIR)/editor/serializer_load_config.c \
          $(SRCDIR)/editor/serializer_load_enemies.c \
          $(SRCDIR)/editor/serializer_load_geometry.c \
          $(SRCDIR)/editor/serializer_load_hazards.c \
          $(SRCDIR)/editor/serializer_load_header.c \
          $(SRCDIR)/editor/serializer_load_layers.c \
          $(SRCDIR)/editor/serializer_load_surfaces.c \
          $(SRCDIR)/editor/serializer_parse.c \
          $(SRCDIR)/editor/serializer_save.c \
          $(SRCDIR)/editor/serializer_types.c \
          vendor/tomlc17/tomlc17.c
OBJS    = $(patsubst %.c,$(OBJDIR)/%.o,$(SRCS))
DEPS    = $(OBJS:.o=.d)

Key Variables

VariableValueDescription
CCclang intended; pass explicitly for parityC compiler. Use CC=clang for CI/local parity; GNU Make may otherwise use its built-in CC=cc.
CFLAGSsee belowCompiler flags
LIBSsee belowLinker flags
TARGETout/super-mangoOutput binary path
SRCSexplicit per-directory wildcards plus editor serializer filesGame C sources from recognized source directories, TOML serializer modules, and tomlc17
OBJDIRout/objObject/dependency root that mirrors source paths
OBJS$(patsubst %.c,$(OBJDIR)/%.o,$(SRCS))Object files under out/obj/...
DEPS$(OBJS:.o=.d)Auto-generated dependency files beside object files under out/obj/...

Compiler Selection Caveat

For reproducible local results, pass CC=clang explicitly:

make test CC=clang
make smoke CC=clang

The Makefile uses CC ?= clang, but GNU Make defines a built-in CC=cc, so some local invocations resolve to cc unless the compiler is overridden on the command line.

Compiler Flags Explained

FlagMeaning
-std=c11Compile as C11 (ISO/IEC 9899:2011)
-WallEnable common warnings
-WextraEnable extra warnings beyond -Wall
-WpedanticStrict ISO compliance warnings
-MMDGenerate .d dependency files for each .o (tracks header changes) — passed in compile rule, not in CFLAGS
-MPAdd phony targets for each dependency (prevents errors when headers are deleted) — passed in compile rule, not in CFLAGS
$(shell sdl2-config --cflags)SDL2 include paths (-I/opt/homebrew/include/SDL2)

Linker Flags Explained

FlagMeaning
$(shell sdl2-config --libs)SDL2 core library (-L/opt/homebrew/lib -lSDL2)
-lSDL2_imagePNG/JPG texture loading
-lSDL2_ttfTrueType font rendering
-lSDL2_mixerAudio mixing (WAV, MP3, OGG)
-lmMath library (math.h functions: sinf, cosf, fmodf, etc.)

Build Targets

make / make all

Compiles game source files from the Makefile’s source directory list to .o objects, then links them into out/super-mango.

make

Steps:

  1. Creates out/ directory if it does not exist
  2. Compiles each listed source file → .o
  3. Links all .o files → out/super-mango
  4. On macOS (uname -s == Darwin), ad-hoc code signs the binary with codesign --force --sign - $@ (required on Apple Silicon to avoid Killed: 9 errors). On other platforms this step is skipped

make run

Builds (if out of date) then immediately executes the binary (no CLI flags).

make run

The binary must be run from the repo root because asset paths are relative:

IMG_LoadTexture(renderer, "assets/sprites/backgrounds/sky_blue.png");
Mix_LoadWAV("assets/sounds/player/player_jump.wav");

make run-debug

Builds (if out of date) then runs the binary with the --debug flag, which enables the debug overlay: FPS counter, collision hitbox visualization, and scrolling event log.

make run-debug

make run-level LEVEL=path

Builds (if out of date) then runs the binary with the --level flag, loading a specific TOML level file.

make run-level LEVEL=levels/00_sandbox_01.toml

make run-level-debug LEVEL=path

Builds (if out of date) then runs the binary with both --debug and --level flags, loading a specific TOML level file with the debug overlay enabled.

make run-level-debug LEVEL=levels/00_sandbox_01.toml

make editor

Compiles the standalone level editor into out/super-mango-editor. The editor is a separate binary with its own source files in src/editor/ and the tomlc17 TOML parser from vendor/tomlc17/.

make editor

make run-editor

Builds the editor (if out of date) then immediately runs it.

make run-editor

make web

Compiles the game to WebAssembly using the Emscripten SDK (emcc). Requires Emscripten to be installed and emcc on PATH.

make web

Produces out/super-mango.html, .js, .wasm, and .data (bundled assets/sounds). SDL2 ports are compiled from source by Emscripten on first build; subsequent builds reuse cached port libraries. Uses a custom shell template from web/shell.html.

The target also produces debug boot artifacts (out/super-mango-debug.html and companions) for direct debug HTML launches. The docs-site browser debug button uses the normal super-mango.js payload and passes --debug at boot.

For release confidence, the GitHub Actions WebAssembly build is authoritative. Some local/container Emscripten installs can fail before reaching Super Mango code when Emscripten 3.1.58 builds SDL_ttf’s HarfBuzz port with newer Clang warnings (-Wnontrivial-memcall). If that host-toolchain issue appears locally, treat the CI make web + artifact smoke from build.yml and the Pages assembly smoke from deploy.yml as the trusted WASM verification path.

make test

Builds and runs native regression harnesses for pure logic that does not require opening an SDL window.

make test

Current test binaries (14):

  • out/level-serializer-test
  • out/level-validate-test
  • out/runtime-load-test
  • out/rail-test
  • out/entity-utils-test
  • out/collision-test
  • out/phase-transition-test
  • out/exporter-test
  • out/editor-validation-test
  • out/gameplay-damage-test
  • out/gameplay-config-test
  • out/gameplay-score-test
  • out/game-overlay-test
  • out/game-events-test

make validate-levels

Runs the Python TOML validator against every levels/*.toml file. It checks parsing, referenced asset paths, next_phase links, and array counts against the C MAX_* constants.

make validate-levels

make smoke

Builds the game and editor, then runs every levels/*.toml with dummy SDL video/audio drivers for a bounded number of frames. It also runs the editor’s headless smoke mode.

make smoke SMOKE_FRAMES=5 SMOKE_SEED=1

make scripted-smoke

Builds the game and editor, then runs tools/run_scripted_smoke.py against every levels/*.toml for each seed in SMOKE_SEEDS. The runner writes deterministic replay scripts under out/replays-smoke/ and passes sanitized replay names to the game with --replay-script, injecting SDL key events such as move-right, jump-right, and pause/resume while still using dummy SDL video/audio in CI.

make scripted-smoke SMOKE_FRAMES=5 SMOKE_SEEDS="1 7 23"

make sanitize

Runs make test in a separate out-sanitize/ tree with AddressSanitizer and UndefinedBehaviorSanitizer enabled.

make sanitize

make sanitize-smoke

Builds sanitizer-instrumented native game/editor binaries in out-sanitize/, then runs the dummy SDL smoke pass against every TOML level plus the editor smoke mode. This complements make sanitize by covering SDL/resource startup paths, not just pure logic harnesses.

make sanitize-smoke SMOKE_FRAMES=5 SMOKE_SEED=1

make level-catalog

Regenerates docs/wiki/level-catalog.md from levels/*.toml using tools/generate_level_catalog.py. Use this after adding levels or changing level metadata/content counts.

make level-catalog

make docs-drift

Runs the generated level-catalog freshness check, generated overlay-snapshot freshness check, tools/check_docs_drift.py, and tools/check_roadmap_quality.py. Together they compare Makefile test targets, README/agent/docs command summaries, source-file map entries, layer TOML snippets, workflow docs, runtime flags, key constants, level prose counts, TOML line endings, overlay text snapshots, local Emscripten caveats, and scripted-smoke wiring against the current repository.

make docs-drift

make clean

Removes all build artifacts.

make clean

Deletes legacy in-source .o / .d files from recognized source directories and removes out/.


Prerequisites

macOS (Apple Silicon / Intel)

# Install Homebrew if needed: https://brew.sh
brew install sdl2 sdl2_image sdl2_ttf sdl2_mixer

# Xcode Command Line Tools (provides clang and make)
xcode-select --install

SDL2 libraries are installed to /opt/homebrew/ on Apple Silicon. sdl2-config resolves the correct paths automatically.

Linux — Debian / Ubuntu

sudo apt update
sudo apt install build-essential clang \
    libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsdl2-mixer-dev

Linux — Fedora / RHEL / CentOS

sudo dnf install clang make \
    SDL2-devel SDL2_image-devel SDL2_ttf-devel SDL2_mixer-devel

Linux — Arch Linux

sudo pacman -S clang make sdl2 sdl2_image sdl2_ttf sdl2_mixer

Windows (MSYS2)

  1. Install MSYS2
  2. Open the MSYS2 UCRT64 terminal:
pacman -S mingw-w64-ucrt-x86_64-clang \
          mingw-w64-ucrt-x86_64-make \
          mingw-w64-ucrt-x86_64-SDL2 \
          mingw-w64-ucrt-x86_64-SDL2_image \
          mingw-w64-ucrt-x86_64-SDL2_ttf \
          mingw-w64-ucrt-x86_64-SDL2_mixer
  1. Build:
cd /c/path/to/super-mango-editor
make
  1. SDL2 DLLs must be in the same directory as the binary. Copy them from the MSYS2 prefix.

CI/CD Pipelines

Four GitHub Actions workflows handle automated builds and docs checks:

WorkflowFileTriggerPurpose
Build & Releasebuild.ymlPush to main, pull requests, v* tags, manualMulti-platform native build, make test, make validate-levels, make editor, native game/editor smoke, Linux scripted smoke, WebAssembly build, WebAssembly artifact/package smoke; GitHub Release creation is limited to v* tags and manual dispatches
Docsdocs.ymlDocs pull requests, manualmake docs-drift, bun install --frozen-lockfile, bun run lint, bun run build under docs/
CodeQLcodeql.ymlPush/PR to main, weeklyAutomated code security and quality analysis
Deploydeploy.ymlSuccessful main Build & Release workflowBuilds docs, copies WebAssembly artifacts, and deploys docs/out/ to GitHub Pages

Native smoke uses dummy SDL drivers where supported: ./out/super-mango --level levels/00_sandbox_01.toml --smoke-test-frames 5 and ./out/super-mango-editor --smoke-test. WebAssembly smoke asserts out/super-mango.html, .js, .wasm, and .data exist.


Adding New Source Files

Because the Makefile uses per-subdirectory wildcards, any new .c file placed in src/ or a recognized source subdirectory is compiled automatically on the next make invocation. New source directories require adding a wildcard, compile rule, and clean entry.

# Example: adding an entity in a subdirectory
touch src/entities/new_enemy.c src/entities/new_enemy.h
make   # new_enemy.c is compiled automatically

See Developer Guide for the full new-entity workflow.


Output Structure

After a successful build:

out/
├── super-mango                          ← the game binary
├── super-mango-editor                   ← the editor binary (make editor)
└── obj/
    ├── src/                             ← game/editor objects mirror source paths
    │   ├── core/*.o / *.d
    │   ├── editor/*.o / *.d
    │   ├── player/*.o / *.d
    │   └── ...
    └── vendor/tomlc17/tomlc17.o / .d