[pypy-commit] pypy cffi-1.0: in-progress

arigo noreply at buildbot.pypy.org
Sun May 17 19:30:57 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r77354:54e4fe4abc1e
Date: 2015-05-17 18:06 +0200
http://bitbucket.org/pypy/pypy/changeset/54e4fe4abc1e/

Log:	in-progress

diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -53,11 +53,16 @@
     if sys.platform == 'win32':
         interpleveldefs['getwinerror'] = 'cerrno.getwinerror'
 
-for _name in ["RTLD_LAZY", "RTLD_NOW", "RTLD_GLOBAL", "RTLD_LOCAL",
-              "RTLD_NODELETE", "RTLD_NOLOAD", "RTLD_DEEPBIND"]:
-    if getattr(rdynload.cConfig, _name) is not None:
-        Module.interpleveldefs[_name] = 'space.wrap(%d)' % (
-            getattr(rdynload.cConfig, _name),)
 
-for _name in ["RTLD_LAZY", "RTLD_NOW", "RTLD_GLOBAL", "RTLD_LOCAL"]:
-    Module.interpleveldefs.setdefault(_name, 'space.wrap(0)')
+def get_dict_rtld_constants():
+    found = {}
+    for name in ["RTLD_LAZY", "RTLD_NOW", "RTLD_GLOBAL", "RTLD_LOCAL",
+                 "RTLD_NODELETE", "RTLD_NOLOAD", "RTLD_DEEPBIND"]:
+        if getattr(rdynload.cConfig, name) is not None:
+            found[name] = getattr(rdynload.cConfig, name)
+    for name in ["RTLD_LAZY", "RTLD_NOW", "RTLD_GLOBAL", "RTLD_LOCAL"]:
+        found.setdefault(name, 0)
+    return found
+
+for _name, _value in get_dict_rtld_constants().items():
+    Module.interpleveldefs[_name] = 'space.wrap(%d)' % _value
diff --git a/pypy/module/_cffi_backend/cffi1_module.py b/pypy/module/_cffi_backend/cffi1_module.py
--- a/pypy/module/_cffi_backend/cffi1_module.py
+++ b/pypy/module/_cffi_backend/cffi1_module.py
@@ -7,8 +7,8 @@
 from pypy.module._cffi_backend.lib_obj import W_LibObject
 
 
-VERSION_MIN    = 0x2600
-VERSION_MAX    = 0x260F
+VERSION_MIN    = 0x2601
+VERSION_MAX    = 0x26FF
 
 VERSION_EXPORT = 0x0A02
 
diff --git a/pypy/module/_cffi_backend/cffi_opcode.py b/pypy/module/_cffi_backend/cffi_opcode.py
--- a/pypy/module/_cffi_backend/cffi_opcode.py
+++ b/pypy/module/_cffi_backend/cffi_opcode.py
@@ -3,16 +3,37 @@
     def __init__(self, op, arg):
         self.op = op
         self.arg = arg
+
     def as_c_expr(self):
         if self.op is None:
             assert isinstance(self.arg, str)
             return '(_cffi_opcode_t)(%s)' % (self.arg,)
         classname = CLASS_NAME[self.op]
         return '_CFFI_OP(_CFFI_OP_%s, %d)' % (classname, self.arg)
+
+    def as_python_bytes(self):
+        if self.op is None:
+            if self.arg.isdigit():
+                value = int(self.arg)     # non-negative: '-' not in self.arg
+                if value >= 2**31:
+                    raise OverflowError("cannot emit %r: limited to 2**31-1"
+                                        % (self.arg,))
+                return format_four_bytes(value)
+            from .ffiplatform import VerificationError
+            raise VerificationError("cannot emit to Python: %r" % (self.arg,))
+        return format_four_bytes((self.arg << 8) | self.op)
+
     def __str__(self):
         classname = CLASS_NAME.get(self.op, self.op)
         return '(%s %s)' % (classname, self.arg)
 
