DEBUG.WIKI
野草云;香港 200Mbps 峰值;不限月流量 · BGP VPS;查看套餐 →
晚安云;香港 CN2 ¥15/月
PanstarCloud:部署应用,接入 AI,云服务器与 AI 网关

Windows PyPy 的 CFFI 扩展编译成功却无法导入,检查文件后缀

Windows PyPy 下 CFFI 扩展已编译却无法导入,setuptools 84.2 的稳定 ABI 后缀选择可能丢失 PyPy 标记。比较实际后缀,再约束真正的构建环境。

Windows 的 PyPy 环境里,CFFI 扩展已经编译出 .pyd,导入仍失败;同一构建在 setuptools 84.0.0 正常,换到 84.2.0 或 84.2.1 才出错,应先比较扩展文件名与解释器要求的后缀。

明确出现过的组合是 Windows x86-64、PyPy 8.0.0 / Python 3.11.16、CFFI 2.1.1 和 setuptools 84.2.1。扩展设置 py_limited_api=True 时,产物可能从 _example.pypy311-pp80-win_amd64.pyd 变成 _example.pyd。文件确实存在,也不表示当前 PyPy 会按扩展模块识别它。

先确认是命名不匹配,还是其他加载错误

在同一个构建解释器中,可以比较 sysconfig 的后缀与 setuptools 为扩展选择的名称。以下是只做文件名选择的示例,不调用 C 编译器:

import sysconfig
from setuptools import Distribution, Extension
from setuptools.command.build_ext import build_ext

extension = Extension("_example", ["example.c"], py_limited_api=True)
command = build_ext(Distribution({"ext_modules": [extension]}))
command.ensure_finalized()
print(sysconfig.get_config_var("EXT_SUFFIX"))
print(command.get_ext_filename("_example"))

example.c 在这里是扩展声明用的示例名称;这段不构建它。真实包还需检查实际 wheel 成员和安装后文件名。若名称正确,错误却是缺少 DLL 或入口符号,则应继续按那个加载错误处理,不能靠改后缀解决 ABI 或依赖不兼容。

84.2.1 的正式源码会把符合条件的 Windows .pyd 后缀转成稳定 ABI 用的 .pyd,这个分支没有先排除上述 PyPy 后缀。不能把 CPython 的稳定 ABI 命名规则直接视为 PyPy 的通用规则。

在构建环境里采用已确认的兼容组合

截至 2026 年 10 月 26 日,正式 setuptools 84.2.1 仍保留上述文件名路径。短期需要恢复构建时,可以在项目允许的范围内固定此前已确认的构建组合,例如这组案例中的 setuptools 84.0.0,并保留 CFFI、PyPy 和目标架构的约束。

约束必须进入实际 PEP 517 构建环境。只在运行虚拟环境安装一个旧 setuptools,隔离构建仍可能另外安装新后端。自己维护的项目可审查现有 build-system.requires;使用构建约束的流水线,则按前端支持的方式传递约束。不要为传递一个版本约束就全面关闭构建隔离。

不要仅把产物重命名后直接发布,也不要把 py_limited_api 全局关闭并继续沿用原 wheel 标记。名称、二进制 ABI 与 wheel 标签需要相互符合,手动改名只能掩盖其中一层。

重新构建后,在目标 Windows PyPy 的独立环境中安装实际 wheel,从源码目录之外导入并调用扩展的必要功能。检查文件后缀之外,也要核对 wheel 平台标签与依赖 DLL。保留原锁定文件和发行物;调整本地构建版本不会替换仓库中已经发布的错误 wheel。