3. 使用 distutils 构建 C 和 C++ 扩展 — Python 文档
3. 使用 distutils 构建 C 和 C++ 扩展
从 Python 1.4 开始,Python 在 Unix 上提供了一个特殊的 make 文件,用于构建用于构建动态链接扩展和自定义解释器的 make 文件。 从 Python 2.0 开始,不再支持此机制(称为与 Makefile.pre.in 和 Setup 文件相关)。 很少使用构建自定义解释器,并且可以使用 distutils 构建扩展模块。
使用 distutils 构建扩展模块需要在构建机器上安装 distutils,它包含在 Python 2.x 中,可单独用于 Python 1.5。 由于 distutils 也支持创建二进制包,用户不一定需要编译器和 distutils 来安装扩展。
distutils 包包含一个驱动程序脚本,setup.py
。 这是一个普通的 Python 文件,在最简单的情况下,它可能如下所示:
from distutils.core import setup, Extension
module1 = Extension('demo',
sources = ['demo.c'])
setup (name = 'PackageName',
version = '1.0',
description = 'This is a demo package',
ext_modules = [module1])
有了这个 setup.py
和一个文件 demo.c
,运行
python setup.py build
将编译 demo.c
,并在 build
目录中生成名为 demo
的扩展模块。 根据系统的不同,模块文件将在子目录 build/lib.system
中结束,并且可能具有类似 demo.so
或 demo.pyd
的名称。
在setup.py
中,所有的执行都是通过调用setup
函数来完成的。 这需要可变数量的关键字参数,上面的示例仅使用其中的一个子集。 具体来说,该示例指定了构建包的元信息,并指定了包的内容。 通常,一个包将包含附加模块,如 Python 源模块、文档、子包等。 请参考 Distributing Python Modules (Legacy version) 中的 distutils 文档,了解更多关于 distutils 的特性; 本节仅解释构建扩展模块。
通常预先计算 setup()
的参数,以更好地构建驱动程序脚本。 在上面的例子中,setup()
的 ext_modules
参数是一个扩展模块列表,每个模块都是 Extension
的一个实例。 在示例中,该实例定义了一个名为 demo
的扩展名,它是通过编译单个源文件 demo.c
来构建的。
在许多情况下,构建扩展更为复杂,因为可能需要额外的预处理器定义和库。 这在下面的示例中进行了演示。
from distutils.core import setup, Extension
module1 = Extension('demo',
define_macros = [('MAJOR_VERSION', '1'),
('MINOR_VERSION', '0')],
include_dirs = ['/usr/local/include'],
libraries = ['tcl83'],
library_dirs = ['/usr/local/lib'],
sources = ['demo.c'])
setup (name = 'PackageName',
version = '1.0',
description = 'This is a demo package',
author = 'Martin v. Loewis',
author_email = 'martin@v.loewis.de',
url = 'https://docs.python.org/extending/building',
long_description = '''
This is really just a demo package.
''',
ext_modules = [module1])
在这个例子中,setup()
被调用时带有额外的元信息,推荐在必须构建分发包时使用。 对于扩展本身,它指定了预处理器定义、包含目录、库目录和库。 根据编译器的不同,distutils 以不同的方式将此信息传递给编译器。 例如,在 Unix 上,这可能会导致编译命令
gcc -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -fPIC -DMAJOR_VERSION=1 -DMINOR_VERSION=0 -I/usr/local/include -I/usr/local/include/python2.2 -c demo.c -o build/temp.linux-i686-2.2/demo.o
gcc -shared build/temp.linux-i686-2.2/demo.o -L/usr/local/lib -ltcl83 -o build/lib.linux-i686-2.2/demo.so
这些线路仅用于演示目的; distutils 用户应该相信 distutils 会正确调用。
3.1. 分发扩展模块
成功构建扩展后,可以通过三种方式使用它。
最终用户通常希望安装该模块,他们通过运行
python setup.py install
模块维护者应该制作源码包; 为此,他们运行
python setup.py sdist
在某些情况下,源代码分发中需要包含其他文件; 这是通过 MANIFEST.in
文件完成的; 有关详细信息,请参阅 distutils 文档。
如果源分发已成功构建,维护人员还可以创建二进制分发。 根据平台,可以使用以下命令之一来执行此操作。
python setup.py bdist_wininst
python setup.py bdist_rpm
python setup.py bdist_dumb