Beispiel #1
0
void
Py_Exit(int sts)
{
    if (Py_FinalizeEx() < 0) {
        sts = 120;
    }

    exit(sts);
}
Beispiel #2
0
/* 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;
}
Beispiel #3
0
void
Py_Finalize(void)
{
    Py_FinalizeEx();
}
Beispiel #4
0
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;
}