diff options
author | Armin Rigo <arigo@tunes.org> | 2014-10-10 20:56:41 +0200 |
---|---|---|
committer | Armin Rigo <arigo@tunes.org> | 2014-10-10 20:56:41 +0200 |
commit | fc53b53095d61a1ec5814c09c3bf2c7e18627fb5 (patch) | |
tree | 5c824926e1165a9ceee4156018b186216b7faee4 | |
parent | 4d0b57bd13b6e0f6a7eaa1e434313c6dc4cec3a8 (diff) | |
parent | 591081e92434f35f1c7bbe5e7bf854ded61ddc18 (diff) | |
download | cffi-fc53b53095d61a1ec5814c09c3bf2c7e18627fb5.tar.gz |
Merge this to default too
-rw-r--r-- | c/_cffi_backend.c | 121 | ||||
-rw-r--r-- | cffi/api.py | 3 | ||||
-rw-r--r-- | cffi/cparser.py | 9 | ||||
-rw-r--r-- | cffi/verifier.py | 20 | ||||
-rw-r--r-- | doc/source/index.rst | 10 | ||||
-rw-r--r-- | testing/test_ffi_backend.py | 10 | ||||
-rw-r--r-- | testing/test_parsing.py | 11 | ||||
-rw-r--r-- | testing/test_zdistutils.py | 4 | ||||
-rw-r--r-- | testing/test_zintegration.py | 87 |
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" + ''') |