[pypy-commit] cffi cffi-1.0: Includes of dlopen-style ffis. Negative constants in "static const int = ...".

arigo noreply at buildbot.pypy.org
Sat May 16 10:58:56 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r2006:f28455444b8f
Date: 2015-05-16 10:59 +0200
http://bitbucket.org/cffi/cffi/changeset/f28455444b8f/

Log:	Includes of dlopen-style ffis. Negative constants in "static const
	int = ...".

diff --git a/c/cdlopen.c b/c/cdlopen.c
--- a/c/cdlopen.c
+++ b/c/cdlopen.c
@@ -134,19 +134,21 @@
     FFIObject *ffi;
     static char *keywords[] = {"module_name", "_version", "_types",
                                "_globals", "_struct_unions", "_enums",
-                               "_typenames", NULL};
+                               "_typenames", "_includes", NULL};
     char *ffiname = NULL, *types = NULL, *building = NULL;
     Py_ssize_t version = -1;
     Py_ssize_t types_len = 0;
     PyObject *globals = NULL, *struct_unions = NULL, *enums = NULL;
-    PyObject *typenames = NULL;
+    PyObject *typenames = NULL, *includes = NULL;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sns#O!O!O!O!:FFI", keywords,
+    if (!PyArg_ParseTupleAndKeywords(args, kwds,
+                                     "|sns#O!O!O!O!O!:FFI", keywords,
                                      &ffiname, &version, &types, &types_len,
                                      &PyTuple_Type, &globals,
                                      &PyTuple_Type, &struct_unions,
                                      &PyTuple_Type, &enums,
-                                     &PyTuple_Type, &typenames))
+                                     &PyTuple_Type, &typenames,
+                                     &PyTuple_Type, &includes))
         return -1;
 
     ffi = (FFIObject *)self;
@@ -337,6 +339,18 @@
         building = NULL;
     }
 
+    if (includes != NULL) {
+        PyObject *included_libs;
+
+        included_libs = PyTuple_New(PyTuple_GET_SIZE(includes));
+        if (included_libs == NULL)
+            return -1;
+
+        Py_INCREF(includes);
+        ffi->types_builder.included_ffis = includes;
+        ffi->types_builder.included_libs = included_libs;
+    }
+
     /* Above, we took directly some "char *" strings out of the strings,
        typically from somewhere inside tuples.  Keep them alive by
        incref'ing the whole input arguments. */
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -271,10 +271,19 @@
                     tp = self._get_type_pointer(tp)
                     self._declare('function ' + decl.name, tp)
                 elif (isinstance(tp, model.PrimitiveType) and
-                      tp.is_integer_type() and
-                      hasattr(decl, 'init') and hasattr(decl.init, 'value')
-                      and _r_int_literal.match(decl.init.value)):
+                        tp.is_integer_type() and
+                        hasattr(decl, 'init') and
+                        hasattr(decl.init, 'value') and
+                        _r_int_literal.match(decl.init.value)):
                     self._add_integer_constant(decl.name, decl.init.value)
+                elif (isinstance(tp, model.PrimitiveType) and
+                        tp.is_integer_type() and
+                        isinstance(decl.init, pycparser.c_ast.UnaryOp) and
+                        decl.init.op == '-' and
+                        hasattr(decl.init.expr, 'value') and
+                        _r_int_literal.match(decl.init.expr.value)):
+                    self._add_integer_constant(decl.name,
+                                               '-' + decl.init.expr.value)
                 elif self._is_constant_globalvar(node):
                     self._declare('constant ' + decl.name, tp)
                 else:
diff --git a/cffi/recompiler.py b/cffi/recompiler.py
--- a/cffi/recompiler.py
+++ b/cffi/recompiler.py
@@ -335,7 +335,7 @@
                 if not hasattr(ffi_to_include, '_recompiler_module_name'):
                     raise ffiplatform.VerificationError(
                         "this ffi includes %r, but the latter has not been "
-                        "turned into a C module" % (ffi_to_include,))
+                        "compiled yet" % (ffi_to_include,))
                 prnt('  "%s",' % (ffi_to_include._recompiler_module_name,))
             prnt('  NULL')
             prnt('};')
@@ -417,6 +417,17 @@
         # header
         prnt("# auto-generated file")
         prnt("import _cffi_backend")
+        #
+        # the 'import' of the included ffis
+        num_includes = len(self.ffi._included_ffis or ())
+        for i in range(num_includes):
+            ffi_to_include = self.ffi._included_ffis[i]
+            if not hasattr(ffi_to_include, '_recompiler_module_name'):
+                raise ffiplatform.VerificationError(
+                    "this ffi includes %r, but the latter has not been "
+                    "compiled yet" % (ffi_to_include,))
+            prnt('from %s import ffi as _ffi%d' % (
+                ffi_to_include._recompiler_module_name, i))
         prnt()
         prnt("ffi = _cffi_backend.FFI(%s," % (self._to_py(self.module_name),))
         #
