使用ctypes分发含Go编译.so文件的Python库遇导入错误
解决导入Go编译共享库时的
ImportError: dynamic module does not define module export function问题 你遇到的问题核心是把普通C共享库当成了Python原生扩展模块来配置setuptools,导致Python导入时找不到它期望的PyInit_display_status函数。咱们一步步拆解解决:
问题根源
你用Go编译的display_status.so是标准的C共享库,不是符合Python扩展规范的模块——Python扩展必须导出PyInit_<module_name>函数,而你的Go库没有这个入口。之前setup.py里的Extension配置,让setuptools误以为要构建Python原生扩展,完全偏离了用ctypes加载普通共享库的需求。
另外,本地运行正常是因为脚本能直接找到当前目录下的.so,但安装到PyPI后,库文件会被放到site-packages的子目录里,原有的相对路径加载方式会失效,这也是要修正的点。
修正后的setup.py配置
先移除错误的Extension部分,正确配置package_data来包含预编译的共享库:
import pathlib from setuptools import setup, find_packages HERE = pathlib.Path(__file__).parent README = (HERE / "README.md").read_text() setup( name="display_status", version="1.0.11", description="Displays the status of links", long_description=README, long_description_content_type="text/markdown", url="https://github.com/KingAkeem/display_status", author="Akeem King", author_email="akeemtlking@gmail.com", license="GNU GPLv3", classifiers=[ "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", ], packages=find_packages(), # 明确指定要打包的共享库文件 package_data={ 'display_status': [ 'display_status.so', # 如果.h文件不需要安装可以移除 'display_status.h' ] }, include_package_data=True, python_requires=">=3.6" )
修改Python库中的.so加载逻辑
安装后.so的路径不再是本地相对路径,需要用Python的资源加载工具获取正确位置,提供两种兼容方案:
方案1:Python 3.7+ 使用importlib.resources
import ctypes from importlib.resources import files def load_go_library(): # 获取安装后共享库的绝对路径 lib_path = files('display_status').joinpath('display_status.so') # 加载共享库 lib = ctypes.CDLL(str(lib_path)) # 根据你的Go函数实际情况,配置参数和返回类型 # 示例:假设Go函数CheckLink接收字符串,返回状态码 lib.CheckLink.argtypes = [ctypes.c_char_p] lib.CheckLink.restype = ctypes.c_int return lib # 初始化全局库实例 go_lib = load_go_library() # 封装成Python函数供用户调用 def check_link_status(url): return go_lib.CheckLink(url.encode('utf-8'))
方案2:兼容Python 3.6 使用pkg_resources
import ctypes import pkg_resources def load_go_library(): # 获取安装后共享库的绝对路径 lib_path = pkg_resources.resource_filename('display_status', 'display_status.so') lib = ctypes.CDLL(lib_path) # 配置Go函数的参数和返回类型 lib.CheckLink.argtypes = [ctypes.c_char_p] lib.CheckLink.restype = ctypes.c_int return lib go_lib = load_go_library()
额外注意事项
- 跨平台支持:预编译的
.so仅适用于对应平台(比如Linux x86_64),如果要支持Windows(.dll)、macOS(.dylib),需要交叉编译Go代码生成对应平台的共享库,再在setup.py中根据平台选择对应文件。 - Go编译验证:确保你用正确命令生成C共享库:
go build -buildmode=c-shared -o display_status.so main.go
内容的提问来源于stack exchange,提问作者Akeem
相关产品推荐
相关产品推荐

