== Getting Started === Setting Up the Toolchains JoeyLib cross-compiles for five machines. It builds on Linux x86-64, and on Windows inside WSL2. One script installs every cross toolchain, pinned to a known-good version and checked against a published checksum, into `toolchains/` in the repository. The only things it installs anywhere else are ordinary packages from your distribution (apt on Debian and Ubuntu, dnf on Fedora), and only when you ask it to. Two commands set up a new machine: [source,console] ---- $ ./install.sh deps toolchains --install $ ./install.sh install toolchains ---- The first installs the distribution packages the toolchains need; it runs `sudo` once. The second downloads or builds every cross toolchain. The first run takes about an hour, almost all of it compiling the Apple IIgs and Amiga compilers. To start working sooner, install only the ports you need: [source,console] ---- $ ./install.sh install toolchain:dos toolchain:atarist ---- Running `install` again is cheap. Components that are already current are skipped, and a component is rebuilt only when its pinned version changes. No environment setup is needed afterwards. `make` reads the tool paths the installer records in `toolchains/config.mk`, and the scripts in `scripts/` load the same settings themselves. To use a cross compiler by hand in a shell, `source toolchains/env.sh` sets the same variables. If a port's toolchain is missing, its build stops at once and says what to install: [source,console] ---- $ make amiga make/amiga.mk:5: *** toolchain:amiga is not installed; run: ./install.sh install toolchain:amiga. Stop. ---- Check what the build can see: [source,console] ---- $ make status Toolchain availability: iigs: yes amiga: yes atarist: yes dos: yes x68000: yes ---- ==== Installer reference `./install.sh [options] COMMAND [TARGETS...]`, run from the top of the repository. [cols="1,3"] |=== | Command | What it does | `list` | Every component, the groups it belongs to, and whether it is current, outdated or missing. | `install TARGETS` | Installs or updates the targets and everything they depend on, and smoke-tests each one it installs. A failure does not stop the rest; the failures are listed at the end. | `deps TARGETS` | Lists the distribution packages the targets need and which are missing. With `--install`, installs the missing ones. | `doctor` | Checks the host, then smoke-tests every installed component (each cross compiler compiles a file, and every prebuilt program must find its shared libraries, for example). It reports anything out of date, any component whose files have gone, and any part of a port you installed only partly, such as FS-UAE without a Kickstart. | `import PATH...` | Installs the files that are not downloaded (see <>) from files, folders or `.zip` archives, matched by checksum. | `bundle FILE` | Packs those files, as present on this machine, into `FILE` (a `.tar.gz`) for a project to host. |=== A target is a component name from `list`, or a group: [cols="1,3"] |=== | Target | Means | `toolchain:PORT` | Everything needed to build for one port: `iigs`, `amiga`, `atarist`, `dos` or `x68000`. | `emulator:PORT` | Everything needed to run that port's programs: the emulator and its firmware. | `PORT` | Both of the above. | `toolchains` | Every port's toolchain. | `emulators` | Every port's emulator. | `all` | Everything except optional components (such as `staxiData`, Space Taxi's level source), which are installed by name. |=== [cols="1,3"] |=== | Option | Effect | `-y`, `--yes` | Install missing distribution packages without stopping to ask. | `--install` | With `deps`: install the missing packages. | `--force` | Reinstall components even when they are current. | `--jobs N` | Parallel build jobs. The default is every core. | `--keep-build` | Keep the scratch build trees (normally deleted after a successful install). | `--llvm816-dir PATH` | Use an existing checkout of llvm816, the IIgs compiler, instead of cloning it. For working on the compiler and JoeyLib together. The setting is remembered; `--llvm816-dir clone` goes back to a managed clone. |=== Everything the installer creates stays inside `toolchains/`: [cols="1,3"] |=== | Path | Contents | `toolchains/opt/` | The installed components, one directory each. | `toolchains/firmware/` | ROM and system-disk images for the emulators. | `toolchains/cache/` | Downloads, kept and re-verified by checksum on reuse, and scratch build trees. | `toolchains/state/` | Which version of each component is installed, and settings such as `--llvm816-dir`. | `toolchains/config.mk`, `toolchains/env.sh` | The tool paths, for `make` and for shells. |=== Nothing in `toolchains/` is part of the repository: delete the whole folder to return the machine to a clean state, and `./install.sh` re-creates it. The installer itself lives in `install.sh` and `installer/` (its component recipes, patches and package lists), and the build helpers the makefiles call live in `make/support/`. === Building [source,console] ---- $ make # every target whose toolchain is installed $ make iigs # Apple IIgs only $ make amiga # Commodore Amiga only $ make atarist # Atari ST only $ make dos # MS-DOS only $ make x68000 # Sharp X68000 only $ make clean # remove all build outputs ---- Built programs land under `build//bin/`. The IIgs additionally produces a bootable disk image: [source,console] ---- $ make iigs-disk # build/iigs/bin/joey.2mg ---- Space Taxi's levels come from the original Commodore 64 game, which is not part of the repository. Without `stuff/spacetaxi/raw.bin` the build still compiles the STAXI program, skips only its data files, and says so: [source,console] ---- note: Space Taxi data skipped: stuff/spacetaxi/raw.bin is not present ---- [TIP] ==== Never judge a retro build by its exit status alone. Check that the file you expect actually appeared and has a recent timestamp. `make iigs` builds the library but *no examples* -- `make iigs-disk` is what builds and packages them. ==== === Hello, JoeyLib The smallest complete program. This is `examples/hello/hello.c`: [source,c] ---- #include #include int main(void) { jlConfigT config; config.codegenBytes = 8 * 1024; config.audioBytes = 64UL * 1024; if (!jlInit(&config)) { fprintf(stderr, "jlInit failed: %s\n", jlLastError()); return 1; } printf("JoeyLib %s\n", jlVersionString()); printf("Platform: %s\n", jlPlatformName()); printf("Hello from JoeyLib.\n"); jlShutdown(); return 0; } ---- Three things to notice, because they apply to every JoeyLib program: . *One header.* `#include ` pulls in everything except the optional serial add-on. . *`jlInit` can fail*, and when it does `jlLastError()` tells you why. Always check it. . *`jlShutdown` is not optional.* It restores the display mode, releases the Memory Manager blocks or DOS memory the library took, and on several ports un-hooks interrupt vectors. Skipping it can leave the machine in an unusable state. === Something on the Screen `hello.c` prints text but never draws. Here is the smallest program that puts graphics on screen and waits for a keypress: [source,c] ---- #include int main(void) { jlConfigT config; jlSurfaceT *stage; uint16_t colors[SURFACE_COLORS_PER_PALETTE]; uint8_t i; config.codegenBytes = 8 * 1024; config.audioBytes = 0; if (!jlInit(&config)) { return 1; } stage = jlStageGet(); // the library-owned back buffer // Build palette 0. Entry 0 is forced black whatever we put here. for (i = 0; i < SURFACE_COLORS_PER_PALETTE; i++) { colors[i] = 0x000; } colors[1] = 0xFFF; // white colors[2] = 0xF00; // red colors[3] = 0x00F; // blue jlPaletteSet(stage, 0, colors); // Every scanline uses palette 0 (this is also the default). jlScbSetRange(stage, 0, SURFACE_HEIGHT - 1, 0); jlSurfaceClear(stage, 0); jlFillRect(stage, 40, 30, 240, 140, 3); jlDrawRect(stage, 40, 30, 240, 140, 1); jlDrawLine(stage, 0, 0, SURFACE_WIDTH - 1, SURFACE_HEIGHT - 1, 2); jlStagePresent(); // nothing is visible until this runs jlWaitForAnyKey(); jlShutdown(); return 0; } ---- The critical line is `jlStagePresent()`. All drawing goes to an off-screen back buffer called the *stage*; nothing reaches the display until you present. === Running What You Built `joey-run`, at the top of the repository, starts a built program in the right emulator. The emulators, and the firmware they boot, come from the installer: [source,console] ---- $ ./install.sh install emulators # every machine $ ./install.sh install emulator:dos # or just one ---- MAME (for the IIgs and X68000) is always built from source, because the test gates need JoeyLib's patches to it. DOSBox Staging is upstream's own Linux release. Hatari and FS-UAE are distribution packages on Debian and Ubuntu; Fedora does not ship the versions the gates expect, so there the installer builds both from source. Point `joey-run` at a program, or name an example together with `--port`: [source,console] ---- $ ./joey-run build/dos/bin/DRAW.EXE $ ./joey-run build/amiga/bin/Draw $ ./joey-run --port atarist draw $ ./joey-run build/iigs/bin/STAXI.2mg ---- It recognises the machine from the file itself. Interactive runs use the program's own folder or disk image, so saves and logs persist from one run to the next. Nothing is written to your home directory. [cols="1,3"] |=== | Option | Effect | `--port PORT` | The machine, when naming an example rather than a file. | `--data DIR` | Copy `DIR`'s files into the program's `DATA` folder for this run, for example an AGI game's files. | `--headless` | No window and no sound, for scripts and continuous integration. Stops after 60 seconds unless `--seconds` says otherwise. | `--seconds N` | Stop after `N` seconds. | `--snapshot FILE` | Save a PNG of the screen when the run stops. | `--machine rom01` | Apple IIgs: the ROM 01 machine instead of ROM 03. | `--ram SIZE` | Apple IIgs: MAME's memory size. The default is `4M`; AGI wants `8M`. | `--debug` | Apple IIgs and X68000: start MAME's debugger. | `-- ARGS` | Pass `ARGS` to the program. DOS only: the other machines' autostart cannot pass arguments. |=== A headless run with a snapshot is the quickest way to check a change: [source,console] ---- $ ./joey-run --headless --seconds 30 --snapshot draw.png --port dos draw ---- ==== The Apple IIgs The IIgs runs programs from disk images. `make -f make/iigs.mk iigs-game-disk GAME=DRAW` builds a bootable one, `build/iigs/bin/DRAW.2mg`, which is also how a game ships. Given a data disk instead, such as `joey.2mg`, `joey-run` boots GS/OS beside it and you open the program in the Finder. Given a bare program, `build/iigs/bin/DRAW`, it builds both disks itself, which needs the IIgs toolchain. ==== Firmware that is not downloaded Almost everything the emulators need is downloaded: EmuTOS for the Atari ST, the Apple IIgs ROMs, GS/OS 6.0.4 and the CFFA2 card's firmware, and Sharp's own free release of the X68000 IPL-ROM and Human68k 3.02. Three files are not, because they were never released for free: the Amiga Kickstart 3.1 ROM, the X68000 CG (font) ROM, and the memory image of the original Space Taxi that its levels are extracted from. Supply your copies once: [source,console] ---- $ ./install.sh import ~/my-roms ---- `import` takes files, folders and `.zip` archives, identifies each file by its checksum (the list is `installer/files.sha1`) and puts it in place. A project that hands its setup to testers can host these files instead: `./install.sh bundle joeylib-private.tar.gz` packs the ones present on a machine that has them, and setting `JOEY_BUNDLE_URL` to where it is hosted, in `installer/bundle.conf`, makes every `install` fetch it automatically. === The Example Programs The `examples/` directory is the best available reference, and every example is built for every platform: [cols="1,4", options="header"] |=== |Example |What it shows |`hello` |Minimal init, version query, shutdown. |`draw` |Every drawing primitive, laid out in four quadrants. |`pattern` |Palette and per-scanline palette (SCB) work. |`keys` |Typed-character input and the key predicates. |`joy` |Joystick axes, buttons and recalibration. |`sprite` |Sprite loading, compiling, save-under and restore. |`audio` |Tracker music, `.MOD` playback and digital sound effects. |`save` |Save files and the disk-space query. |`serial` |The optional RS-232 add-on. |`adventure` |A small complete game. |`agi` |A Sierra AGI interpreter, showing the library under real load. |`spacetaxi` |A full port of Space Taxi: the largest example. |`uber` |The validation and benchmark harness. |===