[Python-checkins] r41927 - in sandbox/trunk/setuptools: setuptools/__init__.py setuptools/command/build_ext.py setuptools/dist.py setuptools/extension.py tests tests/shlib_test tests/shlib_test/hello.c tests/shlib_test/hello.pyx tests/shlib_test/hellolib.c tests/shlib_test/setup.py tests/shlib_test/test_hello.py

phillip.eby python-checkins at python.org
Fri Jan 6 00:14:27 CET 2006


Author: phillip.eby
Date: Fri Jan  6 00:14:21 2006
New Revision: 41927

Added:
   sandbox/trunk/setuptools/tests/
   sandbox/trunk/setuptools/tests/shlib_test/
   sandbox/trunk/setuptools/tests/shlib_test/hello.c   (contents, props changed)
   sandbox/trunk/setuptools/tests/shlib_test/hello.pyx   (contents, props changed)
   sandbox/trunk/setuptools/tests/shlib_test/hellolib.c   (contents, props changed)
   sandbox/trunk/setuptools/tests/shlib_test/setup.py   (contents, props changed)
   sandbox/trunk/setuptools/tests/shlib_test/test_hello.py   (contents, props changed)
Modified:
   sandbox/trunk/setuptools/setuptools/__init__.py
   sandbox/trunk/setuptools/setuptools/command/build_ext.py
   sandbox/trunk/setuptools/setuptools/dist.py
   sandbox/trunk/setuptools/setuptools/extension.py
Log:
First draft of shared library build support.  See tests/shlib_test
for a trivial example.  This has only been tested on Windows with
a MinGW compiler, and the Mac OS support isn't finished.  Testing
w/other platforms+compilers would be helpful.


Modified: sandbox/trunk/setuptools/setuptools/__init__.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/__init__.py	(original)
+++ sandbox/trunk/setuptools/setuptools/__init__.py	Fri Jan  6 00:14:21 2006
@@ -1,8 +1,7 @@
-
 """Extensions to the 'distutils' for large or complex distributions"""
+from setuptools.extension import Extension, SharedLibrary
 from setuptools.dist import Distribution, Feature, _get_unpatched
 import distutils.core, setuptools.command
-from setuptools.extension import Extension
 from setuptools.depends import Require
 from distutils.core import Command as _Command
 from distutils.util import convert_path

Modified: sandbox/trunk/setuptools/setuptools/command/build_ext.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/command/build_ext.py	(original)
+++ sandbox/trunk/setuptools/setuptools/command/build_ext.py	Fri Jan  6 00:14:21 2006
@@ -7,9 +7,11 @@
 
 import os, sys
 from distutils.file_util import copy_file
+from setuptools.extension import SharedLibrary
+from distutils.ccompiler import new_compiler
+from distutils.sysconfig import customize_compiler
 
-class build_ext(_build_ext):
-    
+class build_ext(_build_ext):   
     def run(self):
         """Build extensions in build directory, then copy if --inplace"""
         old_inplace, self.inplace = self.inplace, 0
@@ -21,15 +23,13 @@
     def copy_extensions_to_source(self):
         build_py = self.get_finalized_command('build_py')
         for ext in self.extensions or ():
-            fullname = ext.name
+            fullname = self.get_ext_fullname(ext.name)
+            filename = self.get_ext_filename(fullname)
             modpath = fullname.split('.')
             package = '.'.join(modpath[:-1])
-            base = modpath[-1]
             package_dir = build_py.get_package_dir(package)
-            dest_filename = os.path.join(package_dir,
-                                        self.get_ext_filename(base))
-            src_filename = os.path.join(self.build_lib,
-                                        self.get_ext_filename(fullname))
+            dest_filename = os.path.join(package_dir,os.path.basename(filename))
+            src_filename = os.path.join(self.build_lib,filename)
 
             # Always copy, even if source is older than destination, to ensure
             # that the right extensions for the current Python/platform are
@@ -47,6 +47,88 @@
             # Then do any actual SWIG stuff on the remainder
             return _du_build_ext.swig_sources(self, sources, *otherargs)
 
