如何构建符合 PEP 517 的 C 扩展,即使用 pyproject.toml 而不是 setup.py?

问题描述

我想为 CPython 构建一个 C 扩展。传统上,我可以使用 setup.py 文件来完成。但是,出于 PEP 517 中提到的原因,我更喜欢使用 pyproject.toml 的声明性方法。我知道 setuptools 是唯一可以在所有相关平台上构建 C 扩展的构建后端。事实上,除了过时的 distutils 之外,我根本不知道有任何后端能够构建 C 扩展。

在此背景下,常见的 setup.py 如下所示:

from setuptools import setup,Extension
kwargs = dict(
    name='mypackage',# more metadata
    ext_modules=[
        Extension('mypackage.mymodule',['lib/mymodule.c','lib/mypackage.c','lib/myalloc.c'],include_dirs=['lib'],py_limited_api=True)])

setup(**kwargs)

现在,挑战是将上述内容放入一个 pyproject.toml 加上一个 setup.cfg

setuptools 文档建议使用这样的 pyproject.toml

[build-system]
requires = [
    "setuptools >=52.0",'wheel >= 0.36']
build-backend = "setuptools.build_meta"

此外,实际的元数据应该进入 setup.cfg。但是,我没有找到任何关于如何将 ext_modules kwarg,特别是 Extension() 调用转换为 setup.cfg 语法的解释。

解决方法

pyproject.toml 并不是严格意义上的替换 setup.py,而是确保它在仍然需要时正确执行(参见 PEP 517my answer here):

如果 build-backend 键存在,则优先,源树遵循指定后端的格式和约定(因此不需要 setup.py 除非后端需要它强>)。项目可能仍希望包含 setup.py 以与不使用此规范的工具兼容。

虽然 setuptools 尝试将所有内容从脚本移动到配置文件中,但 it's not always possible

有两种类型的元数据:静态和动态。

  • 静态元数据 (setup.cfg):保证每次都相同。这更简单、更易于阅读,并避免了许多常见错误,例如编码错误。
  • 动态元数据 (setup.py):可能不确定。任何动态的或在安装时确定的项目,以及扩展模块setuptools 的扩展,都需要进入 setup.py

应首选静态元数据,仅在绝对必要时才将动态元数据用作逃生舱。

事实上,setup.cfg-only projects 现在只有 2 年可能,而 setuptools will use an imaginary setup.py if it doesn't exist 无论如何。


话虽如此,如果您想尽可能地坚持静态方式,您可以将所有可以移动到 setup.cfg 文件中,并将其余部分留在 setup.py 中:

setup.cfg
[metadata]
name = mypackage
; more metadata
setup.py
from setuptools import setup,Extension

setup_args = dict(
    ext_modules = [
        Extension(
            'mypackage.mymodule',['lib/mymodule.c','lib/mypackage.c','lib/myalloc.c'],include_dirs = ['lib'],py_limited_api = True
        )
    ]
)
setup(**setup_args)

但我会把所有东西都放在 setup.py 中。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...