解决pypi上传轮子unsupported platform tag 'linux_x86_64'问题

问题背景

在上传某轮子时出现了这样的一个报错:

$ 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平台的测试验证才能发布。

解决方案

经过一番检索,解决该问题的流程大致为:

  1. 选择一个合适的manylinux docker镜像,例如我这里代码中包含了CUDA,因此选择使用pytorch/manylinux-cuda111这个镜像;
  2. 基于docker镜像构建一个开发环境,然后用其中包含的几个不同版本的Python对代码进行构建,例如/opt/_internal/cpython-3.7.5/bin/python3 setup.py sdist bdist_wheel --universal,这样就会在dist目录下生成一个whl包;
  3. 使用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进行包装,仅仅设置packagesinclude_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

posted @ 2024-08-13 10:17  DECHIN  阅读(54)  评论(0编辑  收藏  举报