+def format_four_bytes(num):
+    return '\\x%02X\\x%02X\\x%02X\\x%02X' % (
+        (num >> 24) & 0xFF,
+        (num >> 16) & 0xFF,
+        (num >>  8) & 0xFF,
+        (num      ) & 0xFF)
+
 OP_PRIMITIVE       = 1
 OP_POINTER         = 3
 OP_ARRAY           = 5
@@ -30,6 +51,7 @@
 OP_CONSTANT        = 29
 OP_CONSTANT_INT    = 31
 OP_GLOBAL_VAR      = 33
+OP_DLOPEN_FUNC     = 35
 
 PRIM_VOID          = 0
 PRIM_BOOL          = 1
@@ -139,6 +161,10 @@
 F_EXTERNAL      = 0x08
 F_OPAQUE        = 0x10
 
+G_FLAGS = dict([('_CFFI_' + _key, globals()[_key])
+                for _key in ['F_UNION', 'F_CHECK_FIELDS', 'F_PACKED',
+                             'F_EXTERNAL', 'F_OPAQUE']])
+
 CLASS_NAME = {}
 for _name, _value in list(globals().items()):
     if _name.startswith('OP_') and isinstance(_value, int):
diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py
--- a/pypy/module/_cffi_backend/ffi_obj.py
+++ b/pypy/module/_cffi_backend/ffi_obj.py
@@ -6,6 +6,7 @@
 from rpython.rlib import jit, rgc
 from rpython.rtyper.lltypesystem import rffi
 
+from pypy.module._cffi_backend import get_dict_rtld_constants
 from pypy.module._cffi_backend import parse_c_type, realize_c_type
 from pypy.module._cffi_backend import newtype, cerrno, ccallback, ctypearray
 from pypy.module._cffi_backend import ctypestruct, ctypeptr, handle
@@ -459,7 +460,7 @@
     return space.appexec([], """():
         return type('error', (Exception,), {'__module__': 'ffi'})""")
 
-_extras = {}
+_extras = get_dict_rtld_constants()
 if sys.platform == 'win32':
     _extras['getwinerror'] = interp2app(W_FFIObject.descr_getwinerror)
 
diff --git a/pypy/module/_cffi_backend/src/parse_c_type.h b/pypy/module/_cffi_backend/src/parse_c_type.h
--- a/pypy/module/_cffi_backend/src/parse_c_type.h
+++ b/pypy/module/_cffi_backend/src/parse_c_type.h
@@ -1,3 +1,5 @@
+
+/* See doc/parse_c_type.rst in the source of CFFI for more information */
 
 typedef void *_cffi_opcode_t;
 
@@ -22,6 +24,7 @@
 #define _CFFI_OP_CONSTANT       29
 #define _CFFI_OP_CONSTANT_INT   31
 #define _CFFI_OP_GLOBAL_VAR     33
+#define _CFFI_OP_DLOPEN_FUNC    35
 
 #define _CFFI_PRIM_VOID          0
 #define _CFFI_PRIM_BOOL          1
@@ -83,6 +86,12 @@
     size_t size;             // 0 if unknown
 };
 
