Author: Jeremy Thurgood <[email protected]>
Branch: split-verify
Changeset: r1351:eb2e8acaa3db
Date: 2013-10-05 23:11 +0200
http://bitbucket.org/cffi/cffi/changeset/eb2e8acaa3db/

Log:    FFIBuilder implementation.

diff --git a/cffi/__init__.py b/cffi/__init__.py
--- a/cffi/__init__.py
+++ b/cffi/__init__.py
@@ -1,7 +1,7 @@
 __all__ = ['FFI', 'VerificationError', 'VerificationMissing', 'CDefError',
            'FFIError']
 
-from .api import FFI, CDefError, FFIError
+from .api import FFI, CDefError, FFIError, FFIBuilder
 from .ffiplatform import VerificationError, VerificationMissing
 
 __version__ = "0.7.2"
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -448,3 +448,68 @@
         return None
     else:
         return ffi._get_cached_btype(tp)
+
+
+class FFIBuilder(object):
+    def __init__(self, module_name, module_path, backend=None):
+        self._module_name = module_name
+        self._module_path = module_path
+        self.ffi = FFI(backend=backend)
+        self._module_source = "\n".join([
+            "from cffi import FFI",
+            "",
+            "ffi = FFI()",
+            "",
+        ])
+
+    def cdef(self, csource, override=False):
+        self.ffi.cdef(csource, override=override)
+        self._module_source += "ffi.cdef(%r, override=%r)\n" % (
+            csource, override)
+
+    def add_dlopen(self, libname, name, flags=0):
+        lib = self.ffi.dlopen(name, flags=flags)
+        self._module_source += '\n'.join([
+            "def load_%s():",
+            "    return ffi.dlopen(%r, flags=%r)",
+            "",
+        ]) % (libname, name, flags)
+        return lib
+
+    def makelib(self, libname, source='', **kwargs):
+        # XXX: We use force_generic_engine here because vengine_cpy collects
+        #      types when it writes the source.
+        import os.path
+        from .verifier import Verifier, _caller_dir_pycache, _get_so_suffix
+        tmpdir = _caller_dir_pycache()
+        self.ffi.verifier = Verifier(
+            self.ffi, source, tmpdir, libname, force_generic_engine=True,
+            **kwargs)
+        libfilename = libname + _get_so_suffix()
+        self.ffi.verifier.make_library(
+            os.path.join(self._module_path, libfilename))
+        self._module_source += '\n'.join([
+            "def load_%s():",
+            "    from cffi.verifier import Verifier",
+            "    import os.path",
+            "    module_path = os.path.dirname(__file__)",
+            "    verifier = Verifier(",
+            "        ffi, None, module_path, %r, force_generic_engine=True)",
+            "    verifier._has_module = True",
+            "    return verifier._load_library()",
+            "",
+        ]) % (libname, libname)
+
+    def write_ffi_module(self):
+        import os
+        try:
+            os.makedirs(self._module_path)
+        except OSError:
+            pass
+
+        module_filename = self._module_name + '.py'
+        file = open(os.path.join(self._module_path, module_filename), 'w')
+        try:
+            file.write(self._module_source)
+        finally:
+            file.close()
diff --git a/cffi/verifier.py b/cffi/verifier.py
--- a/cffi/verifier.py
+++ b/cffi/verifier.py
@@ -55,6 +55,17 @@
             self._write_source()
         self._compile_module()
 
+    def make_library(self, libraryfilename):
+        if not self._has_module:
+            self.compile_module()
+        try:
+            same = ffiplatform.samefile(self.modulefilename, libraryfilename)
+        except OSError:
+            same = False
+        if not same:
+            _ensure_dir(libraryfilename)
+            shutil.copy(self.modulefilename, libraryfilename)
+
     def load_library(self):
         """Get a C module from this Verifier instance.
         Returns an instance of a FFILibrary class that behaves like the
diff --git a/testing/test_makelib.py b/testing/test_makelib.py
new file mode 100644
--- /dev/null
+++ b/testing/test_makelib.py
@@ -0,0 +1,69 @@
+import math
+import sys
+from cffi import FFIBuilder
+
+
+def test_ffibuilder_makelib(tmpdir):
+    builder = FFIBuilder("foo_ffi", str(tmpdir))
+    builder.cdef("""
+        double sin(double x);
+    """)
+    builder.makelib('foo', '#include <math.h>')
+    builder.write_ffi_module()
+
+    sys.path.append(str(tmpdir))
+    try:
+        import foo_ffi
+    finally:
+        sys.path.remove(str(tmpdir))
+        for name in sys.modules.keys():
+            if name.endswith('foo_ffi'):
+                sys.modules.pop(name)
+
+    lib = foo_ffi.load_foo()
+    assert lib.sin(12.3) == math.sin(12.3)
+
+
+def test_ffibuilder_dlopen(tmpdir):
+    builder = FFIBuilder("foo_ffi", str(tmpdir))
+    builder.cdef("""
+        double sin(double x);
+    """)
+    builder.add_dlopen('foo', "m")
+    builder.write_ffi_module()
+
+    sys.path.append(str(tmpdir))
+    try:
+        import foo_ffi
+    finally:
+        sys.path.remove(str(tmpdir))
+        for name in sys.modules.keys():
+            if name.endswith('foo_ffi'):
+                sys.modules.pop(name)
+
+    lib = foo_ffi.load_foo()
+    assert lib.sin(12.3) == math.sin(12.3)
+
+
+def test_ffibuilder_makelib_and_dlopen(tmpdir):
+    builder = FFIBuilder("foo_ffi", str(tmpdir))
+    builder.cdef("""
+        double sin(double x);
+    """)
+    builder.makelib('foo', '#include <math.h>')
+    builder.add_dlopen('bar', "m")
+    builder.write_ffi_module()
+
+    sys.path.append(str(tmpdir))
+    try:
+        import foo_ffi
+    finally:
+        sys.path.remove(str(tmpdir))
+        for name in sys.modules.keys():
+            if name.endswith('foo_ffi'):
+                sys.modules.pop(name)
+
+    lib_foo = foo_ffi.load_foo()
+    assert lib_foo.sin(12.3) == math.sin(12.3)
+    lib_bar = foo_ffi.load_bar()
+    assert lib_bar.sin(12.3) == math.sin(12.3)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to