def test_ll2ctypes_array_from_c(self): from rpython.rtyper.lltypesystem import rffi, ll2ctypes A = rffi.CArray(Char) a = malloc(A, 6, flavor='raw', immortal=True) a[0] = 'a' a[1] = 'b' a[2] = 'c' a[3] = 'd' a[4] = '\x00' a[5] = '\x00' # side effects when converting to c structure c = ll2ctypes.lltype2ctypes(a) a = ll2ctypes.ctypes2lltype(Ptr(A), c) def llf(): s = '' for i in range(4): s += a[i] return s == 'abcd' fn = self.getcompiled(llf, []) assert fn()
def build_bridge(space): "NOT_RPYTHON" from pypy.module.cpyext.pyobject import make_ref export_symbols = list(FUNCTIONS) + SYMBOLS_C + list(GLOBALS) from rpython.translator.c.database import LowLevelDatabase db = LowLevelDatabase() generate_macros(export_symbols, rename=True, do_deref=True) # Structure declaration code members = [] structindex = {} for name, func in sorted(FUNCTIONS.iteritems()): restype, args = c_function_signature(db, func) members.append('%s (*%s)(%s);' % (restype, name, args)) structindex[name] = len(structindex) structmembers = '\n'.join(members) struct_declaration_code = """\ struct PyPyAPI { %(members)s } _pypyAPI; struct PyPyAPI* pypyAPI = &_pypyAPI; """ % dict(members=structmembers) functions = generate_decls_and_callbacks(db, export_symbols) global_objects = [] for name, (typ, expr) in GLOBALS.iteritems(): if "#" in name: continue if typ == 'PyDateTime_CAPI*': continue elif name.startswith('PyExc_'): global_objects.append('%s _%s;' % (typ[:-1], name)) else: global_objects.append('%s %s = NULL;' % (typ, name)) global_code = '\n'.join(global_objects) prologue = ("#include <Python.h>\n" "#include <src/thread.c>\n") code = (prologue + struct_declaration_code + global_code + '\n' + '\n'.join(functions)) eci = build_eci(True, export_symbols, code) eci = eci.compile_shared_lib( outputfilename=str(udir / "module_cache" / "pypyapi")) modulename = py.path.local(eci.libraries[-1]) run_bootstrap_functions(space) # load the bridge, and init structure import ctypes bridge = ctypes.CDLL(str(modulename), mode=ctypes.RTLD_GLOBAL) space.fromcache(State).install_dll(eci) # populate static data for name, (typ, expr) in GLOBALS.iteritems(): from pypy.module import cpyext w_obj = eval(expr) if name.endswith('#'): name = name[:-1] isptr = False else: isptr = True if name.startswith('PyExc_'): isptr = False INTERPLEVEL_API[name] = w_obj name = name.replace('Py', 'PyPy') if isptr: ptr = ctypes.c_void_p.in_dll(bridge, name) if typ == 'PyObject*': value = make_ref(space, w_obj) elif typ == 'PyDateTime_CAPI*': value = w_obj else: assert False, "Unknown static pointer: %s %s" % (typ, name) ptr.value = ctypes.cast(ll2ctypes.lltype2ctypes(value), ctypes.c_void_p).value elif typ in ('PyObject*', 'PyTypeObject*'): if name.startswith('PyPyExc_'): # we already have the pointer in_dll = ll2ctypes.get_ctypes_type(PyObject).in_dll(bridge, name) py_obj = ll2ctypes.ctypes2lltype(PyObject, in_dll) else: # we have a structure, get its address in_dll = ll2ctypes.get_ctypes_type(PyObject.TO).in_dll(bridge, name) py_obj = ll2ctypes.ctypes2lltype(PyObject, ctypes.pointer(in_dll)) from pypy.module.cpyext.pyobject import ( track_reference, get_typedescr) w_type = space.type(w_obj) typedescr = get_typedescr(w_type.instancetypedef) py_obj.c_ob_refcnt = 1 py_obj.c_ob_type = rffi.cast(PyTypeObjectPtr, make_ref(space, w_type)) typedescr.attach(space, py_obj, w_obj) track_reference(space, py_obj, w_obj) else: assert False, "Unknown static object: %s %s" % (typ, name) pypyAPI = ctypes.POINTER(ctypes.c_void_p).in_dll(bridge, 'pypyAPI') # implement structure initialization code for name, func in FUNCTIONS.iteritems(): if name.startswith('cpyext_'): # XXX hack continue pypyAPI[structindex[name]] = ctypes.cast( ll2ctypes.lltype2ctypes(func.get_llhelper(space)), ctypes.c_void_p) setup_va_functions(eci) setup_init_functions(eci, translating=False) return modulename.new(ext='')
def build_bridge(space): "NOT_RPYTHON" from pypy.module.cpyext.pyobject import make_ref export_symbols = list(FUNCTIONS) + SYMBOLS_C + list(GLOBALS) from rpython.translator.c.database import LowLevelDatabase db = LowLevelDatabase() generate_macros(export_symbols, prefix='cpyexttest') # Structure declaration code members = [] structindex = {} for name, func in sorted(FUNCTIONS.iteritems()): restype, args = c_function_signature(db, func) members.append('%s (*%s)(%s);' % (restype, name, args)) structindex[name] = len(structindex) structmembers = '\n'.join(members) struct_declaration_code = """\ struct PyPyAPI { %(members)s } _pypyAPI; RPY_EXTERN struct PyPyAPI* pypyAPI = &_pypyAPI; """ % dict(members=structmembers) functions = generate_decls_and_callbacks(db, export_symbols) global_objects = [] for name, (typ, expr) in GLOBALS.iteritems(): if "#" in name: continue if typ == 'PyDateTime_CAPI*': continue elif name.startswith('PyExc_'): global_objects.append('%s _%s;' % (typ[:-1], name)) else: global_objects.append('%s %s = NULL;' % (typ, name)) global_code = '\n'.join(global_objects) prologue = ("#include <Python.h>\n" "#include <src/thread.c>\n") code = (prologue + struct_declaration_code + global_code + '\n' + '\n'.join(functions)) eci = build_eci(True, export_symbols, code) eci = eci.compile_shared_lib( outputfilename=str(udir / "module_cache" / "pypyapi")) modulename = py.path.local(eci.libraries[-1]) run_bootstrap_functions(space) # load the bridge, and init structure import ctypes bridge = ctypes.CDLL(str(modulename), mode=ctypes.RTLD_GLOBAL) space.fromcache(State).install_dll(eci) # populate static data for name, (typ, expr) in GLOBALS.iteritems(): from pypy.module import cpyext w_obj = eval(expr) if name.endswith('#'): name = name[:-1] isptr = False else: isptr = True if name.startswith('PyExc_'): isptr = False INTERPLEVEL_API[name] = w_obj name = name.replace('Py', 'cpyexttest') if isptr: ptr = ctypes.c_void_p.in_dll(bridge, name) if typ == 'PyObject*': value = make_ref(space, w_obj) elif typ == 'PyDateTime_CAPI*': value = w_obj else: assert False, "Unknown static pointer: %s %s" % (typ, name) ptr.value = ctypes.cast(ll2ctypes.lltype2ctypes(value), ctypes.c_void_p).value elif typ in ('PyObject*', 'PyTypeObject*'): if name.startswith('PyPyExc_') or name.startswith('cpyexttestExc_'): # we already have the pointer in_dll = ll2ctypes.get_ctypes_type(PyObject).in_dll(bridge, name) py_obj = ll2ctypes.ctypes2lltype(PyObject, in_dll) else: # we have a structure, get its address in_dll = ll2ctypes.get_ctypes_type(PyObject.TO).in_dll(bridge, name) py_obj = ll2ctypes.ctypes2lltype(PyObject, ctypes.pointer(in_dll)) from pypy.module.cpyext.pyobject import ( track_reference, get_typedescr) w_type = space.type(w_obj) typedescr = get_typedescr(w_type.instancetypedef) py_obj.c_ob_refcnt = 1 py_obj.c_ob_type = rffi.cast(PyTypeObjectPtr, make_ref(space, w_type)) typedescr.attach(space, py_obj, w_obj) track_reference(space, py_obj, w_obj) else: assert False, "Unknown static object: %s %s" % (typ, name) pypyAPI = ctypes.POINTER(ctypes.c_void_p).in_dll(bridge, 'pypyAPI') # implement structure initialization code for name, func in FUNCTIONS.iteritems(): if name.startswith('cpyext_'): # XXX hack continue pypyAPI[structindex[name]] = ctypes.cast( ll2ctypes.lltype2ctypes(func.get_llhelper(space)), ctypes.c_void_p) setup_va_functions(eci) setup_init_functions(eci, translating=False) return modulename.new(ext='')