You are here:  Home » Python » 4.构建C和C ++扩展 – 扩展和嵌入Python解释器(Python教程)(参考资料)

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

评论被关闭。