Author: Armin Rigo <[email protected]>
Branch: cffi-1.0
Changeset: r1876:35dd6cec69f3
Date: 2015-04-29 19:30 +0200
http://bitbucket.org/cffi/cffi/changeset/35dd6cec69f3/

Log:    first attempt at writing setuptools hooks

diff --git a/_cffi1/setuptools_ext.py b/_cffi1/setuptools_ext.py
new file mode 100644
--- /dev/null
+++ b/_cffi1/setuptools_ext.py
@@ -0,0 +1,80 @@
+
+def error(msg):
+    from distutils.errors import DistutilsSetupError
+    raise DistutilsSetupError(msg)
+
+
+def add_cffi_module(dist, mod_spec):
+    import os
+    from cffi.api import FFI
+    from _cffi1 import recompiler
+    from distutils.core import Extension
+    from distutils.command.build_ext import build_ext
+    from distutils.dir_util import mkpath
+    from distutils import log
+
+    if not isinstance(mod_spec, str):
+        error("argument to 'cffi_modules=...' must be a str or a list of str,"
+              " not %r" % (type(mod_spec).__name__,))
+    try:
+        build_mod_name, ffi_var_name = mod_spec.split(':')
+    except ValueError:
+        error("%r must be of the form 'build_mod_name:ffi_variable'" %
+              (mod_spec,))
+    mod = __import__(build_mod_name, None, None, [ffi_var_name])
+    try:
+        ffi = getattr(mod, ffi_var_name)
+    except AttributeError:
+        error("%r: object %r not found in module" % (mod_spec,
+                                                     ffi_var_name))
+    if not isinstance(ffi, FFI):
+        error("%r is not an FFI instance (got %r)" % (mod_spec,
+                                                      type(ffi).__name__))
+    if not hasattr(ffi, '_assigned_source'):
+        error("%r: the set_source() method was not called" % (mod_spec,))
+    module_name = ffi._recompiler_module_name
+    source, kwds = ffi._assigned_source
+
+    allsources = ['$PLACEHOLDER']
+    allsources.extend(kwds.get('sources', []))
+    ext = Extension(name=module_name, sources=allsources, **kwds)
+
+    def make_mod(tmpdir):
+        mkpath(tmpdir)
+        file_name = module_name + '.c'
+        log.info("generating cffi module %r" % file_name)
+        c_file = os.path.join(tmpdir, file_name)
+        c_tmp = '%s.%s' % (c_file, os.getpid())
+        recompiler.make_c_source(ffi, module_name, source, c_tmp)
+        try:
+            with open(c_file, 'r') as f1:
+                with open(c_tmp, 'r') as f2:
+                    if f1.read() != f2.read():
+                        raise IOError
+        except IOError:
+            os.rename(c_tmp, c_file)
+        else:
+            log.info("already up-to-date")
+            os.unlink(c_tmp)
+        return c_file
+
+    if dist.ext_modules is None:
+        dist.ext_modules = []
+    dist.ext_modules.append(ext)
+
+    base_class = dist.cmdclass.get('build_ext', build_ext)
+    class build_ext_make_mod(base_class):
+        def run(self):
+            if ext.sources[0] == '$PLACEHOLDER':
+                ext.sources[0] = make_mod(self.build_temp)
+            base_class.run(self)
+    dist.cmdclass['build_ext'] = build_ext_make_mod
+
+
+def cffi_modules(dist, attr, value):
+    assert attr == 'cffi_modules'
+    if isinstance(value, str):
+        value = [value]
+
+    for cffi_module in value:
+        add_cffi_module(dist, cffi_module)
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -475,6 +475,22 @@
                                        ('_UNICODE', '1')]
         kwds['define_macros'] = defmacros
 
+    def set_source(self, module_name, source, **kwds):
+        if hasattr(self, '_assigned_source'):
+            raise ValueError("set_source() cannot be called several times "
+                             "per ffi object")
+        self._recompiler_module_name = module_name
+        self._assigned_source = (source, kwds)
+
+    def compile(self, tmpdir='.'):
+        from _cffi1 import recompile
+        #
+        if not hasattr(self, '_assigned_source'):
+            raise ValueError("set_source() must be called before compile()")
+        source, kwds = self._assigned_source
+        return recompile(self, self._recompiler_module_name,
+                         source, tmpdir=tmpdir, **kwds)
+
 
 def _load_backend_lib(backend, name, flags):
     if name is None:
diff --git a/demo/bsdopendirtype_build.py b/demo/bsdopendirtype_build.py
--- a/demo/bsdopendirtype_build.py
+++ b/demo/bsdopendirtype_build.py
@@ -1,5 +1,4 @@
 from cffi import FFI
-from _cffi1 import recompile
 
 ffi = FFI()
 ffi.cdef("""
@@ -15,7 +14,10 @@
     static const int DT_BLK, DT_CHR, DT_DIR, DT_FIFO, DT_LNK, DT_REG, DT_SOCK;
 """)
 
-recompile(ffi, "_bsdopendirtype", """
+ffi.set_source("_bsdopendirtype", """
     #include <sys/types.h>
     #include <dirent.h>
 """)
+
+if __name__ == '__main__':
+    ffi.compile()
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -142,8 +142,9 @@
 
 `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_
 """,
-        version='0.9.2',
-        packages=['cffi'],
+        version='1.0.0',
+        packages=['cffi', '_cffi1'],
+        package_data={'_cffi1': ['_cffi_include.h', 'parse_c_type.h']},
         zip_safe=False,
 
         url='http://cffi.readthedocs.org',
@@ -157,6 +158,13 @@
         install_requires=[
             'pycparser',
         ],
+
+        entry_points = {
+            "distutils.setup_keywords": [
+                "cffi_modules = _cffi1.setuptools_ext:cffi_modules",
+            ],
+        },
+
         classifiers=[
             'Programming Language :: Python',
             'Programming Language :: Python :: 2',
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to