// mtpython: the embedded CPython 2.7.18 starts, every statically linked module imports, and the // interpreter runs code (docs/PORT-PLAN.md 批次 2P step 1). Started the way CPythonLauncher does // (no site, no environment), then sys.path is replaced by the host, as tools/py_embed_android/main.c // does on the device. // // py_embed_test [stdlib dir or python27.zip] #include #include #include #include #include #include static int g_failures = 0; #define CHECK(cond) \ do { \ if (!(cond)) \ { \ std::fprintf(stderr, "%s:%d: CHECK(%s)\n", __FILE__, __LINE__, #cond); \ ++g_failures; \ } \ } while (0) int main(int argc, char** argv) { // CPythonLauncher::Create starts the interpreter without site, without environment variables and // without a filesystem prefix; sys.path is handed over by the host afterwards. Py_NoSiteFlag = 1; Py_IgnoreEnvironmentFlag = 1; Py_FrozenFlag = 1; Py_DontWriteBytecodeFlag = 1; Py_SetProgramName(argv[0]); Py_Initialize(); CHECK(Py_IsInitialized()); // Without a stdlib on sys.path the interpreter still runs, but anything that imports a .py // (cPickle -> copy_reg, the codec registry -> encodings) cannot work; the host always supplies one. const std::string stdlib = argc > 1 ? argv[1] : ""; if (!stdlib.empty()) { // Py_Initialize already ran _PyCodecRegistry_Init against the empty path and 2.7 never retries // ("no codec search functions registered"), so the host re-registers encodings.search_function // after handing over sys.path. CPythonLauncher will have to do the same. const std::string boot = "import sys\nsys.path[:] = ['" + stdlib + "']\nimport codecs, encodings\ncodecs.register(encodings.search_function)\n"; CHECK(PyRun_SimpleString(boot.c_str()) == 0); } // The built-in table is what config/config.c (shared by every platform) declares. std::vector names; for (const _inittab* t = PyImport_Inittab; t && t->name; ++t) names.push_back(t->name); CHECK(names.size() == 39); // config/config.c: 30 from Setup.static + marshal/imp/_ast/gc/_warnings + __main__/__builtin__/sys/exceptions size_t imported = 0; for (const std::string& name : names) { if (name == "xxsubtype") // the reference Setup builds it, nothing imports it continue; if (name == "__main__") // importing it re-enters the running module continue; if (stdlib.empty() && name == "cPickle") // needs copy_reg from the stdlib continue; if (PyObject* m = PyImport_ImportModule(name.c_str())) { ++imported; Py_DECREF(m); } else { std::fprintf(stderr, "import %s failed\n", name.c_str()); PyErr_Print(); ++g_failures; } } // The modules the 40250 scripts reach for first, as the spike measured them. for (const char* need : {"posix", "time", "math", "_struct", "operator", "itertools", "_collections", "cStringIO", "cPickle", "_locale", "binascii", "datetime", "zipimport", "_codecs"}) CHECK(std::find(names.begin(), names.end(), need) != names.end()); CHECK(PyRun_SimpleString("import sys, time, math, _struct\n" "assert sys.version.startswith('2.7.18'), sys.version\n" "assert _struct.calcsize('