【问题标题】:How to force a python wheel to be platform specific when building it?如何在构建 python 轮时强制它是特定于平台的?
【发布时间】:2017-12-22 08:22:38
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: python setuptools setup.py python-wheel


    【解决方案1】:

    这是我平时从uwsgi看的代码

    基本做法是:

    setup.py

    # ...
    
    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 位告诉车轮机械制造一个非纯库 (pyX-none-any) 车轮。您也可以通过说存在 binary 平台特定组件但没有 cpython abi 特定组件来获得 fancier

    【讨论】:

    • 非常感谢,正是我想要的 :)
    • 调用 bdist_wheel.finalize_options(self) 最终会递归调用自身。您想改为从“_bdist_wheel”调用 fn。
    • @prac 确实!我在复制粘贴的代码中重命名时错过了这一点——我已经修复了它
    【解决方案2】:

    setuptoolsdistutilswheel 模块通过检查 Python 发行版是否具有 ext_modules 来判断它是否是纯的。

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

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

    这个解决方案对我来说比修补bdist_wheel 命令效果更好。原因是bdist_wheel 在内部调用install 命令并且该命令再次检查ext_modules 的存在以决定purelibplatlib 安装。如果您没有列出外部模块,那么您最终会将 lib 安装在轮子内的 purelib 子文件夹中。这会在使用auditwheel repair 时导致问题,它抱怨扩展程序安装在purelib 文件夹中。

    【讨论】:

    • 这似乎是一个很好的解决方案,但在我需要它的 Windows 版本上导致 distutils/_msvccompiler.py 出现错误:(
    【解决方案3】:

    您还可以通过指定--plat-name 来指定/欺骗特定平台名称:

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

    【讨论】:

    • 所有可能的平台名称是什么?
    • 我很难为您找到准确的列表。从技术上讲,你可以给出你想要的任何参数,我认为是 PyPI 在你上传它时选择它接受的标签。也许packaging.python.org/specifications/platform-compatibility-tags 可以帮助您开始寻找实际列表?
    【解决方案4】:

    root_is_pure 技巧和空 ext_modules 技巧都不适合我,但经过大量搜索,我终于在 'pip setup.py bdist_wheel' no longer builds forced non-pure wheels 找到了一个可行的解决方案

    基本上,您覆盖 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)
    

    【讨论】:

      【解决方案5】:

      我觉得 Anthony Sottile's answer 很棒,但对我不起作用。

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-05-06
        • 2013-11-03
        • 2014-04-22
        • 1970-01-01
        • 2016-05-20
        相关资源
        最近更新 更多