繁体   English   中英

如何在构建时强制 python 轮子特定于平台?

[英]How to force a python wheel to be platform specific when building it?

我正在开发一个 python2 包,其中setup.py<\/code>包含一些自定义安装命令。 这些命令实际上构建了一些 Rust 代码并输出了一些移动到 python 包中的.dylib<\/code>文件。

重要的一点是,Rust 代码在 python 包之外。

setuptools<\/code>应该自动检测 python 包是纯 python 还是特定于平台的(例如,如果它包含一些 C 扩展)。 就我而言,当我运行python setup.py bdist_wheel<\/code> ,生成的轮子被标记为纯 python 轮子: <package_name>-<version>-py2-none-any.whl<\/code> 。 这是有问题的,因为我需要在不同的平台上运行这段代码,因此我需要为每个平台生成一个轮子。

有没有办法在构建轮子时强制构建特定于平台?

下面是我平时从uwsgi看的代码

基本方法是:

设置文件

# ...

try:
    from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
    class bdist_wheel(_bdist_wheel):
        def finalize_options(self):
            _bdist_wheel.finalize_options(self)
            self.root_is_pure = False
except ImportError:
    bdist_wheel = None

setup(
    # ...
    cmdclass={'bdist_wheel': bdist_wheel},
)

root_is_pure位告诉轮子机器构建一个非 purelib ( pyX-none-any ) 轮子。 您还可以得到票友说有二进制平台相关的组件,但没有CPython的ABI特定组件。

模块setuptoolsdistutilswheel通过检查是否有ext_modules决定 python 发行版是否纯。

如果您自己构建外部模块,您仍然可以将其列在ext_modules以便构建工具知道它存在。 诀窍是提供一个空的源列表,这样setuptoolsdistutils就不会尝试构建它。 例如,

setup(
    ...,
    ext_modules=[
        setuptools.Extension(
            name='your.external.module',
            sources=[]
        )
    ]
)

这个解决方案比修补bdist_wheel命令更适合我。 原因是bdist_wheel在内部调用install命令,该命令再次检查ext_modules的存在,以决定是安装purelib还是platlib 如果您没有列出外部模块,您最终purelib lib 安装在purelib内的purelib子文件夹中。 这会在使用auditwheel repair时出现问题,它会抱怨扩展安装在purelib文件夹中。

您还可以在构建轮子时通过指定--plat-name来指定/欺骗特定的平台--plat-name

python setup.py bdist_wheel --plat-name=manylinux1_x86_64

root_is_pure 技巧和空的 ext_modules 技巧都对我不起作用,但经过我自己的大量搜索,我终于在“pip setup.py bdist_wheel”中找到了一个有效的解决方案, 不再构建强制非纯轮子

基本上,您覆盖 Distribution 类中的 'has_ext_modules' 函数,并将 distclass 设置为指向覆盖类。 那时,setup.py 会相信你有一个二进制发行版,并将创建一个带有特定版本的 python、ABI 和当前架构的轮子。 正如https://stackoverflow.com/users/5316090/py-j所建议的:

from setuptools import setup
from setuptools.dist import Distribution

DISTNAME = "packagename"
DESCRIPTION = ""
MAINTAINER = ""
MAINTAINER_EMAIL = ""
URL = ""
LICENSE = ""
DOWNLOAD_URL = ""
VERSION = '1.2'
PYTHON_VERSION = (2, 7)


# Tested with wheel v0.29.0
class BinaryDistribution(Distribution):
    """Distribution which always forces a binary package with platform name"""
    def has_ext_modules(foo):
        return True


setup(name=DISTNAME,
      description=DESCRIPTION,
      maintainer=MAINTAINER,
      maintainer_email=MAINTAINER_EMAIL,
      url=URL,
      license=LICENSE,
      download_url=DOWNLOAD_URL,
      version=VERSION,
      packages=["packagename"],

      # Include pre-compiled extension
      package_data={"packagename": ["_precompiled_extension.pyd"]},
      distclass=BinaryDistribution)

我发现Anthony Sottile 的回答很棒,但对我没有用。

我的情况是我必须强制为 x86_64 创建轮子,但是任何 python3,所以使根不纯实际上导致我的轮子是 py36-cp36 :(

一个更好的方法,IMO,一般来说就是使用sys.argv

from setuptools import setup
import sys

sys.argv.extend(['--plat-name', 'x86_64'])
setup(name='example-wheel')

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM