PPSSPP 构建与验证实战:从 b.sh 到 pspautotests 回归测试的完整构建指南

📅 发布时间:2026/9/14 9:32:04
PPSSPP 构建与验证实战:从 b.sh 到 pspautotests 回归测试的完整构建指南
PPSSPP 构建与验证实战从 b.sh 到 pspautotests 回归测试的完整构建指南【免费下载链接】ppssppA PSP emulator for Android, Windows, Mac, Linux and iOS, written in C. Want to contribute? Join us on Discord at https://discord.gg/5NJB6dD or just send pull requests / issues.项目地址: https://gitcode.com/GitHub_Trending/pp/ppsspp本文基于仓库文档 docs/building.md 及其背后的真实构建脚本、CMake 配置与测试框架源码系统讲解 PPSSPPC 编写的 PSP 模拟器在各平台上的构建验证路径Linux/Mac 的./b.sh快速迭代、Windows 的 Visual Studio 方案与非交互式 MSBuild 驱动、unittest/C 单元测试与 pspautotests 自动化回归、以及 Android NDK 与 libretro core 两条特殊构建线。读完后你可以独立完成一次改动后的构建-测试闭环并避开文档中总结的若干假回归陷阱。一、构建与验证入口b.sh、VS 方案与 MSBuildLinux/Mac用 ./b.sh --debug 验证构建文档给出的第一条基线规则是在 Linux/Mac 上验证构建用./b.sh --debug。b.sh是仓库根目录的 CMake 封装脚本从 b.sh 源码看它把命令行参数翻译成 CMake 选项--debug→-DCMAKE_BUILD_TYPEDebug--release/--reldebug→Release/RelWithDebInfo--unittest→-DUNITTESTON生成单元测试目标--headless→-DHEADLESSON生成无界面目标其余如--ios、--rpi、--sanitize、--clang等分别对应 iOS/树莓派工具链、ASan/UBSan、Clang 切换脚本还会按nprocLinux或sysctl -n hw.physicalcpumacOS自动决定并行线程数原生构建输出到build/目录交叉构建则输出到build-os/。CMake 侧对应两个开关见 CMakeLists.txtoption(HEADLESS Set to OFF to not generate the PPSSPPHeadless target ${HEADLESS}) option(UNITTEST Set to ON to generate the unittest target ${UNITTEST})Windows只走 Windows/PPSSPP.sln并用 MSBuild 非交互式驱动文档对 Windows 的强调很明确始终通过 Windows/PPSSPP.sln 构建即使仓库根目录存在一个 CMake 生成的build/残留目录例如 WSL/MSYS2 实验留下的——那不是你该走的构建路径其工具链可能根本没有正确接好。为了不打开devenv图形界面Agent/脚本可以用MSBuild.exe非交互驱动同一个解决方案。先用vswhere.exe定位 VS 安装路径再用/t:指定要构建的项目$installPath C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -latest -property installationPath $msbuild $installPath\MSBuild\Current\Bin\MSBuild.exe $msbuild Windows\PPSSPP.sln /t:UnitTest /p:ConfigurationDebug /p:Platformx64 /m/t:UnitTest可换成/t:PPSSPPWindows或方案里的其他工程名完全省略/t:则构建整个解决方案。这与 unittest/UnitTest.cpp 头部注释给出的 CMake 侧用法互为对照./b.sh --unittest build/unittest EscapeMenuString小改动不必每次全量Linux 快速重建捷径文档最后给出了日常迭代捷径——配置过一次之后验证小改动只需cd build ; make -j32; cd ..二、C 单元测试unittest/运行方式与新增流程除了 pspautotests 运行器test.py仓库还有一个独立的 C 单元测试程序位于 unittest/ 子目录。文档建议在一揽子较大改动完成之后不必每次编辑后跑一遍Windows构建UnitTest工程对应 unittest/UnitTests.vcxproj然后运行Windows/x64/Debug/UnitTest.exe allLinux/Mac配置时加-DUNITTESTON即./b.sh --unittest然后运行build/PPSSPPUnitTest all它执行的是 unittest/UnitTest.cpp 中availableTests数组登记的全部测试。参数行为由main()实现见 UnitTest.cpp传all跑全部测试传一个或多个测试名大小写不敏感只跑指定项如UnitTest.exe CmdLine Path Utf8任一名字不匹配会打印Unknown test并回退到用法说明不做静默的部分运行不带参数仅列出所有可用测试名后退出。availableTests实际覆盖 60 余项按架构条件编译注册如Arm64Emitter、X64Emitter、RiscVEmitter、LoongArch64Emitter各带PPSSPP_ARCH宏守卫另有VertexJit、Serializer存档序列化器往返与截断/损坏输入防护、Utf8、Path、CmdLine、Jit、MemMap、ThreadManager等。单元测试为什么是最严格的链接检查文档点出一个跨平台差异值得展开单元测试常常是某个函数在自身.cpp之外第一次被调用的地方因此 Android 遗留构建里的ppsspp_unittest目标android/jni/Android.mk成为仓库里最严格的检查——MSVC 会把定义在 .cpp 里的inline函数照样链接进目标而 clang 会正确地拒绝。后果是一个测试可以在 Windows 上构建并通过却只在 Android CI 上因未定义符号链接失败报错指向某个头文件行。文档给出的修复方向明确去掉定义上多余的inline而不是绕开对该函数的调用。另外注意文档提醒unittest/UnitTest.cpp 与 headless/ 目录各自持有独立的main并桩stub掉了大部分System_平台函数源码注释直接说明copied from Headless做跨平台改动时要同时照顾这两套构建。新增测试的完整流程是在 unittest/UnitTest.cpp 的availableTests中登记新测试大测试可单独放unittest/下的新文件如TestUtf8式的独立 .cpp同时更新 CMakeLists.txt 与 Visual Studio 工程两处文件清单。三、陈旧二进制陷阱stash 循环、bisect 与 LNK1168这部分是文档中最事故复盘性质的经验直接关系到你是否相信自己的测试结果1. 触碰头文件后的git stash/git stash pop必须/t:Rebuild。stash 重写文件后时间戳可能导致对象文件看起来比所依据的头文件更新于是增量构建放行结果是各翻译单元对对象布局产生分歧比如增删了一个类成员。典型症状UnitTest.exe在打印任何东西之前就段错误且所有测试都挂——看起来像灾难性代码 bug其实不是。文档的处方是stash 循环之后构建莫名崩溃时先重建再调查其他任何东西。2. bisect 行为变化之前先确认二进制真的变了。检查可执行文件 mtime或让你新加的代码打一行可 grep 的日志。陈旧二进制的回归和真回归无法区分且它持续说谎在陈旧二进制上做的 bisect 会给出自信而完全虚构的结论。文档记述了一次真实耗时数小时的案例一次静默失败的链接把旧的PPSSPPHeadless.exe留在原地此后每一步revert 再测都报同样的失败最终把一个清白改动背了黑锅直到干净重建才澄清。3.LNK1168: cannot open ... for writing是上述问题的最常见来源——通常是还有一个正在运行的实例占着 exe。这就是文档建议无条件在构建前先杀掉残留进程而不只是构建抱怨时再杀的原因详见 docs/debugging.md。4. 已知环境特异性问题Jit测试在个别沙箱中挂死。unittest/JitHarness.cpp 对应的Jit测试在至少一个沙箱化开发环境中会在CPUCore::JIT_IR阶段无限挂起——在未修改的检出上同样复现且与源码改动无关、也不是内存访问故障从未进入Memory::HandleFault。根因未进一步定位那个环境无法挂原生调试器但从CI 在多个平台每个提交都跑等价的UnitTest.exe all且无异常来看很可能是该沙箱自身的问题而非 PPSSPP 真 bug。文档给出的规避方案若all/Jit在你的环境挂死按名字逐个跑其余测试跳过Jit以保住真实覆盖。四、pspautotests像 CI 一样跑回归pspautotests 是针对 PSP 系统 API 面的大型测试集因此实际压测的是 PPSSPP 的 HLE 实现。文档要求检查回归时必须完全按 CI 的方式运行参考 .github/workflows/build.ymlpython test.py -g --graphicssoftware-g是关键。从 test.py 源码看脚本维护两个列表tests_goodtest.py 起回归集——这些测试当前通过且必须保持通过约 314 个tests_nexttest.py 起进行中的测试预期失败相当于待办清单。参数语义与 test.py 的main()一致参数行为-g只跑tests_good回归检查用这个-b只跑tests_next-m 前缀对当前选中的列表做前缀过滤如-m cpu/无-g/-b跑tests_next tests_good约有一百个失败不代表出了问题文档特别警告不要无标志运行然后去追那一百来个失败更不要把它们当回归上报——-g模式下唯一有意义的结果就是0 tests failed。其余参数如--graphicssoftware会被run_tests()原样透传给 PPSSPPHeadless脚本以--compare --timeout5 -方式从 stdin 逐行喂测试文件名见 test.py。另一个容易误判的输出Windows Debug 构建下runner 在汇总行之后会打印调试 CRT 的 Detected memory leaks! 转储。这是正常的不是测试失败——要看的是在它之前的N tests passed, N tests failed行。运行器按可执行文件 mtime 自动挑选最新的PPSSPPHeadless查找路径清单见 test.py覆盖Windows/x64/Debug/、build*/等位置所以再次呼应了第三节的先确认二进制已更新原则。更多基于 pspautotests 改进 PPSSPP 的工作流见 docs/pspautotests.md。五、遗留 Android NDK 构建android/jniandroid/下除了 gradle 构建还有一条遗留的裸 NDK 构建线android/jni/Android.mk ndk-build两者相互独立。它挂在 CI 上见 .github/workflows/build.yml 的android矩阵条目适合做快速测试构建可以构建ppsspp_headless和 Android 版单元测试。默认不需要构建它如需本地测试构建NDK 路径在 Windows 下硬编码于 android/ab.cmdPOSIX 下通过环境变量NDK传给 android/ab.sh。它应与 android/build.gradle.kts 的ndkVersion 29.0.14206865保持一致脚本先拷贝资源再以由机器核数nproc/%NUMBER_OF_PROCESSORS%推导的-j并行度运行ndk-build见 android/ab.sh$NDK/ndk-build -j$(nproc ...) $*POSIX 示例cd android NDK/path/to/ndk ./ab.sh APP_ABIarm64-v8a HEADLESS1产物ppsspp_headless落在android/libs/abi/。六、libretro core 构建Windows规范说明在 libretro/README_WINDOWS.txt文档对其做了摘要并补充了 Agent 相关的坑。要点libretro coreppsspp_libretro.dll在 Windows 上也是用真正的 GNU Make 构建的不是 VS 方案——编译器/链接器是cl.exe/link.exe经由platformwindows_msvc2019_desktop_x64其中 2019 无实际含义MSVC 2022 同样可用但由运行在 MSYS2 shell 里的 GNU Make 编排是纯 MSYS2 安装不是 Git Bash典型位置C:\msys64需要pacman -S makecd libretro make DEBUG1 platformwindows_msvc2019_desktop_x64 -j32去掉DEBUG1即 release 构建-j不必精确等于逻辑核数。验证方式是把ppsspp_libretro.*拷到本地 RetroArch 读取 core 的目录如cores/在 RetroArch 内加载。注意 README 还提醒不带platform的裸make不可行g 链不上 D3D11 部分。Agent 非交互式驱动时的两个环境坑应直接以子进程方式调用C:\msys64\usr\bin\bash.exe -lc ...——-llogin shell标志是关键它才让 MSYS2 自身的PATH、make、cygpath等正确就位在沙箱化调用中区别于人交互打开的 MSYS2 终端Makefile 的 VS 探测逻辑依赖的两个 Windows 环境变量可能没被子进程继承COMSPEC破坏cmd //c bash VSWhere.sh ...这一定位 VS 的调用和ProgramFiles(x86)VSWhere.sh自己找vswhere.exe需要它。若自动探测因此失败可在make命令行上直接覆盖VsInstallRoot跳过探测——GNU Make 的命令行变量优先于 Makefile 内对同名变量的:赋值make VsInstallRoot/c/Program Files/Microsoft Visual Studio/year/edition DEBUG1 platformwindows_msvc2019_desktop_x64 -j32路径要用 MSYS2/cygpath 的 POSIX 形式而非裸 Windows 路径不确定year/edition时用vswhere -latest -property installationPath查真实值。最后文档强调这是一次真实的完整编译链接应优先于用独立的cl.exe /Zs对 libretro 相关文件做语法检查——后者可能漏掉真实 bug例如 include 顺序问题导致VK_USE_PLATFORM_WIN32_KHR这类平台宏在vulkan.h首次带 include guard 的包含前未定义因为语法检查用的更窄的手动 include 路径/宏集未必能复现真实构建步骤的顺序。七、适用前提与限制小结Windows 构建的唯一受支持路径是Windows/PPSSPP.sln根目录残留的 CMakebuild/不可用于 Windows。Linux/Mac 的配置构建一步到位可用./b.sh --debug加--unittest获得PPSSPPUnitTest日常小改动用cd build ; make -j32。回归判定以python test.py -g --graphicssoftware的0 tests failed为准tests_next的失败是预期状态而非回归。Android NDK 遗留构建仅用于快速测试构建且需 NDK 版本与 android/build.gradle.kts 的ndkVersion对齐。所有改了行为却测出同样结果的场景先验证二进制已更新mtime 或新增日志再下结论。本文内容以 docs/building.md 为主体骨架构建脚本行为、测试注册表与运行器参数均已在 b.sh、CMakeLists.txt、unittest/UnitTest.cpp、test.py、android/ab.sh 与 libretro/README_WINDOWS.txt 中逐一核对。【免费下载链接】ppssppA PSP emulator for Android, Windows, Mac, Linux and iOS, written in C. Want to contribute? Join us on Discord at https://discord.gg/5NJB6dD or just send pull requests / issues.项目地址: https://gitcode.com/GitHub_Trending/pp/ppsspp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考