void Py_Exit(int sts) { if (Py_FinalizeEx() < 0) { sts = 120; } exit(sts); }
/* int main(int argc, char **argv) { */ int main(int argc, char *argv[]) { char *env_argument = NULL; char *env_entrypoint = NULL; char *env_logname = NULL; char entrypoint[ENTRYPOINT_MAXLEN]; int ret = 0; FILE *fd; LOGP("Initializing Python for Android"); // Set a couple of built-in environment vars: setenv("P4A_BOOTSTRAP", bootstrap_name, 1); // env var to identify p4a to applications env_argument = getenv("ANDROID_ARGUMENT"); setenv("ANDROID_APP_PATH", env_argument, 1); env_entrypoint = getenv("ANDROID_ENTRYPOINT"); env_logname = getenv("PYTHON_NAME"); if (!getenv("ANDROID_UNPACK")) { /* ANDROID_UNPACK currently isn't set in services */ setenv("ANDROID_UNPACK", env_argument, 1); } if (env_logname == NULL) { env_logname = "python"; setenv("PYTHON_NAME", "python", 1); } // Set additional file-provided environment vars: LOGP("Setting additional env vars from p4a_env_vars.txt"); char env_file_path[256]; snprintf(env_file_path, sizeof(env_file_path), "%s/p4a_env_vars.txt", getenv("ANDROID_UNPACK")); FILE *env_file_fd = fopen(env_file_path, "r"); if (env_file_fd) { char* line = NULL; size_t len = 0; while (getline(&line, &len, env_file_fd) != -1) { if (strlen(line) > 0) { char *eqsubstr = strstr(line, "="); if (eqsubstr) { size_t eq_pos = eqsubstr - line; // Extract name: char env_name[256]; strncpy(env_name, line, sizeof(env_name)); env_name[eq_pos] = '\0'; // Extract value (with line break removed: char env_value[256]; strncpy(env_value, (char*)(line + eq_pos + 1), sizeof(env_value)); if (strlen(env_value) > 0 && env_value[strlen(env_value)-1] == '\n') { env_value[strlen(env_value)-1] = '\0'; if (strlen(env_value) > 0 && env_value[strlen(env_value)-1] == '\r') { // Also remove windows line breaks (\r\n) env_value[strlen(env_value)-1] = '\0'; } } // Set value: setenv(env_name, env_value, 1); } } } fclose(env_file_fd); } else { LOGP("Warning: no p4a_env_vars.txt found / failed to open!"); } LOGP("Changing directory to the one provided by ANDROID_ARGUMENT"); LOGP(env_argument); chdir(env_argument); #if PY_MAJOR_VERSION < 3 Py_NoSiteFlag=1; #endif #if PY_MAJOR_VERSION < 3 Py_SetProgramName("android_python"); #else Py_SetProgramName(L"android_python"); #endif #if PY_MAJOR_VERSION >= 3 /* our logging module for android */ PyImport_AppendInittab("androidembed", initandroidembed); #endif LOGP("Preparing to initialize python"); // Set up the python path char paths[256]; char crystax_python_dir[256]; snprintf(crystax_python_dir, 256, "%s/crystax_python", getenv("ANDROID_UNPACK")); char python_bundle_dir[256]; snprintf(python_bundle_dir, 256, "%s/_python_bundle", getenv("ANDROID_UNPACK")); if (dir_exists(crystax_python_dir) || dir_exists(python_bundle_dir)) { if (dir_exists(crystax_python_dir)) { LOGP("crystax_python exists"); snprintf(paths, 256, "%s/stdlib.zip:%s/modules", crystax_python_dir, crystax_python_dir); } if (dir_exists(python_bundle_dir)) { LOGP("_python_bundle dir exists"); snprintf(paths, 256, "%s/stdlib.zip:%s/modules", python_bundle_dir, python_bundle_dir); } LOGP("calculated paths to be..."); LOGP(paths); #if PY_MAJOR_VERSION >= 3 wchar_t *wchar_paths = Py_DecodeLocale(paths, NULL); Py_SetPath(wchar_paths); #endif LOGP("set wchar paths..."); } else { // We do not expect to see crystax_python any more, so no point // reminding the user about it. If it does exist, we'll have // logged it earlier. LOGP("_python_bundle does not exist"); } Py_Initialize(); #if PY_MAJOR_VERSION < 3 // Can't Py_SetPath in python2 but we can set PySys_SetPath, which must // be applied after Py_Initialize rather than before like Py_SetPath #if PY_MICRO_VERSION >= 15 // Only for python native-build PySys_SetPath(paths); #endif PySys_SetArgv(argc, argv); #endif LOGP("Initialized python"); /* ensure threads will work. */ LOGP("AND: Init threads"); PyEval_InitThreads(); #if PY_MAJOR_VERSION < 3 initandroidembed(); #endif PyRun_SimpleString("import androidembed\nandroidembed.log('testing python " "print redirection')"); /* inject our bootstrap code to redirect python stdin/stdout * replace sys.path with our path */ PyRun_SimpleString("import sys, posix\n"); if (dir_exists("lib")) { /* If we built our own python, set up the paths correctly. * This is only the case if we are using the python2legacy recipe */ LOGP("Setting up python from ANDROID_APP_PATH"); PyRun_SimpleString("private = posix.environ['ANDROID_APP_PATH']\n" "argument = posix.environ['ANDROID_ARGUMENT']\n" "sys.path[:] = [ \n" " private + '/lib/python27.zip', \n" " private + '/lib/python2.7/', \n" " private + '/lib/python2.7/lib-dynload/', \n" " private + '/lib/python2.7/site-packages/', \n" " argument ]\n"); } char add_site_packages_dir[256]; if (dir_exists(crystax_python_dir)) { snprintf(add_site_packages_dir, 256, "sys.path.append('%s/site-packages')", crystax_python_dir); PyRun_SimpleString("import sys\n" "sys.argv = ['notaninterpreterreally']\n" "from os.path import realpath, join, dirname"); PyRun_SimpleString(add_site_packages_dir); /* "sys.path.append(join(dirname(realpath(__file__)), 'site-packages'))") */ PyRun_SimpleString("sys.path = ['.'] + sys.path"); } if (dir_exists(python_bundle_dir)) { snprintf(add_site_packages_dir, 256, "sys.path.append('%s/site-packages')", python_bundle_dir); PyRun_SimpleString("import sys\n" "sys.argv = ['notaninterpreterreally']\n" "from os.path import realpath, join, dirname"); PyRun_SimpleString(add_site_packages_dir); /* "sys.path.append(join(dirname(realpath(__file__)), 'site-packages'))") */ PyRun_SimpleString("sys.path = ['.'] + sys.path"); } PyRun_SimpleString( "class LogFile(object):\n" " def __init__(self):\n" " self.buffer = ''\n" " def write(self, s):\n" " s = self.buffer + s\n" " lines = s.split(\"\\n\")\n" " for l in lines[:-1]:\n" " androidembed.log(l)\n" " self.buffer = lines[-1]\n" " def flush(self):\n" " return\n" "sys.stdout = sys.stderr = LogFile()\n" "print('Android path', sys.path)\n" "import os\n" "print('os.environ is', os.environ)\n" "print('Android kivy bootstrap done. __name__ is', __name__)"); #if PY_MAJOR_VERSION < 3 PyRun_SimpleString("import site; print site.getsitepackages()\n"); #endif LOGP("AND: Ran string"); /* run it ! */ LOGP("Run user program, change dir and execute entrypoint"); /* Get the entrypoint, search the .pyo then .py */ char *dot = strrchr(env_entrypoint, '.'); #if PY_MAJOR_VERSION > 2 char *ext = ".pyc"; #else char *ext = ".pyo"; #endif if (dot <= 0) { LOGP("Invalid entrypoint, abort."); return -1; } if (strlen(env_entrypoint) > ENTRYPOINT_MAXLEN - 2) { LOGP("Entrypoint path is too long, try increasing ENTRYPOINT_MAXLEN."); return -1; } if (!strcmp(dot, ext)) { if (!file_exists(env_entrypoint)) { /* fallback on .py */ strcpy(entrypoint, env_entrypoint); entrypoint[strlen(env_entrypoint) - 1] = '\0'; LOGP(entrypoint); if (!file_exists(entrypoint)) { LOGP("Entrypoint not found (.pyc/.pyo, fallback on .py), abort"); return -1; } } else { strcpy(entrypoint, env_entrypoint); } } else if (!strcmp(dot, ".py")) { /* if .py is passed, check the pyo version first */ strcpy(entrypoint, env_entrypoint); entrypoint[strlen(env_entrypoint) + 1] = '\0'; #if PY_MAJOR_VERSION > 2 entrypoint[strlen(env_entrypoint)] = 'c'; #else entrypoint[strlen(env_entrypoint)] = 'o'; #endif if (!file_exists(entrypoint)) { /* fallback on pure python version */ if (!file_exists(env_entrypoint)) { LOGP("Entrypoint not found (.py), abort."); return -1; } strcpy(entrypoint, env_entrypoint); } } else { LOGP("Entrypoint have an invalid extension (must be .py or .pyc/.pyo), abort."); return -1; } // LOGP("Entrypoint is:"); // LOGP(entrypoint); fd = fopen(entrypoint, "r"); if (fd == NULL) { LOGP("Open the entrypoint failed"); LOGP(entrypoint); return -1; } /* run python ! */ ret = PyRun_SimpleFile(fd, entrypoint); fclose(fd); if (PyErr_Occurred() != NULL) { ret = 1; PyErr_Print(); /* This exits with the right code if SystemExit. */ PyObject *f = PySys_GetObject("stdout"); if (PyFile_WriteString( "\n", f)) /* python2 used Py_FlushLine, but this no longer exists */ PyErr_Clear(); } LOGP("Python for android ended."); /* Shut down: since regular shutdown causes issues sometimes (seems to be an incomplete shutdown breaking next launch) we'll use sys.exit(ret) to shutdown, since that one works. Reference discussion: https://github.com/kivy/kivy/pull/6107#issue-246120816 */ char terminatecmd[256]; snprintf( terminatecmd, sizeof(terminatecmd), "import sys; sys.exit(%d)\n", ret ); PyRun_SimpleString(terminatecmd); /* This should never actually be reached, but we'll leave the clean-up * here just to be safe. */ #if PY_MAJOR_VERSION < 3 Py_Finalize(); LOGP("Unexpectedly reached Py_FinalizeEx(), but was successful."); #else if (Py_FinalizeEx() != 0) // properly check success on Python 3 LOGP("Unexpectedly reached Py_FinalizeEx(), and got error!"); else LOGP("Unexpectedly reached Py_FinalizeEx(), but was successful."); #endif return ret; }
void Py_Finalize(void) { Py_FinalizeEx(); }
int Py_FrozenMain(int argc, char **argv) { _PyInitError err = _PyRuntime_Initialize(); if (_Py_INIT_FAILED(err)) { fprintf(stderr, "Fatal Python error: %s\n", err.msg); fflush(stderr); exit(1); } const char *p; int i, n, sts = 1; int inspect = 0; int unbuffered = 0; char *oldloc = NULL; wchar_t **argv_copy = NULL; /* We need a second copies, as Python might modify the first one. */ wchar_t **argv_copy2 = NULL; if (argc > 0) { argv_copy = PyMem_RawMalloc(sizeof(wchar_t*) * argc); argv_copy2 = PyMem_RawMalloc(sizeof(wchar_t*) * argc); if (!argv_copy || !argv_copy2) { fprintf(stderr, "out of memory\n"); goto error; } } _PyCoreConfig config = _PyCoreConfig_INIT; config._frozen = 1; /* Suppress errors from getpath.c */ if ((p = Py_GETENV("PYTHONINSPECT")) && *p != '\0') inspect = 1; if ((p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0') unbuffered = 1; if (unbuffered) { setbuf(stdin, (char *)NULL); setbuf(stdout, (char *)NULL); setbuf(stderr, (char *)NULL); } oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL)); if (!oldloc) { fprintf(stderr, "out of memory\n"); goto error; } setlocale(LC_ALL, ""); for (i = 0; i < argc; i++) { argv_copy[i] = Py_DecodeLocale(argv[i], NULL); argv_copy2[i] = argv_copy[i]; if (!argv_copy[i]) { fprintf(stderr, "Unable to decode the command line argument #%i\n", i + 1); argc = i; goto error; } } setlocale(LC_ALL, oldloc); PyMem_RawFree(oldloc); oldloc = NULL; #ifdef MS_WINDOWS PyInitFrozenExtensions(); #endif /* MS_WINDOWS */ if (argc >= 1) Py_SetProgramName(argv_copy[0]); err = _Py_InitializeFromConfig(&config); /* No need to call _PyCoreConfig_Clear() since we didn't allocate any memory: program_name is a constant string. */ if (_Py_INIT_FAILED(err)) { _Py_FatalInitError(err); } #ifdef MS_WINDOWS PyWinFreeze_ExeInit(); #endif if (Py_VerboseFlag) fprintf(stderr, "Python %s\n%s\n", Py_GetVersion(), Py_GetCopyright()); PySys_SetArgv(argc, argv_copy); n = PyImport_ImportFrozenModule("__main__"); if (n == 0) Py_FatalError("__main__ not frozen"); if (n < 0) { PyErr_Print(); sts = 1; } else sts = 0; if (inspect && isatty((int)fileno(stdin))) sts = PyRun_AnyFile(stdin, "<stdin>") != 0; #ifdef MS_WINDOWS PyWinFreeze_ExeTerm(); #endif if (Py_FinalizeEx() < 0) { sts = 120; } error: PyMem_RawFree(argv_copy); if (argv_copy2) { for (i = 0; i < argc; i++) PyMem_RawFree(argv_copy2[i]); PyMem_RawFree(argv_copy2); } PyMem_RawFree(oldloc); return sts; }