[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