Hello, Py++ translates the struct
typedef int cb_fun_t(char *); struct info { cb_fun_t* cb_fun; int flag; }; into the Python Structure class info(ctypes.Structure): """class info""" info._fields_ = [ #class info ("cb_fun", ctypes.POINTER( ctypes.CFUNCTYPE( ctypes.c_int, ctypes.c_char_p ) )), ("flag", ctypes.c_int), ] This is wrong and produces segfaults. The correct version is class info(ctypes.Structure): """class info""" info._fields_ = [ #class info ("cb_fun", ctypes.CFUNCTYPE( ctypes.c_int, ctypes.c_char_p ) ), ("flag", ctypes.c_int), ] I have attached a small example that demonstrates the problem. lib.c is a small C library, build_api.py creates the broken api.py with Py++. api_correct.py is the manually corrected API with the correct structure. call.py demonstrates that the first API segfaults and the second API works: $ python call.py Calling do_callback with flag=7 do_callback called with flag=7 cb_fun received 'Hello World' cb_fun returns 42 cb_fun returned 42 do_callback returned 42 Calling do_callback with flag=7 do_callback called with flag=7 Segmentation fault Please let me know if you can reproduce the problem. It took me quite some time to figure this out. Best, -Nikolaus -- »Time flies like an arrow, fruit flies like a Banana.« PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6 02CF A9AD B7F8 AE4E 425C
#include <stdio.h> typedef int cb_fun_t(char *); struct info { cb_fun_t* cb_fun; int flag; }; int do_callback(struct info* info) { char* str = "Hello World"; int ret; printf("do_callback called with flag=%i\n", info->flag); ret = info->cb_fun(str); printf("cb_fun returned %i\n", ret); return(ret); }
#!/usr/bin/env python # Generate the code from pygccxml import parser from pygccxml import declarations from pyplusplus.module_builder import ctypes_module_builder_t, ctypes_decls_dependencies shared_library_path = './lib.so' header_file = './lib.c' gccxml_cfg = parser.gccxml_configuration_t() mb = ctypes_module_builder_t( [header_file], shared_library_path, gccxml_config=gccxml_cfg ) mb.global_ns.decl('cb_fun_t').include() mb.build_code_creator(shared_library_path) mb.write_module('api.py')
# This file has been generated by Py++. import ctypes import ctypes_utils lib_lib = ctypes.CDLL( r"./lib.so" ) lib_lib.undecorated_names = {#mapping between decorated and undecorated names "int do_callback(info * info) [free function]" : "do_callback", "do_callback" : "int do_callback(info * info) [free function]", } class info(ctypes.Structure): """class info""" info._fields_ = [ #class info ("cb_fun", ctypes.POINTER( ctypes.CFUNCTYPE( ctypes.c_int, ctypes.c_char_p ) )), ("flag", ctypes.c_int), ] cb_fun_t = ctypes.CFUNCTYPE( ctypes.c_int, ctypes.c_char_p ) do_callback_type = ctypes.CFUNCTYPE( ctypes.c_int, ctypes.POINTER( info ) ) do_callback = do_callback_type( ( lib_lib.undecorated_names["int do_callback(info * info) [free function]"], lib_lib ) )
# This file has been generated by Py++. import ctypes import ctypes_utils lib_lib = ctypes.CDLL( r"./lib.so" ) lib_lib.undecorated_names = {#mapping between decorated and undecorated names "int do_callback(info * info) [free function]" : "do_callback", "do_callback" : "int do_callback(info * info) [free function]", } class info(ctypes.Structure): """class info""" info._fields_ = [ #class info ("cb_fun", ctypes.CFUNCTYPE( ctypes.c_int, ctypes.c_char_p ) ), ("flag", ctypes.c_int), ] cb_fun_t = ctypes.CFUNCTYPE( ctypes.c_int, ctypes.c_char_p ) do_callback_type = ctypes.CFUNCTYPE( ctypes.c_int, ctypes.POINTER( info ) ) do_callback = do_callback_type( ( lib_lib.undecorated_names["int do_callback(info * info) [free function]"], lib_lib ) )
#!/usr/bin/env python import api import api_correct def cb_fun(str): print 'cb_fun received %r' % str print 'cb_fun returns 42' return 42 # First try the fixed API info = api_correct.info() info.flag = 7 info.cb_fun = api_correct.cb_fun_t(cb_fun) print 'Calling do_callback with flag=%d' % info.flag ret = api_correct.do_callback(info) print 'do_callback returned %d' % ret # And now the one generated by Py++ from ctypes import pointer info = api.info() info.flag = 7 info.cb_fun = pointer(api.cb_fun_t(cb_fun)) print 'Calling do_callback with flag=%d' % info.flag ret = api.do_callback(info) print 'do_callback returned %d' % ret
_______________________________________________ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig