[pypy-commit] cffi cffi-1.0: Change of scope for now: the initial goal is now to avoid breaking
arigo
noreply at buildbot.pypy.org
Fri Apr 24 10:12:43 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1784:6d8fa9486905
Date: 2015-04-24 09:17 +0200
http://bitbucket.org/cffi/cffi/changeset/6d8fa9486905/
Log: Change of scope for now: the initial goal is now to avoid breaking
ffi.dlopen() and ffi.verify(), and only add _cffi1.recompile().
diff --git a/new/PLAN b/_cffi1/PLAN
rename from new/PLAN
rename to _cffi1/PLAN
diff --git a/new/_cffi_include.h b/_cffi1/_cffi_include.h
rename from new/_cffi_include.h
rename to _cffi1/_cffi_include.h
diff --git a/new/bsdopendirtype.py b/_cffi1/bsdopendirtype.py
rename from new/bsdopendirtype.py
rename to _cffi1/bsdopendirtype.py
diff --git a/new/bsdopendirtype_build.py b/_cffi1/bsdopendirtype_build.py
rename from new/bsdopendirtype_build.py
rename to _cffi1/bsdopendirtype_build.py
diff --git a/new/cffi-1.0.rst b/_cffi1/cffi-1.0.rst
rename from new/cffi-1.0.rst
rename to _cffi1/cffi-1.0.rst
diff --git a/new/cffi1 b/_cffi1/cffi1
rename from new/cffi1
rename to _cffi1/cffi1
diff --git a/new/cffi1_module.c b/_cffi1/cffi1_module.c
rename from new/cffi1_module.c
rename to _cffi1/cffi1_module.c
diff --git a/new/cffi_opcode.py b/_cffi1/cffi_opcode.py
rename from new/cffi_opcode.py
rename to _cffi1/cffi_opcode.py
diff --git a/new/cglob.c b/_cffi1/cglob.c
rename from new/cglob.c
rename to _cffi1/cglob.c
diff --git a/new/ffi_obj.c b/_cffi1/ffi_obj.c
rename from new/ffi_obj.c
rename to _cffi1/ffi_obj.c
diff --git a/new/lib_obj.c b/_cffi1/lib_obj.c
rename from new/lib_obj.c
rename to _cffi1/lib_obj.c
diff --git a/new/manual.c b/_cffi1/manual.c
rename from new/manual.c
rename to _cffi1/manual.c
diff --git a/new/parse_c_type.c b/_cffi1/parse_c_type.c
rename from new/parse_c_type.c
rename to _cffi1/parse_c_type.c
diff --git a/new/parse_c_type.h b/_cffi1/parse_c_type.h
rename from new/parse_c_type.h
rename to _cffi1/parse_c_type.h
diff --git a/new/readdir2.py b/_cffi1/readdir2.py
rename from new/readdir2.py
rename to _cffi1/readdir2.py
diff --git a/new/readdir2_build.py b/_cffi1/readdir2_build.py
rename from new/readdir2_build.py
rename to _cffi1/readdir2_build.py
diff --git a/new/realize_c_type.c b/_cffi1/realize_c_type.c
rename from new/realize_c_type.c
rename to _cffi1/realize_c_type.c
diff --git a/new/recompiler.py b/_cffi1/recompiler.py
rename from new/recompiler.py
rename to _cffi1/recompiler.py
diff --git a/new/setup.py b/_cffi1/setup.py
rename from new/setup.py
rename to _cffi1/setup.py
diff --git a/new/setup_manual.py b/_cffi1/setup_manual.py
rename from new/setup_manual.py
rename to _cffi1/setup_manual.py
diff --git a/new/test_dlopen.py b/_cffi1/test_dlopen.py
rename from new/test_dlopen.py
rename to _cffi1/test_dlopen.py
diff --git a/new/test_ffi_obj.py b/_cffi1/test_ffi_obj.py
rename from new/test_ffi_obj.py
rename to _cffi1/test_ffi_obj.py
diff --git a/new/test_parse_c_type.py b/_cffi1/test_parse_c_type.py
rename from new/test_parse_c_type.py
rename to _cffi1/test_parse_c_type.py
diff --git a/new/test_realize_c_type.py b/_cffi1/test_realize_c_type.py
rename from new/test_realize_c_type.py
rename to _cffi1/test_realize_c_type.py
diff --git a/new/test_recompiler.py b/_cffi1/test_recompiler.py
rename from new/test_recompiler.py
rename to _cffi1/test_recompiler.py
diff --git a/new/test_verify1.py b/_cffi1/test_verify1.py
rename from new/test_verify1.py
rename to _cffi1/test_verify1.py
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -5402,6 +5402,12 @@
return NULL;
}
+static PyObject *b__get_types(PyObject *self, PyObject *noarg)
+{
+ return PyTuple_Pack(2, (PyObject *)&CData_Type,
+ (PyObject *)&CTypeDescr_Type);
+}
+
/************************************************************/
static char _testfunc0(char a, char b)
@@ -5706,6 +5712,7 @@
#ifdef MS_WIN32
{"getwinerror", b_getwinerror, METH_VARARGS},
#endif
+ {"_get_types", b__get_types, METH_NOARGS},
{"_testfunc", b__testfunc, METH_VARARGS},
{"_testbuff", b__testbuff, METH_VARARGS},
{NULL, NULL} /* Sentinel */
@@ -5820,7 +5827,7 @@
}
#endif
-#include "../new/cffi1_module.c"
+#include "../_cffi1/cffi1_module.c"
static void *cffi_exports[] = {
(void *)26,
@@ -5861,7 +5868,7 @@
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef FFIBackendModuleDef = {
PyModuleDef_HEAD_INIT,
- "_cffi1_backend",
+ "_cffi_backend",
NULL,
-1,
FFIBackendMethods,
@@ -5875,7 +5882,7 @@
#define INITERROR return
PyMODINIT_FUNC
-init_cffi1_backend(void)
+init_cffi_backend(void)
#endif
{
PyObject *m, *v;
@@ -5892,7 +5899,7 @@
#if PY_MAJOR_VERSION >= 3
m = PyModule_Create(&FFIBackendModuleDef);
#else
- m = Py_InitModule("_cffi1_backend", FFIBackendMethods);
+ m = Py_InitModule("_cffi_backend", FFIBackendMethods);
#endif
if (m == NULL)
diff --git a/cffi/__init__.py b/cffi/__init__.py
--- a/cffi/__init__.py
+++ b/cffi/__init__.py
@@ -1,10 +1,13 @@
__all__ = ['FFI', 'VerificationError', 'VerificationMissing', 'CDefError',
'FFIError']
-from .api import FFI, CDefError
+from .api import FFI, CDefError, FFIError
from .ffiplatform import VerificationError, VerificationMissing
-FFIError = FFI.error # backward compatibility
-
__version__ = "1.0.0"
__version_info__ = (1, 0, 0)
+
+# The verifier module file names are based on the CRC32 of a string that
+# contains the following version number. It may be older than __version__
+# if nothing is clearly incompatible.
+__version_verifier_modules__ = "0.8.6"
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -1,9 +1,5 @@
import sys, types
from .lock import allocate_lock
-import _cffi1_backend
-
-class DeprecatedError(Exception):
- pass
try:
callable
@@ -19,7 +15,8 @@
basestring = str
-FFIError = _cffi1_backend.FFI.error
+class FFIError(Exception):
+ pass
class CDefError(Exception):
def __str__(self):
@@ -30,7 +27,7 @@
return '%s%s' % (line, self.args[0])
-class FFI(_cffi1_backend.FFI):
+class FFI(object):
r'''
The main top-level class that you instantiate once, or once per module.
@@ -48,16 +45,21 @@
C.printf("hello, %s!\n", ffi.new("char[]", "world"))
'''
- def __init__(self):
+ def __init__(self, backend=None):
"""Create an FFI instance. The 'backend' argument is used to
select a non-default backend, mostly for tests.
"""
from . import cparser, model
- from . import __version__
-
- backend = _cffi1_backend
- assert backend.__version__ == __version__, \
- "version mismatch, %s != %s" % (backend.__version__, __version__)
+ if backend is None:
+ # You need PyPy (>= 2.0 beta), or a CPython (>= 2.6) with
+ # _cffi_backend.so compiled.
+ import _cffi_backend as backend
+ from . import __version__
+ assert backend.__version__ == __version__, \
+ "version mismatch, %s != %s" % (backend.__version__, __version__)
+ # (If you insist you can also try to pass the option
+ # 'backend=backend_ctypes.CTypesBackend()', but don't
+ # rely on it! It's probably not going to work well.)
self._backend = backend
self._lock = allocate_lock()
@@ -75,9 +77,18 @@
if name.startswith('RTLD_'):
setattr(self, name, getattr(backend, name))
#
- #with self._lock:
- # self.BVoidP = self._get_cached_btype(model.voidp_type)
- # self.BCharA = self._get_cached_btype(model.char_array_type)
+ with self._lock:
+ self.BVoidP = self._get_cached_btype(model.voidp_type)
+ self.BCharA = self._get_cached_btype(model.char_array_type)
+ if isinstance(backend, types.ModuleType):
+ # _cffi_backend: attach these constants to the class
+ if not hasattr(FFI, 'NULL'):
+ FFI.NULL = self.cast(self.BVoidP, 0)
+ FFI.CData, FFI.CType = backend._get_types()
+ else:
+ # ctypes backend: attach these constants to the instance
+ self.NULL = self.cast(self.BVoidP, 0)
+ self.CData, self.CType = backend._get_types()
def cdef(self, csource, override=False, packed=False):
"""Parse the given C source. This registers all declared functions,
@@ -97,7 +108,6 @@
if override:
for cache in self._function_caches:
cache.clear()
- _set_cdef_types(self)
def dlopen(self, name, flags=0):
"""Load and return a dynamic library identified by 'name'.
@@ -145,7 +155,7 @@
"pointer-to-function type" % (cdecl,))
return btype
- def XXXtypeof(self, cdecl):
+ def typeof(self, cdecl):
"""Parse the C type given as a string and return the
corresponding <ctype> object.
It can also be used on 'cdata' instance to get its C type.
@@ -164,7 +174,7 @@
return self._get_cached_btype(cdecl._cffi_base_type)
raise TypeError(type(cdecl))
- def XXXsizeof(self, cdecl):
+ def sizeof(self, cdecl):
"""Return the size in bytes of the argument. It can be a
string naming a C type, or a 'cdata' instance.
"""
@@ -174,7 +184,7 @@
else:
return self._backend.sizeof(cdecl)
- def XXXalignof(self, cdecl):
+ def alignof(self, cdecl):
"""Return the natural alignment size in bytes of the C type
given as a string.
"""
@@ -182,7 +192,7 @@
cdecl = self._typeof(cdecl)
return self._backend.alignof(cdecl)
- def XXXoffsetof(self, cdecl, *fields_or_indexes):
+ def offsetof(self, cdecl, *fields_or_indexes):
"""Return the offset of the named field inside the given
structure or array, which must be given as a C type name.
You can give several field names in case of nested structures.
@@ -193,7 +203,7 @@
cdecl = self._typeof(cdecl)
return self._typeoffsetof(cdecl, *fields_or_indexes)[1]
- def XXXnew(self, cdecl, init=None):
+ def new(self, cdecl, init=None):
"""Allocate an instance according to the specified C type and
return a pointer to it. The specified C type must be either a
pointer or an array: ``new('X *')`` allocates an X and returns
@@ -220,7 +230,7 @@
cdecl = self._typeof(cdecl)
return self._backend.newp(cdecl, init)
- def XXXcast(self, cdecl, source):
+ def cast(self, cdecl, source):
"""Similar to a C cast: returns an instance of the named C
type initialized with the given 'source'. The source is
casted between integers or pointers of any type.
@@ -229,7 +239,7 @@
cdecl = self._typeof(cdecl)
return self._backend.cast(cdecl, source)
- def XXXstring(self, cdata, maxlen=-1):
+ def string(self, cdata, maxlen=-1):
"""Return a Python string (or unicode string) from the 'cdata'.
If 'cdata' is a pointer or array of characters or bytes, returns
the null-terminated string. The returned string extends until
@@ -247,7 +257,7 @@
"""
return self._backend.string(cdata, maxlen)
- def XXXbuffer(self, cdata, size=-1):
+ def buffer(self, cdata, size=-1):
"""Return a read-write buffer object that references the raw C data
pointed to by the given 'cdata'. The 'cdata' must be a pointer or
an array. Can be passed to functions expecting a buffer, or directly
@@ -260,7 +270,7 @@
"""
return self._backend.buffer(cdata, size)
- def XXXfrom_buffer(self, python_buffer):
+ def from_buffer(self, python_buffer):
"""Return a <cdata 'char[]'> that points to the data of the
given Python object, which must support the buffer interface.
Note that this is not meant to be used on the built-in types str,
@@ -270,7 +280,7 @@
"""
return self._backend.from_buffer(self.BCharA, python_buffer)
- def XXXcallback(self, cdecl, python_callable=None, error=None):
+ def callback(self, cdecl, python_callable=None, error=None):
"""Return a callback object or a decorator making such a
callback object. 'cdecl' must name a C function pointer type.
The callback invokes the specified 'python_callable' (which may
@@ -290,7 +300,7 @@
else:
return callback_decorator_wrap(python_callable) # direct mode
- def XXXgetctype(self, cdecl, replace_with=''):
+ def getctype(self, cdecl, replace_with=''):
"""Return a string giving the C type 'cdecl', which may be itself
a string or a <ctype> object. If 'replace_with' is given, it gives
extra text to append (or insert for more complicated C types), like
@@ -306,7 +316,7 @@
replace_with = ' ' + replace_with
return self._backend.getcname(cdecl, replace_with)
- def XXXgc(self, cdata, destructor):
+ def gc(self, cdata, destructor):
"""Return a new cdata object that points to the same
data. Later, when this new cdata object is garbage-collected,
'destructor(old_cdata_object)' will be called.
@@ -320,15 +330,18 @@
return gc_weakrefs.build(cdata, destructor)
def _get_cached_btype(self, type):
- raise DeprecatedError
+ assert self._lock.acquire(False) is False
+ # call me with the lock!
+ try:
+ BType = self._cached_btypes[type]
+ except KeyError:
+ finishlist = []
+ BType = type.get_cached_btype(self, finishlist)
+ for type in finishlist:
+ type.finish_backend_type(self, finishlist)
+ return BType
- def verify(self, source='', **kwargs):
- from recompiler import verify # XXX must be in the current dir
- FFI._verify_counter += 1
- return verify(self, 'verify%d' % FFI._verify_counter, source, **kwargs)
- _verify_counter = 0
-
- def XXXverify(self, source='', tmpdir=None, **kwargs):
+ def verify(self, source='', tmpdir=None, **kwargs):
"""Verify that the current ffi signatures compile on this
machine, and return a dynamic library object. The dynamic
library can be used to call functions and access global
@@ -362,10 +375,10 @@
return self._backend.get_errno()
def _set_errno(self, errno):
self._backend.set_errno(errno)
- XXXerrno = property(_get_errno, _set_errno, None,
+ errno = property(_get_errno, _set_errno, None,
"the value of 'errno' from/to the C calls")
- def XXXgetwinerror(self, code=-1):
+ def getwinerror(self, code=-1):
return self._backend.getwinerror(code)
def _pointer_to(self, ctype):
@@ -373,7 +386,7 @@
with self._lock:
return model.pointer_cache(self, ctype)
- def XXXaddressof(self, cdata, *fields_or_indexes):
+ def addressof(self, cdata, *fields_or_indexes):
"""Return the address of a <cdata 'struct-or-union'>.
If 'fields_or_indexes' are given, returns the address of that
field or array item in the structure or array, recursively in
@@ -405,7 +418,6 @@
variables, which must anyway be accessed directly from the
lib object returned by the original FFI instance.
"""
- XXX
with ffi_to_include._lock:
with self._lock:
self._parser.include(ffi_to_include._parser)
@@ -413,10 +425,10 @@
self._cdefsources.extend(ffi_to_include._cdefsources)
self._cdefsources.append(']')
- def XXXnew_handle(self, x):
+ def new_handle(self, x):
return self._backend.newp_handle(self.BVoidP, x)
- def XXXfrom_handle(self, x):
+ def from_handle(self, x):
return self._backend.from_handle(x)
def set_unicode(self, enabled_flag):
@@ -426,7 +438,6 @@
declare these types to be (pointers to) plain 8-bit characters.
This is mostly for backward compatibility; you usually want True.
"""
- XXX
if self._windows_unicode is not None:
raise ValueError("set_unicode() can only be called once")
enabled_flag = bool(enabled_flag)
@@ -566,56 +577,3 @@
else:
with ffi._lock:
return ffi._get_cached_btype(tp)
-
-def _set_cdef_types(ffi):
- from . import model
-
- all_structs = {}
- all_typedefs = {}
- for name, tp in ffi._parser._declarations.items():
- kind, basename = name.split(' ', 1)
- if kind == 'struct' or kind == 'union' or kind == 'anonymous':
- all_structs[tp.name] = tp
- elif kind == 'typedef':
- all_typedefs[basename] = tp
- if getattr(tp, "origin", None) == "unknown_type":
- all_structs[tp.name] = tp
- elif isinstance(tp, model.NamedPointerType):
- all_structs[tp.totype.name] = tp.totype
-
- struct_unions = []
- pending_completion = []
- for name, tp in sorted(all_structs.items()):
- if not isinstance(tp, model.UnionType):
- BType = _cffi1_backend.new_struct_type(name)
- else:
- BType = _cffi1_backend.new_union_type(name)
- struct_unions.append(name)
- struct_unions.append(BType)
- if not tp.partial and tp.fldtypes is not None:
- pending_completion.append((tp, BType))
- #
- typenames = []
- for name, tp in sorted(all_typedefs.items()):
- cname = tp._get_c_name()
- if cname == name:
- assert isinstance(tp, model.StructOrUnionOrEnum)
- cname = '%s %s' % (tp.kind, tp.name)
- try:
- BType = ffi.typeof(cname)
- except ffi.error:
- ffi.__set_types(struct_unions, typenames)
- BType = ffi.typeof(cname)
- typenames.append(name)
- typenames.append(BType)
- #
- ffi.__set_types(struct_unions, typenames)
- #
- for tp, BType in pending_completion:
- fldtypes = [ffi.typeof(ftp._get_c_name()) for ftp in tp.fldtypes]
- lst = list(zip(tp.fldnames, fldtypes, tp.fldbitsize))
- sflags = 0
- if tp.packed:
- sflags = 8 # SF_PACKED
- _cffi1_backend.complete_struct_or_union(BType, lst, ffi,
- -1, -1, sflags)
diff --git a/setup_base.py b/setup_base.py
--- a/setup_base.py
+++ b/setup_base.py
@@ -9,7 +9,9 @@
from distutils.core import setup
from distutils.extension import Extension
standard = '__pypy__' not in sys.modules
- setup(ext_modules=[Extension(name = '_cffi1_backend',
+ setup(packages=['cffi'],
+ requires=['pycparser'],
+ ext_modules=[Extension(name = '_cffi_backend',
include_dirs=include_dirs,
sources=sources,
libraries=libraries,
More information about the pypy-commit
mailing list