+    def get_ext_filename(self, fullname):
+        filename = _build_ext.get_ext_filename(self,fullname)
+        for ext in self.shlibs:
+            if self.get_ext_fullname(ext.name)==fullname:
+                fn, ext = os.path.splitext(filename)
+                fn = self.shlib_compiler.library_filename(fn,'shared')
+                print "shlib",fn
+                return fn
+        return filename
+
+    def initialize_options(self):
+        _build_ext.initialize_options(self)
+        self.shlib_compiler = None
+        self.shlibs = []
+
+    def finalize_options(self):
+        _build_ext.finalize_options(self)
+        self.shlibs = [ext for ext in self.extensions or ()
+                        if isinstance(ext,SharedLibrary)]
+        if self.shlibs:
+            self.setup_shlib_compiler()
+            self.library_dirs.append(self.build_lib)
+
+    def build_extension(self, ext):
+        _compiler = self.compiler
+        try:
+            if isinstance(ext,SharedLibrary):
+                self.compiler = self.shlib_compiler
+            _build_ext.build_extension(self,ext)
+        finally:
+            self.compiler = _compiler
+
+
+    def setup_shlib_compiler(self):
+        compiler = self.shlib_compiler = new_compiler(
+            compiler=self.compiler, dry_run=self.dry_run, force=self.force
+        ) 
+        customize_compiler(compiler)
+        if sys.platform == "darwin":
+            # XXX need to fix up compiler_so:ccshared + linker_so:ldshared too
+            compiler.shared_lib_extension = ".dylib"
+
+        if self.include_dirs is not None:
+            compiler.set_include_dirs(self.include_dirs)
+        if self.define is not None:
+            # 'define' option is a list of (name,value) tuples
+            for (name,value) in self.define:
+                compiler.define_macro(name, value)
+        if self.undef is not None:
+            for macro in self.undef:
+                compiler.undefine_macro(macro)
+        if self.libraries is not None:
+            compiler.set_libraries(self.libraries)
+        if self.library_dirs is not None:
+            compiler.set_library_dirs(self.library_dirs)
+        if self.rpath is not None:
+            compiler.set_runtime_library_dirs(self.rpath)
+        if self.link_objects is not None:
+            compiler.set_link_objects(self.link_objects)
+
+        # hack so distutils' build_extension() builds a shared lib instead
+        #
+        def link_shared_object(self, objects, output_libname, output_dir=None,
+            libraries=None, library_dirs=None, runtime_library_dirs=None,
+            export_symbols=None, debug=0, extra_preargs=None,
+            extra_postargs=None, build_temp=None, target_lang=None
+        ):  self.link(
+                self.SHARED_LIBRARY, objects, output_libname,
+                output_dir, libraries, library_dirs, runtime_library_dirs,
+                export_symbols, debug, extra_preargs, extra_postargs,
+                build_temp, target_lang
+            )
+        compiler.link_shared_object = link_shared_object.__get__(compiler)
+
+    def get_export_symbols(self, ext):
+        if isinstance(ext,SharedLibrary):
+            return ext.export_symbols
+        return _build_ext.get_export_symbols(self,ext)
+        
+
+
+
 
 
 

Modified: sandbox/trunk/setuptools/setuptools/dist.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/dist.py	(original)
+++ sandbox/trunk/setuptools/setuptools/dist.py	Fri Jan  6 00:14:21 2006
@@ -1,9 +1,7 @@
 __all__ = ['Distribution', 'Feature']
 
 from distutils.core import Distribution as _Distribution
-from distutils.core import Extension
 from setuptools.depends import Require
-from setuptools.command.build_ext import build_ext
 from setuptools.command.install import install
 from setuptools.command.sdist import sdist
 from setuptools.command.install_lib import install_lib
@@ -39,6 +37,8 @@
 
 
 
+
+
 def assert_string_list(dist, attr, value):
     """Verify that value is a string list or None"""
     try:

Modified: sandbox/trunk/setuptools/setuptools/extension.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/extension.py	(original)
+++ sandbox/trunk/setuptools/setuptools/extension.py	Fri Jan  6 00:14:21 2006
@@ -1,19 +1,20 @@
 from distutils.core import Extension as _Extension
+from dist import _get_unpatched
+_Extension = _get_unpatched(_Extension)
 
 try:
     from Pyrex.Distutils.build_ext import build_ext
-
 except ImportError:
+    have_pyrex = False
+else:
+    have_pyrex = True
 
-    # Pyrex isn't around, so fix up the sources
-
-    from dist import _get_unpatched
-    _Extension = _get_unpatched(_Extension)
-
-    class Extension(_Extension):
 
-        """Extension that uses '.c' files in place of '.pyx' files"""
+class Extension(_Extension):
+    """Extension that uses '.c' files in place of '.pyx' files"""
 
+    if not have_pyrex:
+        # convert .pyx extensions to .c 
         def __init__(self,*args,**kw):
             _Extension.__init__(self,*args,**kw)
             sources = []
@@ -24,14 +25,12 @@
                     sources.append(s)
             self.sources = sources
 
-    import sys, distutils.core, distutils.extension
-    distutils.core.Extension = Extension
-    distutils.extension.Extension = Extension
-    if 'distutils.command.build_ext' in sys.modules:
-        sys.modules['distutils.command.build_ext'].Extension = Extension
-
-else:
+class SharedLibrary(Extension):
+    """Just like a regular Extension, but built as a shared library instead"""
 
