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
The SceLoadCoreExecFileInfo Saga

Worth knowing in detail — it took six commits to land properly and is a good example of the PSPSDK-version whack-a-mole this project deals with.

Root cause: pspmodulemgr_kernel.h (pulled in transitively by pspkernel.h, needed by menu.c/screenshot.c/utils.c) references a type SceLoadCoreExecFileInfo that, in newer PSPSDK, is only defined in psploadcore.h — a header not everyone includes first.

Attempts before the fix stuck (cbdb5476a089546a284d7375dd4bee19b37fa55883): the first attempts scattered a local stub typedef directly at the top of individual .c files — copy-pasted per file, worded slightly differently each time, sometimes a forward declaration, sometimes a stub struct, at one point flip-flopping on whether to include psploadcore.h directly instead.

Final, correct fix (fa55883): a single shared header, src/include/psp_compat.h:

/*
 * Compatibility shim for newer PSPSDK versions.
 * pspmodulemgr_kernel.h references SceLoadCoreExecFileInfo on line 51,
 * but the Docker image's SDK does not define it in any header that's
 * included before use. Include this header BEFORE any PSPSDK kernel headers.
 */
typedef struct { int _dummy; } SceLoadCoreExecFileInfo;
Lesson
If you hit a "PSPSDK header references an undefined type" error again, don't re-invent a local stub in the .c file with the error — check psp_compat.h first, and if the fix belongs there, add it there once rather than scattering copies. This is exactly the mistake the project made (and fixed) before landing on the shared-header approach.
Other Compat-Fix Commits
CommitWhat brokeFix
93093a7float.h used u32 without pulling in the header that defines itAdded #include <pspkerneltypes.h> directly
9162de8CI referenced wrong Docker image name / stale RELVERCorrected image name and RELVER
a06066eNewer SDK started providing its own sceKernelGetGameInfo declaration, conflicting with TempAR's; button_callback signature mismatchRemoved TempAR's own declaration; changed params to u32
4594821cheat_insert had an incompatible-pointer-type assignmentReplaced with explicit memcpy
b3e25d1f_cvt had u32 vs unsigned int mismatches across 3 filesAligned types across all call sites
eaf4897sceKernelGetThreadmanIdList array-pointer warning + unused variableFixed array-pointer usage, removed unused variable
15f2570f_cvt call site passed u32[] to a differently-typed pointerExplicit cast to u32*
14fcb6fsceImposeHomeButton/scePowerGetResumeCount removed from newer PSPSDK headers (still runtime-linkable)-Wno-implicit-function-declaration — permanent, load-bearing flag
5376dc4GCC 14 tightened implicit int-to-pointer/pointer-type/int conversions-Wno-incompatible-pointer-types -Wno-int-conversion -Wno-int-to-pointer-cast
b7d5215atoi not linked into kernel-mode libc build (link-time failure, easy to misdiagnose)Replaced with strtoul
Working theory for future compat breaks
If a Docker image update breaks the build, look for: (1) a PSPSDK header now requiring a type/include it didn't before — extend psp_compat.h, don't scatter local stubs; (2) a function removed from headers but still runtime-linkable — -Wno-implicit-function-declaration (already set) or an imports.S stub if linking also fails; (3) GCC being stricter about a type mismatch that's always technically been there — narrow, targeted -Wno-*, or actually fix the type.
Global State & Lifecycle Traps
  • No RAII / manual cleanup only. menu_show()'s setup must be torn down in exact reverse order on every exit path. See Menu System.
  • No config migration. Changing Config's field set without bumping CONFIG_VER causes old config files to be misread rather than cleanly rejected.
  • No dirty-tracking/autosave. Any new persistent per-cheat state needs an explicit cheat_save() call at the point it's mutated — this was an actual shipped bug (favorites, fixed in 8080309).
  • ctrl_read() force-sets CIRCLE when the menu is closed. Any code reading raw controller state outside a menu-visible context will always see CIRCLE held.
  • Static OBJS lists. Adding a new .c file requires manually adding its .o to every relevant makefile — there's no glob.
  • printf/puts are macros, not the libc functions, in any file that includes menu.h or disasm.h — they draw to the debug-screen framebuffer at the current cursor position, not to any log/stdout.
  • MENU_KEY is a hidden bitmask. get_menu_ctrl()'s inline #define MENU_KEY silently excludes any button not already listed there.
  • Double hotkey registration. sceCtrlRegisterButtonCallback is called at boot and re-called in three places when keys are rebound. A fourth rebinding UI needs a fourth re-registration.
Vendored Code

Two files are vendored from other open-source PSP homebrew projects and carry their own license headers/conventions — treat changes to these more conservatively:

  • disasm.c/disasm.h — from PSPLINK (2006, BSD), MIPS disassembler.
  • pspdebugkb.c/pspdebugkb.h — PSPSDK's own on-screen-keyboard sample utility.
Versioning Is Manual and Duplicated

The release version number exists in at least two places that must be kept in sync by hand: RELVER in the root makefile, and VER_MAIN/VER_SUB (and VER_STR) in src/include/version.h. There is no single source of truth and no build-time check that they match — a release with mismatched values will build fine and just show the wrong version string somewhere.