[pypy-commit] cffi release-0.8: Merge for release 0.8.2

arigo noreply at buildbot.pypy.org
Fri Mar 7 07:52:55 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: release-0.8
Changeset: r1478:a34c2b828964
Date: 2014-03-07 07:52 +0100
http://bitbucket.org/cffi/cffi/changeset/a34c2b828964/

Log:	Merge for release 0.8.2

diff --git a/TODO b/TODO
--- a/TODO
+++ b/TODO
@@ -7,4 +7,4 @@
 an opaque type that works like a struct (so we can't get the value
 out of it).
 
-_cffi backend for PyPy
+accept and kill "static inline" in the cdefs
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -13,6 +13,9 @@
 #include <errno.h>
 #include <ffi.h>
 #include <sys/mman.h>
+#if (defined (__SVR4) && defined (__sun)) || defined(_AIX)
+#  include <alloca.h>
+#endif
 #endif
 
 #include "malloc_closure.h"
@@ -832,7 +835,7 @@
             return new_simple_cdata(ptrdata, ct);
         }
         else if (ct->ct_flags & CT_IS_OPAQUE) {
-            PyErr_Format(PyExc_TypeError, "cannot return a cdata '%s'",
+            PyErr_Format(PyExc_TypeError, "cdata '%s' is opaque",
                          ct->ct_name);
             return NULL;
         }
@@ -3580,9 +3583,40 @@
     return cf;   /* borrowed reference */
 }
 
-#define SF_MSVC_BITFIELDS 1
-#define SF_GCC_ARM_BITFIELDS 2
-#define SF_GCC_BIG_ENDIAN 4
+#define SF_MSVC_BITFIELDS     0x01
+#define SF_GCC_ARM_BITFIELDS  0x02
+#define SF_GCC_X86_BITFIELDS  0x10
+
+#define SF_GCC_BIG_ENDIAN     0x04
+#define SF_GCC_LITTLE_ENDIAN  0x40
+
+#define SF_PACKED             0x08
+
+static int complete_sflags(int sflags)
+{
+    /* add one of the SF_xxx_BITFIELDS flags if none is specified */
+    if (!(sflags & (SF_MSVC_BITFIELDS | SF_GCC_ARM_BITFIELDS |
+                    SF_GCC_X86_BITFIELDS))) {
+#ifdef MS_WIN32
+        sflags |= SF_MSVC_BITFIELDS;
+#else
+# ifdef __arm__
+        sflags |= SF_GCC_ARM_BITFIELDS;
+# else
+        sflags |= SF_GCC_X86_BITFIELDS;
+# endif
+#endif
+    }
+    /* add one of SF_GCC_xx_ENDIAN if none is specified */
+    if (!(sflags & (SF_GCC_BIG_ENDIAN | SF_GCC_LITTLE_ENDIAN))) {
+        int _check_endian = 1;
+        if (*(char *)&_check_endian == 0)
+            sflags |= SF_GCC_BIG_ENDIAN;
+        else
+            sflags |= SF_GCC_LITTLE_ENDIAN;
+    }
+    return sflags;
+}
 
 static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
 {
@@ -3594,18 +3628,7 @@
     int totalalignment = -1;
     CFieldObject **previous;
     int prev_bitfield_size, prev_bitfield_free;
-#ifdef MS_WIN32
-    int sflags = SF_MSVC_BITFIELDS;
-#else
-# ifdef __arm__
-    int sflags = SF_GCC_ARM_BITFIELDS;
-# else
     int sflags = 0;
-# endif
-    int _check_endian = 1;
-    if (*(char *)&_check_endian == 0)
-        sflags |= SF_GCC_BIG_ENDIAN;
-#endif
 
     if (!PyArg_ParseTuple(args, "O!O!|Onii:complete_struct_or_union",
                           &CTypeDescr_Type, &ct,
@@ -3613,6 +3636,8 @@
                           &ignored, &totalsize, &totalalignment, &sflags))
         return NULL;
 
+    sflags = complete_sflags(sflags);
+
     if ((ct->ct_flags & (CT_STRUCT|CT_IS_OPAQUE)) ==
                         (CT_STRUCT|CT_IS_OPAQUE)) {
         is_union = 0;
@@ -3668,8 +3693,8 @@
             boffset = 0;   /* reset each field at offset 0 */
 
         /* update the total alignment requirement, but skip it if the
-           field is an anonymous bitfield */
-        falign = get_alignment(ftype);
+           field is an anonymous bitfield or if SF_PACKED */
+        falign = (sflags & SF_PACKED) ? 1 : get_alignment(ftype);
         if (falign < 0)
             goto error;
 
@@ -3781,6 +3806,7 @@
                     PyErr_Format(PyExc_TypeError,
                                  "field '%s.%s' is declared with :0",
                                  ct->ct_name, PyText_AS_UTF8(fname));
+                    goto error;
                 }
                 if (!(sflags & SF_MSVC_BITFIELDS)) {
                     /* GCC's notion of "ftype :0;" */
@@ -3812,6 +3838,14 @@
                     if (bits_already_occupied + fbitsize > 8 * ftype->ct_size) {
                         /* it would not fit, we need to start at the next
                            allowed position */
+                        if ((sflags & SF_PACKED) &&
+                            (bits_already_occupied & 7)) {
+                            PyErr_Format(PyExc_NotImplementedError,
+                                "with 'packed', gcc would compile field "
+                                "'%s.%s' to reuse some bits in the previous "
+                                "field", ct->ct_name, PyText_AS_UTF8(fname));
+                            goto error;
+                        }
                         field_offset_bytes += falign;
                         assert(boffset < field_offset_bytes * 8);
                         boffset = field_offset_bytes * 8;
@@ -5448,7 +5482,7 @@
     if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0)
         INITERROR;
 
-    v = PyText_FromString("0.8");
+    v = PyText_FromString("0.8.2");
     if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0)
         INITERROR;
 
diff --git a/c/minibuffer.h b/c/minibuffer.h
--- a/c/minibuffer.h
+++ b/c/minibuffer.h
@@ -93,6 +93,14 @@
         *lenp = self->mb_size;
     return 1;
 }
+
+static PyObject *mb_str(MiniBufferObj *self)
+{
+    /* Python 2: we want str(buffer) to behave like buffer[:], because
+       that's what bytes(buffer) does on Python 3 and there is no way
+       we can prevent this. */
+    return PyString_FromStringAndSize(self->mb_data, self->mb_size);
+}
 #endif
 
 static int mb_getbuf(MiniBufferObj *self, Py_buffer *view, int flags)
@@ -249,7 +257,11 @@
 #endif
     0,                                          /* tp_hash */
     0,                                          /* tp_call */
+#if PY_MAJOR_VERSION < 3
+    (reprfunc)mb_str,                           /* tp_str */
+#else
     0,                                          /* tp_str */
+#endif
     PyObject_GenericGetAttr,                    /* tp_getattro */
     0,                                          /* tp_setattro */
     &mb_as_buffer,                              /* tp_as_buffer */
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -370,6 +370,9 @@
     assert x.load_function(BVoidP, 'strcpy')
     py.test.raises(KeyError, x.load_function,
                    BVoidP, 'xxx_this_function_does_not_exist')
+    # the next one is from 'libm', not 'libc', but we assume
+    # that it is already loaded too, so it should work
+    assert x.load_function(BVoidP, 'sqrt')
 
 def test_hash_differences():
     BChar = new_primitive_type("char")
