1. Python CFFI
  2. Untitled project
  3. cffi

Commits

Armin Rigo  committed 0d40d81

verify() can read constants declared e.g. with #define.

  • Participants
  • Parent commits 9538059
  • Branches cpy-extension

Comments (0)

Files changed (3)

File cffi/cparser.py

View file
  • Ignore whitespace
                                     decl)
             #
             if decl.name:
-                self._declare('variable ' + decl.name, self._get_type(node))
+                tp = self._get_type(node)
+                if 'const' in decl.quals:
+                    self._declare('constant ' + decl.name, tp)
+                else:
+                    self._declare('variable ' + decl.name, tp)
 
     def parse_type(self, cdecl, force_pointer=False):
         ast = self._parse('void __dummy(%s);' % cdecl)

File cffi/verifier.py

View file
  • Ignore whitespace
     def verify(self, preamble, stop_on_warnings=True):
         modname = ffiplatform.undercffi_module_name()
         filebase = os.path.join(ffiplatform.tmpdir(), modname)
+        self.chained_list_constants = None
         
         with open(filebase + '.c', 'w') as f:
             self.f = f
             #
             self.generate("decl")
             #
+            self.prnt('static PyObject *_cffi_setup_custom(void)')
+            self.prnt('{')
+            self.prnt('  PyObject *dct = PyDict_New();')
+            if self.chained_list_constants is not None:
+                self.prnt('  if (dct == NULL)')
+                self.prnt('    return NULL;')
+                self.prnt('  if (%s(dct) < 0) {' % self.chained_list_constants)
+                self.prnt('    Py_DECREF(dct);')
+                self.prnt('    return NULL;')
+                self.prnt('  }')
+            self.prnt('  return dct;')
+            self.prnt('}')
+            self.prnt()
+            #
             self.prnt('static PyMethodDef _cffi_methods[] = {')
             self.generate("method")
             self.prnt('  {"_cffi_setup", _cffi_setup, METH_O},')
             self.prnt('void init%s()' % modname)
             self.prnt('{')
             self.prnt('  Py_InitModule("%s", _cffi_methods);' % modname)
-            self.prnt('  if (PyErr_Occurred() || _cffi_init()) return;')
-            self.generate("init")
             self.prnt('}')
             #
             del self.f
         revmapping = dict([(value, key)
                            for (key, value) in self.typesdict.items()])
         lst = [revmapping[i] for i in range(len(revmapping))]
-        module._cffi_setup(lst)
+        dct = module._cffi_setup(lst)
         del module._cffi_setup
+        module.__dict__.update(dct)
         #
         self.load(module, 'loading')
         self.load(module, 'loaded')
 
     generate_cpy_typedef_decl   = generate_nothing
     generate_cpy_typedef_method = generate_nothing
-    generate_cpy_typedef_init   = generate_nothing
     loading_cpy_typedef         = loaded_noop
     loaded_cpy_typedef          = loaded_noop
 
             meth = 'METH_VARARGS'
         self.prnt('  {"%s", _cffi_f_%s, %s},' % (name, name, meth))
 
-    generate_cpy_function_init = generate_nothing
     loading_cpy_function       = loaded_noop
     loaded_cpy_function        = loaded_noop
 
         self.prnt('  {"_cffi_struct_%s", _cffi_struct_%s, METH_NOARGS},' % (
             name, name))
 
-    generate_cpy_struct_init = generate_nothing
-
     def loading_cpy_struct(self, tp, name, module):
         assert name == tp.name
         function = getattr(module, '_cffi_struct_%s' % name)
         self.ffi._get_cached_btype(tp)   # force 'fixedlayout' to be considered
 
     # ----------
+    # constants, likely declared with '#define'
 
+    def generate_cpy_constant_decl(self, tp, name):
+        prnt = self.prnt
+        my_func_name = '_cffi_const_%s' % name
+        prnt('static int %s(PyObject *dct)' % my_func_name)
+        prnt('{')
+        prnt('  %s;' % tp.get_c_name(' i'))
+        prnt('  PyObject *o;')
+        prnt('  int res;')
+        if self.chained_list_constants is not None:
+            prnt('  if (%s(dct) < 0)' % self.chained_list_constants)
+            prnt('    return -1;')
+        self.chained_list_constants = my_func_name
+        prnt('  i = (%s);' % (name,))
+        prnt('  o = %s;' % (self.convert_expr_from_c(tp, 'i'),))
+        prnt('  if (o == NULL)')
+        prnt('    return -1;')
+        prnt('  res = PyDict_SetItemString(dct, "%s", o);' % name)
+        prnt('  Py_DECREF(o);')
+        prnt('  return res;')
+        prnt('}')
+        prnt()
+
+    generate_cpy_constant_method = generate_nothing
+
+    loading_cpy_constant = loaded_noop
+    loaded_cpy_constant  = loaded_noop
+
+    # ----------
 
 cffimod_header = r'''
 #include <Python.h>
 static void **_cffi_exports;
 static PyObject *_cffi_types;
 
-static int _cffi_init(void)
+static PyObject *_cffi_setup_custom(void);   /* forward */
+
+static PyObject *_cffi_setup(PyObject *self, PyObject *arg)
 {
     PyObject *module = PyImport_ImportModule("_ffi_backend");
     PyObject *c_api_object;
 
     if (module == NULL)
-        return -1;
+        return NULL;
 
     c_api_object = PyObject_GetAttrString(module, "_C_API");
     if (c_api_object == NULL)
-        return -1;
+        return NULL;
     if (!PyCObject_Check(c_api_object)) {
         PyErr_SetNone(PyExc_ImportError);
-        return -1;
+        return NULL;
     }
     _cffi_exports = (void **)PyCObject_AsVoidPtr(c_api_object);
-    return 0;
-}
 
-static PyObject *_cffi_setup(PyObject *self, PyObject *arg)
-{
     Py_INCREF(arg);
     _cffi_types = arg;
-    Py_INCREF(Py_None);
-    return Py_None;
+
+    return _cffi_setup_custom();
 }
 
 #define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num))

File testing/test_verify.py

View file
  • Ignore whitespace
     assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
     s = ffi.new("struct foo_s")
     assert ffi.sizeof(s.a) == 17 * ffi.sizeof('int')
+
+def test_global_constants():
+    ffi = FFI()
+    # use 'static const int', as generally documented, although in this
+    # case the 'static' is completely ignored.
+    ffi.cdef("static const int AA, BB, CC;")
+    lib = ffi.verify("#define AA 42\n"
+                     "#define BB (-43)\n"
+                     "#define CC (22*2)\n")
+    assert lib.AA == 42
+    assert lib.BB == -43
+    assert lib.CC == 44