Files
Mozilla/mozilla/extensions/python/xpcom/src/loader/pyloader.cpp
mhammond%skippinet.com.au 2d0f1e8673 Move Linux to the new loader system. This requires a shared library
version of Python (rather than the static lib generally built.)

The simplest way to get a shared library version is to install
ActivePython.

Not part of the build.


git-svn-id: svn://10.0.0.236/trunk@115884 18797224-902f-48f8-a5cc-f745e15eee43
2002-03-06 00:01:12 +00:00

327 lines
9.6 KiB
C++

/*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Original Code is the Python XPCOM language bindings.
*
* The Initial Developer of the Original Code is ActiveState Tool Corp.
* Portions created by ActiveState Tool Corp. are Copyright (C) 2000, 2001
* ActiveState Tool Corp. All Rights Reserved.
*
* Contributor(s): Mark Hammond <mhammond@skippinet.com.au> (original author)
*
*/
// pyloader
//
// Not part of the main Python _xpcom package, but a seperate, thin DLL/Library
//
// The main loader and registrar for Python. A thin DLL that is designed to live in
// the xpcom "components" directory. Simply locates and loads the standard
// _xpcom support module and transfers control to that.
#include "xp_core.h"
#include "nsIComponentLoader.h"
#include "nsIRegistry.h"
#include "nsISupports.h"
#include "nsIModule.h"
#include "nsDirectoryServiceDefs.h"
#include "nsILocalFile.h"
#include "nsXPIDLString.h"
#include <nsFileStream.h> // For console logging.
#ifdef HAVE_LONG_LONG
#undef HAVE_LONG_LONG
#endif
// Insist on dynamic loading
#define LOADER_LINKS_WITH_PYTHON
#ifdef LOADER_LINKS_WITH_PYTHON
#include "Python.h"
static PyThreadState *ptsGlobal = nsnull;
static char *PyTraceback_AsString(PyObject *exc_tb);
#endif // LOADER_LINKS_WITH_PYTHON
#ifdef XP_WIN
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif
#ifdef XP_UNIX
#include <dlfcn.h>
#include <sys/stat.h>
#endif
typedef nsresult (*pfnPyXPCOM_NSGetModule)(nsIComponentManager *servMgr,
nsIFile* location,
nsIModule** result);
pfnPyXPCOM_NSGetModule pfnEntryPoint = nsnull;
static void LogError(const char *fmt, ...);
static void LogDebug(const char *fmt, ...);
#ifdef LOADER_LINKS_WITH_PYTHON
// Ensure that any paths guaranteed by this package exist on sys.path
// Only called once as we are first loaded into the process.
void AddStandardPaths()
{
// Put {bin}\Python on the path if it exists.
nsCOMPtr<nsIFile> aFile;
nsCOMPtr<nsILocalFile> aLocalFile;
NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR, getter_AddRefs(aFile));
if (!aFile) {
LogError("The Python XPCOM loader could not locate the 'bin' directory\n");
return;
}
aFile->Append("python");
nsXPIDLCString pathBuf;
aFile->GetPath(getter_Copies(pathBuf));
PyObject *obPath = PySys_GetObject("path");
if (!obPath) {
LogError("The Python XPCOM loader could not get the Python sys.path variable\n");
return;
}
LogDebug("The Python XPCOM loader is adding '%s' to sys.path\n", (const char *)pathBuf);
PyObject *newStr = PyString_FromString(pathBuf);
PyList_Insert(obPath, 0, newStr);
Py_XDECREF(newStr);
}
#endif
extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr,
nsIFile* location,
nsIModule** result)
{
PRBool bDidInitPython = !Py_IsInitialized(); // well, I will next line, anyway :-)
if (bDidInitPython) {
Py_Initialize();
if (!Py_IsInitialized()) {
LogError("Python initialization failed!\n");
return NS_ERROR_FAILURE;
}
#ifndef NS_DEBUG
Py_OptimizeFlag = 1;
#endif
AddStandardPaths();
}
if (pfnEntryPoint == nsnull) {
PyObject *mod = PyImport_ImportModule("xpcom._xpcom");
if (mod==NULL) {
LogError("Could not import the Python XPCOM extension\n");
return NS_ERROR_FAILURE;
}
PyObject *obEntryPoint = PyObject_GetAttrString(mod, "_NSGetModule_FuncPtr");
if (obEntryPoint==NULL) {
LogError("Could not locate the Python XPCOM module entry point\n");
return NS_ERROR_FAILURE;
}
pfnEntryPoint = (pfnPyXPCOM_NSGetModule)PyLong_AsVoidPtr(obEntryPoint);
if (obEntryPoint==NULL) {
LogError("Could not convert the Python XPCOM module entry point to a function pointer\n");
return NS_ERROR_FAILURE;
}
}
// We abandon the thread-lock, as the first thing Python does
// is re-establish the lock (the Python thread-state story SUCKS!!!
if (bDidInitPython)
ptsGlobal = PyEval_SaveThread();
// Note this is never restored, and Python is never finalized!
return (*pfnEntryPoint)(servMgr, location, result);
}
// The internal helper that actually moves the
// formatted string to the target!
void LogMessage(const char *prefix, const char *pszMessageText)
{
nsOutputConsoleStream console;
console << prefix << pszMessageText;
}
// A helper for the various logging routines.
static void VLogF(const char *prefix, const char *fmt, va_list argptr)
{
char buff[512];
vsprintf(buff, fmt, argptr);
LogMessage(prefix, buff);
}
static void LogError(const char *fmt, ...)
{
va_list marker;
va_start(marker, fmt);
VLogF("PyXPCOM Loader Error: ", fmt, marker);
#ifdef LOADER_LINKS_WITH_PYTHON
// If we have a Python exception, also log that:
PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL;
PyErr_Fetch( &exc_typ, &exc_val, &exc_tb);
if (exc_typ) {
char *string1 = nsnull;
nsOutputStringStream streamout(string1);
if (exc_tb) {
const char *szTraceback = PyTraceback_AsString(exc_tb);
if (szTraceback == NULL)
streamout << "Can't get the traceback info!";
else {
streamout << "Traceback (most recent call last):\n";
streamout << szTraceback;
PyMem_Free((void *)szTraceback);
}
}
PyObject *temp = PyObject_Str(exc_typ);
if (temp) {
streamout << PyString_AsString(temp);
Py_DECREF(temp);
} else
streamout << "Can convert exception to a string!";
streamout << ": ";
if (exc_val != NULL) {
temp = PyObject_Str(exc_val);
if (temp) {
streamout << PyString_AsString(temp);
Py_DECREF(temp);
} else
streamout << "Can convert exception value to a string!";
}
streamout << "\n";
LogMessage("PyXPCOM Exception:", string1);
}
PyErr_Restore(exc_typ, exc_val, exc_tb);
#endif // LOADER_LINKS_WITH_PYTHON
}
static void LogWarning(const char *fmt, ...)
{
va_list marker;
va_start(marker, fmt);
VLogF("PyXPCOM Loader Warning: ", fmt, marker);
}
#ifdef DEBUG
static void LogDebug(const char *fmt, ...)
{
va_list marker;
va_start(marker, fmt);
VLogF("PyXPCOM Loader Debug: ", fmt, marker);
}
#else
static void LogDebug(const char *fmt, ...)
{
}
#endif
#ifdef LOADER_LINKS_WITH_PYTHON
/* Obtains a string from a Python traceback.
This is the exact same string as "traceback.print_exc" would return.
Pass in a Python traceback object (probably obtained from PyErr_Fetch())
Result is a string which must be free'd using PyMem_Free()
*/
#define TRACEBACK_FETCH_ERROR(what) {errMsg = what; goto done;}
char *PyTraceback_AsString(PyObject *exc_tb)
{
char *errMsg = NULL; /* a static that hold a local error message */
char *result = NULL; /* a valid, allocated result. */
PyObject *modStringIO = NULL;
PyObject *modTB = NULL;
PyObject *obFuncStringIO = NULL;
PyObject *obStringIO = NULL;
PyObject *obFuncTB = NULL;
PyObject *argsTB = NULL;
PyObject *obResult = NULL;
/* Import the modules we need - cStringIO and traceback */
modStringIO = PyImport_ImportModule("cStringIO");
if (modStringIO==NULL)
TRACEBACK_FETCH_ERROR("cant import cStringIO\n");
modTB = PyImport_ImportModule("traceback");
if (modTB==NULL)
TRACEBACK_FETCH_ERROR("cant import traceback\n");
/* Construct a cStringIO object */
obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO");
if (obFuncStringIO==NULL)
TRACEBACK_FETCH_ERROR("cant find cStringIO.StringIO\n");
obStringIO = PyObject_CallObject(obFuncStringIO, NULL);
if (obStringIO==NULL)
TRACEBACK_FETCH_ERROR("cStringIO.StringIO() failed\n");
/* Get the traceback.print_exception function, and call it. */
obFuncTB = PyObject_GetAttrString(modTB, "print_tb");
if (obFuncTB==NULL)
TRACEBACK_FETCH_ERROR("cant find traceback.print_tb\n");
argsTB = Py_BuildValue("OOO",
exc_tb ? exc_tb : Py_None,
Py_None,
obStringIO);
if (argsTB==NULL)
TRACEBACK_FETCH_ERROR("cant make print_tb arguments\n");
obResult = PyObject_CallObject(obFuncTB, argsTB);
if (obResult==NULL)
TRACEBACK_FETCH_ERROR("traceback.print_tb() failed\n");
/* Now call the getvalue() method in the StringIO instance */
Py_DECREF(obFuncStringIO);
obFuncStringIO = PyObject_GetAttrString(obStringIO, "getvalue");
if (obFuncStringIO==NULL)
TRACEBACK_FETCH_ERROR("cant find getvalue function\n");
Py_DECREF(obResult);
obResult = PyObject_CallObject(obFuncStringIO, NULL);
if (obResult==NULL)
TRACEBACK_FETCH_ERROR("getvalue() failed.\n");
/* And it should be a string all ready to go - duplicate it. */
if (!PyString_Check(obResult))
TRACEBACK_FETCH_ERROR("getvalue() did not return a string\n");
{ // a temp scope so I can use temp locals.
char *tempResult = PyString_AsString(obResult);
result = (char *)PyMem_Malloc(strlen(tempResult)+1);
if (result==NULL)
TRACEBACK_FETCH_ERROR("memory error duplicating the traceback string");
strcpy(result, tempResult);
} // end of temp scope.
done:
/* All finished - first see if we encountered an error */
if (result==NULL && errMsg != NULL) {
result = (char *)PyMem_Malloc(strlen(errMsg)+1);
if (result != NULL)
/* if it does, not much we can do! */
strcpy(result, errMsg);
}
Py_XDECREF(modStringIO);
Py_XDECREF(modTB);
Py_XDECREF(obFuncStringIO);
Py_XDECREF(obStringIO);
Py_XDECREF(obFuncTB);
Py_XDECREF(argsTB);
Py_XDECREF(obResult);
return result;
}
#endif // LOADER_LINKS_WITH_PYTHON