-    # Pyrex is here, just use regular extension type
-    Extension = _Extension
+import sys, distutils.core, distutils.extension
+distutils.core.Extension = Extension
+distutils.extension.Extension = Extension
+if 'distutils.command.build_ext' in sys.modules:
+    sys.modules['distutils.command.build_ext'].Extension = Extension
 

Added: sandbox/trunk/setuptools/tests/shlib_test/hello.c
==============================================================================
--- (empty file)
+++ sandbox/trunk/setuptools/tests/shlib_test/hello.c	Fri Jan  6 00:14:21 2006
@@ -0,0 +1,168 @@
+/* Generated by Pyrex 0.9.3 on Thu Jan 05 17:47:12 2006 */
+
+#include "Python.h"
+#include "structmember.h"
+#ifndef PY_LONG_LONG
+  #define PY_LONG_LONG LONG_LONG
+#endif
+
+
+typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/
+typedef struct {PyObject **p; char *s; long n;} __Pyx_StringTabEntry; /*proto*/
+static PyObject *__Pyx_UnpackItem(PyObject *, int); /*proto*/
+static int __Pyx_EndUnpack(PyObject *, int); /*proto*/
+static int __Pyx_PrintItem(PyObject *); /*proto*/
+static int __Pyx_PrintNewline(void); /*proto*/
+static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
+static void __Pyx_ReRaise(void); /*proto*/
+static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/
+static PyObject *__Pyx_GetExcValue(void); /*proto*/
+static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed, char *name); /*proto*/
+static int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); /*proto*/
+static int __Pyx_GetStarArgs(PyObject **args, PyObject **kwds, char *kwd_list[], int nargs, PyObject **args2, PyObject **kwds2); /*proto*/
+static void __Pyx_WriteUnraisable(char *name); /*proto*/
+static void __Pyx_AddTraceback(char *funcname); /*proto*/
+static PyTypeObject *__Pyx_ImportType(char *module_name, char *class_name, long size);  /*proto*/
+static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/
+static int __Pyx_GetVtable(PyObject *dict, void *vtabptr); /*proto*/
+static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, char *modname); /*proto*/
+static int __Pyx_InternStrings(__Pyx_InternTabEntry *t); /*proto*/
+static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/
+static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/
+
+static PyObject *__pyx_m;
+static PyObject *__pyx_b;
+static int __pyx_lineno;
+static char *__pyx_filename;
+staticforward char **__pyx_f;
+
+/* Declarations from hello */
+
+char (*(get_hello_msg(void))); /*proto*/
+
+/* Implementation of hello */
+
+static PyObject *__pyx_n_hello;
+
+static PyObject *__pyx_f_5hello_hello(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_f_5hello_hello(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_r;
+  PyObject *__pyx_1 = 0;
+  static char *__pyx_argnames[] = {0};
+  if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0;
+
+  /* "C:\cygwin\home\pje\setuptools\tests\shlib_test\hello.pyx":4 */
+  __pyx_1 = PyString_FromString(get_hello_msg()); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; goto __pyx_L1;}
+  __pyx_r = __pyx_1;
+  __pyx_1 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; Py_INCREF(__pyx_r);
+  goto __pyx_L0;
+  __pyx_L1:;
+  Py_XDECREF(__pyx_1);
+  __Pyx_AddTraceback("hello.hello");
+  __pyx_r = 0;
+  __pyx_L0:;
+  return __pyx_r;
+}
+
+static __Pyx_InternTabEntry __pyx_intern_tab[] = {
+  {&__pyx_n_hello, "hello"},
+  {0, 0}
+};
+
+static struct PyMethodDef __pyx_methods[] = {
+  {"hello", (PyCFunction)__pyx_f_5hello_hello, METH_VARARGS|METH_KEYWORDS, 0},
+  {0, 0, 0, 0}
+};
+
+DL_EXPORT(void) inithello(void); /*proto*/
+DL_EXPORT(void) inithello(void) {
+  __pyx_m = Py_InitModule4("hello", __pyx_methods, 0, 0, PYTHON_API_VERSION);
+  if (!__pyx_m) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; goto __pyx_L1;};
+  __pyx_b = PyImport_AddModule("__builtin__");
+  if (!__pyx_b) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; goto __pyx_L1;};
+  if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; goto __pyx_L1;};
+  if (__Pyx_InternStrings(__pyx_intern_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; goto __pyx_L1;};
+
+  /* "C:\cygwin\home\pje\setuptools\tests\shlib_test\hello.pyx":3 */
+  return;
+  __pyx_L1:;
+  __Pyx_AddTraceback("hello");
+}
+
+static char *__pyx_filenames[] = {
+  "hello.pyx",
+};
+statichere char **__pyx_f = __pyx_filenames;
+
+/* Runtime support code */
+
+static int __Pyx_InternStrings(__Pyx_InternTabEntry *t) {
+    while (t->p) {
+        *t->p = PyString_InternFromString(t->s);
+        if (!*t->p)
+            return -1;
+        ++t;
+    }
+    return 0;
+}
+
+#include "compile.h"
+#include "frameobject.h"
+#include "traceback.h"
+
+static void __Pyx_AddTraceback(char *funcname) {
+    PyObject *py_srcfile = 0;
+    PyObject *py_funcname = 0;
+    PyObject *py_globals = 0;
+    PyObject *empty_tuple = 0;
+    PyObject *empty_string = 0;
+    PyCodeObject *py_code = 0;
+    PyFrameObject *py_frame = 0;
+    
+    py_srcfile = PyString_FromString(__pyx_filename);
+    if (!py_srcfile) goto bad;
+    py_funcname = PyString_FromString(funcname);
+    if (!py_funcname) goto bad;
+    py_globals = PyModule_GetDict(__pyx_m);
+    if (!py_globals) goto bad;
+    empty_tuple = PyTuple_New(0);
+    if (!empty_tuple) goto bad;
+    empty_string = PyString_FromString("");
+    if (!empty_string) goto bad;
+    py_code = PyCode_New(
+        0,            /*int argcount,*/
+        0,            /*int nlocals,*/
+        0,            /*int stacksize,*/
+        0,            /*int flags,*/
+        empty_string, /*PyObject *code,*/
+        empty_tuple,  /*PyObject *consts,*/
+        empty_tuple,  /*PyObject *names,*/
+        empty_tuple,  /*PyObject *varnames,*/
+        empty_tuple,  /*PyObject *freevars,*/
+        empty_tuple,  /*PyObject *cellvars,*/
+        py_srcfile,   /*PyObject *filename,*/
+        py_funcname,  /*PyObject *name,*/
+        __pyx_lineno,   /*int firstlineno,*/
+        empty_string  /*PyObject *lnotab*/
+    );
+    if (!py_code) goto bad;
+    py_frame = PyFrame_New(
+        PyThreadState_Get(), /*PyThreadState *tstate,*/
+        py_code,             /*PyCodeObject *code,*/
+        py_globals,          /*PyObject *globals,*/
+        0                    /*PyObject *locals*/
+    );
+    if (!py_frame) goto bad;
+    py_frame->f_lineno = __pyx_lineno;
+    PyTraceBack_Here(py_frame);
+bad:
+    Py_XDECREF(py_srcfile);
+    Py_XDECREF(py_funcname);
+    Py_XDECREF(empty_tuple);
+    Py_XDECREF(empty_string);
+    Py_XDECREF(py_code);
+    Py_XDECREF(py_frame);
+}