@@ -1429,8 +1432,10 @@
     p = newp(BStructPtr, [12])
     assert p.a1 == 12
     e = py.test.raises(TypeError, newp, BStructPtr, [None])
-    assert ("an integer is required" in str(e.value) or
-        "unsupported operand type for int(): 'NoneType'" in str(e.value)) #PyPy
+    msg = str(e.value)
+    assert ("an integer is required" in msg or  # CPython
+            "unsupported operand type for int(): 'NoneType'" in msg or  # old PyPys
+            "expected integer, got NoneType object" in msg) # newer PyPys
     py.test.raises(TypeError, 'p.a1 = "def"')
     if sys.version_info < (3,):
         BEnum2 = new_enum_type(unicode("foo"), (unicode('abc'),), (5,), BInt)
@@ -2154,7 +2159,13 @@
     c = newp(BCharArray, b"hi there")
     #
     buf = buffer(c)
-    assert str(buf).startswith('<_cffi_backend.buffer object at 0x')
+    assert repr(buf).startswith('<_cffi_backend.buffer object at 0x')
+    assert bytes(buf) == b"hi there\x00"
+    if sys.version_info < (3,):
+        assert str(buf) == "hi there\x00"
+        assert unicode(buf) == u+"hi there\x00"
+    else:
+        assert str(buf) == repr(buf)
     # --mb_length--
     assert len(buf) == len(b"hi there\x00")
     # --mb_item--
@@ -2886,7 +2897,7 @@
                                        ('b1', BInt, 9),
                                        ('b2', BUInt, 7),
                                        ('c', BChar, -1)], -1, -1, -1, flag)
-    if flag % 2 == 0:   # gcc, any variant
+    if not (flag & SF_MSVC_BITFIELDS):   # gcc, any variant
         assert typeoffsetof(BStruct, 'c') == (BChar, 3)
         assert sizeof(BStruct) == 4
     else:               # msvc
@@ -2901,20 +2912,20 @@
     p.c = b'\x9D'
     raw = buffer(p)[:]
     if sys.byteorder == 'little':
-        if flag == 0 or flag == 2:  # gcc, little endian
+        if flag & SF_MSVC_BITFIELDS:
+            assert raw == b'A\x00\x00\x007\xC7\x00\x00\x9D\x00\x00\x00'
+        elif flag & SF_GCC_LITTLE_ENDIAN:
             assert raw == b'A7\xC7\x9D'
-        elif flag == 1: # msvc
-            assert raw == b'A\x00\x00\x007\xC7\x00\x00\x9D\x00\x00\x00'
-        elif flag == 4: # gcc, big endian
+        elif flag & SF_GCC_BIG_ENDIAN:
             assert raw == b'A\xE3\x9B\x9D'
         else:
             raise AssertionError("bad flag")
     else:
-        if flag == 0 or flag == 2:  # gcc
+        if flag & SF_MSVC_BITFIELDS:
+            assert raw == b'A\x00\x00\x00\x00\x00\xC77\x9D\x00\x00\x00'
+        elif flag & SF_GCC_LITTLE_ENDIAN:
             assert raw == b'A\xC77\x9D'
-        elif flag == 1: # msvc
-            assert raw == b'A\x00\x00\x00\x00\x00\xC77\x9D\x00\x00\x00'
-        elif flag == 4: # gcc, big endian
+        elif flag & SF_GCC_BIG_ENDIAN:
             assert raw == b'A\x9B\xE3\x9D'
         else:
             raise AssertionError("bad flag")
@@ -2924,18 +2935,15 @@
                                        ('',  BShort, 9),
                                        ('c', BChar, -1)], -1, -1, -1, flag)
     assert typeoffsetof(BStruct, 'c') == (BChar, 4)
-    if flag == 0:   # gcc
+    if flag & SF_MSVC_BITFIELDS:
+        assert sizeof(BStruct) == 6
+        assert alignof(BStruct) == 2
+    elif flag & SF_GCC_X86_BITFIELDS:
         assert sizeof(BStruct) == 5
         assert alignof(BStruct) == 1
-    elif flag == 1: # msvc
+    elif flag & SF_GCC_ARM_BITFIELDS:
         assert sizeof(BStruct) == 6
         assert alignof(BStruct) == 2
-    elif flag == 2: # gcc ARM
-        assert sizeof(BStruct) == 6
-        assert alignof(BStruct) == 2
-    elif flag == 4: # gcc, big endian
-        assert sizeof(BStruct) == 5
-        assert alignof(BStruct) == 1
     else:
         raise AssertionError("bad flag")
     #
@@ -2944,37 +2952,43 @@
                                        ('',  BInt, 0),
                                        ('',  BInt, 0),
                                        ('c', BChar, -1)], -1, -1, -1, flag)
-    if flag == 0:    # gcc
+    if flag & SF_MSVC_BITFIELDS:
+        assert typeoffsetof(BStruct, 'c') == (BChar, 1)
+        assert sizeof(BStruct) == 2
+        assert alignof(BStruct) == 1
+    elif flag & SF_GCC_X86_BITFIELDS:
         assert typeoffsetof(BStruct, 'c') == (BChar, 4)
         assert sizeof(BStruct) == 5
         assert alignof(BStruct) == 1
-    elif flag == 1:  # msvc
-        assert typeoffsetof(BStruct, 'c') == (BChar, 1)
-        assert sizeof(BStruct) == 2
-        assert alignof(BStruct) == 1
-    elif flag == 2:  # gcc ARM
+    elif flag & SF_GCC_ARM_BITFIELDS:
         assert typeoffsetof(BStruct, 'c') == (BChar, 4)
         assert sizeof(BStruct) == 8
         assert alignof(BStruct) == 4
-    elif flag == 4:  # gcc, big endian
-        assert typeoffsetof(BStruct, 'c') == (BChar, 4)
-        assert sizeof(BStruct) == 5
-        assert alignof(BStruct) == 1
     else:
         raise AssertionError("bad flag")
 
 
-def test_bitfield_as_gcc():
-    _test_bitfield_details(flag=0)
+SF_MSVC_BITFIELDS     = 0x01
+SF_GCC_ARM_BITFIELDS  = 0x02
+SF_GCC_X86_BITFIELDS  = 0x10
+
+SF_GCC_BIG_ENDIAN     = 0x04
+SF_GCC_LITTLE_ENDIAN  = 0x40
+
+SF_PACKED             = 0x08
+
+def test_bitfield_as_x86_gcc():
+    _test_bitfield_details(flag=SF_GCC_X86_BITFIELDS|SF_GCC_LITTLE_ENDIAN)
 
 def test_bitfield_as_msvc():
-    _test_bitfield_details(flag=1)
+    _test_bitfield_details(flag=SF_MSVC_BITFIELDS|SF_GCC_LITTLE_ENDIAN)
 
 def test_bitfield_as_arm_gcc():
-    _test_bitfield_details(flag=2)
+    _test_bitfield_details(flag=SF_GCC_ARM_BITFIELDS|SF_GCC_LITTLE_ENDIAN)
 
-def test_bitfield_as_big_endian():
-    _test_bitfield_details(flag=4)
+def test_bitfield_as_ppc_gcc():
+    # PowerPC uses the same format as X86, but is big-endian
+    _test_bitfield_details(flag=SF_GCC_X86_BITFIELDS|SF_GCC_BIG_ENDIAN)
 
 
 def test_struct_array_no_length():
@@ -3136,7 +3150,53 @@
     py.test.raises(TypeError, "p + cast(new_primitive_type('int'), 42)")
     py.test.raises(TypeError, "p - cast(new_primitive_type('int'), 42)")
 
