summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Rigo <arigo@tunes.org>2014-10-10 20:56:41 +0200
committerArmin Rigo <arigo@tunes.org>2014-10-10 20:56:41 +0200
commitfc53b53095d61a1ec5814c09c3bf2c7e18627fb5 (patch)
tree5c824926e1165a9ceee4156018b186216b7faee4
parent4d0b57bd13b6e0f6a7eaa1e434313c6dc4cec3a8 (diff)
parent591081e92434f35f1c7bbe5e7bf854ded61ddc18 (diff)
downloadcffi-fc53b53095d61a1ec5814c09c3bf2c7e18627fb5.tar.gz
Merge this to default too
-rw-r--r--c/_cffi_backend.c121
-rw-r--r--cffi/api.py3
-rw-r--r--cffi/cparser.py9
-rw-r--r--cffi/verifier.py20
-rw-r--r--doc/source/index.rst10
-rw-r--r--testing/test_ffi_backend.py10
-rw-r--r--testing/test_parsing.py11
-rw-r--r--testing/test_zdistutils.py4
-rw-r--r--testing/test_zintegration.py87
9 files changed, 158 insertions, 117 deletions
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
index fcbbbc2..536ea5c 100644
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -740,95 +740,90 @@ _my_PyLong_AsUnsignedLongLong(PyObject *ob, int strict)
return (unsigned PY_LONG_LONG)-1;
}
+#define _read_raw_data(type) \
+ do { \
+ if (size == sizeof(type)) { \
+ type r; \
+ memcpy(&r, target, sizeof(type)); \
+ return r; \
+ } \
+ } while(0)
+
static PY_LONG_LONG
read_raw_signed_data(char *target, int size)
{
- if (size == sizeof(signed char))
- return *((signed char*)target);
- else if (size == sizeof(short))
- return *((short*)target);
- else if (size == sizeof(int))
- return *((int*)target);
- else if (size == sizeof(long))
- return *((long*)target);
- else if (size == sizeof(PY_LONG_LONG))
- return *((PY_LONG_LONG*)target);
- else {
- Py_FatalError("read_raw_signed_data: bad integer size");
- return 0;
- }
+ _read_raw_data(signed char);
+ _read_raw_data(short);
+ _read_raw_data(int);
+ _read_raw_data(long);
+ _read_raw_data(PY_LONG_LONG);
+ Py_FatalError("read_raw_signed_data: bad integer size");
+ return 0;
}
static unsigned PY_LONG_LONG
read_raw_unsigned_data(char *target, int size)
{
- if (size == sizeof(unsigned char))
- return *((unsigned char*)target);
- else if (size == sizeof(unsigned short))
- return *((unsigned short*)target);
- else if (size == sizeof(unsigned int))
- return *((unsigned int*)target);
- else if (size == sizeof(unsigned long))
- return *((unsigned long*)target);
- else if (size == sizeof(unsigned PY_LONG_LONG))
- return *((unsigned PY_LONG_LONG*)target);
- else {
- Py_FatalError("read_raw_unsigned_data: bad integer size");
- return 0;
- }
+ _read_raw_data(unsigned char);
+ _read_raw_data(unsigned short);
+ _read_raw_data(unsigned int);
+ _read_raw_data(unsigned long);
+ _read_raw_data(unsigned PY_LONG_LONG);
+ Py_FatalError("read_raw_unsigned_data: bad integer size");
+ return 0;
}
+#define _write_raw_data(type) \
+ do { \
+ if (size == sizeof(type)) { \
+ type r = (type)source; \
+ memcpy(target, &r, sizeof(type)); \
+ return; \
+ } \
+ } while(0)
+
static void
write_raw_integer_data(char *target, unsigned PY_LONG_LONG source, int size)
{
- if (size == sizeof(unsigned char))
- *((unsigned char*)target) = (unsigned char)source;
- else if (size == sizeof(unsigned short))
- *((unsigned short*)target) = (unsigned short)source;
- else if (size == sizeof(unsigned int))
- *((unsigned int*)target) = (unsigned int)source;
- else if (size == sizeof(unsigned long))
- *((unsigned long*)target) = (unsigned long)source;
- else if (size == sizeof(unsigned PY_LONG_LONG))
- *((unsigned PY_LONG_LONG*)target) = source;
- else
- Py_FatalError("write_raw_integer_data: bad integer size");
+ _write_raw_data(unsigned char);
+ _write_raw_data(unsigned short);
+ _write_raw_data(unsigned int);
+ _write_raw_data(unsigned long);
+ _write_raw_data(unsigned PY_LONG_LONG);
+ Py_FatalError("write_raw_integer_data: bad integer size");
}
static double
read_raw_float_data(char *target, int size)
{
- if (size == sizeof(float))
- return *((float*)target);
- else if (size == sizeof(double))
- return *((double*)target);
- else {
- Py_FatalError("read_raw_float_data: bad float size");
- return 0;
- }
+ _read_raw_data(float);
+ _read_raw_data(double);
+ Py_FatalError("read_raw_float_data: bad float size");
+ return 0;
}
static long double
read_raw_longdouble_data(char *target)
{
- return *((long double*)target);
+ int size = sizeof(long double);
+ _read_raw_data(long double);
+ Py_FatalError("read_raw_longdouble_data: bad long double size");
+ return 0;
}
static void
write_raw_float_data(char *target, double source, int size)
{
- if (size == sizeof(float))
- *((float*)target) = (float)source;
- else if (size == sizeof(double))
- *((double*)target) = source;
- else
- Py_FatalError("write_raw_float_data: bad float size");
+ _write_raw_data(float);
+ _write_raw_data(double);
+ Py_FatalError("write_raw_float_data: bad float size");
}
static void
write_raw_longdouble_data(char *target, long double source)
{
- *((long double*)target) = source;
+ int size = sizeof(long double);
+ _write_raw_data(long double);
}
static PyObject *
@@ -1248,6 +1243,16 @@ convert_struct_from_object(char *data, CTypeDescrObject *ct, PyObject *init,
return _convert_error(init, ct->ct_name, expected);
}
+#ifdef __GNUC__
+# if __GNUC__ >= 4
+/* Don't go inlining this huge function. Needed because occasionally
+ it gets inlined in places where is causes a warning: call to
+ __builtin___memcpy_chk will always overflow destination buffer
+ (which is places where the 'ct' should never represent such a large
+ primitive type anyway). */
+__attribute__((noinline))
+# endif
+#endif
static int
convert_from_object(char *data, CTypeDescrObject *ct, PyObject *init)
{
@@ -1959,7 +1964,7 @@ cdata_ass_slice(CDataObject *cd, PySliceObject *slice, PyObject *v)
if ((ctv->ct_flags & CT_ARRAY) && (ctv->ct_itemdescr == ct) &&
(get_array_length((CDataObject *)v) == length)) {
/* fast path: copying from exactly the correct type */
- memcpy(cdata, ((CDataObject *)v)->c_data, itemsize * length);
+ memmove(cdata, ((CDataObject *)v)->c_data, itemsize * length);
return 0;
}
}
@@ -3622,7 +3627,7 @@ static int complete_sflags(int sflags)
#ifdef MS_WIN32
sflags |= SF_MSVC_BITFIELDS;
#else
-# ifdef __arm__
+# if defined(__arm__) || defined(__aarch64__)
sflags |= SF_GCC_ARM_BITFIELDS;
# else
sflags |= SF_GCC_X86_BITFIELDS;
diff --git a/cffi/api.py b/cffi/api.py
index aed9715..ddfe430 100644
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -334,8 +334,7 @@ class FFI(object):
(including calling macros). This is unlike 'ffi.dlopen()',
which requires binary compatibility in the signatures.
"""
- from .verifier import Verifier, _caller_dir_pycache
- tmpdir = tmpdir or _caller_dir_pycache()
+ from .verifier import Verifier
self.verifier = Verifier(self, source, tmpdir, **kwargs)
lib = self.verifier.load_library()
self._libraries.append(lib)
diff --git a/cffi/cparser.py b/cffi/cparser.py
index a53d4c3..e7a164e 100644
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -1,4 +1,3 @@
-
from . import api, model
from .commontypes import COMMON_TYPES, resolve_common_type
try:
@@ -460,6 +459,8 @@ class Parser(object):
elif kind == 'union':
tp = model.UnionType(explicit_name, None, None, None)
elif kind == 'enum':
+ if explicit_name == '__dotdotdot__':
+ raise CDefError("Enums cannot be declared with ...")
tp = self._build_enum_type(explicit_name, type.values)
else:
raise AssertionError("kind = %r" % (kind,))
@@ -532,11 +533,15 @@ class Parser(object):
def _parse_constant(self, exprnode, partial_length_ok=False):
# for now, limited to expressions that are an immediate number
- # or negative number
+ # or positive/negative number
if isinstance(exprnode, pycparser.c_ast.Constant):
return int(exprnode.value, 0)
#
if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and
+ exprnode.op == '+'):
+ return self._parse_constant(exprnode.expr)
+ #
+ if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and
exprnode.op == '-'):
return -self._parse_constant(exprnode.expr)
# load previously defined int constant
diff --git a/cffi/verifier.py b/cffi/verifier.py
index 9603a7e..cb4e0bb 100644
--- a/cffi/verifier.py
+++ b/cffi/verifier.py
@@ -1,7 +1,17 @@
-import sys, os, binascii, imp, shutil
+import sys, os, binascii, shutil
from . import __version__
from . import ffiplatform
+if sys.version_info >= (3, 3):
+ import importlib.machinery
+ def _extension_suffixes():
+ return importlib.machinery.EXTENSION_SUFFIXES[:]
+else:
+ import imp
+ def _extension_suffixes():
+ return [suffix for suffix, _, type in imp.get_suffixes()
+ if type == imp.C_EXTENSION]
+
class Verifier(object):
@@ -32,7 +42,7 @@ class Verifier(object):
modulename = '_cffi_%s_%s%s%s' % (tag, self._vengine._class_key,
k1, k2)
suffix = _get_so_suffixes()[0]
- self.tmpdir = tmpdir or _caller_dir_pycache()
+ self.tmpdir = tmpdir or os.environ.get('CFFI_TMPDIR') or _caller_dir_pycache()
self.sourcefilename = os.path.join(self.tmpdir, modulename + '.c')
self.modulefilename = os.path.join(self.tmpdir, modulename + suffix)
self.ext_package = ext_package
@@ -222,11 +232,7 @@ def cleanup_tmpdir(tmpdir=None, keep_so=False):
pass
def _get_so_suffixes():
- suffixes = []
- for suffix, mode, type in imp.get_suffixes():
- if type == imp.C_EXTENSION:
- suffixes.append(suffix)
-
+ suffixes = _extension_suffixes()
if not suffixes:
# bah, no C_EXTENSION available. Occurs on pypy without cpyext
if sys.platform == 'win32':
diff --git a/doc/source/index.rst b/doc/source/index.rst
index c70a620..8aa592b 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -380,7 +380,10 @@ your test suite, a call to ``cffi.verifier.cleanup_tmpdir()``.
Alternatively, you can just completely remove the ``__pycache__``
directory.
-
+An alternative cache directory can be given as the ``tmpdir`` argument
+to ``verify()``, via the environment variable ``CFFI_TMPDIR``, or by
+calling ``cffi.verifier.set_tmpdir(path)`` prior to calling
+``verify``.
=======================================================
@@ -636,8 +639,9 @@ not recommended.
.. versionadded:: 0.4
The ``tmpdir`` argument to ``verify()`` controls where the C
- files are created and compiled. By default it is
- ``directory_containing_the_py_file/__pycache__``, using the
+ files are created and compiled. Unless the ``CFFI_TMPDIR`` environment
+ variable is set, the default is
+ ``directory_containing_the_py_file/__pycache__`` using the
directory name of the .py file that contains the actual call to
``ffi.verify()``. (This is a bit of a hack but is generally
consistent with the location of the .pyc files for your library.
diff --git a/testing/test_ffi_backend.py b/testing/test_ffi_backend.py
index ff06929..2518a51 100644
--- a/testing/test_ffi_backend.py
+++ b/testing/test_ffi_backend.py
@@ -122,7 +122,7 @@ class TestBitfield:
self.check("int a:2; short b:15; char c:2; char y;", 5, 4, 8)
self.check("int a:2; char b:1; char c:1; char y;", 1, 4, 4)
- @pytest.mark.skipif("platform.machine().startswith('arm')")
+ @pytest.mark.skipif("platform.machine().startswith(('arm', 'aarch64'))")
def test_bitfield_anonymous_no_align(self):
L = FFI().alignof("long long")
self.check("char y; int :1;", 0, 1, 2)
@@ -135,7 +135,8 @@ class TestBitfield:
self.check("char x; long long z:57; char y;", L + 8, L, L + 8 + L)
self.check("char x; long long :57; char y;", L + 8, 1, L + 9)
- @pytest.mark.skipif("not platform.machine().startswith('arm')")
+ @pytest.mark.skipif(
+ "not platform.machine().startswith(('arm', 'aarch64'))")
def test_bitfield_anonymous_align_arm(self):
L = FFI().alignof("long long")
self.check("char y; int :1;", 0, 4, 4)
@@ -148,7 +149,7 @@ class TestBitfield:
self.check("char x; long long z:57; char y;", L + 8, L, L + 8 + L)
self.check("char x; long long :57; char y;", L + 8, L, L + 8 + L)
- @pytest.mark.skipif("platform.machine().startswith('arm')")
+ @pytest.mark.skipif("platform.machine().startswith(('arm', 'aarch64'))")
def test_bitfield_zero(self):
L = FFI().alignof("long long")
self.check("char y; int :0;", 0, 1, 4)
@@ -159,7 +160,8 @@ class TestBitfield:
self.check("char x; int :0; short b:1; char y;", 5, 2, 6)
self.check("int a:1; int :0; int b:1; char y;", 5, 4, 8)
- @pytest.mark.skipif("not platform.machine().startswith('arm')")
+ @pytest.mark.skipif(
+ "not platform.machine().startswith(('arm', 'aarch64'))")
def test_bitfield_zero_arm(self):
L = FFI().alignof("long long")
self.check("char y; int :0;", 0, 4, 4)
diff --git a/testing/test_parsing.py b/testing/test_parsing.py
index 594796a..97a16f9 100644
--- a/testing/test_parsing.py
+++ b/testing/test_parsing.py
@@ -288,3 +288,14 @@ def test__is_constant_globalvar():
decl = ast.children()[0][1]
node = decl.type
assert p._is_constant_globalvar(node) == expected_output
+
+def test_enum():
+ ffi = FFI()
+ ffi.cdef("""
+ enum Enum { POS = +1, TWO = 2, NIL = 0, NEG = -1};
+ """)
+ C = ffi.dlopen(None)
+ assert C.POS == 1
+ assert C.TWO == 2
+ assert C.NIL == 0
+ assert C.NEG == -1
diff --git a/testing/test_zdistutils.py b/testing/test_zdistutils.py
index f97d015..aede0ca 100644
--- a/testing/test_zdistutils.py
+++ b/testing/test_zdistutils.py
@@ -15,6 +15,10 @@ class DistUtilsTest(object):
if distutils.ccompiler.get_default_compiler() == 'msvc':
self.lib_m = 'msvcrt'
+ def teardown_class(self):
+ if udir.isdir():
+ udir.remove()
+
def test_locate_engine_class(self):
cls = _locate_engine_class(FFI(), self.generic)
if self.generic:
diff --git a/testing/test_zintegration.py b/testing/test_zintegration.py
index 499f5ec..0ab84eb 100644
--- a/testing/test_zintegration.py
+++ b/testing/test_zintegration.py
@@ -72,50 +72,55 @@ def run_setup_and_program(dirname, python_snippet):
assert not os.path.exists(str(SNIPPET_DIR.join(dirname, 'lextab.py')))
assert not os.path.exists(str(SNIPPET_DIR.join(dirname, 'yacctab.py')))
-def test_infrastructure():
- run_setup_and_program('infrastructure', '''
- import snip_infrastructure
- assert snip_infrastructure.func() == 42
- ''')
+class TestZIntegration(object):
+ def teardown_class(self):
+ if udir.isdir():
+ udir.remove()
-def test_distutils_module():
- run_setup_and_program("distutils_module", '''
- import snip_basic_verify
- p = snip_basic_verify.C.getpwuid(0)
- assert snip_basic_verify.ffi.string(p.pw_name) == b"root"
- ''')
+ def test_infrastructure(self):
+ run_setup_and_program('infrastructure', '''
+ import snip_infrastructure
+ assert snip_infrastructure.func() == 42
+ ''')
-def test_distutils_package_1():
- run_setup_and_program("distutils_package_1", '''
- import snip_basic_verify1
- p = snip_basic_verify1.C.getpwuid(0)
- assert snip_basic_verify1.ffi.string(p.pw_name) == b"root"
- ''')
+ def test_distutils_module(self):
+ run_setup_and_program("distutils_module", '''
+ import snip_basic_verify
+ p = snip_basic_verify.C.getpwuid(0)
+ assert snip_basic_verify.ffi.string(p.pw_name) == b"root"
+ ''')
-def test_distutils_package_2():
- run_setup_and_program("distutils_package_2", '''
- import snip_basic_verify2
- p = snip_basic_verify2.C.getpwuid(0)
- assert snip_basic_verify2.ffi.string(p.pw_name) == b"root"
- ''')
+ def test_distutils_package_1(self):
+ run_setup_and_program("distutils_package_1", '''
+ import snip_basic_verify1
+ p = snip_basic_verify1.C.getpwuid(0)
+ assert snip_basic_verify1.ffi.string(p.pw_name) == b"root"
+ ''')
-def test_setuptools_module():
- run_setup_and_program("setuptools_module", '''
- import snip_setuptools_verify
- p = snip_setuptools_verify.C.getpwuid(0)
- assert snip_setuptools_verify.ffi.string(p.pw_name) == b"root"
- ''')
+ def test_distutils_package_2(self):
+ run_setup_and_program("distutils_package_2", '''
+ import snip_basic_verify2
+ p = snip_basic_verify2.C.getpwuid(0)
+ assert snip_basic_verify2.ffi.string(p.pw_name) == b"root"
+ ''')
-def test_setuptools_package_1():
- run_setup_and_program("setuptools_package_1", '''
- import snip_setuptools_verify1
- p = snip_setuptools_verify1.C.getpwuid(0)
- assert snip_setuptools_verify1.ffi.string(p.pw_name) == b"root"
- ''')
+ def test_setuptools_module(self):
+ run_setup_and_program("setuptools_module", '''
+ import snip_setuptools_verify
+ p = snip_setuptools_verify.C.getpwuid(0)
+ assert snip_setuptools_verify.ffi.string(p.pw_name) == b"root"
+ ''')
-def test_setuptools_package_2():
- run_setup_and_program("setuptools_package_2", '''
- import snip_setuptools_verify2
- p = snip_setuptools_verify2.C.getpwuid(0)
- assert snip_setuptools_verify2.ffi.string(p.pw_name) == b"root"
- ''')
+ def test_setuptools_package_1(self):
+ run_setup_and_program("setuptools_package_1", '''
+ import snip_setuptools_verify1
+ p = snip_setuptools_verify1.C.getpwuid(0)
+ assert snip_setuptools_verify1.ffi.string(p.pw_name) == b"root"
+ ''')
+
+ def test_setuptools_package_2(self):
+ run_setup_and_program("setuptools_package_2", '''
+ import snip_setuptools_verify2
+ p = snip_setuptools_verify2.C.getpwuid(0)
+ assert snip_setuptools_verify2.ffi.string(p.pw_name) == b"root"
+ ''')