如何用Poetry+Cython构建跨平台通用Python Wheel包?
问题描述
我正在使用Poetry v1.4.1和Cython 3.0.5,我的包中包含需要编译的.pyx文件。若使用pyximport而非预编译,导入耗时极长;但通过poetry build(代码如下)构建时,生成的并非版本与平台无关的通用Wheel包my_package-1.0.0-py3-none-any.whl,而是特定的my_package-1.0.0-cp39-cp39-manylinux_2_31_x86_64.whl。
请问是否有办法构建全平台通用的Wheel包?能否在Wheel包安装时进行cythonize/编译C文件?
相关代码
pyproject.toml(部分)
... [tool.poetry.build] generate-setup-file = false script = 'build.py' [build-system] requires = ["poetry-core", "Cython", "numpy"] build-backend = "poetry.core.masonry.api"
build.py
import os import shutil from distutils.core import Distribution import warnings if os.environ.get("NO_BUILD", False): exit(0) try: from Cython.Build import build_ext, cythonize import numpy ext_modules = cythonize("my_package/**/*.pyx", output_dir="build", include_path=["dmcommon"], build_dir="build", aliases={'NUMPY': numpy.get_include()}) dist = Distribution({"ext_modules": ext_modules}) cmd = build_ext(dist) cmd.ensure_finalized() cmd.run() # Move compiled near origin files. for output in cmd.get_outputs(): relative_extension = os.path.relpath(output, cmd.build_lib) relative_output_folder = os.path.dirname(relative_extension) os.makedirs(relative_output_folder, exist_ok=True) shutil.copyfile(output, relative_extension) except Exception as ex: warnings.warn(f"Failed to build Cython extensions: {ex}")
解决方案
1. 构建全平台通用Wheel包(安装时编译)
要实现安装时自动编译Cython代码,需要调整构建流程,不在poetry build阶段预编译,而是把.pyx文件打包进Wheel,让pip在用户安装时完成编译。具体步骤:
修改pyproject.toml
- 移除自定义
build.py的配置,让Poetry自动生成setup文件,或改用setuptools作为构建后端:
[tool.poetry] name = "my_package" version = "1.0.0" # 其他元信息... [tool.poetry.dependencies] python = "^3.7" numpy = "^1.21" # 其他依赖... [tool.poetry.build] generate-setup-file = true # 启用自动生成setup.py [build-system] requires = ["poetry-core>=1.0.0", "Cython>=3.0.5", "numpy>=1.21"] build-backend = "poetry.core.masonry.api"
手动编写setup.py(可选,精细控制编译逻辑)
如果Poetry自动生成的setup文件无法满足需求,可手动创建setup.py,用setuptools处理Cython扩展:
from setuptools import setup from Cython.Build import cythonize import numpy setup( name="my_package", version="1.0.0", ext_modules=cythonize("my_package/**/*.pyx", include_path=[numpy.get_include()]), include_dirs=[numpy.get_include()], )
同时修改pyproject.toml的构建后端:
[build-system] requires = ["setuptools", "wheel", "Cython", "numpy"] build-backend = "setuptools.build_meta"
这样构建出的通用Wheel会包含.pyx文件和编译配置,用户安装时pip会自动调用Cython编译代码,生成适配其平台的二进制文件。
2. 原流程生成平台特定Wheel的原因
你当前的build.py在poetry build阶段就完成了Cython代码的编译,生成了适配当前构建环境的二进制扩展,因此打包出的Wheel会带有平台标签,只能在对应平台使用。
注意事项
- 用户安装环境需具备C编译器(如GCC、MSVC),否则编译会失败。若要兼容无编译器的环境,可同时发布通用Wheel和多平台预编译Wheel。
- 可用
cibuildwheel工具自动化构建多平台预编译Wheel,同时保留通用Wheel选项。
内容的提问来源于stack exchange,提问作者EZLearner
相关产品推荐
相关产品推荐

