spike(python): CPython 2.7.18 runs the 40250 root scripts on Android arm64

libpython2.7.a cross-builds with NDK 27.2 (API 24) after disabling
HAVE_LANGINFO_H; 30 C modules built in. On a OnePlus 13 (API 36) the
harness runs system.py -> prototype.RunApp() and imports the root modules
with results identical to macOS (66/74; the 8 failures are stub values or
dev-only scripts). py_embed_spike.py now isolates __main__ like
CPythonLauncher and reports stdlib usage.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-22 18:16:44 +09:00
co-authored by Claude Opus 5
parent 9d0e50de8f
commit b02c49bb2f
4 changed files with 151 additions and 24 deletions
+33 -13
View File
@@ -8,7 +8,7 @@
| 项 | 数据 |
| --- | --- |
| 解释器 | CPython 2.7.6 内嵌(`extern/include/Python-2.7``python27.lib` |
| 启动 | `ScriptLib/PythonLauncher.cpp``CPythonLauncher::Create` 注入 `TRUE`/`FALSE``__builtin__`,然后把 `system.py` 作为 `__main__` 运行;`system.py` 替换 `__import__`,从 pack 读源码并 `compile` |
| 启动 | `ScriptLib/PythonLauncher.cpp``CPythonLauncher::Create` 注入 `TRUE`/`FALSE``__builtin__`,然后把 `system.py` 作为 `__main__` 运行`__main__``__builtins__` 是模块,不是 dict`system.py` 替换 `__import__`,从 pack 读源码并 `compile` |
| 脚本 | `root/*.py` 90 个(其中 74 个 `.py` 模块),`uiscript/uiscript/*.py` 94 个 |
| 语法 | 154 个文件在 Python 2.7.18 下全部能编译;Python 3 下有 56 个编译失败;约 292 行只在 Python 2 下成立(`print` 语句、`except X, e``has_key``iteritems` 等) |
| 语义风险 | 约 185 行在整数之间用 `/`Python 2 是整除,Python 3 是浮点);字符串是 CP949 字节串 |
@@ -27,12 +27,16 @@
-`CPythonLauncher::Create` 注入 `TRUE`/`FALSE`,所有 C++ 模块用返回 0 的桩代替,`pack` 用目录代替;
- 原样运行 40250 的 `system.py`,再通过它自己的 `__pack_import` 导入全部 74 个 root 模块。
结果:**不改任何脚本,67/74 个模块加载成功**,引导过程一路执行到 `prototype.py`
`app.Create` 等调用。剩下 7 个失败都是桩的问题,不是解释器或脚本的问题:
结果:**不改任何脚本**`system.py` 引导后 `prototype.py` 完整执行了 `RunApp()`:创建 MainStream、进入 logo
阶段、加载 `UIScript/PopupDialog.py``app.Loop`、Destroy。之后逐个导入全部 74 root 模块,66 个成功。
剩下 8 个失败都不是解释器或脚本的问题:
- `chr.MOTION_SKILL + 121` 这类常量需要真实整数(真实模块用 `PyModule_AddIntConstant` 提供)
- locale 数据路径(`app.GetLocaleServiceName` 等返回值决定走哪个 locale 目录);
- `rootlibcythonizer``test_affect` 是开发用脚本,40250 运行时也不加载。
- `prototype`:已经由 `system.py` 执行过,再导入时 `RunApp` 结束触发 `SystemExit`,属正常
- `game``interfacemodule``chr.MOTION_SKILL + 121` 这类常量需要真实整数(真实模块用 `PyModule_AddIntConstant` 提供);
- `introloading``consolemodule`locale 数据路径(`app.GetLocaleServiceName` 等返回值决定走哪个 locale 目录);
- `system`:只能作为 `__main__` 运行;`rootlibcythonizer``test_affect` 是开发用脚本,40250 运行时也不加载。
引导过程中脚本调用了 33 个 C++ 模块函数(`app.Create``wndMgr.Register``net.SetHandler` 等)。
结论:在 Python 2.7 上,40250 的脚本和导入机制可以原封不动运行;工作量集中在 C++ 模块本身。
@@ -71,12 +75,28 @@ Godot 这边只剩一个宿主 Control:把输入转发给 `CPythonWindowManage
`root/*.py``uiscript/` 直接从 pack 读取,和 40250 相同。port-map 中 `Client/root` 的 3350 个函数
全部记为 `N_A`(原样运行,无需移植),python 层剩下约 1540 个 C++ 函数要移植。
## 下一步:原型 2(待确认后执行
## Android 验证(2026-09-22,已通过
1. 把 CPython 2.7.18 静态编进 `libmtgodot`,先做 macOS arm64 和 Android arm64,再做 iOS 模拟器;
2. 在 Godot 进程里运行 `py_embed_spike.py` 的同等流程(C++ 桩模块),确认 67/74 的结果在三个平台上一致;
3. 验收门槛:Android 和 iOS 都能加载 `system.py` 并导入 `ui.py`。如果 Android/iOS 编译在合理时间内做不出来,
就改用方案 B,并对每处 `/` 做单独核对。
设备:一加 13PJZ110),Android API 36arm64-v8a。复现:`tools/py_embed_android/build-and-run.sh`
原型 2 通过之前,python 层(`Client/root``EterPythonLib``ScriptLib``*Module.cpp`)不开工;
逻辑层(阶段 2)不受影响,可以并行推进
- **编译**CPython 2.7.18 官方源码,用 NDK 27.2 的 `aarch64-linux-android24-clang` 交叉 configure
`make libpython2.7.a` 一次通过。只需要一处改动:关掉 `HAVE_LANGINFO_H`,因为 bionic 从 API 26 才声明 `nl_langinfo`
另外 30 个 C 模块静态编进去,包括 `posix` `math` `time` `_struct` `operator` `itertools` `_collections`
`cStringIO` `cPickle` `_locale` `binascii` `datetime` `select` `fcntl` 等。全部编译通过,库大小 13 MB(含调试信息)。
- **链接**:测试程序 `tools/py_embed_android/main.c` 链接 `libpython2.7.a -lm -ldl`,没有任何未定义符号。
- **运行**`Py_NoSiteFlag`/`Py_IgnoreEnvironmentFlag`/`Py_FrozenFlag` 启动,标准库以不压缩的 zip(8 MB)
加入 `sys.path`,然后运行 `py_embed_spike.py`:**结果与 macOS 逐项相同**,66/74 个模块加载,失败的 8 个完全相同,
引导期调用的 33 个 C++ 函数也完全相同。
- **尚未验证**
- 这次是用 `adb shell` 运行的独立可执行文件,还没有在 APK 的 app 进程里跑过;
- 标准库是从文件系统读的,还没有走 PCK 或 `asset_io`
这两点属于集成工作,不涉及解释器本身能不能跑。
## 下一步
1. 把 CPython 2.7.18 放进 `extension/third_party/`,用我们自己的 CMake 编译(macOS / Android / iOS 共用一份源码清单和
`pyconfig.h`),静态链接进 `libmtgodot`
2. `pack` 模块走 `asset_io`,标准库的纯 Python 文件放进资源包,用 `system.py` 自带的导入钩子加载;
3. 在 APK 里跑同样的引导流程(C++ 桩模块),然后按同样方法验证 iOS;
4. 之后 python 层才开始移植:`ScriptLib/PythonLauncher.cpp``EterPythonLib` 窗口系统 → `*Module.cpp`