+def test_sizeof_sliced_array():
+    BInt = new_primitive_type("int")
+    BArray = new_array_type(new_pointer_type(BInt), 10)
+    p = newp(BArray, None)
+    assert sizeof(p[2:9]) == 7 * sizeof(BInt)
+
+def test_packed():
+    BLong = new_primitive_type("long")
+    BChar = new_primitive_type("char")
+    BShort = new_primitive_type("short")
+    BStruct = new_struct_type("struct foo")
+    complete_struct_or_union(BStruct, [('a1', BLong, -1),
+                                       ('a2', BChar, -1),
+                                       ('a3', BShort, -1)],
+                             None, -1, -1, SF_PACKED)
+    d = BStruct.fields
+    assert len(d) == 3
+    assert d[0][0] == 'a1'
+    assert d[0][1].type is BLong
+    assert d[0][1].offset == 0
+    assert d[0][1].bitshift == -1
+    assert d[0][1].bitsize == -1
+    assert d[1][0] == 'a2'
+    assert d[1][1].type is BChar
+    assert d[1][1].offset == sizeof(BLong)
+    assert d[1][1].bitshift == -1
+    assert d[1][1].bitsize == -1
+    assert d[2][0] == 'a3'
+    assert d[2][1].type is BShort
+    assert d[2][1].offset == sizeof(BLong) + sizeof(BChar)
+    assert d[2][1].bitshift == -1
+    assert d[2][1].bitsize == -1
+    assert sizeof(BStruct) == sizeof(BLong) + sizeof(BChar) + sizeof(BShort)
+    assert alignof(BStruct) == 1
+
+def test_packed_with_bitfields():
+    if sys.platform == "win32":
+        py.test.skip("testing gcc behavior")
+    BLong = new_primitive_type("long")
+    BChar = new_primitive_type("char")
+    BStruct = new_struct_type("struct foo")
+    py.test.raises(NotImplementedError,
+                   complete_struct_or_union,
+                   BStruct, [('a1', BLong, 30),
+                             ('a2', BChar, 5)],
+                   None, -1, -1, SF_PACKED)
 
 def test_version():
     # this test is here mostly for PyPy
-    assert __version__ == "0.8"
+    assert __version__ == "0.8.2"
diff --git a/cffi/__init__.py b/cffi/__init__.py
--- a/cffi/__init__.py
+++ b/cffi/__init__.py
@@ -4,5 +4,5 @@
 from .api import FFI, CDefError, FFIError
 from .ffiplatform import VerificationError, VerificationMissing
 
-__version__ = "0.8.1"
-__version_info__ = (0, 8, 1)
+__version__ = "0.8.2"
+__version_info__ = (0, 8, 2)
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -1,4 +1,4 @@
-import types
+import sys, types
 from .lock import allocate_lock
 
 try:
@@ -88,18 +88,20 @@
             self.NULL = self.cast(self.BVoidP, 0)
             self.CData, self.CType = backend._get_types()
 
-    def cdef(self, csource, override=False):
+    def cdef(self, csource, override=False, packed=False):
         """Parse the given C source.  This registers all declared functions,
         types, and global variables.  The functions and global variables can
         then be accessed via either 'ffi.dlopen()' or 'ffi.verify()'.
         The types can be used in 'ffi.new()' and other functions.
+        If 'packed' is specified as True, all structs declared inside this
+        cdef are packed, i.e. laid out without any field alignment at all.
         """
         if not isinstance(csource, str):    # unicode, on Python 2
             if not isinstance(csource, basestring):
                 raise TypeError("cdef() argument must be a string")
             csource = csource.encode('ascii')
         with self._lock:
-            self._parser.parse(csource, override=override)
+            self._parser.parse(csource, override=override, packed=packed)
             self._cdefsources.append(csource)
             if override:
                 for cache in self._function_caches:
@@ -387,22 +389,27 @@
         return self._backend.from_handle(x)
 
 
-def _make_ffi_library(ffi, libname, flags):
-    import os
-    name = libname
+def _load_backend_lib(backend, name, flags):
     if name is None:
-        name = 'c'    # on Posix only
-    backend = ffi._backend
+        if sys.platform != "win32":
+            return backend.load_library(None, flags)
+        name = "c"    # Windows: load_library(None) fails, but this works
+                      # (backward compatibility hack only)
     try:
         if '.' not in name and '/' not in name:
             raise OSError("library not found: %r" % (name,))
-        backendlib = backend.load_library(name, flags)
+        return backend.load_library(name, flags)
     except OSError:
         import ctypes.util
         path = ctypes.util.find_library(name)
         if path is None:
             raise     # propagate the original OSError
-        backendlib = backend.load_library(path, flags)
+        return backend.load_library(path, flags)
+
+def _make_ffi_library(ffi, libname, flags):
+    import os
+    backend = ffi._backend
+    backendlib = _load_backend_lib(backend, libname, flags)
     copied_enums = []
     #
     def make_accessor_locked(name):
diff --git a/cffi/backend_ctypes.py b/cffi/backend_ctypes.py
--- a/cffi/backend_ctypes.py
+++ b/cffi/backend_ctypes.py
@@ -720,7 +720,7 @@
         return self._new_struct_or_union('union', name, ctypes.Union)
 
     def complete_struct_or_union(self, CTypesStructOrUnion, fields, tp,
-                                 totalsize=-1, totalalignment=-1):
+                                 totalsize=-1, totalalignment=-1, sflags=0):
         if totalsize >= 0 or totalalignment >= 0:
             raise NotImplementedError("the ctypes backend of CFFI does not support "
                                       "structures completed by verify(); please "
@@ -739,6 +739,8 @@
             else:
                 cfields.append((fname, BField._ctype, bitsize))
                 bfield_types[fname] = Ellipsis
+        if sflags & 8:
+            struct_or_union._pack_ = 1
         struct_or_union._fields_ = cfields
         CTypesStructOrUnion._bfield_types = bfield_types
         #
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -98,6 +98,7 @@
         self._anonymous_counter = 0
         self._structnode2type = weakref.WeakKeyDictionary()
         self._override = False
+        self._packed = False
 
     def _parse(self, csource):
         csource, macros = _preprocess(csource)
@@ -147,13 +148,16 @@
             msg = 'parse error\n%s' % (msg,)
         raise api.CDefError(msg)
 
-    def parse(self, csource, override=False):
+    def parse(self, csource, override=False, packed=False):
         prev_override = self._override
+        prev_packed = self._packed
         try:
             self._override = override
+            self._packed = packed
             self._internal_parse(csource)
         finally:
             self._override = prev_override
+            self._packed = prev_packed
 
     def _internal_parse(self, csource):
         ast, macros = self._parse(csource)
@@ -476,6 +480,7 @@
             if isinstance(tp, model.StructType) and tp.partial:
                 raise NotImplementedError("%s: using both bitfields and '...;'"
                                           % (tp,))
+        tp.packed = self._packed
         return tp
 
     def _make_partial(self, tp, nested):
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -1,4 +1,6 @@
+import types
 import weakref
+
 from .lock import allocate_lock
 
 
@@ -81,29 +83,29 @@
         'long':               'i',
         'long long':          'i',
         'signed char':        'i',
-        'unsigned char':      'u',
-        'unsigned short':     'u',
-        'unsigned int':       'u',
-        'unsigned long':      'u',
-        'unsigned long long': 'u',
+        'unsigned char':      'i',
+        'unsigned short':     'i',
+        'unsigned int':       'i',
+        'unsigned long':      'i',
+        'unsigned long long': 'i',
         'float':              'f',
         'double':             'f',
         'long double':        'f',
-        '_Bool':              'u',
+        '_Bool':              'i',
         # the following types are not primitive in the C sense
         'wchar_t':            'c',
         'int8_t':             'i',
-        'uint8_t':            'u',
+        'uint8_t':            'i',
         'int16_t':            'i',
-        'uint16_t':           'u',
+        'uint16_t':           'i',
         'int32_t':            'i',
-        'uint32_t':           'u',
+        'uint32_t':           'i',
         'int64_t':            'i',
-        'uint64_t':           'u',
+        'uint64_t':           'i',
         'intptr_t':           'i',
-        'uintptr_t':          'u',
+        'uintptr_t':          'i',
         'ptrdiff_t':          'i',
-        'size_t':             'u',
+        'size_t':             'i',
         'ssize_t':            'i',
         }
 
