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