首页 > 代码库 > PHP扩展调用C++静态库
PHP扩展调用C++静态库
概述
php通过扩展方式,调用c++源码,这样做的理由有很多,当你搜到这篇文章时,相信你已经有自己的考虑了。
写这篇博客的理由有二:
- 整理下php扩展调用c++代码的过程。嗯,对,网上有很多类似的文章,不过对于php扩展c++的方式,很多文章在关键的地方并没有说明,或者说,大部分都是扩展调用c代码的。
- 已经两年有余没写博客了,在这2017刚开始的时候,开个博客,开始新的旅程,也是不错的,哈哈。
大概目录
- c++编译静态库
- php 扩展编辑
- 结语
注:下面步骤的操作环境——系统macOS10.12.2,PHP版本 5.6.29.
c++编译静态库
头文件:hello.h
#include<string> std::string hello_joint(std::string a, std::string b);
实现头文件定义的函数:hello.cpp
#include "hello.h" std::string hello_joint(std::string a, std::string b) { std::string str = a+b; return str; }
生成hello.o文件
g++ -c hello.cpp
生成静态库libhello.a文件
ar -r libhello.a hello.o
写个简单的test.cpp测试下:
1 #include<iostream> 2 #include "hello.h" 3 int main() 4 { 5 std::string a = std::string("Hello "); 6 std::string b = std::string("World!"); 7 std::cout<<hello_joint(a, b)<<std::endl; 8 return 0; 9 }
编译
g++ test.cpp libhello.a
运行
./a.out
终端输出
Hello World!
这样,你的c++静态库制作完成。
php 扩展编辑
如果要编辑php扩展,需要下载php源码,这里下载的是php-5.6.16。写文章的时候,才发现php源码版本和系统的php版本不一致。因为是先下载的php源码,然后通过brew install php56,不过,影响不大,不用纠结。
运行如下命令,产生扩展文件夹january。
./ext_skel --extname=january
命名为january,主要是不想跟c++源码hello产生任何关系,以免后面混淆,当然,也是因为想不出其他比较好的名字。
首先编辑config.m4,需要改的地方大概归结为三处:
1、找到如下三行,并把前面的注释dnl去掉。
PHP_ARG_ENABLE(january, whether to enable january support,
Make sure that the comment is aligned:
[ --enable-january Enable january support])
2、找到如下的代码,并在它的下面加上相应代码,以支持c++调用。
if test "$PHP_JANUARY" != "no"; then dnl Write more examples of tests here...
要加上的相应代码,注意其中的参数名。
if test "$PHP_JANUARY" != "no"; then dnl Write more examples of tests here... PHP_ADD_INCLUDE(./include) PHP_ADD_LIBRARY(stdc++, 1, JANUARY_SHARED_LIBADD) PHP_ADD_LIBRARY_WITH_PATH(hello, ./lib, JANUARY_SHARED_LIBADD) PHP_REQUIRE_CXX() PHP_SUBST(JANUARY_SHARED_LIBADD)
3、同时,在该函数的最后一行,把january.c改为january.cpp
PHP_NEW_EXTENSION(january, january.cpp, $ext_shared)
january.cpp需要做的工作比较多:
1、重命名:把january.c改为为january.cpp;
2、在两处地方加上EXTERN "C"标识,这点不要忘了:
第一处加extern "C"{},并在下面加上需要的c++头文件:
extern "C" { #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" #include "php_january.h" } #include<string> #include "hello.h"
第二处加BEGIN_EXTERN_C()和END_EXTERN_C():
#ifdef COMPILE_DL_JANUARY BEGIN_EXTERN_C() ==>添加的 ZEND_GET_MODULE(january) END_EXTERN_C() ==>添加的 #endif
3、在如下的地方,加入函数名称,可以理解为php要调用的函数的声明:
const zend_function_entry january_functions[] = { PHP_FE(confirm_january_compiled, NULL) /* For testing, remove later. */ PHP_FE(january_say, NULL) PHP_FE_END /* Must be the last line in january_functions[] */ };
4、注意到january.cpp中,它编写了一个函数例子confirm_january_compiled,现在,我们也需要完成january_say的函数实现,它接收来自php的参数,并在函数中调用c++函数。
PHP_FUNCTION(january_say) { char *arg1 = NULL, *arg2 = NULL; int arg1_len, arg2_len; int argc = ZEND_NUM_ARGS(); if(zend_parse_parameters(argc TSRMLS_CC, "ss", &arg1, &arg1_len, &arg2, &arg2_len) == FAILURE) return; std::string a = std::string(arg1); std::string b = std::string(arg2); std::string res = hello_joint(a, b); RETURN_STRING(res.c_str(), res.length()); }
完成这些步骤之后,剩下的工作就少多了。
要接下去做其他步骤的话,建议先做两个拷贝动作:
1,新建lib文件夹,将之前制作的libhello.a拷贝到lib里;
2,新建include文件夹(也可以等到./configure的时候,它会帮你创建这个文件夹),将hello.h头文件拷贝到这里。
利用php工具,按顺序运行如下四个命令:
phpize ./configure make make install
注:如果中间修改了程序代码什么的,记得要从第一个phpize重新执行来过。
运行正常的话,january.so会安装到.../lib/php/extensions/no-debug-non-zts-20131226/目录下。
最后,需要加载january.so,主要是改配置php.ini。如果不知道这个文件在哪的话,你可以在php程序中输出(echo phpinfo())。
echo phpinfo()的输出,可以看到指明了php.ini的所在目录。 Virtual Directory Support => disabled Configuration File (php.ini) Path => /usr/local/etc/php/5.6 Loaded Configuration File => /usr/local/etc/php/5.6/php.ini
首先,找到enable_dl,改为On;
enable_dl = On --在php.ini 中开启php动态加载dl
再找到有很多extension=xxxxxx.so的地方,添加下面句子,加载动态库,当然也可以在程序中手动加载。
extension=january.so
在php程序中测试:
echo january_say("hello ", "world!");
输出:
hello world!
结语
快过年了,都不能静心的好好写博客了(真的是水平不够,经验有限的极好借口\(^o^)/~),如果有错误的地方,欢迎指正。
同时,刚开始做的时候,可能会碰到这样那样的问题,希望你最终能顺利完成!当然,如果这篇博客能对你有一点点帮助的话,就更好了.
PHP扩展调用C++静态库