4.构建C和C ++扩展

CPython的AC扩展是一个共享库(例如Linux上的.so文件,Windows上的.pyd),它导出initialization function.

要导入,共享库必须在PYTHONPATH上可用,并且必须以模块名称命名,并带有适当的扩展名。使用distutils时,会自动生成正确的文件名.

初始化函数有签名:

PyObject * PyInit_modulename void

它返回一个完全 -初始化模块,或PyModuleDef实例。参见初始化C模块了解详情.

对于只有ASCII名称的模块,该函数必须命名为PyInit_<modulename>,并带有<modulename>替换为了模块的名称。当使用多阶段初始化时,允许使用非ASCII模块名称。在这种情况下,初始化函数名称为PyInitU_<modulename>,其中<modulename>使用Python的punycode编码进行编码,连字符替换为下划线。在Python中:

def initfunc_name(name):      try:          suffix = b'_' + name.encode('ascii')      except UnicodeEncodeError:          suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')      return b'PyInit' + suffix

通过定义多个初始化函数,可以从单个共享库中导出多个模块。但是,导入它们需要使用符号链接或自定义导入器,因为默认情况下只找到与文件名对应的功能。请参阅“Multiple modules in one library”部分 PEP 489 了解详情.

4.1。使用distutils构建C和C ++扩展

可以使用distutils构建扩展模块,distutils包含在Python中。由于distutils还支持创建二进制包,用户不一定需要编译器和distutils来安装扩展。

distutils包中包含一个驱动脚本setup.py。这是一个plainPython文件,在最简单的情况下,它看起来像这样:

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,并在demo目录中生成一个名为build的扩展模块。根据系统的不同,模块文件将在一个子目录build/lib.system中结束,并且可能具有类似demo.sodemo.pyd.

setup.py中,所有执行都是通过调用setup功能。这需要可变数量的关键字参数,上面的示例仅使用子集。具体来说,该示例指定了构建包的信息,并指定了包的内容。通常,包将包含其他模块,如Pythonsource模块,文档,子包等。请参考分发Python模块(旧版)了解更多关于distutils的特点;本节仅介绍构建扩展模块.

通常预先计算setup(),以更好地构造驱动程序脚本。在上面的例子中,ext_modulessetup()参数是一个扩展模块列表,每个扩展模块都是Extension。在这个例子中,instance定义了一个名为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()使用additionalmeta-information调用,这是在建立分发包时建议的。对于extensionitself,它指定预处理器定义,包括目录,库目录和库。根据编译器的不同,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得到正确的调用.

 

4.2。分发您的扩展模块

成功构建扩展后,有三种方法可以使用它.

End-users通常会想要安装模块,他们通过运行

python setup.py install

模块维护者应该生成源包;这样做,他们跑

python setup.py sdist

在某些情况下,需要在源代码分发中包含其他文件;这是通过MANIFEST.in文件完成的;请参阅指定要分发的文件以获取详细信息.

如果源代码分发已成功构建,维护者可以同时创建二进制分发。根据平台的不同,可以使用以下命令之一.

python setup.py bdist_wininst  python setup.py bdist_rpm  python setup.py bdist_dumb