pybind11方法调用共享库函数的原理及CPython对.so文件的处理
核心问题一:CPython是否会将模块路径下的.so文件视为Python模块?
是的,CPython完全支持将符合规则的.so文件(Windows下对应.pyd,本质也是动态链接库)作为Python模块导入——这类文件就是C/C++编写的Python扩展模块,pybind11生成的产物正属于这类。只要.so文件放在Python的模块搜索路径(比如sys.path包含的目录)下,且命名符合Python模块规则(无特殊字符),就可以直接用import语句导入。
核心问题二:Python运行时如何加载pybind11生成的.so并绑定方法调用?
整个流程可以拆解为以下关键步骤:
步骤1:加载共享对象到进程空间
当执行import <模块名>时,CPython内部会调用系统的动态链接库加载函数:Linux/macOS下是dlopen(),Windows下是LoadLibrary(),把目标.so文件加载到当前Python进程的地址空间中。步骤2:定位并执行模块初始化函数
每个Python C扩展模块都必须导出一个固定命名的初始化函数:Python 3版本要求函数名为PyInit_<模块名>(比如模块叫calc,函数就是PyInit_calc)。pybind11在编译时会自动生成这个函数,无需手动编写。
CPython会找到这个初始化函数并调用它,这是整个绑定过程的核心入口。步骤3:注册C++对象到Python解释器
在PyInit_<模块名>函数内部,pybind11会调用自身API(比如py::module_相关方法),把C++代码中定义的函数、类、变量等,一一映射为Python能识别的对象结构(如Python函数、类对象),并将这些映射关系注册到CPython的模块结构体(PyModuleDef)中。最后函数返回该结构体,CPython用它在Python环境中创建对应的模块对象。步骤4:方法调用的路由与执行
当Python代码调用模块里的方法(比如calc.add(1,2))时,CPython会通过之前注册的映射关系找到对应的C函数指针。接着解释器切换到C/C执行上下文,自动完成参数转换(把Python的int对象转成C的int类型),执行对应的C函数,再把返回值转换回Python对象,最终返回给Python代码。
整个参数和返回值的转换逻辑,由pybind11自动实现,只需在C++代码中用pybind11语法声明绑定关系即可。
内容的提问来源于stack exchange,提问作者Jeenu

