创新互联Python教程:4.构建C/C++扩展

4. 构建C/C++扩展

一个Cpython的C扩展是一个共享库(例如一个Linux上的 .so ,或者Windows上的 .pyd ),其会导出一个 初始化函数

专注于为中小企业提供成都网站制作、成都做网站服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业宿州免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了近千家企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。

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

初始化函数的声明如下:

PyObject *PyInit_modulename(void)

It returns either a fully initialized module, or a PyModuleDef instance. See 初始化 C 模块 for details.

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

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

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

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

扩展模块可以用distutils来构建,这是Python自带的。distutils也支持创建二进制包,用户无需编译器而distutils就能安装扩展。

一个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 ,运行如下

 
 
 
 
  1. python setup.py build

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

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

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

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

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

例子中函数 setup() 在调用时额外传递了元信息,是推荐发布包构建时的内容。对于这个扩展,其指定了预处理器定义,include目录,库目录,库。依赖于编译器,distutils还会用其他方式传递信息给编译器。例如在Unix上,结果是如下编译命令

 
 
 
 
  1. 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
  2. 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. 发布你的扩展模块

当一个扩展已经成功地被构建时,有三种方式来使用它。

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

 
 
 
 
  1. python setup.py install

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

 
 
 
 
  1. python setup.py sdist

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

如果源码发行包被成功地构建,维护者还可以创建二进制发行包。 取决于具体平台,以下命令中的一个可以用来完成此任务

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

网页题目:创新互联Python教程:4.构建C/C++扩展
URL标题:http://www.shufengxianlan.com/qtweb/news27/284227.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联