Python是否支持定义可被共享库直接调用的C函数?
Python能否定义可被共享库直接调用的C函数?
可以实现,通过Python的C扩展机制,将Python函数包装为符合C调用约定的导出函数,让共享库直接调用该包装函数即可。
实现原理
Python函数本质是虚拟机字节码,无法直接被C的call指令调用。我们需要编写一个C风格的包装函数,内部通过Python C API调用目标Python函数,再将这个包装函数导出为共享库符号,让你的mod.so可以直接链接调用。
具体实现步骤
1. 编写C扩展包装代码
创建wrapper.c,将Python的bar()包装为符合C ABI的导出函数:
#include <Python.h> // 全局保存Python的bar函数对象,避免重复查找 static PyObject* py_bar_func = NULL; // 供mod.so直接调用的C风格函数 int bar() { // 首次调用时获取Python中的bar函数 if (!py_bar_func) { PyObject* main_module = PyImport_ImportModule("main"); py_bar_func = PyObject_GetAttrString(main_module, "bar"); Py_XDECREF(main_module); // 释放模块引用 } // 调用Python函数并转换返回值 PyObject* result = PyObject_CallObject(py_bar_func, NULL); int ret_val = PyLong_AsInt(result); Py_XDECREF(result); // 释放结果引用 return ret_val; } // Python模块初始化(必须存在) static struct PyModuleDef wrapper_module = { PyModuleDef_HEAD_INIT, "wrapper", NULL, -1, NULL }; PyMODINIT_FUNC PyInit_wrapper(void) { return PyModule_Create(&wrapper_module); }
2. 编译C扩展为共享库
用gcc编译成wrapper.so(替换python3.x为你的Python版本):
gcc -shared -fPIC -I/usr/include/python3.x wrapper.c -o wrapper.so -lpython3.x
3. 修改Python代码加载扩展与共享库
确保wrapper.so的符号全局可见,让mod.so能解析到bar函数:
import ctypes import sys def bar(): return 1337 # 加载自定义C扩展,初始化Python函数引用 sys.path.insert(0, '.') import wrapper # 加载wrapper.so并设置符号全局可见,让mod.so能找到bar wrapper_dll = ctypes.CDLL("./wrapper.so", mode=ctypes.RTLD_GLOBAL) # 加载mod.so,此时它可以直接调用bar() dll = ctypes.PyDLL("./mod.so") assert dll.foo(ctypes.c_float(42)) == 42 + 1337
4. 简化mod.so的C代码
现在mod.so的代码可以直接写成你想要的形式:
// 声明外部的bar函数 int bar(); int foo(float f) { return f + bar(); }
关键注意事项
- 符号可见性:必须用
RTLD_GLOBAL加载wrapper.so,否则mod.so无法解析bar符号。 - 引用计数管理:在C扩展中要正确处理Python对象的引用计数,避免内存泄漏。
- 自动生成:结合你已有的
mod_api.json,可以编写脚本自动生成wrapper.c的包装函数代码,完全省去手动编写的步骤。
内容的提问来源于stack exchange,提问作者MyNameIsTrez
相关产品推荐
相关产品推荐

