无法在Python 3.10安装cffi-1.15.1-cp36-cp36m-win_amd64 wheel的问题
问题背景
我正在为自定义构建的Python wheel包制作离线安装包,该包间接依赖cffi。操作流程是:
- 调用
python3 -m pip download my-custom-package -d package-content下载所有依赖 - 用7zip制作自解压安装器
- 通过Windows批处理脚本,利用pip的
--find-links功能完成离线安装
我的包在setup.py中约束为Python 3.6,因此使用Python 3.6解释器执行pip download命令,原本以为这样获取的wheel包能在Python 3.6及以上的3.x版本中安装。
实际测试发现:
- 针对Windows x86_64打包时,下载到的
cffi-1.15.1-cp36-cp36m-win_amd64.whl可以在Python 3.6至3.9上正常安装 - 但在Python 3.10上安装时,会提示:
ERROR: cffi-1.15.1-cp36-cp36m-win_amd64.whl is not a supported wheel on this platform.
- 手动将文件名改为
cffi-1.15.1-cp310-cp310m-win_amd64.whl后,即可正常安装并使用,说明包本身不存在Python 3.10不兼容的问题,问题出在pip对文件名中ABI标识的解析逻辑上。
当前环境:打包端pip版本为21.3.1,安装端为23.0.1。我原本计划针对Python 3.6至3.10的每个小版本多次执行pip download,但操作繁琐,因此有以下疑问:
- 这是pip的已知bug吗?
- 是否有文档说明此问题仅针对cffi包?
- 还是cp3x系列ABI的固有限制?
问题原因
这不是pip的bug,而是Python ABI标识规则变化 + pip版本校验逻辑共同导致的:
- ABI标识规则变更:Python 3.10开始,Windows平台的ABI标识从
cp3X-cp3Xm(比如cp36-cp36m)改为cp3X-cp3X(去掉末尾的m),这是PEP 425定义的wheel命名规则的更新。 - pip校验逻辑差异:
- 对于Python 3.6-3.9,pip会兼容匹配更早版本的ABI标识,因此
cp36的wheel可以在3.7-3.9上正常识别 - 但Python 3.10+的pip(比如你使用的23.0.1)会严格校验ABI标识是否与当前版本的格式匹配,旧格式的
cp3Xm标识会被判定为不兼容。
- 对于Python 3.6-3.9,pip会兼容匹配更早版本的ABI标识,因此
- cffi包本身兼容:你测试的cffi 1.15.1二进制wheel本身是兼容Python 3.10的,只是文件名不符合3.10的ABI命名规则,因此修改文件名后就能通过校验。
可行解决方案
1. 动态重命名wheel文件(推荐)
在Windows批处理安装脚本中,根据当前Python版本动态修改cffi的wheel文件名,再执行安装:
- 先获取当前Python的次版本号:
for /f "tokens=2" %%v in ('python -c "import sys; print(sys.version_info.minor)"') do set PY_MINOR=%%v - 如果是Python 3.10+,重命名cffi的wheel文件:
if %PY_MINOR% geq 10 ( ren package-content\cffi-1.15.1-cp36-cp36m-win_amd64.whl cffi-1.15.1-cp3%PY_MINOR%-cp3%PY_MINOR%-win_amd64.whl ) - 最后执行安装命令:
python -m pip install my-custom-package --find-links=package-content
2. 下载纯Python版本的cffi wheel
如果cffi对应版本提供纯Python wheel(文件名格式为cffi-1.15.1-py3-none-any.whl),可以在下载时指定参数获取该版本:
python3 -m pip download my-custom-package -d package-content --only-binary :all: --python-version 36 --platform win_amd64 --abi none
纯Python wheel不绑定特定ABI,能兼容所有Python 3.6+版本,无需担心版本匹配问题。
3. 手动补充兼容版本的cffi wheel
仅针对cffi单独处理:从PyPI手动下载支持Python 3.10的cffi wheel(比如cffi-1.15.1-cp310-cp310-win_amd64.whl),放到离线安装目录中,pip会自动匹配对应版本的wheel进行安装,无需重复下载整个依赖链。
补充说明
- 此问题并非cffi专属,任何使用旧ABI标识命名的二进制wheel,只要本身兼容Python 3.10+,都会遇到相同的文件名校验问题。
- 该问题的核心是PEP 425定义的wheel命名规则在Python 3.10的更新,属于ABI标识的版本适配限制,而非pip的bug。
内容的提问来源于stack exchange,提问作者Vinny

