python基础教程之用distutils来构建C/C++扩展
3. 用distutils来构建C/C++扩展¶
从Python 1.4开始,在Unix上,Python提供了一个特殊的makefile以产生一些makefile,使用这些产生的makefile可以构建动态链接的扩展和客制化的解释器。从Python 2.0开始,这个机制(即Makefile.pre.in和Setup文件)不再支持。构建客制化的解释器极少被应用,而扩展模块可以由distutils来构建。
使用distutils构建扩展模块需要构建机器上安装distutils。Python 2.x中都包含distutils,且从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中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 = 'http://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