使用带有嵌入式 PyPy 的 extern "Python" 风格的 cffi 回调

Use extern "Python" style cffi callbacks with embedded PyPy

是否可以使用新的 extern "Python" 样式 cffi 回调嵌入 PyPy? PyPy 的文档仅显示旧式 cffi 回调,但 cffi 文档建议不要使用它们。 PyPy 文档未提及新样式回调,我无法使新样式回调起作用。

Embedding PyPy

Extern “Python” (new-style callbacks)

# file "interface.py"

import cffi

# add new extern "Python" declaration
ffi = cffi.FFI() ffi.cdef('''
struct API {
    double (*add_numbers)(double x, double y);

    extern "Python" void add_numbers2(double, double);
}; ''')

# Better define callbacks at module scope, it's important to
# keep this object alive.
@ffi.callback("double (double, double)")
def add_numbers(x, y):
    return x + y

# new function
@ffi.def_extern()
def add_numbers2(x, y):
    return x + y


def fill_api(ptr):
    global api
    api = ffi.cast("struct API*", ptr)
    api.add_numbers = add_numbers

运行 编译 C 时出错(C 的源代码与 PyPy 文档相同):

debug: OperationError:
debug: operator-type: CDefError
debug: operator-value: cannot parse "extern "Python" void add_numbers2(double, double);"
:6:5: before: extern
Error calling pypy_execute_source_ptr!

"extern Python" 并不是真的要 现在 在嵌入情况下使用,就像您所指的那样。为了很好地支持这种情况,cffi 的开发人员(包括我 :-) 需要付出更多的努力。换句话说,未来的 cffi 版本应该提供一种替代方法来进行嵌入,比 CPython 和 PyPy 的自定义解决方案(分别为 "using the CPython C API" 和 "following https://pypy.readthedocs.org/en/latest/embedding.html")更简单。它还应该提供一个单一的通用解决方案。然而,现在还没有完成。

您可以在 PyPy 文档的示例之上应用现有的 (cffi 1.4) "extern Python" 解决方案,但它需要一些重构---值得注意的是,该示例使用 "in-line ABI mode",而 "extern Python" 仅适用于 "out-of-line API mode"。如果我们将 https://pypy.readthedocs.org/en/latest/embedding.html 视为描述纯 ABI 模式方法,那么使用 ffi.callback() 仍然是在 CFFI 中记录的唯一方法。

更新: CFFI 1.5 完全支持 "extern Python" 样式中的嵌入 (http://cffi.readthedocs.org/en/latest/embedding.html)。它现在在 CPython 上可用。 PyPy 需要主干版本(或 PyPy 4.1,应该在 2016 年 3 月或 4 月推出)。