如何在Python Wheel中纳入预构建的.so共享库?
搞定Python 2.7平台特定Wheel包的打包方案
针对你这种已经手动编译好.so库、没法用常规setup.py编译的场景,完全可以直接把预编译的库打包进Wheel里,我给你一步步说怎么做:
第一步:搭建基础目录结构
首先得创建符合Python包规范的目录,哪怕没有Python源码,也得有个空的__init__.py让Python识别这是个合法包。假设你的包名叫my_custom_lib,结构应该是这样:
my_custom_lib_project/ ├── my_custom_lib/ │ ├── __init__.py # 空文件也行,或者用来加载.so │ └── my_compiled_lib.so # 你手动编译好的Ubuntu16.04专属.so └── setup.py
第二步:编写setup.py配置
重点是告诉setuptools要把你的.so文件包含进去,还要声明这是平台特定包,避免被当成纯Python包处理。下面是示例代码,你可以根据自己的情况修改:
from setuptools import setup, find_packages setup( name="my_custom_lib", version="0.1.0", # 自动找到我们的包目录 packages=find_packages(), # 指定要包含的包内资源:把my_custom_lib目录下的所有.so都打包进去 package_data={ "my_custom_lib": ["*.so"], }, # 明确标注支持的平台,方便用户识别 platforms=["Ubuntu 16.04 x86_64"], # 可选:如果需要更精确控制Wheel的平台标签,打包时可以加--plat-name参数 )
如果希望用户能直接从包导入.so里的函数,可以在__init__.py里用ctypes加载库(不用写编译逻辑,只是加载):
# my_custom_lib/__init__.py import ctypes import os # 获取.so文件的绝对路径 _lib_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "my_compiled_lib.so") # 加载库 _custom_lib = ctypes.CDLL(_lib_path) # 示例:导出库中的函数(根据你的实际函数签名调整) # 假设你的.so里有个add(a, b)函数,返回int _custom_lib.add.argtypes = [ctypes.c_int, ctypes.c_int] _custom_lib.add.restype = ctypes.c_int # 把函数暴露给外部 add = _custom_lib.add
第三步:构建Wheel包
首先确保你的Python2.7环境安装了setuptools和wheel:
pip2 install setuptools wheel
然后在项目根目录(setup.py所在的目录)执行打包命令:
python2 setup.py bdist_wheel
如果想明确指定平台标签(比如针对Ubuntu16.04的x86_64,用manylinux1标签兼容性更好,因为Ubuntu16.04的glibc版本符合manylinux1要求),可以加--plat-name参数:
python2 setup.py bdist_wheel --plat-name manylinux1_x86_64
打包完成后,会在dist/目录下生成类似my_custom_lib-0.1.0-manylinux1_x86_64.whl的文件。你可以用unzip -l dist/your_wheel_file.whl验证一下,看看里面是否包含了你的.so文件。
注意事项
- 这个Wheel是平台专属的,只能在Ubuntu16.04(或拥有兼容glibc版本的Linux系统)上安装使用,没法跨平台。
- 如果你需要上传到PyPI,要注意平台特定包的上传规则,不过如果只是内部分发,直接把Wheel文件发给别人就行,对方用
pip2 install your_wheel_file.whl就能安装。
内容的提问来源于stack exchange,提问作者Josh Reed




