- extension/src/{port,platform,codepage} -> src/; native_render -> src/host
(+ dxt, shaders/); libgr2 -> src/gr2; extension/third_party -> third_party
- extension/tests -> tests/port, libgr2/tests -> tests/gr2
- android-native -> android (build.sh, push-client.sh moved in)
- script -> scripts; tools/40250 -> tools/server; oracle -> tools/granny-oracle;
perf tools -> tools/perf
- all build trees under build/ (native, release, android, port-gate)
- xrender:: CMake aliases -> mt::; port-map ledger impl paths rewritten
No code changes. ctest 15/15, port_gate macos+android PASS, port_map check 0 errors.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
118 lines
3.6 KiB
C++
118 lines
3.6 KiB
C++
// See PythonHost.h: the interpreter setup 40250 got from a real python27 installation.
|
|
#include "ScriptLib/StdAfx.h"
|
|
#include "PythonHost.h"
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
|
|
namespace
|
|
{
|
|
// The pending exception as text, so a failed bootstrap says what went wrong instead of leaving the
|
|
// error for the first unrelated script to trip over.
|
|
std::string take_error()
|
|
{
|
|
if (!PyErr_Occurred())
|
|
return "no exception";
|
|
|
|
PyObject *type = NULL, *value = NULL, *tb = NULL;
|
|
PyErr_Fetch(&type, &value, &tb);
|
|
PyErr_NormalizeException(&type, &value, &tb);
|
|
std::string text;
|
|
if (PyObject* str = value ? PyObject_Str(value) : NULL)
|
|
{
|
|
if (PyString_Check(str))
|
|
text = PyString_AS_STRING(str);
|
|
Py_DECREF(str);
|
|
}
|
|
if (type && text.empty())
|
|
text = ((PyTypeObject*) type)->tp_name;
|
|
Py_XDECREF(type);
|
|
Py_XDECREF(value);
|
|
Py_XDECREF(tb);
|
|
return text.empty() ? "unknown error" : text;
|
|
}
|
|
|
|
bool fail(std::string* error, const std::string& text)
|
|
{
|
|
if (error)
|
|
*error = text;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
namespace PythonHost
|
|
{
|
|
|
|
void Configure(const char* program_name)
|
|
{
|
|
// site.py lives in a prefix this interpreter does not have, the environment must not be able to
|
|
// redirect a game's script layer (PYTHONPATH/PYTHONHOME), the "could not find platform libraries"
|
|
// probe has nothing to find, and the pack directories are read-only on the mobile targets.
|
|
Py_NoSiteFlag = 1;
|
|
Py_IgnoreEnvironmentFlag = 1;
|
|
Py_FrozenFlag = 1;
|
|
Py_DontWriteBytecodeFlag = 1;
|
|
Py_SetProgramName((char*) program_name);
|
|
}
|
|
|
|
bool InstallStdLib(const char* stdlib_path, std::string* error)
|
|
{
|
|
if (!Py_IsInitialized())
|
|
return fail(error, "interpreter is not initialized");
|
|
if (!stdlib_path || !*stdlib_path)
|
|
return fail(error, "no stdlib path (set MT_PYTHON_STDLIB or pass python27.zip)");
|
|
|
|
// zipimport and the source importer both go through the C library, so the path has to be a real
|
|
// file: a pack entry or an Android asset must be staged out first (step 3c).
|
|
if (FILE* fp = fopen(stdlib_path, "rb"))
|
|
fclose(fp);
|
|
else if (FILE* dir = fopen((std::string(stdlib_path) + "/os.py").c_str(), "rb"))
|
|
fclose(dir);
|
|
else
|
|
return fail(error, std::string("cannot open ") + stdlib_path);
|
|
|
|
PySys_SetPath((char*) stdlib_path);
|
|
|
|
// Py_Initialize ran _PyCodecRegistry_Init against the then-empty path and 2.7 never retries it
|
|
// ("no codec search functions registered" for the rest of the process), so the search function is
|
|
// registered again now that encodings is importable.
|
|
PyObject* encodings = PyImport_ImportModule("encodings");
|
|
if (!encodings)
|
|
return fail(error, "import encodings: " + take_error());
|
|
PyObject* search = PyObject_GetAttrString(encodings, (char*) "search_function");
|
|
Py_DECREF(encodings);
|
|
if (!search)
|
|
return fail(error, "encodings.search_function: " + take_error());
|
|
|
|
PyObject* codecs = PyImport_ImportModule("codecs");
|
|
PyObject* registered = codecs ? PyObject_CallMethod(codecs, (char*) "register", (char*) "O", search) : NULL;
|
|
Py_DECREF(search);
|
|
Py_XDECREF(codecs);
|
|
if (!registered)
|
|
return fail(error, "codecs.register: " + take_error());
|
|
Py_DECREF(registered);
|
|
return true;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
std::string g_staged_path;
|
|
}
|
|
|
|
void SetDefaultStdLibPath(const char* stdlib_path)
|
|
{
|
|
g_staged_path = stdlib_path ? stdlib_path : "";
|
|
}
|
|
|
|
std::string DefaultStdLibPath()
|
|
{
|
|
// The environment still wins, so a developer can point a build at another stdlib without rebuilding.
|
|
if (const char* env = getenv("MT_PYTHON_STDLIB"))
|
|
return env;
|
|
// Whatever staged the zip for this platform (extension/src/python_stdlib.cpp inside Godot; nothing
|
|
// in the native tests, which pass the build tree's copy on the command line).
|
|
return g_staged_path;
|
|
}
|
|
|
|
}
|