@@ -114,12 +116,8 @@
 
     def is_char_type(self):
         return self.ALL_PRIMITIVE_TYPES[self.name] == 'c'
-    def is_signed_type(self):
+    def is_integer_type(self):
         return self.ALL_PRIMITIVE_TYPES[self.name] == 'i'
-    def is_unsigned_type(self):
-        return self.ALL_PRIMITIVE_TYPES[self.name] == 'u'
-    def is_integer_type(self):
-        return self.ALL_PRIMITIVE_TYPES[self.name] in 'iu'
     def is_float_type(self):
         return self.ALL_PRIMITIVE_TYPES[self.name] == 'f'
 
@@ -259,6 +257,7 @@
     fixedlayout = None
     completed = False
     partial = False
+    packed = False
 
     def __init__(self, name, fldnames, fldtypes, fldbitsize):
         self.name = name
@@ -315,7 +314,11 @@
             fldtypes = [tp.get_cached_btype(ffi, finishlist)
                         for tp in self.fldtypes]
             lst = list(zip(self.fldnames, fldtypes, self.fldbitsize))
-            ffi._backend.complete_struct_or_union(BType, lst, self)
+            sflags = 0
+            if self.packed:
+                sflags = 8    # SF_PACKED
+            ffi._backend.complete_struct_or_union(BType, lst, self,
+                                                  -1, -1, sflags)
             #
         else:
             fldtypes = []
@@ -468,8 +471,7 @@
         # initialize the __typecache attribute, either at the module level
         # if ffi._backend is a module, or at the class level if ffi._backend
         # is some instance.
-        ModuleType = type(weakref)
-        if isinstance(ffi._backend, ModuleType):
+        if isinstance(ffi._backend, types.ModuleType):
             ffi._backend.__typecache = weakref.WeakValueDictionary()
         else:
             type(ffi._backend).__typecache = weakref.WeakValueDictionary()
diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py
--- a/cffi/vengine_cpy.py
+++ b/cffi/vengine_cpy.py
@@ -214,10 +214,7 @@
         extraarg = ''
         if isinstance(tp, model.PrimitiveType):
             if tp.is_integer_type() and tp.name != '_Bool':
-                if tp.is_signed_type():
-                    converter = '_cffi_to_c_SIGNED'
-                else:
-                    converter = '_cffi_to_c_UNSIGNED'
+                converter = '_cffi_to_c_int'
                 extraarg = ', %s' % tp.name
             else:
                 converter = '_cffi_to_c_%s' % (tp.name.replace(' ', '_'),)
@@ -270,10 +267,7 @@
     def _convert_expr_from_c(self, tp, var, context):
         if isinstance(tp, model.PrimitiveType):
             if tp.is_integer_type():
-                if tp.is_signed_type():
-                    return '_cffi_from_c_SIGNED(%s, %s)' % (var, tp.name)
-                else:
-                    return '_cffi_from_c_UNSIGNED(%s, %s)' % (var, tp.name)
+                return '_cffi_from_c_int(%s, %s)' % (var, tp.name)
             elif tp.name != 'long double':
                 return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var)
             else:
@@ -801,25 +795,23 @@
 #define _cffi_to_c_double PyFloat_AsDouble
 #define _cffi_to_c_float PyFloat_AsDouble
 
-#define _cffi_from_c_SIGNED(x, type)                                     \
-    (sizeof(type) <= sizeof(long) ? PyInt_FromLong(x) :                  \
-                                    PyLong_FromLongLong(x))
-#define _cffi_from_c_UNSIGNED(x, type)                                   \
-    (sizeof(type) < sizeof(long) ? PyInt_FromLong(x) :                   \
-     sizeof(type) == sizeof(long) ? PyLong_FromUnsignedLong(x) :         \
-                                    PyLong_FromUnsignedLongLong(x))
+#define _cffi_from_c_int(x, type)                                        \
+    (((type)-1) > 0 ?   /* unsigned */                                   \
+        (sizeof(type) < sizeof(long) ? PyInt_FromLong(x) :               \
+         sizeof(type) == sizeof(long) ? PyLong_FromUnsignedLong(x) :     \
+                                        PyLong_FromUnsignedLongLong(x))  \
+      : (sizeof(type) <= sizeof(long) ? PyInt_FromLong(x) :              \
+                                        PyLong_FromLongLong(x)))
 
