Author: Armin Rigo <[email protected]>
Branch: release-1.0
Changeset: r2074:b29ad54a7e0e
Date: 2015-05-21 11:27 +0200
http://bitbucket.org/cffi/cffi/changeset/b29ad54a7e0e/
Log: hg merge default
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -6050,7 +6050,7 @@
if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0)
INITERROR;
- v = PyText_FromString("1.0.0");
+ v = PyText_FromString("1.0.1");
if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0)
INITERROR;
diff --git a/c/misc_win32.h b/c/misc_win32.h
--- a/c/misc_win32.h
+++ b/c/misc_win32.h
@@ -218,8 +218,7 @@
static int dlclose(void *handle)
{
- FreeLibrary((HMODULE)handle);
- return 0;
+ return !FreeLibrary((HMODULE)handle);
}
static const char *dlerror(void)
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -3346,4 +3346,4 @@
def test_version():
# this test is here mostly for PyPy
- assert __version__ == "1.0.0"
+ assert __version__ == "1.0.1"
diff --git a/cffi/__init__.py b/cffi/__init__.py
--- a/cffi/__init__.py
+++ b/cffi/__init__.py
@@ -4,8 +4,8 @@
from .api import FFI, CDefError, FFIError
from .ffiplatform import VerificationError, VerificationMissing
-__version__ = "1.0.0"
-__version_info__ = (1, 0, 0)
+__version__ = "1.0.1"
+__version_info__ = (1, 0, 1)
# 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__
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -109,6 +109,11 @@
if override:
for cache in self._function_caches:
cache.clear()
+ finishlist = self._parser._recomplete
+ if finishlist:
+ self._parser._recomplete = []
+ for tp in finishlist:
+ tp.finish_backend_type(self, finishlist)
def dlopen(self, name, flags=0):
"""Load and return a dynamic library identified by 'name'.
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -101,6 +101,7 @@
self._override = False
self._packed = False
self._int_constants = {}
+ self._recomplete = []
def _parse(self, csource):
csource, macros = _preprocess(csource)
@@ -555,6 +556,9 @@
raise NotImplementedError("%s: using both bitfields and '...;'"
% (tp,))
tp.packed = self._packed
+ if tp.completed: # must be re-completed: it is not opaque any more
+ tp.completed = 0
+ self._recomplete.append(tp)
return tp
def _make_partial(self, tp, nested):
@@ -604,19 +608,21 @@
def _build_enum_type(self, explicit_name, decls):
if decls is not None:
- enumerators1 = [enum.name for enum in decls.enumerators]
- enumerators = [s for s in enumerators1
- if not _r_enum_dotdotdot.match(s)]
- partial = len(enumerators) < len(enumerators1)
- enumerators = tuple(enumerators)
+ partial = False
+ enumerators = []
enumvalues = []
nextenumvalue = 0
- for enum in decls.enumerators[:len(enumerators)]:
+ for enum in decls.enumerators:
+ if _r_enum_dotdotdot.match(enum.name):
+ partial = True
+ continue
if enum.value is not None:
nextenumvalue = self._parse_constant(enum.value)
+ enumerators.append(enum.name)
enumvalues.append(nextenumvalue)
self._add_constants(enum.name, nextenumvalue)
nextenumvalue += 1
+ enumerators = tuple(enumerators)
enumvalues = tuple(enumvalues)
tp = model.EnumType(explicit_name, enumerators, enumvalues)
tp.partial = partial
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -293,7 +293,7 @@
class StructOrUnion(StructOrUnionOrEnum):
fixedlayout = None
- completed = False
+ completed = 0
partial = False
packed = False
@@ -351,12 +351,13 @@
"for '%s'" % (self.name,))
return
BType = ffi._cached_btypes[self]
- if self.fldtypes is None:
- return # not completing it: it's an opaque struct
#
self.completed = 1
#
- if self.fixedlayout is None:
+ if self.fldtypes is None:
+ pass # not completing it: it's an opaque struct
+ #
+ elif self.fixedlayout is None:
fldtypes = [tp.get_cached_btype(ffi, finishlist)
for tp in self.fldtypes]
lst = list(zip(self.fldnames, fldtypes, self.fldbitsize))
diff --git a/cffi/setuptools_ext.py b/cffi/setuptools_ext.py
--- a/cffi/setuptools_ext.py
+++ b/cffi/setuptools_ext.py
@@ -76,7 +76,7 @@
from cffi import recompiler
allsources = ['$PLACEHOLDER']
- allsources.extend(kwds.get('sources', []))
+ allsources.extend(kwds.pop('sources', []))
ext = Extension(name=module_name, sources=allsources, **kwds)
def make_mod(tmpdir):
diff --git a/doc/source/cdef.rst b/doc/source/cdef.rst
--- a/doc/source/cdef.rst
+++ b/doc/source/cdef.rst
@@ -5,7 +5,9 @@
There are three or four different ways to use CFFI in a project.
In order of complexity:
-* The **"in-line", "ABI mode"**::
+* The **"in-line", "ABI mode"**:
+
+ .. code-block:: python
import cffi
@@ -18,7 +20,9 @@
.. _out-of-line-abi:
* The **"out-of-line",** but still **"ABI mode",** useful to organize
- the code and reduce the import time::
+ the code and reduce the import time:
+
+ .. code-block:: python
# in a separate file "package/foo_build.py"
import cffi
@@ -31,7 +35,9 @@
ffi.compile()
Running ``python foo_build.py`` produces a file ``_foo.py``, which
- can then be imported in the main program::
+ can then be imported in the main program:
+
+ .. code-block:: python
from package._foo import ffi
lib = ffi.dlopen("libpath")
@@ -42,7 +48,9 @@
* The **"out-of-line", "API mode"** gives you the most flexibility to
access a C library at the level of C, instead of at the binary
- level::
+ level:
+
+ .. code-block:: python
# in a separate file "package/foo_build.py"
import cffi
@@ -57,7 +65,9 @@
Running ``python foo_build.py`` produces a file ``_foo.c`` and
invokes the C compiler to turn it into a file ``_foo.so`` (or
``_foo.pyd`` or ``_foo.dylib``). It is a C extension module which
- can be imported in the main program::
+ can be imported in the main program:
+
+ .. code-block:: python
from package._foo import ffi, lib
# no ffi.dlopen()
@@ -68,7 +78,9 @@
* Finally, you can (but don't have to) use CFFI's **Distutils** or
**Setuptools integration** when writing a ``setup.py``. For
- Distutils (only in out-of-line API mode)::
+ Distutils (only in out-of-line API mode):
+
+ .. code-block:: python
# setup.py (requires CFFI to be installed first)
from distutils.core import setup
@@ -81,7 +93,9 @@
)
For Setuptools (out-of-line, but works in ABI or API mode;
- recommended)::
+ recommended):
+
+ .. code-block:: python
# setup.py (with automatic dependency tracking)
from setuptools import setup
@@ -95,8 +109,8 @@
Note that CFFI actually contains two different ``FFI`` classes. The
page `Using the ffi/lib objects`_ describes the common functionality.
-This minimum is what you get in the ``from package._foo import ffi``
-lines above. The extended ``FFI`` class is the one you get from
+It is what you get in the ``from package._foo import ffi`` lines above.
+On the other hand, the extended ``FFI`` class is the one you get from
``import cffi; ffi = cffi.FFI()``. It has the same functionality (for
in-line use), but also the extra methods described below (to prepare
the FFI).
@@ -111,6 +125,15 @@
split into a different PyPI package that only installs
``_cffi_backend``.)
+Note that a few small differences do exist: notably, ``from _foo import
+ffi`` returns an object of a type written in C, which does not let you
+add random attributes to it (nor does it have all the
+underscore-prefixed internal attributes of the Python version).
+Similarly, the ``lib`` objects returned by the C version are read-only,
+apart from writes to global variables. Also, ``lib.__dict__`` no
+longer works (it now tries to look up a hypothetical symbol
+``__dict__`` from the C library); use instead ``dir(lib)``.
+
ffi.cdef(): declaring types and functions
-----------------------------------------
@@ -277,6 +300,7 @@
like definitions for custom "wrapper" C functions. The goal is that
the .c file can be generated like this::
+ // C file "module_name.c"
#include <Python.h>
...c_header_source...
@@ -297,7 +321,7 @@
least ``libraries=['foo']`` in order to link with ``libfoo.so`` or
``libfoo.so.X.Y``, or ``foo.dll`` on Windows. The ``sources`` is a
list of extra .c files compiled and linked together (the file
-``module_name.c`` is always generated and automatically added as the
+``module_name.c`` shown above is always generated and automatically added as
the
first argument to ``sources``). See the distutils documentations for
`more information about the other arguments`__.
@@ -309,7 +333,9 @@
``source_extension``, defaulting to ``".c"``. The file generated will
be actually called ``module_name + source_extension``. Example for
C++ (but note that there are still a few known issues of C-versus-C++
-compatibility)::
+compatibility):
+
+.. code-block:: python
ffi.set_source("mymodule", '''
extern "C" {
@@ -456,6 +482,12 @@
for large projects where one CFFI-based interface depends on some
types declared in a different CFFI-based interface.
+*Note that you should only use one ffi object per library; the intended
+usage of ffi.include() is if you want to interface with several
+inter-dependent libraries.* For only one library, make one ``ffi``
+object. (You can write several ``cdef()`` calls over the same ``ffi``
+from several Python files, if one file would be too large.)
+
For out-of-line modules, the ``ffi.include(other_ffi)`` line should
occur in the build script, and the ``other_ffi`` argument should be
another FFI that comes from another build script. When the two build
@@ -474,11 +506,6 @@
In ABI mode, these must be accessed via the original ``other_lib``
object returned by the ``dlopen()`` method on ``other_ffi``.
-*Note that you should only use one ffi object per library; the
-intended usage of ffi.include() is if you want to interface with
-several inter-dependent libraries.* For only one library, make one
-``ffi`` object.
-
ffi.cdef() limitations
----------------------
@@ -571,7 +598,9 @@
One remaining use case for ``ffi.verify()`` would be the following
hack to find explicitly the size of any type, in bytes, and have it
available in Python immediately (e.g. because it is needed in order to
-write the rest of the build script)::
+write the rest of the build script):
+
+.. code-block:: python
ffi = cffi.FFI()
ffi.cdef("const int mysize;")
@@ -652,7 +681,9 @@
consider moving to the out-of-line approach new in 1.0. Here are the
steps.
-**ABI mode:** if your CFFI project uses::
+**ABI mode** if your CFFI project uses ``ffi.dlopen()``:
+
+.. code-block:: python
import cffi
@@ -668,7 +699,9 @@
.. __: distutils-setuptools_
-**API mode:** if your CFFI project uses::
+**API mode** if your CFFI project uses ``ffi.verify()``:
+
+.. code-block:: python
import cffi
@@ -689,7 +722,9 @@
The following example should work both with old (pre-1.0) and new
versions of CFFI---supporting both is important to run on PyPy,
-because CFFI 1.0 does not work in PyPy < 2.6::
+because CFFI 1.0 does not work in PyPy < 2.6:
+
+.. code-block:: python
# in a separate file "package/foo_build.py"
import cffi
@@ -710,7 +745,9 @@
if __name__ == "__main__":
ffi.compile()
-And in the main program::
+And in the main program:
+
+.. code-block:: python
try:
from package._foo import ffi, lib
@@ -723,7 +760,9 @@
Writing a ``setup.py`` script that works both with CFFI 0.9 and 1.0
requires explicitly checking the version of CFFI that we can have---it
-is hard-coded as a built-in module in PyPy::
+is hard-coded as a built-in module in PyPy:
+
+.. code-block:: python
if '_cffi_backend' in sys.builtin_module_names: # PyPy
import _cffi_backend
@@ -732,7 +771,9 @@
requires_cffi = "cffi>=1.0.0"
Then we use the ``requires_cffi`` variable to give different arguments to
-``setup()`` as needed, e.g.::
+``setup()`` as needed, e.g.:
+
+.. code-block:: python
if requires_cffi.startswith("cffi==0."):
# backward compatibility: we have "cffi==0.*"
diff --git a/doc/source/conf.py b/doc/source/conf.py
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -47,7 +47,7 @@
# The short X.Y version.
version = '1.0'
# The full version, including alpha/beta/rc tags.
-release = '1.0.0'
+release = '1.0.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -120,7 +120,7 @@
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+#html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
diff --git a/doc/source/installation.rst b/doc/source/installation.rst
--- a/doc/source/installation.rst
+++ b/doc/source/installation.rst
@@ -51,13 +51,13 @@
Download and Installation:
-* http://pypi.python.org/packages/source/c/cffi/cffi-1.0.0.tar.gz
+* http://pypi.python.org/packages/source/c/cffi/cffi-1.0.1.tar.gz
- Or grab the most current version by following the instructions below.
- - MD5: e0a938e4880fe60b8d0200e8370f8940
+ - MD5: ...
- - SHA: c97ff6f3dfc41ba3a762feea8ac13cdafa76a475
+ - SHA: ...
* Or get it from the `Bitbucket page`_:
``hg clone https://bitbucket.org/cffi/cffi``
diff --git a/doc/source/overview.rst b/doc/source/overview.rst
--- a/doc/source/overview.rst
+++ b/doc/source/overview.rst
@@ -83,7 +83,9 @@
For distribution purposes, remember that there is a new
``_simple_example.py`` file generated. You can either include it
statically within your project's source files, or, with Setuptools,
-you can say in the ``setup.py``::
+you can say in the ``setup.py``:
+
+.. code-block:: python
from setuptools import setup
@@ -196,6 +198,53 @@
.. _array: http://docs.python.org/library/array.html
+.. _performance:
+
+Purely for performance (API level, out-of-line)
+-----------------------------------------------
+
+A variant of the `section above`__ where the goal is not to call an
+existing C library, but to compile and call some C function written
+directly in the build script:
+
+.. __: real-example_
+
+.. code-block:: python
+
+ # file "example_build.py"
+
+ from cffi import FFI
+ ffi = FFI()
+
+ ffi.cdef("int foo(int *, int *, int);")
+
+ ffi.set_source("_example",
+ """
+ static int foo(int *buffer_in, int *buffer_out, int x)
+ {
+ /* some algorithm that is seriously faster in C than in Python */
+ }
+ """)
+
+ if __name__ == "__main__":
+ ffi.compile()
+
+.. code-block:: python
+
+ # file "example.py"
+
+ from _example import ffi, lib
+
+ buffer_in = ffi.new("int[]", 1000)
+ # initialize buffer_in here...
+
+ # easier to do all buffer allocations in Python and pass them to C,
+ # even for output-only arguments
+ buffer_out = ffi.new("int[]", 1000)
+
+ result = lib.foo(buffer_in, buffer_out, 1000)
+
+
What actually happened?
-----------------------
@@ -256,12 +305,20 @@
errors, as usual e.g. if you misdeclare some function's signature.
Note that the ``C header`` part can contain arbitrary C code. You can
-use it to declare some more helpers written in C. To export these
-helpers to Python, put their signature in the ``cdef()`` too. This
-can be used for example to wrap "crazy" macros into more standard C
-functions. (If all you need is to call "non-crazy" macros, then you
-can directly declare them in the ``cdef()`` as if they were
-functions.)
+use it to declare some more helper functions written in C. To export
+these helpers to Python, put their signature in the ``cdef()`` too.
+(You can use the ``static`` C keyword, as in ``static int
+myhelper(int x) { real_code_here; }``, because these helpers are only
+referenced from the "magic" C code that is generated afterwards in the
+same C file.)
+
+This can be used for example to wrap "crazy" macros into more standard
+C functions. The extra layer of C can be useful for other reasons
+too, like calling functions that expect some complicated argument
+structures that you prefer to build in C rather than in Python. On
+the other hand, if all you need is to call "function-like" macros,
+then you can directly declare them in the ``cdef()`` as if they were
+functions.
The generated piece of C code should be the same independently on the
platform on which you run it, so in simple cases you can simply
diff --git a/doc/source/using.rst b/doc/source/using.rst
--- a/doc/source/using.rst
+++ b/doc/source/using.rst
@@ -57,7 +57,9 @@
ownership, so you must keep it alive. As soon as you forget it, then
the casted pointer will point to garbage! In other words, the ownership
rules are attached to the *wrapper* cdata objects: they are not, and
-cannot, be attached to the underlying raw memory.) Example::
+cannot, be attached to the underlying raw memory.) Example:
+
+.. code-block:: python
global_weakkeydict = weakref.WeakKeyDictionary()
@@ -102,7 +104,9 @@
place to keep alive the original pointer object (returned by
``ffi.new()``).
-Example::
+Example:
+
+.. code-block:: python
# void somefunction(int *);
@@ -184,7 +188,9 @@
it all the time.
The C99 variable-sized structures are supported too, as long as the
-initializer says how long the array should be::
+initializer says how long the array should be:
+
+.. code-block:: python
# typedef struct { int x; int y[]; } foo_t;
@@ -267,7 +273,9 @@
When calling C functions, passing arguments follows mostly the same
rules as assigning to structure fields, and the return value follows the
-same rules as reading a structure field. For example::
+same rules as reading a structure field. For example:
+
+.. code-block:: python
# int foo(short a, int b);
@@ -276,7 +284,9 @@
You can pass to ``char *`` arguments a normal Python string (but don't
pass a normal Python string to functions that take a ``char *``
-argument and may mutate it!)::
+argument and may mutate it!):
+
+.. code-block:: python
# size_t strlen(const char *);
@@ -286,14 +296,18 @@
in general, there is no difference between C argument declarations that
use ``type *`` or ``type[]``. For example, ``int *`` is fully
equivalent to ``int[]`` or ``int[5]``. So you can pass an ``int *`` as
-a list of integers::
+a list of integers:
+
+.. code-block:: python
# void do_something_with_array(int *array);
lib.do_something_with_array([1, 2, 3, 4, 5])
CFFI supports passing and returning structs to functions and callbacks.
-Example::
+Example:
+
+.. code-block:: python
# struct foo_s { int a, b; };
# struct foo_s function_returning_a_struct(void);
@@ -319,7 +333,9 @@
function>``). This means you cannot e.g. pass them to some other C
function expecting a function pointer argument. Only ``ffi.typeof()``
works on them. If you really need a cdata pointer to the function,
-use the following workaround::
+use the following workaround:
+
+.. code-block:: python
ffi.cdef(""" int (*foo)(int a, int b); """)
@@ -335,18 +351,22 @@
all the arguments passed in the variable part *must* be cdata objects.
This is because it would not be possible to guess, if you wrote this::
- lib.printf("hello, %d\n", 42)
+ lib.printf("hello, %d\n", 42) # doesn't work!
that you really meant the 42 to be passed as a C ``int``, and not a
``long`` or ``long long``. The same issue occurs with ``float`` versus
``double``. So you have to force cdata objects of the C type you want,
-if necessary with ``ffi.cast()``::
+if necessary with ``ffi.cast()``:
+
+.. code-block:: python
lib.printf("hello, %d\n", ffi.cast("int", 42))
lib.printf("hello, %ld\n", ffi.cast("long", 42))
lib.printf("hello, %f\n", ffi.cast("double", 42))
-But of course::
+But of course:
+
+.. code-block:: python
lib.printf("hello, %s\n", ffi.new("char[]", "world"))
@@ -400,7 +420,9 @@
Note that callbacks of a variadic function type are not supported. A
workaround is to add custom C code. In the following example, a
callback gets a first argument that counts how many extra ``int``
-arguments are passed::
+arguments are passed:
+
+.. code-block:: python
# file "example_build.py"
@@ -427,7 +449,7 @@
}
""")
-::
+.. code-block:: python
# file "example.py"
@@ -450,7 +472,9 @@
and the C-level callback is made to return a default value.
The returned value in case of errors is 0 or null by default, but can be
-specified with the ``error`` keyword argument to ``ffi.callback()``::
+specified with the ``error`` keyword argument to ``ffi.callback()``:
+
+.. code-block:: python
@ffi.callback("int(int, int)", error=-1)
@@ -588,7 +612,9 @@
accepts a C type can receive either a string or a pre-parsed ``ctype``
object (and because of caching of the string, there is no real
performance difference). It can still be useful in writing typechecks,
-e.g.::
+e.g.:
+
+.. code-block:: python
def myfunction(ptr):
assert ffi.typeof(ptr) is ffi.typeof("foo_t*")
diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst
--- a/doc/source/whatsnew.rst
+++ b/doc/source/whatsnew.rst
@@ -3,6 +3,19 @@
======================
+1.0.1
+=====
+
+* ``ffi.set_source()`` crashed if passed a ``sources=[..]`` argument.
+ Fixed by chrippa on pull request #60.
+
+* Issue #193: if we use a struct between the first cdef() where it is
+ declared and another cdef() where its fields are defined, then this
+ definition was ignored.
+
+* Enums were buggy if you used too many "..." in their definition.
+
+
1.0.0
=====
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -143,7 +143,7 @@
`Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_
""",
- version='1.0.0',
+ version='1.0.1',
packages=['cffi'],
package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h']},
zip_safe=False,
diff --git a/testing/cffi0/backend_tests.py b/testing/cffi0/backend_tests.py
--- a/testing/cffi0/backend_tests.py
+++ b/testing/cffi0/backend_tests.py
@@ -1703,3 +1703,13 @@
assert lib.DOT_HEX == 0x100
assert lib.DOT_HEX2 == 0x10
assert lib.DOT_UL == 1000
+
+ def test_opaque_struct_becomes_nonopaque(self):
+ # Issue #193: if we use a struct between the first cdef() where it is
+ # declared and another cdef() where its fields are defined, then the
+ # definition was ignored.
+ ffi = FFI(backend=self.Backend())
+ ffi.cdef("struct foo_s;")
+ py.test.raises(TypeError, ffi.new, "struct foo_s *")
+ ffi.cdef("struct foo_s { int x; };")
+ ffi.new("struct foo_s *")
diff --git a/testing/cffi0/test_verify.py b/testing/cffi0/test_verify.py
--- a/testing/cffi0/test_verify.py
+++ b/testing/cffi0/test_verify.py
@@ -764,6 +764,11 @@
assert ffi.string(ffi.cast('enum ee2', -1239)) == 'EE4'
assert ffi.string(ffi.cast('enum ee2', -1238)) == 'EE5'
+def test_nonfull_enum_bug3():
+ ffi = FFI()
+ ffi.cdef("enum ee2 { EE4=..., EE5=... };")
+ ffi.cdef("enum ee6 { EE7=10, EE8=..., EE9=... };")
+
def test_get_set_errno():
ffi = FFI()
ffi.cdef("int foo(int);")
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit