如何嵌入pyrex
如何嵌入pyrex
译者: | gashero |
---|
简介
对于大多数Py程序员来说,pyrex已经是一个实现Python/C包装的成功解决方案,他消除了所有Python/C之间的杂七杂八的问题。
但是大部分的pyrex使用都是集中于构建扩展类型和模块,使得他们可以象一般的Python模块一样的使用。
这个小教程会引导你制作单独的可执行程序,其实是将pyrex嵌入了Python解释器来运行。
嵌入Python?怎么做到的?为什么这么做?
现代,操作系统、编程语言和开发工具都成为了一种信仰,Python也无法逃脱。
如果你尝试嵌入,那么会有一大堆Python程序员嘲笑你,他们更推崇扩展,而不是嵌入。
在大多数情况下,他们是对的。而且大多数时候,扩展Python也比嵌入Python到C程序更有意义。
但是仍然有一些情况嵌入是更方便的,例如:
- 一个程序需要711权限(u+rwx,go-rw+x)
- 一个程序需要在ps和top命令中按照名称显示,而不是python
- 懒得区别用户的Python版本
- 适合你的其他理由
这个教程会谈到哪些东西?
这个文档中会介绍使用pyrex构建单独的可执行程序的过程,或者说看起来像一个可执行程序,当然运行时会动态的链接libpython2.x.so文件。
处方
创建一个简单的.pyx文件
如下代码是完整的pyrex源码,可以直接编译成可执行文件:
""" 实验通过pyrex嵌入Python """ #从C头文件中获取我们需要的功能 cdef extern from "stdio.h": int printf(char* format,...) cdef extern from "Python.h": #嵌入函数 void Py_Initialize() void Py_Finalize() void PySys_SetArgv(int argc, char** argv) #声明其他的Python/C接口函数 void Py_INCREF(object o) void Py_DECREF(object o) object PyString_FromStringAndSize(char *, int) #注意:必须声明函数原型 'init<mymodulename>()' 而mymodulename就是这段 #代码的文件名,比如本例就叫做testpyx.pyx cdef public void inittestpyx() #这里可以定义一系列的Python扩展类型、类、方法等 cdef class Testclass: cdef public int someint cdef public char* somestring def __init__(self): self.someint=43 self.somestring="this is a string" def hello(self): print "Hello, this is an instance of %s"%self.__class__.__name__ #现在可以声明C的main()函数了 cdef public int main(int argc, char** argv): Py_Initialize() PySys_SetArgv(argc,argv) printf("initialising testpyx\n") inittestpyx() #初始化完成,可以做Python的功能了 printf("testmain: instantiating Testclass\n") testobj=Testclass() printf("testmain: created testobj\n") print "testobj.someint=%s"%testobj.someint print "testobj.somestring=%s"%testobj.somestring print "calling testobj.hello()" testobj.hello() #离开程序之前释放资源 print "cleaning up" Py_Finalize()
编写Makefile
如下的Makefile对我工作的很好,希望对你有用:
#创建单独的Pyrex程序 PYVERSION=2.3 PYPREFIX=/usr INCLUDES=-i$(PYPREFIX)/include/python$(PYVERSION)testpyx: testpyx.o gcc -o $@ $^ -lpython$(PYVERSION) testpyx.o: testpyx.c gcc -c $^ $(INCLUDES) testpyx.c: testpyx.pyx pyrexc testpyx.pyx
总结
想要做可以单独工作的pyrex可执行程序,必须要:
导入必须的几个API: Py_Initialize() 、 Py_Finalize() 、 PySys_SetArgv() ,还有就是你需要调用的其他函数
必须明确的声明pyrex生成的模块初始化函数的C原型,如本例的’inittestpyx’。
创建一个C可以调用的’main()’函数,需要注意:
- 初始化Python解释器
- 调用pyrex生成的模块初始化函数
- 随程序需要随便写Python语句
- 停止Python解释器
创建一个Makefile需要:
- 明确的编译.pyx到.c文件,使用单独的命令 pyrexc
- 编译生成的.c文件到.o或.obj文件,确保提供正确的include路径
- 链接结果到最终的可执行文件,并确保它可以找到Python运行时库