4. 构建C/C++扩展

    为了可导入,共享库必须在 PYTHONPATH 中有效,且必须命名遵循模块名字,通过适当的扩展。当使用distutils时,会自动生成正确的文件名。

    初始化函数的声明如下:

    * PyInit_modulename(void)

    该函数返回完整初始化过的模块,或一个 PyModuleDef 实例。查看 了解更多细节。

    对于仅有ASCII编码的模块名,函数必须是 PyInit_<modulename> ,将 <modulename> 替换为模块的名字。当使用 Multi-phase initialization 时,允许使用非ASCII编码的模块名。此时初始化函数的名字是 PyInitU_<modulename> ,而 <modulename> 需要用Python的 punycode 编码,连字号需替换为下划线。在Python里:

    可以在一个动态库里导出多个模块,通过定义多个初始化函数。而导入他们需要符号链接或自定义导入器,因为缺省时只有对应了文件名的函数才会被发现。查看 “一个库里的多模块” 章节,在 了解更多细节。

    一个distutils包包含了一个驱动脚本 setup.py 。这是个纯Python文件,大多数时候也很简单,看起来如下:

    1. from distutils.core import setup, Extension
    2. module1 = Extension('demo',
    3. sources = ['demo.c'])
    4. setup (name = 'PackageName',
    5. version = '1.0',
    6. description = 'This is a demo package',
    7. ext_modules = [module1])

    通过文件 setup.py ,和文件 demo.c ,运行如下

    这会编译 ,然后产生一个扩展模块叫做 demo 在目录 build 里。依赖于系统,模块文件会放在某个子目录形如 build/lib.system ,名字可能是 demo.sodemo.pyd

    在文件 setup.py 里,所有动作的入口通过 setup 函数。该函数可以接受可变数量个关键字参数,上面的例子只使用了一个子集。特别需要注意的例子指定了构建包的元信息,以及指定了包内容。通常一个包会包括多个模块,就像Python的源码模块、文档、子包等。请参数distutils的文档,在 分发 Python 模块(遗留版本) 来了解更多distutils的特性;本章节只解释构建扩展模块的部分。

    通常预计算参数给 setup() ,想要更好的结构化驱动脚本。有如如上例子函数 的 ext_modules 参数是一列扩展模块,每个是一个 Extension 类的实例。例子中的实例定义了扩展命名为 demo ,从单一源码文件构建 demo.c

    更多时候,构建一个扩展会复杂的多,需要额外的预处理器定义和库。如下例子展示了这些。

    1. module1 = Extension('demo',
    2. define_macros = [('MAJOR_VERSION', '1'),
    3. ('MINOR_VERSION', '0')],
    4. include_dirs = ['/usr/local/include'],
    5. library_dirs = ['/usr/local/lib'],
    6. sources = ['demo.c'])
    7. setup (name = 'PackageName',
    8. version = '1.0',
    9. author = 'Martin v. Loewis',
    10. author_email = 'martin@v.loewis.de',
    11. url = 'https://docs.python.org/extending/building',
    12. long_description = '''
    13. This is really just a demo package.
    14. ''',
    15. ext_modules = [module1])

    这些行代码仅用于展示目的;distutils用户应该相信distutils能正确调用。

    4.2. 发布你的扩展模块

    当一个扩展已经成功的构建过,有三种方式使用。

    最终用户通常想要安装模块,可以这么运行

    1. python setup.py install

    模块维护者应该制作源码包;要实现可以运行

    有些情况下,需要在源码发布包里包含额外的文件;这通过 MANIFEST.in 文件实现,查看 了解细节。

    如果源码发行包成功构建了,维护者也可以创建二进制发行包。依赖于平台,一个可用的命令如下

    1. python setup.py bdist_wininst
    2. python setup.py bdist_rpm
    3. python setup.py bdist_dumb