mhammond%skippinet.com.au d410bbfc5a [Bug 348426] Python extensions fail to build with libxul
r=benjamin@smedbergs.us, sr=jst


git-svn-id: svn://10.0.0.236/trunk@213164 18797224-902f-48f8-a5cc-f745e15eee43
2006-10-05 10:44:03 +00:00

284 lines
9.7 KiB
C++

/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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 the Initial Developer are Copyright (C) 2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mark Hammond <mhammond@skippinet.com.au> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
//
// This code is part of the XPCOM extensions for Python.
//
// Written May 2000 by Mark Hammond.
//
// Based heavily on the Python COM support, which is
// (c) Mark Hammond and Greg Stein.
//
// (c) 2000, ActiveState corp.
#include "PyXPCOM_std.h"
#include "nsDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsILocalFile.h"
#include "nsITimelineService.h"
#include "nspr.h" // PR_fprintf
#ifdef XP_WIN
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include "windows.h"
#endif
#ifdef XP_UNIX
#include <dlfcn.h>
#include <sys/stat.h>
#endif
static PRLock *g_lockMain = nsnull;
PYXPCOM_EXPORT PyObject *PyXPCOM_Error = NULL;
PYXPCOM_EXPORT PRBool PyXPCOM_ModuleInitialized = PR_FALSE;
PyXPCOM_INTERFACE_DEFINE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager)
PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager)
PyXPCOM_INTERFACE_DEFINE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator)
PyXPCOM_INTERFACE_DEFINE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator)
PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo)
PyXPCOM_INTERFACE_DEFINE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream)
PyXPCOM_INTERFACE_DEFINE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo)
PyXPCOM_INTERFACE_DEFINE(Py_nsIVariant, nsIVariant, PyMethods_IVariant)
////////////////////////////////////////////////////////////
// Lock/exclusion global functions.
//
PYXPCOM_EXPORT void
PyXPCOM_AcquireGlobalLock(void)
{
NS_PRECONDITION(g_lockMain != nsnull, "Cant acquire a NULL lock!");
PR_Lock(g_lockMain);
}
PYXPCOM_EXPORT void
PyXPCOM_ReleaseGlobalLock(void)
{
NS_PRECONDITION(g_lockMain != nsnull, "Cant release a NULL lock!");
PR_Unlock(g_lockMain);
}
// 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.
nsresult rv;
nsCOMPtr<nsIFile> aFile;
// XXX - this needs more thought for XULRunner - we want to stick the global
// 'python' dir on sys.path (for xpcom etc), but also want to support a way
// of adding a local application directory (in the case of xulrunner) too.
// NS_XPCOM_CURRENT_PROCESS_DIR is the XULRunner app dir (ie, where application.ini lives)
// NS_GRE_DIR is the 'bin' dir for XULRunner itself.
rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(aFile));
if (NS_FAILED(rv)) {
PyXPCOM_LogError("The Python XPCOM loader could not locate the 'bin' directory");
return;
}
aFile->Append(NS_LITERAL_STRING("python"));
nsAutoString pathBuf;
aFile->GetPath(pathBuf);
PyObject *obPath = PySys_GetObject("path");
if (!obPath) {
PyXPCOM_LogError("The Python XPCOM loader could not get the Python sys.path variable");
return;
}
// XXX - this should use the file-system encoding...
NS_LossyConvertUTF16toASCII pathCBuf(pathBuf);
#ifdef NS_DEBUG
PR_fprintf(PR_STDERR,"The Python XPCOM loader is adding '%s' to sys.path\n",
pathCBuf.get());
#endif
PyObject *newStr = PyString_FromString(pathCBuf.get());
PyList_Insert(obPath, 0, newStr);
Py_XDECREF(newStr);
// And now try and get Python to process this directory as a "site dir"
// - ie, look for .pth files, etc
nsCAutoString cmdBuf(NS_LITERAL_CSTRING("import site;site.addsitedir(r'"));
cmdBuf.Append(pathCBuf);
cmdBuf.Append(NS_LITERAL_CSTRING("')\n"));
if (0 != PyRun_SimpleString((char *)cmdBuf.get())) {
PyXPCOM_LogError("The directory '%s' could not be added as a site directory", pathCBuf.get());
PyErr_Clear();
}
// and somewhat like Python itself (site, citecustomize), we attempt
// to import "sitepyxpcom" ignoring ImportError
PyObject *mod = PyImport_ImportModule("sitepyxpcom");
if (NULL==mod) {
if (!PyErr_ExceptionMatches(PyExc_ImportError))
PyXPCOM_LogError("Failed to import 'sitepyxpcom'");
PyErr_Clear();
} else
Py_DECREF(mod);
}
static PRBool bIsInitialized = PR_FALSE;
// Our 'entry point' into initialization - just call this any time you
// like, and the world will be setup!
PYXPCOM_EXPORT void
PyXPCOM_EnsurePythonEnvironment(void)
{
// Must be thread-safe - but only while set to FALSE - so check for
// set before getting the lock - then check again after!
if (bIsInitialized)
return;
CEnterLeaveXPCOMFramework _celf;
if (bIsInitialized)
return; // another thread beat us to the init.
#if defined(XP_UNIX) && !defined(XP_MACOSX)
/* *sob* - seems necessary to open the .so as RTLD_GLOBAL. Without
this we see:
Traceback (most recent call last):
File "<string>", line 1, in ?
File "/usr/lib/python2.4/logging/__init__.py", line 29, in ?
import sys, os, types, time, string, cStringIO, traceback
ImportError: /usr/lib/python2.4/lib-dynload/time.so: undefined
symbol: PyExc_IOError
On osx, ShaneC writes that is it unnecessary (and fails anyway since
PYTHON_SO is wrong.) More clues about this welcome!
*/
dlopen(PYTHON_SO,RTLD_NOW | RTLD_GLOBAL);
#endif
PRBool bDidInitPython = !Py_IsInitialized(); // well, I will next line, anyway :-)
if (bDidInitPython) {
NS_TIMELINE_START_TIMER("PyXPCOM: Python initializing");
Py_Initialize(); // NOTE: We never finalize Python!!
#ifndef NS_DEBUG
Py_OptimizeFlag = 1;
#endif // NS_DEBUG
// Must force Python to start using thread locks, as
// this is certainly a threaded environment we are playing in
PyEval_InitThreads();
NS_TIMELINE_STOP_TIMER("PyXPCOM: Python initializing");
NS_TIMELINE_MARK_TIMER("PyXPCOM: Python initializing");
}
// Get the Python interpreter state
NS_TIMELINE_START_TIMER("PyXPCOM: Python threadstate setup");
PyGILState_STATE state = PyGILState_Ensure();
#ifdef MOZ_TIMELINE
// If the timeline service is installed, see if we can install our hooks.
if (NULL==PyImport_ImportModule("timeline_hook")) {
if (!PyErr_ExceptionMatches(PyExc_ImportError))
PyXPCOM_LogError("Failed to import 'timeline_hook'");
PyErr_Clear(); // but don't care if we can't.
}
#endif
// Make sure we have _something_ as sys.argv.
if (PySys_GetObject("argv")==NULL) {
PyObject *path = PyList_New(0);
PyObject *str = PyString_FromString("");
PyList_Append(path, str);
PySys_SetObject("argv", path);
Py_XDECREF(path);
Py_XDECREF(str);
}
// Add the standard extra paths we assume
AddStandardPaths();
// The exception object pyxpcom uses.
if (PyXPCOM_Error == NULL) {
PRBool rc = PR_FALSE;
PyObject *mod = NULL;
mod = PyImport_ImportModule("xpcom");
if (mod!=NULL) {
PyXPCOM_Error = PyObject_GetAttrString(mod, "Exception");
Py_DECREF(mod);
}
rc = (PyXPCOM_Error != NULL);
}
// Register our custom interfaces.
Py_nsISupports::InitType();
Py_nsIComponentManager::InitType();
Py_nsIInterfaceInfoManager::InitType();
Py_nsIEnumerator::InitType();
Py_nsISimpleEnumerator::InitType();
Py_nsIInterfaceInfo::InitType();
Py_nsIInputStream::InitType();
Py_nsIClassInfo::InitType();
Py_nsIVariant::InitType();
bIsInitialized = PR_TRUE;
// import the xpcom module itself to setup the loggers etc.
// We must do this after setting bIsInitialized, as it too tries to
// initialize!
PyImport_ImportModule("xpcom");
// If we initialized Python, then we will also have acquired the thread
// lock. In that case, we want to leave it unlocked, so other threads
// are free to run, even if they aren't running Python code.
PyGILState_Release(bDidInitPython ? PyGILState_UNLOCKED : state);
NS_TIMELINE_STOP_TIMER("PyXPCOM: Python threadstate setup");
NS_TIMELINE_MARK_TIMER("PyXPCOM: Python threadstate setup");
}
void pyxpcom_construct(void)
{
// Create the lock we will use to ensure startup thread
// safetly, but don't actually initialize Python yet.
g_lockMain = PR_NewLock();
return; // PR_TRUE;
}
void pyxpcom_destruct(void)
{
PR_DestroyLock(g_lockMain);
}
// Yet another attempt at cross-platform library initialization and finalization.
struct DllInitializer {
DllInitializer() {
pyxpcom_construct();
}
~DllInitializer() {
pyxpcom_destruct();
}
} dll_initializer;