问题背景
在上传某轮子时出现了这样的一个报错:
$ twine upload --repository-url https://upload.pypi.org/legacy/ dist/*
Uploading distributions to https://upload.pypi.org/legacy/
Enter your username: __token__
Uploading xxx-1.0-cp37-cp37m-linux_x86_64.whl
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 347.0/347.0 kB • 00:00 • 6.2 MB/s
WARNING Error during upload. Retry with the --verbose option for more details.
ERROR HTTPError: 400 Bad Request from https://upload.pypi.org/legacy/
Binary wheel 'xxx-1.0-cp37-cp37m-linux_x86_64.whl' has an unsupported
platform tag 'linux_x86_64'.
遂发现当前的pypi对于轮子中含有C/C++等代码的库要求不同于纯Python的代码,需要经过many_linux平台的测试验证才能发布。
解决方案
经过一番检索,解决该问题的流程大致为:
- 选择一个合适的manylinux docker镜像,例如我这里代码中包含了CUDA,因此选择使用
pytorch/manylinux-cuda111
这个镜像; - 基于docker镜像构建一个开发环境,然后用其中包含的几个不同版本的Python对代码进行构建,例如
/opt/_internal/cpython-3.7.5/bin/python3 setup.py sdist bdist_wheel --universal
,这样就会在dist目录下生成一个whl包; - 使用auditwheel对前面生成的whl包进行修复:
/opt/_internal/cpython-3.7.5/bin/python3 -m auditwheel repair dist/xxx-*-cp37-cp37m-linux_x86_64.whl --plat manylinux2014_x86_64 -w fix-dist/
,以固化动态链接库(如有),最终会在fix-dist/
路径下得到一个可以发布的轮子。
setup.py关于data_files的配置
有一些动态构建的动态链接库,直接使用MANIFEST.in或者package_data配置不生效。那么有一种解决的办法是,动态构建完成后,将生成的文件保存到build/
路径(Python包构建默认路径)下,然后使用data_files
的配置把相关文件包含进来:
data_files=[('xxx', ['build/xxx/libxxx.so',
'build/xxx/libxxx.1.so'])]
如果不使用data_files进行包装,仅仅设置packages
和include_package_data
,得到的最终轮子内容是这样的:
$ unzip -l dist/xxx-1.7-cp37-cp37m-linux_x86_64.whl
Archive: dist/xxx-1.7-cp37-cp37m-linux_x86_64.whl
Length Date Time Name
--------- ---------- ----- ----
1111024 2024-08-12 09:03 xxx.cpython-37m-x86_64-linux-gnu.so
1100448 2024-08-12 09:03 xxx.cpython-37m-x86_64-linux-gnu.so
1265 2024-08-12 01:23 xxx/__init__.py
3012 2024-08-12 06:05 xxx/__main__.py
1176880 2024-08-12 09:03 xxx/xxx.c
1181116 2024-08-12 09:03 xxx/xxx.c
0 2024-08-12 03:15 xxx/kernels/__init__.py
1063 2024-08-12 09:03 xxx-1.7.dist-info/LICENSE
2071 2024-08-12 09:03 xxx-1.7.dist-info/METADATA
104 2024-08-12 09:03 xxx-1.7.dist-info/WHEEL
26 2024-08-12 09:03 xxx-1.7.dist-info/top_level.txt
950 2024-08-12 09:04 xxx-1.7.dist-info/RECORD
--------- -------
4577959 12 files
如果加上这个data_files
的配置,whl包中会多出这么两个动态链接库:
844648 2024-08-13 02:06 xxx-1.7.data/data/xxx/xxx.1.so
844648 2024-08-13 02:06 xxx-1.7.data/data/xxx/xxx.so
需要注意的是,使用这个轮子pip安装以后,这两个文件存放的地址跟其他文件不一样(跟Python版本有关,这里我们考虑通用情景)。其他文件是存放在对应的site-packages路径下,如/usr/local/python-3.7.5/lib/python3.7/site-packages/xxx/
,而data_files
一般是存放在Python路径下,如/usr/local/python-3.7.5/xxx/
。知道这个信息之后,我们就可以从对应的路径下去索引动态链接库了。
总结概要
对于一个纯Python的项目,从构建到发布是比较容易的。但是如果构建的轮子中含有C代码或者生成的动态链接库,那么构建发布有另外一套规则。我们需要经过manylinux平台的验证,以及动态链接库的固化等过程,还需要当心动态链接库的存放地址等信息。本文主要是提供了一个流程化的思路,具体操作对于不同的项目和平台来说差异是比较大的。
版权声明
本文首发链接为:https://www.cnblogs.com/dechinphy/p/pypi-manylinux.html
作者ID:DechinPhy
更多原著文章:https://www.cnblogs.com/dechinphy/
请博主喝咖啡:https://www.cnblogs.com/dechinphy/gallery/image/379634.html