与Python相识一周年,重拾Python。
之前的开发中,发现实现GObject的代码有许多重复的编码工作,于是借助Python,花了几天时间写了一份代码生成工具,最终生成的框架代码(含各种注释)将近7000行。最近需要对之前的工作实现一个自动化测试工具,如使用C,工作将极为繁琐;不如重用Python,希望在这个方向仍能大放异彩。
该中间件产品为C语言API,虽然内部以GObject为对象封装,但有部分API直接基于C语言实现,因此有必要对所有的C语言API再次封装,用于在Python中调用。
在Python中,使用C语言扩展的方法举例如下:
1. Python C语言扩展(hello.c):
#include <Python.h>
#include <string.h>
extern int print( char * s );
/* module functions */
static PyObject * /* returns object */
message(PyObject *self, PyObject *args) /* self unused in modules */
{ /* args from Python call */
char *fromPython, result[1024];
if (! PyArg_Parse(args, "(s)", &fromPython)) /* convert Python -> C */
return NULL; /* null=raise exception */
else {
print( fromPython );
strcpy(result, "Hello, "); /* build up C string */
strcat(result, fromPython); /* add passed Python string */
return Py_BuildValue("s", result); /* convert C -> Python */
}
}
/* registration table */
static PyMethodDef libhello_methods[] = {
{"message", message, METH_VARARGS, "func doc"}, /* name, &func, fmt, doc */
{NULL, NULL, 0, NULL} /* end of table marker */
};
/* module definition structure */
static struct PyModuleDef libhellomodule = {
PyModuleDef_HEAD_INIT,
"libhello", /* name of module */
"mod doc", /* module documentation, may be NULL */
-1, /* size of per-interpreter module state, −1=in global vars */
libhello_methods /* link to methods table */
};
/* module initializer */
PyMODINIT_FUNC
PyInit_libhello() /* called on first import */
{ /* name matters if loaded dynamically */
return PyModule_Create(&libhellomodule);
}
2. hello模块中调用的外部C代码(print.c):
#include <stdio.h>
int print( char * s )
{
printf( "[C] String [%s] from Python\n", s );
}
3. Python主程序(main.py):
#!/usr/bin/python
import libhello
libhello.message( 'world' )
libhello.message( 'extending' )
4. 编译运行:
$gcc print.c -shared -o libprint.so
$gcc hello.c -shared -o libhello.so `pkg-config python-3.4 --cflags --libs` -L. -lprint
$./main.py
5. 输出:
[C] String [world] from Python
[C] String [extending] from Python
接下来就是编写一系列的Python Glue Code,用于调用中间件的各个API进行测试了。