v1.70.4 is out now - crash recovery added - fixed a memory allocator bug that crashed GTA: Liberty City Stories - config self-heal - CWCheat + PSPAR in one plugin - works on CFW only, not OFW - full changelog inside
TL;DR
docker run -it -v "${PWD}:/src" -w "/src" pspdev/pspsdk make release

That's it for a full local build — Docker supplies the entire PSP MIPS toolchain and PSPSDK so you don't install anything on the host. Output lands in build/tempar-<RELVER>.zip.

CI (.github/workflows/build.yml) does the same thing but against the pspdev/pspdev image (a superset/newer image than pspdev/pspsdk — see Gotchas for why the image name matters and has broken before).

The Three Makefiles

There's a top-level makefile that orchestrates everything, plus per-binary makefiles in src/ that PSPSDK's own build system (build.mak) consumes.

makefile (repo root):

export RELVER := 1.70.4

release:    prep psp lite pack clean
release_pr: prep psppr litepr pack clean
TargetWhat it does
prepCompiles src/languages/english.bin into a C header (english.h) via bin2c, so language strings can be #included as data rather than loaded from a separate file at first boot.
pspmake -C src -f makefile_psp — builds the full tempar.prx.
litemake -C src -f makefile_lite — builds the lite tempar_lite.prx.
psppr / liteprSame, but using makefile_psppr/makefile_litepr — variants used by the release_pr target.
packCreates build/temp, copies src/resources/* (the seplugins folder structure users install) and docs/ (end-user docs) into it, moves the built .prx files into build/temp/seplugins/TempAR, then zips the whole thing to build/tempar-$(RELVER).zip.
cleanRemoves build artifacts: .elf/.prx outputs, objects/*.o, generated language headers, build/temp.

release runs prep, builds both psp and lite, packs, then cleans. RELVER must be bumped by hand in this file for every release — it's also duplicated in src/include/version.h (VER_MAIN/VER_SUB/VER_PATCH) and must be kept in sync manually.

Makefile consolidation (v1.70.4)
src/makefile_psp and src/makefile_lite are no longer the real build logic — both are now thin wrappers around one parameterized src/makefile:
# src/makefile_psp:
VARIANT = psp
include makefile
The real makefile is invoked as make -C src -f makefile VARIANT=psp|lite (default psp). The old per-variant names still work unchanged from the top-level makefile's perspective — nothing above this layer needed to change. If you're adding a new build variant, add it to src/makefile's VARIANT branching, not as a fourth copy-pasted file.
src/makefile_psp and src/makefile_lite

These are now thin wrappers (see above) around src/makefile, which include $(PSPSDK)/lib/build.mak at the bottom, where all the actual compile/link rules live.

Key variables and what changing them means:

  • TARGET — output PRX name (tempar / tempar_lite).
  • OBJS — the full, explicit list of .o files to link. Adding a new .c file means adding its .o here in both makefiles (and in the PR variants if needed) — there's no wildcard/glob, it's a static list.
  • CFLAGS — compiler flags, most importantly the -D_FEATURE_ defines that gate which optional subsystems compile in. Also carries several -Wno-* flags — not optional cleanliness, some are load-bearing for the build to succeed at all with the current toolchain (see Gotchas).
  • BUILD_PRX = 1, PRX_EXPORTS = exports.exp — tells PSPSDK's build system to produce a loadable PRX (see SDK Usage for what exports.exp does).
  • USE_KERNEL_LIBC = 1, USE_KERNEL_LIBS = 1 — link against the kernel-mode libc/libs instead of the normal user-mode PSP libc. This is why kmalloc.c/syslibc.c exist.
  • LIBS — PSP system libraries to link. Differs between full and lite builds, tied to which features are compiled in.
Full vs. Lite: The Actual -D Diff

Full (makefile_psp):

_FONT_acorn _CWCHEAT_ _PSPAR_ _USB_ _PSID_ _SCREENSHOT_ _GUIDE_ _UMDDUMP_ _MODLIST_ _THLIST_
_MIPS_ _AUTOOFF_ _MULTILANGUAGE_

Lite (makefile_lite):

_FONT_acorn _CWCHEAT_ _PSPAR_ _GUIDE_ _MIPS_ _AUTOOFF_ _LITE_ _MULTILANGUAGE_

Lite drops _USB_, _PSID_, _SCREENSHOT_, _UMDDUMP_, _MODLIST_, _THLIST_, and adds its own _LITE_ flag (used in a couple of places to alter behavior, not just strip code). Per the FAQ, lite is what you use for POPS (PS1-on-PSP) titles.

What bin2c Is and Why prep Exists

bin2c (provided by the PSPSDK/toolchain image) turns an arbitrary binary file into a C source array. The prep step turns the compiled language binary (english.bin) into english.h so it can be compiled directly into the PRX rather than shipped/loaded as a loose file.

Host-Side Test Suite (tests/)

As of v1.70.4, address-mapping and config-validation logic lives in shared headers (addr.h, config_core.h) that compile both into the PRX and into standalone host binaries — so the real logic can be unit-tested on any machine with a C compiler, no PSP SDK or Docker required:

cd tests
make run
# == test_address ==
# == test_config_core ==

This runs as its own host-tests CI job, separate from and before the Docker-based PRX build. If you're touching address clamping or config validation, run this locally first — it's much faster than a full Docker build cycle.

CI (.github/workflows/build.yml)

Triggers: push to main/master/feat/*, PRs into main/master, tag pushes (v*), and manual workflow_dispatch. Two jobs run: host-tests (the suite above) and build (the actual PRX build), independently.

  1. docker run ... pspdev/pspdev make prep psp lite — builds both PRXs (does not run pack here, that's separate).
  2. make pack on the runner directly (installs zip via apt first if missing).
  3. Collects every *.prx and *.zip under build/ into artifacts/.
  4. Uploads artifacts/ as a workflow artifact.
  5. If the trigger was a tag push or manual dispatch, creates a GitHub Release with those artifacts attached.
Watch out
permissions: contents: write is required for the release-creation step — this was a real fix commit (ef2ec3d). If release creation starts failing with a 403, check this block first.
Manual (Non-Docker) Builds

Not documented/tested in this repo — the README explicitly says "Build process tested on Windows 10" using the Docker flow above. If you want a native PSPSDK install instead, you're on your own for toolchain setup; the makefiles are ordinary PSPSDK makefiles and don't assume Docker specifically, only PSPSDK = $(shell psp-config --pspsdk-path) needs to resolve correctly on your PATH.