Added: sandbox/trunk/setuptools/tests/shlib_test/hello.pyx
==============================================================================
--- (empty file)
+++ sandbox/trunk/setuptools/tests/shlib_test/hello.pyx	Fri Jan  6 00:14:21 2006
@@ -0,0 +1,4 @@
+cdef extern char *get_hello_msg()
+
+def hello():
+    return get_hello_msg()

Added: sandbox/trunk/setuptools/tests/shlib_test/hellolib.c
==============================================================================
--- (empty file)
+++ sandbox/trunk/setuptools/tests/shlib_test/hellolib.c	Fri Jan  6 00:14:21 2006
@@ -0,0 +1,3 @@
+extern char* get_hello_msg() {
+    return "Hello, world!";
+}

Added: sandbox/trunk/setuptools/tests/shlib_test/setup.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/setuptools/tests/shlib_test/setup.py	Fri Jan  6 00:14:21 2006
@@ -0,0 +1,10 @@
+from setuptools import setup, Extension, SharedLibrary
+
+setup(
+    name="shlib_test",
+    ext_modules = [
+        SharedLibrary("hellolib", ["hellolib.c"]),
+        Extension("hello", ["hello.pyx"], libraries=["hellolib"])
+    ],
+    test_suite="test_hello.HelloWorldTest",
+)

Added: sandbox/trunk/setuptools/tests/shlib_test/test_hello.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/setuptools/tests/shlib_test/test_hello.py	Fri Jan  6 00:14:21 2006
@@ -0,0 +1,7 @@
+from unittest import TestCase
+
+class HelloWorldTest(TestCase):
+    def testHelloMsg(self):
+        from hello import hello
+        self.assertEqual(hello(), "Hello, world!")
+


More information about the Python-checkins mailing list