如何嵌入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可执行程序,必须要:

  1. 导入必须的几个API: Py_Initialize()Py_Finalize()PySys_SetArgv() ,还有就是你需要调用的其他函数

  2. 必须明确的声明pyrex生成的模块初始化函数的C原型,如本例的’inittestpyx’。

  3. 创建一个C可以调用的’main()’函数,需要注意:

    1. 初始化Python解释器
    2. 调用pyrex生成的模块初始化函数
    3. 随程序需要随便写Python语句
    4. 停止Python解释器
  4. 创建一个Makefile需要:

    1. 明确的编译.pyx到.c文件,使用单独的命令 pyrexc
    2. 编译生成的.c文件到.o或.obj文件,确保提供正确的include路径
    3. 链接结果到最终的可执行文件,并确保它可以找到Python运行时库

Leave a Reply