+struct _cffi_getconst_s {
+    unsigned long long value;
+    const struct _cffi_type_context_s *ctx;
+    int gindex;
+};
+
 struct _cffi_struct_union_s {
     const char *name;
     int type_index;          // -> _cffi_types, on a OP_STRUCT_UNION
@@ -97,6 +106,7 @@
                                      // "standard layout" or if some are missing
 #define _CFFI_F_PACKED        0x04   // for CHECK_FIELDS, assume a packed struct
 #define _CFFI_F_EXTERNAL      0x08   // in some other ffi.include()
+#define _CFFI_F_OPAQUE        0x10   // opaque
 
 struct _cffi_field_s {
     const char *name;
diff --git a/pypy/module/_cffi_backend/test/test_re_python.py b/pypy/module/_cffi_backend/test/test_re_python.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/test/test_re_python.py
@@ -0,0 +1,151 @@
+import py
+from rpython.tool.udir import udir
+from pypy.interpreter.gateway import interp2app
+
+
+class AppTestRecompilerPython:
+    spaceconfig = dict(usemodules=['_cffi_backend'])
+
+    def setup_class(cls):
+        try:
+            from cffi import FFI           # <== the system one, which
+            from cffi import recompiler    # needs to be at least cffi 1.0.0
+            from cffi import ffiplatform
+        except ImportError:
+            py.test.skip("system cffi module not found or older than 1.0.0")
+        SRC = """
+        #define FOOBAR (-42)
+        static const int FOOBAZ = -43;
+        #define BIGPOS 420000000000L
+        #define BIGNEG -420000000000L
+        int add42(int x) { return x + 42; }
+        int globalvar42 = 1234;
+        struct foo_s;
+        typedef struct bar_s { int x; signed char a[]; } bar_t;
+        enum foo_e { AA, BB, CC };
+
+        void init_test_re_python(void) { }      /* windows hack */
+        void PyInit__test_re_python(void) { }   /* windows hack */
+        """
+        tmpdir = udir.join('test_re_python')
+        tmpdir.ensure(dir=1)
+        c_file = tmpdir.join('_test_re_python.c')
+        c_file.write(SRC)
+        ext = ffiplatform.get_extension(str(c_file), '_test_re_python',
+                                        export_symbols=['add42', 'globalvar42'])
+        outputfilename = ffiplatform.compile(str(tmpdir), ext)
+        #mod.extmod = outputfilename
+        #mod.tmpdir = tmpdir
+        #
+        ffi = FFI()
+        ffi.cdef("""
+        #define FOOBAR -42
+        static const int FOOBAZ = -43;
+        #define BIGPOS 420000000000L
+        #define BIGNEG -420000000000L
+        int add42(int);
+        int globalvar42;
+        struct foo_s;
+        typedef struct bar_s { int x; signed char a[]; } bar_t;
+        enum foo_e { AA, BB, CC };
+        """)
+        ffi.set_source('re_python_pysrc', None)
+        ffi.emit_python_code(str(tmpdir.join('re_python_pysrc.py')))
+        #mod.original_ffi = ffi
+        #
+        space = cls.space
+        space.appexec([space.wrap(str(tmpdir))], """(path):
+            import _cffi_backend     # force it to be initialized
+            import sys
+            sys.path.insert(0, path)
+        """)
+
+
+    def test_constant(self):
+        from re_python_pysrc import ffi
+        assert ffi.integer_const('FOOBAR') == -42
+        assert ffi.integer_const('FOOBAZ') == -43
+
+    def test_large_constant():
+        from re_python_pysrc import ffi
+        assert ffi.integer_const('BIGPOS') == 420000000000
+        assert ffi.integer_const('BIGNEG') == -420000000000
+
+    def test_function():
+        import _cffi_backend
+        from re_python_pysrc import ffi
+        lib = ffi.dlopen(extmod)
+        assert lib.add42(-10) == 32
+        assert type(lib.add42) is _cffi_backend.FFI.CData
+
+    def test_dlclose():
+        import _cffi_backend
+        from re_python_pysrc import ffi
+        lib = ffi.dlopen(extmod)
+        ffi.dlclose(lib)
+        e = py.test.raises(ffi.error, ffi.dlclose, lib)
+        assert str(e.value) == (
+            "library '%s' is already closed or was not created with ffi.dlopen()"
+            % (extmod,))
+
+    def test_constant_via_lib():
+        from re_python_pysrc import ffi
+        lib = ffi.dlopen(extmod)
+        assert lib.FOOBAR == -42
+        assert lib.FOOBAZ == -43
+
+    def test_opaque_struct():
+        from re_python_pysrc import ffi
+        ffi.cast("struct foo_s *", 0)
+        py.test.raises(TypeError, ffi.new, "struct foo_s *")
+
+    def test_nonopaque_struct():
+        from re_python_pysrc import ffi
+        for p in [ffi.new("struct bar_s *", [5, b"foobar"]),
+                  ffi.new("bar_t *", [5, b"foobar"])]:
+            assert p.x == 5
+            assert p.a[0] == ord('f')
+            assert p.a[5] == ord('r')
+
+    def test_enum():
+        from re_python_pysrc import ffi
+        assert ffi.integer_const("BB") == 1
+        e = ffi.cast("enum foo_e", 2)
+        assert ffi.string(e) == "CC"
+
+    def test_include_1():
+        sub_ffi = FFI()
+        sub_ffi.cdef("static const int k2 = 121212;")
+        sub_ffi.include(original_ffi)
+        assert 'macro FOOBAR' in original_ffi._parser._declarations
+        assert 'macro FOOBAZ' in original_ffi._parser._declarations
+        sub_ffi.set_source('re_python_pysrc', None)
+        sub_ffi.emit_python_code(str(tmpdir.join('_re_include_1.py')))
+        #
+        from _re_include_1 import ffi
+        assert ffi.integer_const('FOOBAR') == -42
+        assert ffi.integer_const('FOOBAZ') == -43
+        assert ffi.integer_const('k2') == 121212
+        lib = ffi.dlopen(extmod)     # <- a random unrelated library would be fine
+        assert lib.FOOBAR == -42
+        assert lib.FOOBAZ == -43
+        assert lib.k2 == 121212
+        #
+        p = ffi.new("bar_t *", [5, b"foobar"])
+        assert p.a[4] == ord('a')
+
+    def test_global_var():
+        from re_python_pysrc import ffi
+        lib = ffi.dlopen(extmod)
+        assert lib.globalvar42 == 1234
+        p = ffi.addressof(lib, 'globalvar42')
+        lib.globalvar42 += 5
+        assert p[0] == 1239
+        p[0] -= 1
+        assert lib.globalvar42 == 1238
+
+    def test_rtld_constants():
+        from re_python_pysrc import ffi
+        ffi.RTLD_NOW    # check that we have the attributes
+        ffi.RTLD_LAZY
+        ffi.RTLD_GLOBAL
diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py b/pypy/module/_cffi_backend/test/test_recompiler.py
--- a/pypy/module/_cffi_backend/test/test_recompiler.py
+++ b/pypy/module/_cffi_backend/test/test_recompiler.py
@@ -9,8 +9,8 @@
 @unwrap_spec(cdef=str, module_name=str, source=str)
 def prepare(space, cdef, module_name, source, w_includes=None):
     try:
-        from cffi import FFI              # <== the system one, which
-        from _cffi1 import recompiler     # needs to be at least cffi 1.0.0b3
+        from cffi import FFI            # <== the system one, which
+        from cffi import recompiler     # needs to be at least cffi 1.0.0
         from cffi import ffiplatform
     except ImportError:
         py.test.skip("system cffi module not found or older than 1.0.0")
@@ -222,6 +222,15 @@
         assert lib.FOOBAR == -6912
         raises(AttributeError, "lib.FOOBAR = 2")
 
+    def test_check_value_of_static_const(self):
+        ffi, lib = self.prepare(
+            "static const int FOOBAR = 042;",
+            'test_check_value_of_static_const',
+            "#define FOOBAR (-6912)")
+        e = raises(ffi.error, getattr, lib, 'FOOBAR')
+        assert str(e.value) == (
+           "the C compiler says 'FOOBAR' is equal to -6912, but the cdef disagrees")
+
     def test_constant_nonint(self):
         ffi, lib = self.prepare(
             "static const double FOOBAR;",


More information about the pypy-commit mailing list