@@ -426,13 +437,20 @@
         prnt('    _types = %s,' % (self._to_py(''.join(types_lst)),))
         typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()])
         #
+        # the keyword arguments from ALL_STEPS
         for step_name in self.ALL_STEPS:
             lst = self._lsts[step_name]
             if len(lst) > 0 and step_name != "field":
                 prnt('    _%ss = %s,' % (step_name, self._to_py(lst)))
         #
+        # the '_includes' keyword argument
+        if num_includes > 0:
+            prnt('    _includes = (%s,),' % (
+                ', '.join(['_ffi%d' % i for i in range(num_includes)]),))
+        #
         # the footer
         prnt(')')
+        self.ffi._recompiler_module_name = self.module_name
 
     # ----------
 
diff --git a/testing/cffi1/test_dlopen.py b/testing/cffi1/test_dlopen.py
--- a/testing/cffi1/test_dlopen.py
+++ b/testing/cffi1/test_dlopen.py
@@ -82,3 +82,45 @@
     _struct_unions = ((b'\x00\x00\x00\x03\x00\x00\x00\x10bar_s',),(b'\x00\x00\x00\x04\x00\x00\x00\x02foo_s',b'\x00\x00\x00\x11a',b'\x00\x00\x02\x11b')),
 )
 """
+
+def test_include():
+    ffi = FFI()
+    ffi.cdef("#define ABC 123")
+    target = udir.join('test_include.py')
+    assert make_py_source(ffi, 'test_include', str(target))
+    assert target.read() == r"""# auto-generated file
+import _cffi_backend
+
+ffi = _cffi_backend.FFI(b'test_include',
+    _types = b'',
+    _globals = (b'\xFF\xFF\xFF\x1FABC',123,),
+)
+"""
+    #
+    ffi2 = FFI()
+    ffi2.include(ffi)
+    target2 = udir.join('test2_include.py')
+    assert make_py_source(ffi2, 'test2_include', str(target2))
+    assert target2.read() == r"""# auto-generated file
+import _cffi_backend
+from test_include import ffi as _ffi0
+
+ffi = _cffi_backend.FFI(b'test2_include',
+    _types = b'',
+    _includes = (_ffi0,),
+)
+"""
+
+def test_negative_constant():
+    ffi = FFI()
+    ffi.cdef("static const int BB = -42;")
+    target = udir.join('test_negative_constant.py')
+    assert make_py_source(ffi, 'test_negative_constant', str(target))
+    assert target.read() == r"""# auto-generated file
+import _cffi_backend
+
+ffi = _cffi_backend.FFI(b'test_negative_constant',
+    _types = b'',
+    _globals = (b'\xFF\xFF\xFF\x1FBB',-42,),
+)
+"""
diff --git a/testing/cffi1/test_re_python.py b/testing/cffi1/test_re_python.py
--- a/testing/cffi1/test_re_python.py
+++ b/testing/cffi1/test_re_python.py
@@ -8,6 +8,7 @@
 def setup_module(mod):
     SRC = """
     #define FOOBAR (-42)
+    static const int FOOBAZ = -43;
     int add42(int x) { return x + 42; }
     struct foo_s;
     typedef struct bar_s { int x; signed char a[]; } bar_t;
@@ -20,10 +21,12 @@
     ext = ffiplatform.get_extension(str(c_file), '_test_re_python')
     outputfilename = ffiplatform.compile(str(tmpdir), ext)
     mod.extmod = outputfilename
+    mod.tmpdir = tmpdir
     #
     ffi = FFI()
     ffi.cdef("""
     #define FOOBAR -42
+    static const int FOOBAZ = -43;
     int add42(int);
     struct foo_s;
     typedef struct bar_s { int x; signed char a[]; } bar_t;
@@ -31,6 +34,7 @@
     """)
     ffi.set_source('re_python_pysrc', None)
     ffi.emit_python_code(str(tmpdir.join('re_python_pysrc.py')))
+    mod.original_ffi = ffi
     #
     sys.path.insert(0, str(tmpdir))
 
@@ -38,6 +42,7 @@
 def test_constant():
     from re_python_pysrc import ffi
     assert ffi.integer_const('FOOBAR') == -42
+    assert ffi.integer_const('FOOBAZ') == -43
 
 def test_function():
     from re_python_pysrc import ffi
@@ -48,6 +53,7 @@
     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
@@ -67,3 +73,21 @@
     assert ffi.integer_const("BB") == 1
     e = ffi.cast("enum foo_e", 2)
     assert ffi.string(e) == "CC"
+
+def test_include_1():
+    ffi2 = FFI()
+    ffi2.cdef("static const int k2 = 121212;")
+    ffi2.include(original_ffi)
+    assert 'macro FOOBAR' in original_ffi._parser._declarations
+    assert 'macro FOOBAZ' in original_ffi._parser._declarations
+    ffi2.set_source('re_python_pysrc', None)
+    ffi2.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(None)
+    assert lib.FOOBAR == -42
+    assert lib.FOOBAZ == -43
+    assert lib.k2 == 121212


More information about the pypy-commit mailing list