feat(python): 在 app 进程里起 40250 脚本层(2P step 4,macOS)
移植 UserInterface/RunMainScript 到 platform/ScriptLib/PythonBoot:40250 把
CPythonLauncher 放在 Main() 的栈上,这里进程归 Godot,launcher 必须活过创建它的
那次调用,所以拆成 Start / RunMainScript / RunLine / Stop。37 个模块初始化函数里
只调已移植的 initpack(),system.py 因此仍停在第一个 import。
脚本报错能传回 GDScript,靠的是 platform/EterBase/Debug.cpp 实现 LogBox/LogBoxf:
ScriptLib 的 Traceback() 在 PyErr_Fetch 之后只剩这一条路,LastLogBoxMessage()
(platform/EterBase/LogBox.h)是 traceback 唯一幸存的地方。
GDScript 侧新增 Metin2PythonHost(python_host_node.{h,cpp})——唯一同时认识
godot-cpp 和 port 树的单元,PythonBoot 保持 godot-free。检查脚本
python_host_check.gd 分两段:解释器 + 标准库那段不需要 40250 的 pack,哪个平台都
能跑;system.py 那段需要 pack,没有就跳过。桌面入口 python_host_test.gd,真机入口
MT_TEST_MODE=python(导出模板不接受 --script)。
验证(macOS):标准库可 import、codec 注册表可用、sys.path 非空,system.py 停在和
ctest port.python_launcher 完全相同的 ImportError: No module named app;
ctest 27/27。Android/iOS 进程内未做,正式启动路径仍不起解释器(2V0)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
// Starting the script layer inside a host process (docs/PORT-PLAN.md 批次 2P step 4).
|
||||
//
|
||||
// 40250 runs the interpreter on Main()'s stack (UserInterface/UserInterface.cpp:419-434): construct
|
||||
// CPythonLauncher, Create(), RunMainScript(), Clear(), all inside one WinMain. Godot owns the process
|
||||
// here and calls in from GDScript, so the launcher has to outlive the call that starts it — that split
|
||||
// (Start / RunMainScript / Stop) is the only difference from the original control flow.
|
||||
//
|
||||
// It lives under platform/ScriptLib rather than platform/UserInterface because it is only buildable
|
||||
// with the embedded interpreter, and that is the directory both port_logic and port_platform drop when
|
||||
// `mtpython` is absent (extension/src/port/CMakeLists.txt).
|
||||
//
|
||||
// godot-free, like everything else under platform/: extension/src/python_host_node.cpp is what GDScript
|
||||
// talks to.
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace PythonBoot
|
||||
{
|
||||
// PythonHost::Configure() -> CPythonLauncher -> Create() -> PythonHost::InstallStdLib(stdlib_path).
|
||||
// An empty stdlib_path means PythonHost::DefaultStdLibPath(). Starting twice is a no-op that succeeds.
|
||||
// On failure *error is set and the interpreter is shut down again, so the next attempt starts clean.
|
||||
// The packs must already be registered (platform/PackBackend.h), as 40250 registers them in Main()
|
||||
// before the launcher exists.
|
||||
bool Start(const char* stdlib_path, std::string* error);
|
||||
bool IsRunning();
|
||||
|
||||
// 40250: RunMainScript(CPythonLauncher&, const char*) — the module initializers, __DEBUG__,
|
||||
// __COMMAND_LINE__ and RunFile("system.py"). Only the initializers that are ported are called; the rest
|
||||
// arrive with the 2V slices, which is why system.py still stops at its first import.
|
||||
// False leaves *error set to what the launcher reported through LogBox (platform/EterBase/LogBox.h).
|
||||
bool RunMainScript(const char* lpCmdLine, std::string* error);
|
||||
|
||||
// CPythonLauncher::RunLine, with the reported text handed back rather than only shown. The host's own
|
||||
// check uses it to prove the interpreter and the standard library work in-process on a device that has
|
||||
// no 40250 packs, which is where RunMainScript cannot run at all.
|
||||
bool RunLine(const char* source, std::string* error);
|
||||
|
||||
// 40250 Main() calls Clear() and lets the launcher leave scope.
|
||||
void Stop();
|
||||
}
|
||||
Reference in New Issue
Block a user