2016年三月月 发布的文章

php的tcc扩展

最近学习编译器的实现,看到tcc。觉得不错,因为可以编译之后获得函数指针调用。想着能不能实现成一个PHP扩展。动态编译代码并提供给php代码调用,这样对于web可能意义并不大,但是常驻的程序却很有意义。尤其一些简单而重复或者多变的东西,做成扩展虽然可以提升,但相对来说过于麻烦并且不灵活。而这种形式就方便很多了。

花了2天时间,同时熟悉了下好久没写过的php扩展API。写了个简单原型出来了,只支持long float和char*,并且有些内存释放的地方还没处理。只是想做个原型看看效果。

调试了几小时,跑通了之后测试了下。

第一个是php 5.6.5,第二个是使用tcc扩展,加载so和编译时间算在里面了。第三个是想到刚编译了php 7的git最新版,就正好拿来对比下,用的就是php的测试代码。

 php 37014178 cost:1.3031008243561
c   37014178 cost:0.030487060546875
php 37014178 cost:0.67009902000427

调用c版本快了很多,但php7的也非常快。之前测试的并没有那么明显的优势。现在明显快了一倍。

tcc嵌入

最近看编译器实现的时候,在github上查tcc,找到一个luajit tcc的项目,是用luajit的ffi来封装的libtcc的库。发现libtcc有些东西非常不错,比如可以编译一段c代码然后生成可执行文件或者调用。于是看了下tcc,api很简单和清晰。于是用c试了下。

#include "libtcc/libtcc.h"
#include <stdio.h>
#include <stdlib.h>
typedef int (*func)(int a,int b);
char *source = "int add(int a,int b){return a+b;}";
int main(int argc,char **argv){
TCCState *tcc = tcc_new();
func f = NULL;
int a = 0;
tcc_add_library_path(tcc, "./lib");
tcc_add_library(tcc, "tcc1");
tcc_set_output_type(tcc, TCC_OUTPUT_MEMORY);
if(tcc_compile_string(tcc,source) == -1){
printf("compile string error.\n");
}
if(tcc_relocate(tcc,TCC_RELOCATE_AUTO) == -1){
printf("relocate error.\n");
}
f = (func)tcc_get_symbol(tcc, "add");
a = f(1,2);
printf("1+2=%d.\n",a);
tcc_delete(tcc);
return 0;
}

开始编译过了一直报错,发现是缺tcc_relocate,在getsymbol之前必须调用这个去分配内存。但是加上去之后还是报错,发现少了tcc_set_output_type,但这个注释里写默认就是TCC_OUTPUT_MEMORY选项啊。。。开始没加tcc_add_library_path会提示缺少libtcc1.a。