使用SCons作为distutils的构建引擎

pyg*_*iel 7 python distutils scons

我有一个python包,其中包含构建扩展所需的一些C代码(具有一些非常重要的构建需求).我使用SCons作为我的构建系统,因为它非常好而且灵活.

我正在寻找一种方法来编译我的python扩展与SCons准备与distutils一起分发.我希望用户只需键入setup.py install并获取使用SCons编译的扩展,而不是默认的distutils构建引擎.

想到的一个想法是在distutils中重新定义build_ext命令,但我找不到它的大量文档.

有什么建议吗?

Mat*_*kin 2

enscons似乎是为了完成问题所要求的而设计的。这里有一个使用它构建带有 C 扩展的包的示例。

您可以有一个基本的包结构,例如:

pkgroot/
    pyproject.toml
    setup.py
    SConstruct
    README.md
    pkgname/
        __init__.py
        pkgname.py
        cfile.c
Run Code Online (Sandbox Code Playgroud)

在这个文件中,该pyproject.toml文件可能类似于:

[build-system]
requires = ["enscons"]

[tool.enscons]
name = "pkgname"
description = "My nice packahe"
version = "0.0.1"
author = "Me"
author_email = "me@me.com"
keywords = ["spam"]
url = "https://github.com/me/pkgname"
src_root = ""
packages = ["pkgname"]
Run Code Online (Sandbox Code Playgroud)

其中该[tool.enscons]部分包含许多与 setuptools/distutilssetup函数相似的内容。从这里复制,该setup.py函数可能包含类似以下内容:

#!/usr/bin/env python

# Call enscons to emulate setup.py, installing if necessary.

import sys, subprocess, os.path

sys.path[0:0] = ['setup-requires']

try:
    import enscons.setup
except ImportError:
    requires = ["enscons"] 
    subprocess.check_call([sys.executable, "-m", "pip", "install", 
        "-t", "setup-requires"] + requires)
    del sys.path_importer_cache['setup-requires'] # needed if setup-requires was absent
    import enscons.setup

enscons.setup.setup()
Run Code Online (Sandbox Code Playgroud)

最后,该SConstruct文件可能类似于:

# Build pkgname

import sys, os
import pytoml as toml
import enscons, enscons.cpyext

metadata = dict(toml.load(open('pyproject.toml')))['tool']['enscons']

# most specific binary, non-manylinux1 tag should be at the top of this list
import wheel.pep425tags
full_tag = next(tag for tag in wheel.pep425tags.get_supported() if not 'manylinux' in tag)

env = Environment(tools=['default', 'packaging', enscons.generate, enscons.cpyext.generate],
                  PACKAGE_METADATA=metadata,
                  WHEEL_TAG=full_tag)

ext_filename = os.path.join('pkgname', 'libcfile')

extension = env.SharedLibrary(target=ext_filename,
                              source=['pkgname/cfile.c'])

py_source = Glob('pkgname/*.py')

platlib = env.Whl('platlib', py_source + extension, root='')
whl = env.WhlFile(source=platlib)

# Add automatic source files, plus any other needed files.
sdist_source=list(set(FindSourceFiles() + 
    ['PKG-INFO', 'setup.py'] + 
    Glob('pkgname/*', exclude=['pkgname/*.os'])))

sdist = env.SDist(source=sdist_source)
env.Alias('sdist', sdist)

install = env.Command("#DUMMY", whl, 
                      ' '.join([sys.executable, '-m', 'pip', 'install', '--no-deps', '$SOURCE']))
env.Alias('install', install)
env.AlwaysBuild(install)

env.Default(whl, sdist)
Run Code Online (Sandbox Code Playgroud)

之后你应该能够运行

sudo python setup.py install
Run Code Online (Sandbox Code Playgroud)

编译 C 扩展并构建一个轮子,然后安装 python 包,或者

python setup.py sdist
Run Code Online (Sandbox Code Playgroud)

构建源代码发行版。

我认为你基本上可以用文件中的 SCons 做任何你能做的事情SConstruct