Had Claude clean up its own notes.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Henrik RydgårdandClaude Opus 5 committed 2026-09-15 11:21:02 -06:00
1 parent 992b8bd9b6
commit 6bc20ab64b
4 files changed
+141 -82

No files matched your search

+36
View File
@@ -0,0 +1,36 @@
# Command-line parsing
All command-line parsing for both the main app and the headless build belongs in `Core/CmdLine.cpp` /
`Core/CmdLine.h` (`CommandLineOptions`), not in the platform entry points (`Windows/main.cpp`,
`headless/Headless.cpp`, `UI/NativeApp.cpp`, etc.). Don't re-parse `argv` in those files - add a field
to `CommandLineOptions` instead.
## Declaring an option
Most options are declared in the `g_autoParams` table in `CmdLine.cpp` as:
```cpp
{offsetof(...), type, longName, shortName, docString, mode}
```
`mode` gates the option to `CmdLineMode::Application`, `::Headless`, or `::Both` (the default if the
field is omitted from the initializer).
The same long name can be reused for both modes with different types and meanings, because a given
`Parse()` call only matches params whose mode is `Both` or equal to the current mode. `--log` is the
example to know: a `String` "log to FILE" option in Application mode, a `Bool` "full log output" option
in Headless mode. They don't collide.
Options that can be repeated (e.g. `--ignore TESTNAME`, collected into a `std::vector<std::string>`), or
that don't fit the generic single-value table, need manual handling in the `else if` chain inside
`CommandLineOptions::Parse()` - the same way `--graphics=` and the `boot` filenames are handled.
## Getting a parsed option into the emulator
`ApplyToConfig()` is where parsed options are pushed into `g_Config` / `g_logManager`. Prefer wiring a
new option through there, so every platform gets it for free, rather than reading `CommandLineOptions`
fields ad-hoc at each call site.
`NativeInit()` in `UI/NativeApp.cpp` still takes `argc`/`argv`, because several platform entry points
pass them in, but it shouldn't read them directly: by the time `NativeInit()` runs,
`CommandLineOptions` should already hold everything.
+16
View File
@@ -121,6 +121,22 @@ A working invocation, and the traps around it:
- **To line input injection up with a wall-clock repro, use `cpu.status`'s `us` field** (emulated microseconds), not
`ticks`. The PSP's clock frequency is changeable and games do change it - CrossCraft Classic runs at 333MHz, so
`ticks / 222000000` is off by a factor of 1.5. `clockHz` is reported alongside.
- **`--graphics=software` cannot see "the screen stops updating" bugs.** When HLE writes pixels straight into a
display buffer - video decoding, `sceJpeg`, `sceMpegAvcCsc` - the hardware backends only find out because the HLE
calls `gpu->PerformWriteFormattedFromMemory()`. The software renderer reads that memory directly and so renders
the frame whether or not anything was notified. A missing notification therefore looks perfect under
`--graphics=software` and shows up as a frozen screen on every real backend, while the decode logs keep scrolling
past as if all were well. Reproduce display bugs on `--graphics=d3d11` or `--graphics=vulkan` (`directx9` is not
a valid value) and compare `--screenshot-save=` output, not the log.
- **`wsdbg --launch` only works with the headless build.** The app build is a GUI-subsystem exe with no stdout, so
the `Listening on port N` line never reaches the launcher and it gives up. Start it yourself with an explicit
`--debugger=PORT` and point wsdbg at that port. Note also that `--debugger-run` is `CmdLineMode::Headless`; the
app takes plain `--debugger=PORT`.
- **`--launch` needs `--log` to find the port.** Without it, headless prints only emulated printfs, so the
`Listening on port N` NOTICE never appears and `--launch` fails with "PPSSPP never reported a debugger port".
`--log --loglevel=3` keeps the port line while cutting the debug flood - full `--log` at the default level costs
a lot of emulation speed (a 25-second run of a game playing video wrote 450k lines and ran several times slower
than real time, which on its own looks like the stall you're hunting).
## Debugging and breakpoint considerations
+50
View File
@@ -0,0 +1,50 @@
# Patching files from a script
Most edits should go through an editor tool that does exact string replacement. This document is about
the cases where you reach for a script instead - a repetitive change across many files, say - and the
two ways that silently corrupts a diff on Windows.
The short versions of both live in `AGENTS.md` (General instructions, rules 5 and 6). This is the detail.
## Line endings
Which ending a file has depends on where it was checked out. Markdown, `.cpp` and most sources are
stored in git with LF, and a Windows checkout converts them to CRLF on the way out; a Linux checkout
leaves them alone. So the same file - `.vcxproj`, `.vcxproj.filters`, `android/jni/Android.mk`,
`libretro/Makefile.common`, `AGENTS.md`, much of the source - is CRLF in one working copy and LF in
another. Don't hardcode either, and don't "fix" a file's endings to match what a doc claims.
If you patch one with a script, read **and** write with `newline=''`, which keeps whatever was there.
Reading with Python's default universal-newline translation and writing with `newline=''` silently
converts the whole file, turning a two-line addition into a 5000-line diff.
Check `git diff --stat` before committing - a whole-file rewrite is obvious there and invisible in the
editor.
## Backslashes in a bash heredoc
**Don't feed Python to `bash -c` via a heredoc when the code contains backslashes.** The Git Bash /
MinGW layer strips one level of backslash escaping on the way in, *even with a quoted delimiter*
(`<<'PY'`), which normally suppresses all substitution. So the script Python receives is not the one
you wrote:
| You write in the heredoc | Python actually sees | Result |
|---|---|---|
| `"\r\n"` | `"\r\n"` | fine - survives, because you *want* Python to interpret it |
| `"\\n"` (intending a literal `\n` in the output) | `"\n"` | **a real newline is written into the file** |
| `'foo \\\r\n'` as a match anchor | `'foo \<CR><LF>'` | **anchor silently doesn't match**, reported as "anchor missing" |
The tell for the first case is a compiler error like `C2001: newline in string literal`; the second case
produces no error at all, just a patch that quietly did nothing. Both are invisible in the heredoc you
wrote.
The rule: **a heredoc is fine as long as every backslash in the script is one you want Python to
interpret. The moment you need a literal backslash in the *output*, stop.** Then either:
- use an exact-string-replacement editor tool instead (no shell in the path - the best option for the
common case of "insert a few lines of C++ that contain `\n`"), or
- write the script to a file and run `python thescript.py`, or
- build the backslash as `chr(92)` so no literal backslash appears in the heredoc at all.
Note this is about the *Python source*, not the data: reading and rewriting a CRLF file with
`newline=''` and `\r\n` anchors works fine in a heredoc, and is the normal way to patch files here.