我正在尝试使用PyBindGen为我的C库创建一个python扩展模块,它有一个回调。尽管PyBindGen frontpage说回调是一个缺少的特性,但是当前的源代码和this discussion和archive都有如何设置PyBindGen将回调函数从python传递到C库的示例。你知道吗
问题是,该示例将回调方法定义为将PyObject*
作为void *
参数来携带回调函数指针信息。因为我的API没有这样的上下文指针,所以我尝试将对回调的引用保留在C绑定代码similar to standard python example中。问题是我不知道如何让PyBindGen设置全局PyObject*my\u回调。我该怎么做?这是我的密码
我的库头文件
typedef void (*CallbackType) (int value);
void register_cb(CallbackType cb);
void set_num(int n);
我的库源文件
#include "c.h"
static CallbackType cb_;
void register_cb(CallbackType cb)
{
cb_ = cb;
}
void set_num(int n)
{
cb_(n);
}
我的皮宾根模块gen.py需要添加到自动生成代码中的注释部分
import sys
import pybindgen
from pybindgen import ReturnValue, Parameter, Module, Function, FileCodeSink
from pybindgen import CppMethod, CppConstructor, CppClass, Enum
from pybindgen.typehandlers.base import ForwardWrapperBase
class CallbackTypeParam(Parameter):
DIRECTIONS = [Parameter.DIRECTION_IN]
CTYPES = ['CallbackType']
def convert_python_to_c(self, wrapper):
assert isinstance(wrapper, ForwardWrapperBase)
py_cb = wrapper.declarations.declare_variable("PyObject*", self.name)
wrapper.parse_params.add_parameter('O', ['&'+py_cb], self.name)
wrapper.before_call.write_error_check("!PyCallable_Check(%s)" % py_cb, """PyErr_SetString(PyExc_TypeError, "CallbackType parameter must be callable");""")
#####
# NEED TO INSERT THE FOLLOWING TWO LINES INTO AUTOGENERATED OUTPUT HERE
# Py_XDECREF(my_callback); // NEEDS TO BE AUTO-GENERATED !!!
# my_callback = cb; // NEEDS TO BE AUTO-GENERATED !!!
#####
wrapper.call_params.append("_wrap_callback")
wrapper.before_call.write_code("Py_INCREF(%s);" % py_cb)
wrapper.before_call.add_cleanup_code("Py_DECREF(%s);" % py_cb)
def convert_c_to_python(self, wrapper):
raise NotImplementedError
def my_module_gen(out_file):
mod = Module('c')
mod.add_include('"c.h"')
mod.header.writeln("""
void _wrap_callback(int value);
static PyObject *my_callback = NULL;
""")
mod.body.writeln("""
void _wrap_callback(int value)
{
int arg;
PyObject *arglist;
arg = value;
printf("@@@@ Inside the binding: %d %p\\n", value, my_callback); fflush(NULL);
arglist = Py_BuildValue("(i)", arg);
PyObject_CallObject(my_callback, arglist);
Py_DECREF(arglist);
}
""")
mod.add_function("register_cb", None, [Parameter.new("CallbackType", "cb")])
mod.add_function("set_num", None, [Parameter.new("int", "n")])
mod.generate(FileCodeSink(out_file))
if __name__ == '__main__':
my_module_gen(sys.stdout)
我的设置.py用于构建扩展模块的文件
#!/usr/bin/env python
import os
from distutils.core import setup, Extension
from modulegen import my_module_gen as generate
try:
os.mkdir("build")
except OSError:
pass
os.environ["CC"] = "g++"
module_fname = os.path.join("build", "autogen-binding.c")
with open(module_fname, "wt") as file_:
print("Generating file {}".format(module_fname))
generate(file_)
mymodule = Extension('c',
sources = [module_fname, 'c.cc'],
include_dirs=['.'])
setup(name='PyBindGen-example',
version="0.0",
description='PyBindGen example',
author='xxx',
author_email='yyy@zz',
ext_modules=[mymodule],
)
使用扩展模块的python脚本
import c
def my_callback(value):
print("In Callback: " + str(value))
c.register_cb(my_callback)
c.set_num(10);
c.set_num(20);
我想出来了。事后看来,这是显而易见的。我只需将所需的行放入对
wrapper.before_call.write_code()
的调用中,调用的位置是我期望实际的C行出现的位置。你知道吗相关问题 更多 >
编程相关推荐