== Adding Your Program to the Build JoeyLib does not install as a system library. Programs are built from inside the repository by the same makefiles that build the library, because each target needs its own cross compiler, link script, packaging step and disk image. Adding a program means adding it to each port's makefile. === The Shape of a Program Directory Put your sources under `examples/`, one directory per program: ---- examples/mygame/ mygame.c mygame.h assets/ tiles.png sprites.png music.song ---- Keep the authoring assets next to the code and let the makefiles bake them into `DATA/`, as described in <<_creating_assets>>. === Adding It to One Port Each port's makefile declares programs explicitly. The pattern in `make/atarist.mk`, for a single-source program: [source,makefile] ---- MYGAME_SRC := $(EXAMPLES)/mygame/mygame.c MYGAME_BIN := $(BINDIR)/MYGAME.PRG ---- Add the binary to the port's `all` target so it gets built: [source,makefile] ---- all atarist: $(LIB) ... $(MYGAME_BIN) $(DATA_FILES) ---- And give it a build rule, copying the shape of an existing example in that file. Do not invent your own compiler invocation: the flags, include paths and link order in those rules encode real constraints, several of them the result of long debugging. For a multi-file program, list the sources: [source,makefile] ---- MYGAME_SRCS := $(EXAMPLES)/mygame/mygame.c \ $(EXAMPLES)/mygame/world.c \ $(EXAMPLES)/mygame/render.c ---- Repeat for each port you want to support: `make/iigs.mk`, `make/amiga.mk`, `make/atarist.mk`, `make/dos.mk` and `make/x68000.mk`. [NOTE] ==== Yes, that is five makefile edits for one program. The ports genuinely differ: the IIgs needs OMF segmentation and a disk image, the Amiga a startup-sequence entry, DOS a DPMI stub, and the X68000 a Human68k floppy layout. There is no single rule that covers all five. ==== === Naming File naming conventions differ per platform and the makefiles reflect that: [cols="2,2,4", options="header"] |=== |Platform |Convention |Example |Apple IIgs |Uppercase, 8 characters |`MYGAME` |Atari ST |Uppercase 8.3, `.PRG` |`MYGAME.PRG` |MS-DOS |Uppercase 8.3, `.EXE` |`MYGAME.EXE` |Amiga |Mixed case, no extension |`MyGame` |Sharp X68000 |Uppercase 8.3, `.X` |`MYGAME.X` |=== Keep the base name to 8 characters and letters and digits only, so the same name works everywhere. === Disk Images and Packaging Some ports need a packaging step beyond compiling. *Apple IIgs.* Programs are placed on an 800 KB ProDOS disk image: [source,console] ---- $ make iigs-disk $ JOEY_DISK_EXAMPLES="MYGAME" make iigs-disk # just yours ---- The floppy cannot hold every example at once, so the packager drops some. If your program is missing from the image, build it with `JOEY_DISK_EXAMPLES` naming it explicitly, and check the `added:` line the packager prints. A program plus large assets may not fit 800 KB at all, in which case use the bigger game-disk image on a CFFA2 card: [source,console] ---- $ JOEY_GAME_DISK_SIZE=2048KB scripts/make-iigs-game-disk.sh \ build/iigs/bin/mygame.2mg MYGAME ---- *Sharp X68000.* Programs ship on a Human68k floppy. Be aware that a stale image can hide hundreds of kilobytes in subdirectories that a directory listing does not show; rebuild from empty rather than deleting files if space seems to vanish. *Amiga.* `joey-run` writes an `s/startup-sequence` that invokes your binary. === Verifying It Actually Runs Build success is weak evidence on retro targets. Run it with `joey-run` (see <>), on every machine: [source,console] ---- $ ./joey-run --port iigs mygame $ ./joey-run --port amiga mygame $ ./joey-run --port atarist mygame $ ./joey-run --port dos mygame $ ./joey-run --port x68000 mygame ---- Without a window, which is what you want while iterating, run it headless and look at the snapshot; the program's log lands next to it as usual: [source,console] ---- $ ./joey-run --headless --seconds 90 --snapshot mygame.png --port atarist mygame ---- === The Gates The repository carries automated checks. They exist because several classes of bug on these machines are invisible until measured, and they are worth running against your own program too. [cols="2,4", options="header"] |=== |Command |What it proves |`make verify-audio` |Every port's audio gate: the IIgs DOC and X68000 chips are read directly, the ST's YM2149 register writes are traced, and the Amiga and DOS output is recorded and graded. Exits 3, not 0, if a gate had to be skipped. |`make iigs-verify` |The IIgs actually reached the program and drew something. |`scripts/verify--tilebank.sh` |The port's own tile-bank bake loads pixel-exact both ways, with the same surface hash as the host check `scripts/check-tilebank.sh`, and banks baked for the other machines are refused. `scripts/verify-all.sh tilebank` runs every port's. |`scripts/bench-.sh` |Per-operation throughput for that port. |`tools/diff-uber-hashes` |Compares a port's rendered output against the IIgs golden reference, operation by operation, by surface hash. |=== That last one is the strongest tool in the repository. `jlSurfaceHash` produces the same value for the same logical pixels on every platform regardless of internal storage format, so a hash mismatch means one port is genuinely drawing different pixels from the others. === Logging from the Target Debugging a program running on an emulated 1988 machine is awkward. JoeyLib provides a logger that writes to a file next to the executable: [source,c] ---- jlLogReset(); jlLogF("level %d loaded, %u cels", levelNum, celCount); jlLogFlush(); ---- The headless runners retrieve that file automatically. [NOTE] ==== The logger needs a multi-kilobyte ring buffer, which some targets cannot afford. Space Taxi compiles it out entirely on the IIgs and X68000 for that reason. If you are debugging a memory-tight program, expect to do the same, and fall back to observing hardware state through an emulator instead. ====