[Zope-Perl] features.
Gisle Aas
gisle@ActiveState.com
01 Feb 2001 16:46:52 -0800
Gisle Aas <gisle@ActiveState.com> writes:
> > 7. Relatedly, do we know of a stock
> > Python/Perl combination that does not require patching of Python?
> > I'm using Zope-Perl happily with AS Perl 623 and stock Python 1.5.2
> > on Windows. Are there particular configurations which require
> > patching? If we adopt Python 2.X, will we still potentially
> > require that folks build their own patched Python? It's not
> > really clear from the docs under what configurations you need
> > to patch.
>
> The patching is needed on platforms that use dlopen() to load dynamic
> libraries. This include Linux and Solaris. I don't know what the
> requirements are for other Unix platforms. For windows no patching
> should be needed.
>
> If the Python dist provide the "dl" module then it should actually be
> possible to avoid patching even on Linux and Solaris. The RTLD_GLOBAL
> can actually be turned on after the library has been loaded by code
> like this:
>
> import perl # python will load it with dlopen() the standard way
>
> # turn on the RTLD_GLOBAL flag for the perl module so that perl
> # can load perl XS-extensions.
> try:
> import dl
> dl.open(perl.__file__, dl.RTLD_NOW | dl.RTLD_GLOBAL)
> except:
> pass
>
> # we should now be able to use perl extensions
> perl.eval("use Socket");
>
> One problem is that this technique appears to require glibc-2.2 to
> work and current Linux distributions have not really moved there yet.
This is a better hack. After this patch to pyperl there should not be
any need for patching neither perl nor python on Linux or Solaris. I
can now build pyperl on top of the standard Active{Perl,Python}
distributions.
After the patch 'import perl' will actually just load a fake module
("dlhack.c") whose only purpose is to track down the real module and
dlopen(..., RTLD_GLOBAL) it. After that everything works as it
should. The idea for this cool workaround popped out of Sarathy's
head last week.
Regards,
Gisle
# To apply this patch, chdir to you source directory and enter
#
# /bin/sh <this-file>
# patch -p1 -N < <this-file>
touch dlhack.c
exit
Index: MANIFEST
####### pyperl/ => pyperl
--- pyperl.old/MANIFEST Thu Feb 1 16:29:28 2001
+++ pyperl/MANIFEST Thu Feb 1 16:29:55 2001
@@ -5,6 +5,7 @@
TODO
dbi-test.py
dbi.py
+dlhack.c
lang_lock.c
lang_lock.h
lang_map.c
Index: dlhack.c
####### pyperl/ => pyperl
--- /dev/null Tue May 5 13:32:27 1998
+++ pyperl/dlhack.c Thu Feb 1 16:29:55 2001
@@ -0,0 +1,50 @@
+#include <Python.h>
+#include <dlfcn.h>
+
+/* This is a fake perl module that will look for the real thing ('perl2.so')
+ * in sys.path and then load this one with the RTLD_GLOBAL set in order to
+ * make the symbols available for extension modules that perl might load.
+ */
+
+extern void initperl()
+{
+ void* handle;
+ int i, npath, len;
+ char buf[1024];
+
+ PyObject *path = PySys_GetObject("path");
+ if (path == NULL || !PyList_Check(path)) {
+ PyErr_SetString(PyExc_ImportError,
+ "sys.path must be a list of directory names");
+ return;
+ }
+
+ npath = PyList_Size(path);
+ for (i = 0; i < npath; i++) {
+ PyObject *v = PyList_GetItem(path, i);
+ if (!PyString_Check(v))
+ continue;
+ len = PyString_Size(v);
+ if (len + 10 >= sizeof(buf))
+ continue; /* Too long */
+ strcpy(buf, PyString_AsString(v));
+ if (buf[0] != '/')
+ continue; /* Not absolute */
+ if (strlen(buf) != len)
+ continue; /* v contains '\0' */
+ strcpy(buf+len, "/perl2.so");
+
+ handle = dlopen(buf, RTLD_NOW | RTLD_GLOBAL);
+ if (handle) {
+ void (*f)() = dlsym(handle, "initperl2");
+ if (f) {
+ f();
+ }
+ else {
+ PyErr_SetString(PyExc_ImportError, "initperl2 entry point not found");
+ }
+ return;
+ }
+ }
+ PyErr_SetString(PyExc_ImportError, "perl2.so not found");
+}
Index: patches/README
####### pyperl/ => pyperl
--- pyperl.old/patches/README Thu Feb 1 16:29:28 2001
+++ pyperl/patches/README Thu Feb 1 16:29:55 2001
@@ -15,6 +15,8 @@
inclusion in upcoming perl-5.6.1 (change #6125).
python-20-dynload-global
+ THIS PATCH SHOULD NOT BE NEEDED ANY MORE!!
+
This patch to python-2.0 is needed to be able to load
XS modules with the perl embedded in python. It make sure
dynamic objects are loaded with the RTLD_GLOBAL flag, so
Index: perlmodule.c
####### pyperl/ => pyperl
--- pyperl.old/perlmodule.c Thu Feb 1 16:29:28 2001
+++ pyperl/perlmodule.c Thu Feb 1 16:29:55 2001
@@ -730,29 +730,6 @@
return pyo;
}
-#if 0
-#include <dlfcn.h>
-
-static PyObject *
-dl_make_global(self, args, keywds)
- PyObject *self;
- PyObject *args;
- PyObject *keywds;
-{
- char *file;
- void *handle;
-
- if (!PyArg_ParseTuple(args, "s:perl.dl_global", &file))
- return NULL;
- handle = dlopen(file, RTLD_NOW | RTLD_GLOBAL);
- if (!handle)
- fprintf(stderr, "dlopen: %s\n", dlerror());
- if (handle)
- dlclose(handle);
- return Py_BuildValue("");
-}
-#endif
-
static PyMethodDef PerlMethods[] = {
{ "call", call, METH_VARARGS|METH_KEYWORDS},
{ "call_tuple", call_tuple, METH_VARARGS|METH_KEYWORDS},
@@ -766,15 +743,16 @@
{ "defined", defined, METH_VARARGS},
{ "get_ref", get_ref, METH_VARARGS|METH_KEYWORDS},
{ "array", array, METH_VARARGS},
-#ifdef RTLD_GLOBAL
- { "dl_make_global", dl_make_global, METH_VARARGS},
-#endif
{ NULL, NULL } /* Sentinel */
};
void
+#ifdef DL_HACK
+initperl2()
+#else
initperl()
+#endif
{
PyObject *m, *d;
#ifndef MULTI_PERL
Index: setup.py
####### pyperl/ => pyperl
--- pyperl.old/setup.py Thu Feb 1 16:29:28 2001
+++ pyperl/setup.py Thu Feb 1 16:29:55 2001
@@ -1,5 +1,7 @@
#!/usr/bin/env python
+from distutils.core import setup, Extension
+
DEBUG = 0
perl = 'perl'
@@ -17,6 +19,7 @@
perl_ldopts = p.readline()
p.close()
+ext_name = "perl"
include_dirs = []
macros = []
cc_extra = []
@@ -42,6 +45,8 @@
o_extra = []
sym_extra = []
+extra_ext = []
+
# XXX hack name to get it to compile as C++ file on Windows
svrv_object_c_name = "svrv_object.c"
if sys.platform[:3] == "win":
@@ -51,6 +56,7 @@
os.chmod(svrv_object_c_name, 0777)
os.unlink(svrv_object_c_name)
shutil.copy("svrv_object.c", svrv_object_c_name)
+
sources = ['perlmodule.c',
'lang_lock.c',
'lang_map.c',
@@ -84,6 +90,18 @@
system(perl + " -MExtUtils::Embed -e xsinit")
sources.append('perlxsi.c');
+ # Try to figure out if we use dlopen on this platform
+ p = popen(perl + ' -V:dlsrc')
+ dlsrc = p.readline()
+ p.close()
+ if dlsrc == "dlsrc='dl_dlopen.xs';\n":
+ ext_name = "perl2"
+ cc_extra.append("-DDL_HACK")
+ extra_ext.append(Extension(name = "perl",
+ sources = ["dlhack.c"],
+ libraries = ["dl"],
+ ))
+
if MULTI_PERL:
cc_extra.append("-DMULTI_PERL")
@@ -103,8 +121,6 @@
sym_extra.append('sv2pyo')
sym_extra.append('pyo2sv')
-from distutils.core import setup, Extension
-
if DEBUG:
print "Macros:", macros
print "Include: ", include_dirs
@@ -114,6 +130,21 @@
print "Lib dirs:", lib_dirs
print "Extra LD: ", ld_extra
+ext_modules = []
+ext_modules.append(Extension(name = ext_name,
+ sources = sources,
+ define_macros = macros,
+ include_dirs = include_dirs,
+ extra_compile_args = cc_extra,
+
+ extra_objects = o_extra,
+ libraries = libs,
+ library_dirs = lib_dirs,
+ extra_link_args = ld_extra,
+ export_symbols = sym_extra,
+ ))
+ext_modules.extend(extra_ext)
+
setup (name = "pyperl",
version = "1.0.beta6",
description = "Embed a perl interpreter",
@@ -121,17 +152,5 @@
author = "ActiveState Tool Corp.",
author_email= "gisle@ActiveState.com",
py_modules = ['dbi', 'perlpickle'],
- ext_modules = [Extension(name = "perl",
- sources = sources,
- define_macros = macros,
- include_dirs = include_dirs,
- extra_compile_args = cc_extra,
-
- extra_objects = o_extra,
- libraries = libs,
- library_dirs = lib_dirs,
- extra_link_args = ld_extra,
- export_symbols = sym_extra,
- ),
- ],
+ ext_modules = ext_modules,
)