打包的Python C扩展so文件缺失PyInit_gazepy()导致导入失败
问题
我创建了C库libgac,并使用ctypes编写了Python绑定模块gazepy,项目结构如下:
pyproject.toml setup.py src gazepy gac # 包含C库libgac的仓库 gazepy.py # 为libgac编写的Python绑定 __init__.py # 空文件 tests
执行sudo pip install .后生成并安装了so文件gazepy.cpython-38-x86_64-linux-gnu.so,但在Python3 shell中导入该库时出现错误:
ImportError: dynamic module does not define module export function (PyInit_gazepy)
我的pyproject.toml文件内容:
[build-system] requires = ["setuptools>=61"] build-backend = "setuptools.build_meta" [project] name = "gazepy" # ...
我的setup.py文件内容:
from setuptools import setup, Extension, find_packages import subprocess module_name = "gazepy" module_path = "src/" + module_name gac_path = module_path + "/gac" cglm_path = gac_path + "/cglm" def main(): setup( name=module_name, packages=find_packages(), ext_modules=[ Extension(module_name, [gac_path + '/src/gac.c'], include_dirs=[gac_path + '/include', cglm_path + '/include'], libraries=['m']) ] ) if __name__ == "__main__": main()
查看so文件时,未找到PyInit_gazepy()的定义:
nm /usr/local/lib/python3.8/dist-packages/gazepy.cpython-38-x86_64-linux-gnu.so | grep PyInit
请问我遗漏了什么?
原因与解决方法
核心问题是混淆了两种Python扩展开发方式:
你用ctypes写了gazepy.py作为绑定,但同时又在setup.py里用Extension把普通C库直接编译成Python原生扩展模块。而Python原生扩展要求C代码必须实现PyInit_xxx入口函数,你的libgac是普通C库,没有这个入口,所以导入报错。
两种正确方案:
方案一:仅用ctypes绑定(推荐,适配你已写好的gazepy.py)
- 删除
setup.py里的ext_modules配置项,只保留packages=find_packages(),让setuptools只安装你的Python绑定代码(gazepy.py、init.py)。 - 提前将libgac编译成系统可识别的动态库(比如
libgac.so),确保系统能找到它;或者在gazepy.py里指定该库的绝对路径。 - 重新执行
sudo pip install .,此时不会生成原生扩展so,只会安装你的Python绑定模块,导入即可正常使用。
方案二:改用Python原生扩展(放弃ctypes)
- 修改libgac的C代码,按照Python C API规范添加
PyInit_gazepy入口函数,并封装你需要暴露给Python的函数。 - 保留
setup.py里的Extension配置,编译后生成的so就是合法的Python原生扩展,可直接导入使用。
内容的提问来源于stack exchange,提问作者moiri
相关产品推荐
相关产品推荐

