C++程序  |  125行  |  4.76 KB

// Copyright 2017 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "launcher_internal.h"

#include <Python.h>
#include <android-base/file.h>
#include <osdefs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>

int main(int argc, char *argv[]) {
  int result = 0 /* Used to mark if current program runs with success/failure. */;

  // Clear PYTHONPATH and PYTHONHOME so Python doesn't attempt to check the local
  // disk for Python modules to load. The value of PYTHONHOME will replace "prefix"
  // and "exe_prefix" based on the description in getpath.c.
  // Please don't use PYTHONPATH and PYTHONHOME within user program.
  // TODO(nanzhang): figure out if unsetenv("PYTHONPATH") is better.
  unsetenv(const_cast<char *>("PYTHONPATH"));
  // TODO(nanzhang): figure out if Py_SetPythonHome() is better.
  unsetenv(const_cast<char *>("PYTHONHOME"));
  // PYTHONEXECUTABLE is only used on MacOs X, when the Python interpreter
  // embedded in an application bundle. It is not sure that we have this use case
  // for Android hermetic Python. So override this environment variable to empty
  // for now to make our self-contained environment more strict.
  // For user (.py) program, it can access hermetic .par file path through
  // sys.argv[0].
  unsetenv(const_cast<char *>("PYTHONEXECUTABLE"));

  // Resolving absolute path based on argv[0] is not reliable since it may
  // include something unusable, too bad.
  // android::base::GetExecutablePath() also handles for Darwin/Windows.
  std::string executable_path = android::base::GetExecutablePath();

  argv[0] = strdup(executable_path.c_str());
  // argv[0] is used for setting internal path, and Python sys.argv[0]. It
  // should not exceed MAXPATHLEN defined for CPython.
  if (!argv[0] || strlen(argv[0]) > MAXPATHLEN) {
    fprintf(stderr, "The executable path %s is NULL or of invalid length.\n", argv[0]);
    return 1;
  }

  // For debugging/logging purpose, set stdin/stdout/stderr unbuffered through
  // environment variable.
  // TODO(nanzhang): Set Py_VerboseFlag if more debugging requests needed.
  const char *unbuffered_env = getenv("PYTHONUNBUFFERED");
  if (unbuffered_env && unbuffered_env[0]) {
    #if defined(MS_WINDOWS) || defined(__CYGWIN__)
      _setmode(fileno(stdin), O_BINARY);
      _setmode(fileno(stdout), O_BINARY);
    #endif
    #ifdef HAVE_SETVBUF
      setvbuf(stdin,  (char *)NULL, _IONBF, BUFSIZ);
      setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
      setvbuf(stderr, (char *)NULL, _IONBF, BUFSIZ);
    #else /* !HAVE_SETVBUF */
      setbuf(stdin,  (char *)NULL);
      setbuf(stdout, (char *)NULL);
      setbuf(stderr, (char *)NULL);
    #endif /* !HAVE_SETVBUF */
  }
  //For debugging/logging purpose, Warning control.
  //Python’s warning machinery by default prints warning messages to sys.stderr.
  //The full form of argument is:action:message:category:module:line
  char *warnings_env = getenv("PYTHONWARNINGS");
  if (warnings_env && warnings_env[0]) {
      char *warnings_buf, *warning;

      // Note: "new" operation; we need free this chuck of data after use.
      warnings_buf = new char[strlen(warnings_env) + 1];
      if (warnings_buf == NULL)
          Py_FatalError(
             "not enough memory to copy PYTHONWARNINGS");
      strcpy(warnings_buf, warnings_env);
      for (warning = strtok(warnings_buf, ",");
           warning != NULL;
           warning = strtok(NULL, ","))
          PySys_AddWarnOption(warning);
      delete[] warnings_buf;
  }

  // Always enable Python "-s" option. We don't need user-site directories,
  // everything's supposed to be hermetic.
  Py_NoUserSiteDirectory = 1;

  Py_SetProgramName(argv[0]);
  Py_Initialize();
  PySys_SetArgvEx(argc, argv, 0);

  // Set sys.executable to None. The real executable is available as
  // sys.argv[0], and too many things assume sys.executable is a regular Python
  // binary, which isn't available. By setting it to None we get clear errors
  // when people try to use it.
  if (PySys_SetObject(const_cast<char *>("executable"), Py_None) < 0) {
    PyErr_Print();
    result = 1;
    goto error;
  }

  result = android::cpython2::python_launcher::RunEntryPointOrMainModule(argv[0]);
  if (result < 0) {
    PyErr_Print();
    goto error;
  }

error:
  Py_Finalize();

  free(argv[0]);
  exit(abs(result));
}