port(2P step 3a/3b): stdlib on sys.path + the pack module
step 3a — 标准库: tools/py_embed/make_stdlib_zip.py packs the vendored Lib/ into <build>/python27.zip (397 modules, 6876547 bytes, ZIP_STORED — the zlib module is trimmed out of our CPython, so zipimport cannot inflate). The mtpython_stdlib target builds it; py_embed_test and the launcher test both run against it. platform/ScriptLib/PythonHost sets the embedding flags before Py_Initialize and, after it, puts the zip on sys.path and re-registers encodings.search_function with codecs — 2.7 builds the codec registry once, at startup, so replacing sys.path afterwards needs it back. step 3b — pack 模块: UserInterface/PythonPackModule.cpp copied verbatim; packExist/packGet/ initpack read root/ and uiscript/ through CEterPackManager, i.e. through asset_io. The CHINA_CRYPT_KEY block in that unit is CAccountConnector's and is kept #if 0 until the login slice (2V1). UserInterface/StdAfx.h is a documented partial mirror — the original is the whole client's PCH. The launcher test now runs initpack() as RunMainScript does (its first line), reads system.py / uiscript / locale text back out of the packs, and confirms cp1252 decoding works off the zip. system.py still stops at "No module named app" — the C++ modules are the 2V0 slice. gates: port_map.py check 0 errors · key leak check 8/8 none · macOS ctest 27/27 · android + ios port_platform compile clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,8 @@
|
||||
#include "ScriptLib/StdAfx.h"
|
||||
#include "ScriptLib/PythonLauncher.h"
|
||||
#include "EterPack/EterPackManager.h"
|
||||
#include "UserInterface/StdAfx.h" // initpack
|
||||
#include "../src/platform/ScriptLib/PythonHost.h"
|
||||
#include "../src/platform/UserInterface/UserInterface.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -58,6 +60,7 @@ int main(int argc, char** argv)
|
||||
const char* strict = std::getenv("MT_ASSETS_STRICT");
|
||||
const bool is_strict = strict && std::string(strict) == "1";
|
||||
const std::string client = argc > 1 ? argv[1] : "";
|
||||
const std::string stdlib = argc > 2 ? argv[2] : PythonHost::DefaultStdLibPath();
|
||||
if (client.empty() || chdir(client.c_str()) != 0 || access("pack/Index", 0) != 0)
|
||||
{
|
||||
std::fprintf(stderr, "port_python_launcher_test: no 40250 Client/pack at '%s'\n", client.c_str());
|
||||
@@ -67,21 +70,36 @@ int main(int argc, char** argv)
|
||||
PackSingletons();
|
||||
CHECK(PackInitialize("pack"));
|
||||
|
||||
// Host policy, set before the launcher's ctor runs Py_Initialize: 40250 shipped a Python with a real
|
||||
// prefix on disk, the embedded one has none, so `import site` would fail at startup. The flags are the
|
||||
// ones tools/py_embed_android/main.c uses; step 3 moves them, and the stdlib on sys.path, into the
|
||||
// platform layer that every host shares.
|
||||
Py_NoSiteFlag = 1;
|
||||
Py_IgnoreEnvironmentFlag = 1;
|
||||
Py_FrozenFlag = 1;
|
||||
Py_DontWriteBytecodeFlag = 1;
|
||||
Py_SetProgramName((char*) "eter.python"); // CPythonLauncher::Create's default program name
|
||||
// What a real python27 installation did for 40250, the host does here: flags before Py_Initialize,
|
||||
// stdlib on sys.path after it (platform/ScriptLib/PythonHost.cpp).
|
||||
PythonHost::Configure();
|
||||
|
||||
{
|
||||
CPythonLauncher launcher; // ctor runs Py_Initialize, as 40250 Main() does on the stack
|
||||
CHECK(Py_IsInitialized());
|
||||
CHECK(launcher.Create());
|
||||
|
||||
std::string stdlib_error;
|
||||
CHECK(PythonHost::InstallStdLib(stdlib.c_str(), &stdlib_error));
|
||||
if (!stdlib_error.empty())
|
||||
std::fprintf(stderr, "InstallStdLib: %s\n", stdlib_error.c_str());
|
||||
// The stdlib is what the script layer's imports and the CP949/cp1252 text in the packs need.
|
||||
CHECK(launcher.RunLine("import os, string, types, codecs\nassert u'\\xe4'.encode('cp1252') == '\\xe4'"));
|
||||
|
||||
// RunMainScript's first line (UserInterface.cpp:243): the pack module, which is how system.py's
|
||||
// import hook and the window system read root/ and uiscript/ out of the registered packs.
|
||||
initpack();
|
||||
CHECK(launcher.RunLine("import pack"));
|
||||
CHECK(launcher.RunLine("assert pack.Exist('system.py') == 1"));
|
||||
CHECK(launcher.RunLine("assert pack.Exist('no/such.py') == 0"));
|
||||
CHECK(launcher.RunLine("__pack_len__ = len(pack.Get('system.py'))"));
|
||||
CHECK(launcher.RunLine("assert len(pack.Get('uiscript/selectcharacterwindow.py')) > 0"));
|
||||
CHECK(launcher.RunLine("assert len(pack.Get('locale/en/locale_game.txt')) > 0"));
|
||||
// Only .py/.pyc/.txt come out of it, and a miss is None rather than an exception
|
||||
// (packGet returns Py_BuildException(), which clears the error and builds None).
|
||||
CHECK(launcher.RunLine("assert pack.Get('icon/item/00000.tga') is None"));
|
||||
CHECK(launcher.RunLine("assert pack.Get('no/such.py') is None"));
|
||||
|
||||
// RegisterDebugFlag / RegisterCommandLine, verbatim from RunMainScript.
|
||||
CHECK(launcher.RunLine("__DEBUG__ = 0"));
|
||||
CHECK(launcher.RunLine("__COMMAND_LINE__ = \"\""));
|
||||
@@ -141,6 +159,7 @@ int main(int argc, char** argv)
|
||||
const VOID* data = NULL;
|
||||
CHECK(CEterPackManager::Instance().Get(file, "system.py", &data));
|
||||
CHECK(file.Size() > 0);
|
||||
CHECK(main_long("__pack_len__") == (long) file.Size()); // pack.Get returned the same entry
|
||||
|
||||
// Where it stops, spelled out: RunFile reports through Traceback(), which fetches the
|
||||
// exception and so leaves nothing behind, and LogBoxf is a platform stub. Running the same
|
||||
|
||||
Reference in New Issue
Block a user