Test C API using Inline in Perl
时间:2009-04-12 来源:crook
项目中需要测试一组C API,除了开发人员那边的单元测试,我们可能还需要对这组API进行一些功能
测试. 对于我这样好久没写C程序的懒人来说,写C程序来测试API实在是在很痛苦的事情. 感觉写
C程序必须小心翼翼,不然一步小心就内存泄露. 如果可以用perl/python等脚本语言来直接
调用C函数, 问题就解决了.
2. Solution
在Perl中,有三种方式可以实现这样的想法:
1. XS
XS是perl的接口编程语言,可以方便的写出perl的扩展.
2. Inline
此perl模块可以让用户在perl程序中直接内嵌其他语言的代码,这些其他语言的代码会自动编译,然后在
运行的时候自动加载.本质上Inline也是基于XS的.
3. SWIG
SWIG是个帮助使用C或者C++编写的软件能与其它各种高级编程语言进行嵌入联接的开发工具。SWIG能应
用于各种不同类型的语言包括常用脚本编译语言例如Perl, PHP, Python, Tcl, Ruby and PHP.
http://swig.minidx.com/
上述3者的关系可以用下图表示:
_________________________
| C/C++ Code |
|________________________|
| Inline | |
|________|_______________|
| XS | SWIG |
|___________|____________|
| Perl Core |
|________________________|
3. Inline Example
首先尝试下第二种Inline::C, 相比XS来说,inline的学习曲线可能小些. 但是你还是得研究下列文档:
1)perlapi 2)perlguts 2)perldoc Inline. 内联的一个非常实用的地方是可以依据 C语言的库
编写出快速包装代码并将在 Perl上使用它,这样(就我而言)就可以将 Perl变成一个很好的测试平台.
内联得到您的 C 语言代码,然后在它基础上构建一个 XS 文件,就像一个人工的扩展模块编写器所执行
的一样,接着创建那个模块,然后装载它。接下来的代码调用就会很容易找到以前构建过的那个模块,然
后直接装载它.
总的来说,大体步骤分为步:
a. 在Inline中设置C API的库路径和头文件路径. 这个跟gcc的用法的一致. 例如:
use Inline C => Config => MYEXTLIB => "/home/ray/study/perl/inline/share/lib/libmy_ctags.so",
INC => "-I/home/ray/study/perl/inline/share/include";
# LIBS => "-L/home/ray/study/perl/inline/share/include -lmy_ctags";
b. 选择perl程序中C代码的导入方式. 这样有很多方式,最省事的就是用string,
use Inline C => <<'END_CODE';
// Your C source code here
END_CODE
还可以把perl内嵌c程序单独做成一个文件,然后把这个文件内容保存在一个变量中,然后再导入到inline中.
$source_code_string = read(file);
use Inline C => $source_code_string;
c. 编写C API的warpper函数,方便让perl调用.特别需要注意的地方就是合理的映射C和perl的数据结构.
如果某C函数A中需要返回指针, 那么A的wrapper函数就必须返回一个引用,这样perl中才可以直接调用.
如果A中指针的内容是数组,那么wrapper函数中对应就必须有一个数组HV.
如果A中指针的内容是定义的struct,wrapper中就可以映射成一个哈希表AV.
下面写个例子实际操作下,参考的C API就是我的一篇文章.
http://blog.chinaunix.net/u2/68938/showart_718163.html
工作路径如下
|-- MyCtags.pm
|-- ctags.pl
|-- include
| `-- my_ctags.h
|-- lib
| `-- libmy_ctags.so
`-- src
|-- my_ctags.c
`-- my_ctags.h
这里面src目录是souce code, 生成共享库, 然后放到lib目录下.
gcc -o libmy_ctags.so -shared my_ctags.c
此共享库中,有3个开放的API, 可以创建一个tag list,然后打印出来.
taglist* setup_taglist(char *filename, const char* pattern);
void output_taglist(taglist *list);
int cleanup_taglist(taglist **list);
ctags.pl就是一个测试脚本,简单的测试了Myctags.pm
MyCtags.pm就是此共享库的perl语言绑定, 让用户可以创建一个tag class, 然后打印出来.
列举几个简单的用法, 具体用法参见ctags.pl.
my $tags_ref = MyCtags->new($filename, $pattern);
$tags_ref->dump();
最后把所有代码打包出来,与大家共享.
|
[ray@localhost share]$ cat -n MyCtags.pm |