-#define _cffi_to_c_SIGNED(o, type)                                       \
-    (sizeof(type) == 1 ? _cffi_to_c_i8(o) :                              \
-     sizeof(type) == 2 ? _cffi_to_c_i16(o) :                             \
-     sizeof(type) == 4 ? _cffi_to_c_i32(o) :                             \
-     sizeof(type) == 8 ? _cffi_to_c_i64(o) :                             \
-     (Py_FatalError("unsupported size for type " #type), 0))
-#define _cffi_to_c_UNSIGNED(o, type)                                     \
-    (sizeof(type) == 1 ? _cffi_to_c_u8(o) :                              \
-     sizeof(type) == 2 ? _cffi_to_c_u16(o) :                             \
-     sizeof(type) == 4 ? _cffi_to_c_u32(o) :                             \
-     sizeof(type) == 8 ? _cffi_to_c_u64(o) :                             \
+#define _cffi_to_c_int(o, type)                                          \
+    (sizeof(type) == 1 ? (((type)-1) > 0 ? _cffi_to_c_u8(o)              \
+                                         : _cffi_to_c_i8(o)) :           \
+     sizeof(type) == 2 ? (((type)-1) > 0 ? _cffi_to_c_u16(o)             \
+                                         : _cffi_to_c_i16(o)) :          \
+     sizeof(type) == 4 ? (((type)-1) > 0 ? _cffi_to_c_u32(o)             \
+                                         : _cffi_to_c_i32(o)) :          \
+     sizeof(type) == 8 ? (((type)-1) > 0 ? _cffi_to_c_u64(o)             \
+                                         : _cffi_to_c_i64(o)) :          \
      (Py_FatalError("unsupported size for type " #type), 0))
 
 #define _cffi_to_c_i8                                                    \
@@ -905,11 +897,13 @@
     if (c_api_object == NULL)
         return;
     if (!PyCapsule_CheckExact(c_api_object)) {
+        Py_DECREF(c_api_object);
         PyErr_SetNone(PyExc_ImportError);
         return;
     }
     memcpy(_cffi_exports, PyCapsule_GetPointer(c_api_object, "cffi"),
            _CFFI_NUM_EXPORTS * sizeof(void *));
+    Py_DECREF(c_api_object);
 }
 
 #define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num))
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 = '0.8'
 # The full version, including alpha/beta/rc tags.
-release = '0.8.1'
+release = '0.8.2'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -85,13 +85,13 @@
 
 Download and Installation:
 
-* http://pypi.python.org/packages/source/c/cffi/cffi-0.8.1.tar.gz
+* http://pypi.python.org/packages/source/c/cffi/cffi-0.8.2.tar.gz
 
    - Or grab the most current version by following the instructions below.
 
-   - MD5: 1a877bf113bfe90fdefedbf9e39310d2
+   - MD5: ...
 
-   - SHA: d46b7cf92956fa01d9f8e0a8d3c7e2005ae40893
+   - SHA: ...
 
 * Or get it from the `Bitbucket page`_:
   ``hg clone https://bitbucket.org/cffi/cffi``
@@ -851,6 +851,14 @@
 ``ffi`` normally caches the string ``"int[]"`` to not need to re-parse
 it all the time.
 
+.. versionadded:: 0.9
+   The ``ffi.cdef()`` call takes an optional argument ``packed``: if
+   True, then all structs declared within this cdef are "packed".  This
+   has a meaning similar to ``__attribute__((packed))`` in GCC.  It
+   specifies that all structure fields should have an alignment of one
+   byte.  (Note that the packed attribute has no effect on bit fields so
+   far, which mean that they may be packed differently than on GCC.)
+
 
 Python 3 support
 ----------------
@@ -1172,7 +1180,7 @@
    because these objects' API changes too much across Python versions.
    Instead it has the following Python API (a subset of ``buffer``):
 
-- ``buf[:]``: fetch a copy as a regular byte string (or
+- ``buf[:]`` or ``bytes(buf)``: fetch a copy as a regular byte string (or
   ``buf[start:end]`` for a part)
 
 - ``buf[:] = newstr``: change the original content (or ``buf[start:end]
@@ -1187,6 +1195,14 @@
    owned memory will not be freed as long as the buffer is alive.
    Moreover buffer objects now support weakrefs to them.
 
+.. versionchanged:: 0.9
+   Before version 0.9, ``bytes(buf)`` was supported in Python 3 to get
+   the content of the buffer, but on Python 2 it would return the repr
+   ``<_cffi_backend.buffer object>``.  This has been fixed.  But you
+   should avoid using ``str(buf)``: it now gives inconsistent results
+   between Python 2 and Python 3 (this is similar to how ``str()``
+   gives inconsistent results on regular byte strings).
+
 
 ``ffi.typeof("C type" or cdata object)``: return an object of type
 ``<ctype>`` corresponding to the parsed string, or to the C type of the
@@ -1257,13 +1273,19 @@
 ``void *`` that contains an opaque reference to ``python_object``.  You
 can pass it around to C functions or store it into C structures.  Later,
 you can use ``ffi.from_handle(p)`` to retrive the original
-``python_object`` from a value with the same ``void *`` pointer.  The
-cdata object returned by ``new_handle()`` has *ownership*, in the same
-sense as ``ffi.new()`` or ``ffi.gc()``: the association ``void * ->
-python_object`` is only valid as long as *this* exact cdata returned by
-``new_handle()`` is alive.  *Calling ffi.from_handle(p) is invalid and
-will likely crash if the cdata object returned by new_handle() is not
-kept alive!* *New in version 0.7.*
+``python_object`` from a value with the same ``void *`` pointer.
+*Calling ffi.from_handle(p) is invalid and will likely crash if
+the cdata object returned by new_handle() is not kept alive!*
+*New in version 0.7.*
+
+Note that ``from_handle()`` conceptually works like this: it searches in
+the list of cdata objects made by ``new_handle()`` the one which has got
+the same ``void *`` value; and then it fetches in that cdata object the
+corresponding Python object.  The cdata object keeps the Python object
+alive, similar to how ``ffi.new()`` returns a cdata object that keeps a
+piece of memory alive.  If the cdata object *itself* is not alive any
+more, then the association ``void * -> python_object`` is dead and
+``from_handle()`` will crash.
 
 .. "versionadded:: 0.7" --- inlined in the previous paragraph
 
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -42,6 +42,11 @@
             resultlist[:] = res
 
 def ask_supports_thread():
+    if sys.platform == "darwin":
+        sys.stderr.write("OS/X: confusion between 'cc' versus 'gcc'")
+        sys.stderr.write(" (see issue 123)\n")
+        sys.stderr.write("will not use '__thread' in the C code\n")
+        return
     import distutils.errors
     from distutils.ccompiler import new_compiler
     compiler = new_compiler(force=1)
@@ -91,11 +96,23 @@
 
 
 if __name__ == '__main__':
-  from setuptools import setup, Feature, Extension
-  setup(
-    name='cffi',
-    description='Foreign Function Interface for Python calling C code.',
-    long_description="""
+    from setuptools import setup, Extension
+    ext_modules = []
+    if '__pypy__' not in sys.modules:
+        ext_modules.append(Extension(
+            name='_cffi_backend',
+            include_dirs=include_dirs,
+            sources=sources,
+            libraries=libraries,
+            define_macros=define_macros,
+            library_dirs=library_dirs,
+            extra_compile_args=extra_compile_args,
+            extra_link_args=extra_link_args,
+        ))
+    setup(
+        name='cffi',
+        description='Foreign Function Interface for Python calling C code.',
+        long_description="""
 CFFI
 ====
 
@@ -106,36 +123,29 @@
 -------
 
 `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_
-    """,
-    version='0.8.1',
-    packages=['cffi'],
-    zip_safe=False,
+""",
+        version='0.8.2',
+        packages=['cffi'],
+        zip_safe=False,
 
-    url='http://cffi.readthedocs.org',
-    author='Armin Rigo, Maciej Fijalkowski',
-    author_email='python-cffi at googlegroups.com',
+        url='http://cffi.readthedocs.org',
+        author='Armin Rigo, Maciej Fijalkowski',
+        author_email='python-cffi at googlegroups.com',
 
-    license='MIT',
+        license='MIT',
 
-    features={
-        'cextension': Feature(
-            "fast c backend for cpython",
-            standard='__pypy__' not in sys.modules,
-            ext_modules=[
-                Extension(name='_cffi_backend',
-                          include_dirs=include_dirs,
-                          sources=sources,
-                          libraries=libraries,
-                          define_macros=define_macros,
-                          library_dirs=library_dirs,
-                          extra_compile_args=extra_compile_args,
-                          extra_link_args=extra_link_args,
-                          ),
-            ],
-        ),
-    },
+        ext_modules=ext_modules,
 
-    install_requires=[
-        'pycparser',
-    ]
-  )
+        install_requires=[
+            'pycparser',
+        ],
+        classifiers=[
+            'Programming Language :: Python',
+            'Programming Language :: Python :: 2',
+            'Programming Language :: Python :: 2.6',
+            'Programming Language :: Python :: 2.7',
+            'Programming Language :: Python :: 3',
+            'Programming Language :: Python :: 3.2',
+            'Programming Language :: Python :: 3.3',
+        ],
+    )
diff --git a/testing/backend_tests.py b/testing/backend_tests.py
--- a/testing/backend_tests.py
+++ b/testing/backend_tests.py
@@ -1,4 +1,5 @@
 import py
+import platform
 import sys, ctypes
 from cffi import FFI, CDefError
 from testing.support import *
@@ -755,6 +756,8 @@
         p = ffi.cast("long long", ffi.cast("wchar_t", -1))
         if SIZE_OF_WCHAR == 2:      # 2 bytes, unsigned
             assert int(p) == 0xffff
+        elif platform.machine() == 'aarch64': # 4 bytes, unsigned
+            assert int(p) == 0xffffffff
         else:                       # 4 bytes, signed
             assert int(p) == -1
         p = ffi.cast("int", u+'\u1234')
@@ -1549,3 +1552,21 @@
         ffi2.include(ffi1)
         p = ffi2.new("foo_p", [142])
         assert p.x == 142
+
+    def test_struct_packed(self):
+        ffi = FFI(backend=self.Backend())
+        ffi.cdef("struct nonpacked { char a; int b; };")
+        ffi.cdef("struct is_packed { char a; int b; };", packed=True)
+        assert ffi.sizeof("struct nonpacked") == 8
+        assert ffi.sizeof("struct is_packed") == 5
+        assert ffi.alignof("struct nonpacked") == 4
+        assert ffi.alignof("struct is_packed") == 1
+        s = ffi.new("struct is_packed[2]")
+        s[0].b = 42623381
+        s[0].a = b'X'
+        s[1].b = -4892220
+        s[1].a = b'Y'
+        assert s[0].b == 42623381
+        assert s[0].a == b'X'
+        assert s[1].b == -4892220
+        assert s[1].a == b'Y'
diff --git a/testing/test_function.py b/testing/test_function.py
--- a/testing/test_function.py
+++ b/testing/test_function.py
@@ -34,6 +34,12 @@
     def getvalue(self):
         return self._value
 
+lib_m = 'm'
+if sys.platform == 'win32':
+    #there is a small chance this fails on Mingw via environ $CC
+    import distutils.ccompiler
+    if distutils.ccompiler.get_default_compiler() == 'msvc':
+        lib_m = 'msvcrt'
 
 class TestFunction(object):
     Backend = CTypesBackend
@@ -43,18 +49,18 @@
         ffi.cdef("""
             double sin(double x);
         """)
-        m = ffi.dlopen("m")
+        m = ffi.dlopen(lib_m)
         x = m.sin(1.23)
         assert x == math.sin(1.23)
 
     def test_sinf(self):
         if sys.platform == 'win32':
-            py.test.skip("no 'sinf'")
+            py.test.skip("no sinf found in the Windows stdlib")
         ffi = FFI(backend=self.Backend())
         ffi.cdef("""
             float sinf(float x);
         """)
-        m = ffi.dlopen("m")
+        m = ffi.dlopen(lib_m)
         x = m.sinf(1.23)
         assert type(x) is float
         assert x != math.sin(1.23)    # rounding effects
@@ -66,14 +72,14 @@
         ffi.cdef("""
             void sin(double x);
         """)
-        m = ffi.dlopen("m")
+        m = ffi.dlopen(lib_m)
         x = m.sin(1.23)
         assert x is None
 
     def test_dlopen_filename(self):
-        path = ctypes.util.find_library("m")
+        path = ctypes.util.find_library(lib_m)
         if not path:
-            py.test.skip("libm not found")
+            py.test.skip("%s not found" % lib_m)
         ffi = FFI(backend=self.Backend())
         ffi.cdef("""
             double cos(double x);
@@ -91,7 +97,7 @@
         ffi.cdef("""
             double cos(double x);
         """)
-        m = ffi.dlopen("m", ffi.RTLD_LAZY | ffi.RTLD_LOCAL)
+        m = ffi.dlopen(lib_m, ffi.RTLD_LAZY | ffi.RTLD_LOCAL)
         x = m.cos(1.23)
         assert x == math.cos(1.23)
 
@@ -250,22 +256,14 @@
             py.test.skip("probably no symbol 'stdout' in the lib")
         ffi = FFI(backend=self.Backend())
         ffi.cdef("""
-            int puts(const char *);
-            void *stdout, *stderr;
+            void *stdout;
         """)
-        ffi.C = ffi.dlopen(None)
-        pout = ffi.C.stdout
-        perr = ffi.C.stderr
-        assert repr(pout).startswith("<cdata 'void *' 0x")
-        assert repr(perr).startswith("<cdata 'void *' 0x")
-        with FdWriteCapture(2) as fd:     # capturing stderr
-            ffi.C.stdout = perr
-            try:
-                ffi.C.puts(b"hello!") # goes to stdout, which is equal to stderr now
-            finally:
-                ffi.C.stdout = pout
-        res = fd.getvalue()
-        assert res == b"hello!\n"
+        C = ffi.dlopen(None)
+        pout = C.stdout
+        C.stdout = ffi.NULL
+        assert C.stdout == ffi.NULL
+        C.stdout = pout
+        assert C.stdout == pout
 
     def test_strchr(self):
         ffi = FFI(backend=self.Backend())
@@ -300,7 +298,7 @@
             typedef double func_t(double);
             func_t sin;
         """)
-        m = ffi.dlopen("m")
+        m = ffi.dlopen(lib_m)
         x = m.sin(1.23)
         assert x == math.sin(1.23)
 
@@ -363,7 +361,7 @@
         ffi.cdef("""
             int nonexistent();
         """)
-        m = ffi.dlopen("m")
+        m = ffi.dlopen(lib_m)
         assert not hasattr(m, 'nonexistent')
 
     def test_wraps_from_stdlib(self):
@@ -377,7 +375,7 @@
             def wrapper(*args):
                 return f(*args) + 100
             return wrapper
-        m = ffi.dlopen("m")
+        m = ffi.dlopen(lib_m)
         sin100 = my_decorator(m.sin)
         x = sin100(1.23)
         assert x == math.sin(1.23) + 100
diff --git a/testing/test_parsing.py b/testing/test_parsing.py
--- a/testing/test_parsing.py
+++ b/testing/test_parsing.py
@@ -11,9 +11,9 @@
 
     def load_library(self, name, flags):
         if sys.platform == 'win32':
-            assert "msvcr" in name
+            assert name is None or "msvcr" in name
         else:
-            assert "libc" in name or "libm" in name
+            assert name is None or "libc" in name or "libm" in name
         return FakeLibrary()
 
     def new_function_type(self, args, result, has_varargs):
@@ -32,10 +32,11 @@
     def new_struct_type(self, name):
         return FakeStruct(name)
 
-    def complete_struct_or_union(self, s, fields, tp=None):
+    def complete_struct_or_union(self, s, fields, tp=None,
+                                 totalsize=-1, totalalignment=-1, sflags=0):
         assert isinstance(s, FakeStruct)
         s.fields = fields
-    
+
     def new_array_type(self, ptrtype, length):
         return FakeType('<array %s x %s>' % (ptrtype, length))
 
@@ -59,7 +60,7 @@
         return ', '.join([str(y) + str(x) for x, y, z in self.fields])
 
 class FakeLibrary(object):
-    
+
     def load_function(self, BType, name):
         return FakeFunction(BType, name)
 
@@ -69,11 +70,17 @@
         self.BType = str(BType)
         self.name = name
 
+lib_m = "m"
+if sys.platform == 'win32':
+    #there is a small chance this fails on Mingw via environ $CC
+    import distutils.ccompiler
+    if distutils.ccompiler.get_default_compiler() == 'msvc':
+        lib_m = 'msvcrt'
 
 def test_simple():
     ffi = FFI(backend=FakeBackend())
     ffi.cdef("double sin(double x);")
-    m = ffi.dlopen("m")
+    m = ffi.dlopen(lib_m)
     func = m.sin    # should be a callable on real backends
     assert func.name == 'sin'
     assert func.BType == '<func (<double>), <double>, False>'
@@ -147,7 +154,7 @@
         x, double/*several*//*comment*/y) /*on the same line*/
         ;
     """)
-    m = ffi.dlopen("m")
+    m = ffi.dlopen(lib_m)
     func = m.sin
     assert func.name == 'sin'
     assert func.BType == '<func (<double>, <double>), <double>, False>'
diff --git a/testing/test_unicode_literals.py b/testing/test_unicode_literals.py
--- a/testing/test_unicode_literals.py
+++ b/testing/test_unicode_literals.py
@@ -10,6 +10,13 @@
 import sys, math
 from cffi import FFI
 
+lib_m = "m"
+if sys.platform == 'win32':
+    #there is a small chance this fails on Mingw via environ $CC
+    import distutils.ccompiler
+    if distutils.ccompiler.get_default_compiler() == 'msvc':
+        lib_m = 'msvcrt'
+
 
 def test_cast():
     ffi = FFI()
@@ -55,7 +62,7 @@
 def test_dlopen():
     ffi = FFI()
     ffi.cdef("double sin(double x);")
-    m = ffi.dlopen("m")                           # unicode literal
+    m = ffi.dlopen(lib_m)                           # unicode literal
     x = m.sin(1.23)
     assert x == math.sin(1.23)
 
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -4,7 +4,12 @@
 from testing.support import *
 
 
+lib_m = ['m']
 if sys.platform == 'win32':
+    #there is a small chance this fails on Mingw via environ $CC
+    import distutils.ccompiler
+    if distutils.ccompiler.get_default_compiler() == 'msvc':
+        lib_m = ['msvcrt']
     pass      # no obvious -Werror equivalent on MSVC
 else:
     if (sys.platform == 'darwin' and
@@ -63,13 +68,13 @@
 def test_simple_case():
     ffi = FFI()
     ffi.cdef("double sin(double x);")
-    lib = ffi.verify('#include <math.h>')
+    lib = ffi.verify('#include <math.h>', libraries=lib_m)
     assert lib.sin(1.23) == math.sin(1.23)
 
 def test_rounding_1():
     ffi = FFI()
     ffi.cdef("float sin(double x);")
-    lib = ffi.verify('#include <math.h>')
+    lib = ffi.verify('#include <math.h>', libraries=lib_m)
     res = lib.sin(1.23)
     assert res != math.sin(1.23)     # not exact, because of double->float
     assert abs(res - math.sin(1.23)) < 1E-5
@@ -77,7 +82,7 @@
 def test_rounding_2():
     ffi = FFI()
     ffi.cdef("double sin(float x);")
-    lib = ffi.verify('#include <math.h>')
+    lib = ffi.verify('#include <math.h>', libraries=lib_m)
     res = lib.sin(1.23)
     assert res != math.sin(1.23)     # not exact, because of double->float
     assert abs(res - math.sin(1.23)) < 1E-5
@@ -103,7 +108,7 @@
 def test_longdouble():
     ffi = FFI()
     ffi.cdef("long double sinl(long double x);")
-    lib = ffi.verify('#include <math.h>')
+    lib = ffi.verify('#include <math.h>', libraries=lib_m)
     for input in [1.23,
                   ffi.cast("double", 1.23),
                   ffi.cast("long double", 1.23)]:
@@ -148,28 +153,27 @@
 
 
 all_primitive_types = model.PrimitiveType.ALL_PRIMITIVE_TYPES
-all_signed_integer_types = sorted(tp for tp in all_primitive_types
-                                     if all_primitive_types[tp] == 'i')
-all_unsigned_integer_types = sorted(tp for tp in all_primitive_types
-                                       if all_primitive_types[tp] == 'u')
+all_integer_types = sorted(tp for tp in all_primitive_types
+                           if all_primitive_types[tp] == 'i')
 all_float_types = sorted(tp for tp in all_primitive_types
                             if all_primitive_types[tp] == 'f')
 
+def all_signed_integer_types(ffi):
+    return [x for x in all_integer_types if int(ffi.cast(x, -1)) < 0]
+
+def all_unsigned_integer_types(ffi):
+    return [x for x in all_integer_types if int(ffi.cast(x, -1)) > 0]
+
+
 def test_primitive_category():
     for typename in all_primitive_types:
         tp = model.PrimitiveType(typename)
         C = tp.is_char_type()
-        U = tp.is_unsigned_type()
-        S = tp.is_signed_type()
         F = tp.is_float_type()
         I = tp.is_integer_type()
         assert C == (typename in ('char', 'wchar_t'))
-        assert U == (typename.startswith('unsigned ') or
-                     typename == '_Bool' or typename == 'size_t' or
-                     typename == 'uintptr_t' or typename.startswith('uint'))
         assert F == (typename in ('float', 'double', 'long double'))
-        assert S + U + F + C == 1      # one and only one of them is true
-        assert I == (S or U)
+        assert I + F + C == 1      # one and only one of them is true
 
 def test_all_integer_and_float_types():
     typenames = []
@@ -207,7 +211,7 @@
 
 def test_var_signed_integer_types():
     ffi = FFI()
-    lst = all_signed_integer_types
+    lst = all_signed_integer_types(ffi)
     csource = "\n".join(["%s somevar_%s;" % (tp, tp.replace(' ', '_'))
                          for tp in lst])
     ffi.cdef(csource)
@@ -226,7 +230,7 @@
 
 def test_var_unsigned_integer_types():
     ffi = FFI()
-    lst = all_unsigned_integer_types
+    lst = all_unsigned_integer_types(ffi)
     csource = "\n".join(["%s somevar_%s;" % (tp, tp.replace(' ', '_'))
                          for tp in lst])
     ffi.cdef(csource)
@@ -247,7 +251,7 @@
 
 def test_fn_signed_integer_types():
     ffi = FFI()
-    lst = all_signed_integer_types
+    lst = all_signed_integer_types(ffi)
     cdefsrc = "\n".join(["%s somefn_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
                          for tp in lst])
     ffi.cdef(cdefsrc)
@@ -267,7 +271,7 @@
 
 def test_fn_unsigned_integer_types():
     ffi = FFI()
-    lst = all_unsigned_integer_types
+    lst = all_unsigned_integer_types(ffi)
     cdefsrc = "\n".join(["%s somefn_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
                          for tp in lst])
     ffi.cdef(cdefsrc)
@@ -464,11 +468,12 @@
 def test_struct_float_vs_int():
     if sys.platform == 'win32':
         py.test.skip("XXX fixme: only gives warnings")
-    for typename in all_signed_integer_types:
+    ffi = FFI()
+    for typename in all_signed_integer_types(ffi):
         for real in all_float_types:
             _check_field_match(typename, real, expect_mismatch=True)
     for typename in all_float_types:
-        for real in all_signed_integer_types:
+        for real in all_signed_integer_types(ffi):
             _check_field_match(typename, real, expect_mismatch=True)
 
 def test_struct_array_field():
@@ -1133,6 +1138,9 @@
     xxx
 
 def test_opaque_integer_as_function_result():
+    import platform
+    if platform.machine().startswith('sparc'):
+        py.test.skip('Breaks horribly on sparc (SIGILL + corrupted stack)')
     # XXX bad abuse of "struct { ...; }".  It only works a bit by chance
     # anyway.  XXX think about something better :-(
     ffi = FFI()
@@ -1855,3 +1863,24 @@
 
 def test_various_calls_libffi():
     _test_various_calls(force_libffi=True)
+
+def test_ptr_to_opaque():
+    ffi = FFI()
+    ffi.cdef("typedef ... foo_t; int f1(foo_t*); foo_t *f2(int);")
+    lib = ffi.verify("""
+        #include <stdlib.h>
+        typedef struct { int x; } foo_t;
+        int f1(foo_t* p) {
+            int x = p->x;
+            free(p);
+            return x;
+        }
+        foo_t *f2(int x) {
+            foo_t *p = malloc(sizeof(foo_t));
+            p->x = x;
+            return p;
+        }
+    """)
+    p = lib.f2(42)
+    x = lib.f1(p)
+    assert x == 42
diff --git a/testing/test_version.py b/testing/test_version.py
--- a/testing/test_version.py
+++ b/testing/test_version.py
@@ -9,7 +9,7 @@
     '0.4.2': '0.4',     # did not change
     '0.7.1': '0.7',     # did not change
     '0.7.2': '0.7',     # did not change
-    '0.8.1': '0.8',     # did not change
+    '0.8.1': '0.8',     # did not change (essentially)
     }
 
 def test_version():
@@ -24,7 +24,7 @@
     content = open(p).read()
     #
     v = cffi.__version__
-    assert ("version = '%s'\n" % BACKEND_VERSIONS.get(v, v)) in content
+    assert ("version = '%s'\n" % v[:3]) in content
     assert ("release = '%s'\n" % v) in content
 
 def test_doc_version_file():
diff --git a/testing/test_zdistutils.py b/testing/test_zdistutils.py
--- a/testing/test_zdistutils.py
+++ b/testing/test_zdistutils.py
@@ -7,6 +7,13 @@
 
 
 class DistUtilsTest(object):
+    def setup_class(self):
+        self.lib_m = "m"
+        if sys.platform == 'win32':
+            #there is a small chance this fails on Mingw via environ $CC
+            import distutils.ccompiler
+            if distutils.ccompiler.get_default_compiler() == 'msvc':
+                self.lib_m = 'msvcrt'
 
     def test_locate_engine_class(self):
         cls = _locate_engine_class(FFI(), self.generic)
@@ -25,7 +32,8 @@
         ffi = FFI()
         ffi.cdef("double sin(double x);")
         csrc = '/*hi there %s!*/\n#include <math.h>\n' % self
-        v = Verifier(ffi, csrc, force_generic_engine=self.generic)
+        v = Verifier(ffi, csrc, force_generic_engine=self.generic,
+                     libraries=[self.lib_m])
         v.write_source()
         with open(v.sourcefilename, 'r') as f:
             data = f.read()
@@ -35,7 +43,8 @@
         ffi = FFI()
         ffi.cdef("double sin(double x);")
         csrc = '/*hi there %s!*/\n#include <math.h>\n' % self
-        v = Verifier(ffi, csrc, force_generic_engine=self.generic)
+        v = Verifier(ffi, csrc, force_generic_engine=self.generic,
+                     libraries=[self.lib_m])
         v.sourcefilename = filename = str(udir.join('write_source.c'))
         v.write_source()
         assert filename == v.sourcefilename
@@ -47,7 +56,8 @@
         ffi = FFI()
         ffi.cdef("double sin(double x);")
         csrc = '/*hi there %s!*/\n#include <math.h>\n' % self
-        v = Verifier(ffi, csrc, force_generic_engine=self.generic)
+        v = Verifier(ffi, csrc, force_generic_engine=self.generic,
+                     libraries=[self.lib_m])
         try:
             from StringIO import StringIO
         except ImportError:
@@ -60,7 +70,8 @@
         ffi = FFI()
         ffi.cdef("double sin(double x);")
         csrc = '/*hi there %s!*/\n#include <math.h>\n' % self
-        v = Verifier(ffi, csrc, force_generic_engine=self.generic)
+        v = Verifier(ffi, csrc, force_generic_engine=self.generic,
+                     libraries=[self.lib_m])
         v.compile_module()
         assert v.get_module_name().startswith('_cffi_')
         if v.generates_python_module():
@@ -71,7 +82,8 @@
         ffi = FFI()
         ffi.cdef("double sin(double x);")
         csrc = '/*hi there %s!2*/\n#include <math.h>\n' % self
-        v = Verifier(ffi, csrc, force_generic_engine=self.generic)
+        v = Verifier(ffi, csrc, force_generic_engine=self.generic,
+                     libraries=[self.lib_m])
         basename = self.__class__.__name__ + 'test_compile_module'
         v.modulefilename = filename = str(udir.join(basename + '.so'))
         v.compile_module()
@@ -87,7 +99,8 @@
             ffi = FFI()
             ffi.cdef("%s sin(double x);" % csrc)
             v = Verifier(ffi, "#include <math.h>",
-                         force_generic_engine=self.generic)
+                         force_generic_engine=self.generic,
+                         libraries=[self.lib_m])
             names.append(v.get_module_name())
         assert names[0] == names[1] != names[2]
 
@@ -104,7 +117,8 @@
         ffi = FFI()
         ffi.cdef("double sin(double x);")
         csrc = '/*hi there %s!3*/\n#include <math.h>\n' % self
-        v = Verifier(ffi, csrc, force_generic_engine=self.generic)
+        v = Verifier(ffi, csrc, force_generic_engine=self.generic,
+                     libraries=[self.lib_m])
         library = v.load_library()
         assert library.sin(12.3) == math.sin(12.3)
 
@@ -114,7 +128,8 @@
         csrc = '/*hi there %s!4*/#include "test_verifier_args.h"\n' % self
         udir.join('test_verifier_args.h').write('#include <math.h>\n')
         v = Verifier(ffi, csrc, include_dirs=[str(udir)],
-                     force_generic_engine=self.generic)
+                     force_generic_engine=self.generic,
+                     libraries=[self.lib_m])
         library = v.load_library()
         assert library.sin(12.3) == math.sin(12.3)
 
@@ -122,7 +137,8 @@
         ffi = FFI()
         ffi.cdef("double sin(double x);")
         csrc = "/*6%s*/\n#include <math.h>" % self
-        lib = ffi.verify(csrc, force_generic_engine=self.generic)
+        lib = ffi.verify(csrc, force_generic_engine=self.generic,
+                         libraries=[self.lib_m])
         assert lib.sin(12.3) == math.sin(12.3)
         assert isinstance(ffi.verifier, Verifier)
         with open(ffi.verifier.sourcefilename, 'r') as f:
@@ -139,7 +155,8 @@
     #endif
     '''
         lib = ffi.verify(csrc, define_macros=[('TEST_EXTENSION_OBJECT', '1')],
-                         force_generic_engine=self.generic)
+                         force_generic_engine=self.generic,
+                         libraries=[self.lib_m])
         assert lib.sin(12.3) == math.sin(12.3)
         v = ffi.verifier
         ext = v.get_extension()
@@ -152,7 +169,8 @@
         ffi = FFI()
         ffi.cdef("double sin(double x);")
         csrc = '/*hi there9!%s*/\n#include <math.h>\n' % self
-        v = Verifier(ffi, csrc, force_generic_engine=self.generic)
+        v = Verifier(ffi, csrc, force_generic_engine=self.generic,
+                     libraries=[self.lib_m])
         assert not os.path.exists(v.sourcefilename)
         v.get_extension()
         assert os.path.exists(v.sourcefilename)


More information about the pypy-commit mailing list