php调用第三方C语言库步骤与说明
网上的资料要么不全,要么有错误,要么没说清楚,操,走了不少弯路,浪费了一些时间。
1.用C语言写一个.so或者.a的库,一般最好不要用.CPP,否则因为.cpp会改函数名,可能在调用的时候找不到函数。导出了my_test函数
/*a.c*/
long my_test(long a, char *str)
{
printf(“%sn”, str);
return a;
}
/*a.h*/
long my_test(long a, char *str);
/*Makefile for so*/
liba.so:a.c
gcc -fpic -shared a.c -o liba.so
clean:
rm -f *.o
/*Makefile for static*/
liba.a:a.c
g++ -c a.c
ar -rsv liba.a a.o
clean:
rm -f *.o
make
2.下载PHP代码并解压,在源代码当前文件夹下:
3../buildconf –force
4../configure –prefix=/usr/local/php/
5. make
6. make install
6. cd ext
7. ./ext_skel –extname=myext,会生成一个myext目录
8. vim myext/config.m4
动态方式:
PHP_ARG_ENABLE(myext, whether to enable myext support,
dnl Make sure that the comment is aligned:
[ –enable-myext Enable myext support])
if test “$PHP_MYEXT” != “no”; then
dnl Write more examples of tests here…
dnl # –with-myoverpass -> check with-path
dnl SEARCH_PATH=”/usr/local /usr” # you might want to change this
dnl SEARCH_FOR=”/include/myoverpass.h” # you most likely want to change this
dnl if test -r $PHP_MYOVERPASS/$SEARCH_FOR; then # path given as parameter
dnl MYOVERPASS_DIR=$PHP_MYOVERPASS
dnl else # search default path list
dnl AC_MSG_CHECKING([for myoverpass files in default path])
dnl for i in $SEARCH_PATH ; do
dnl if test -r $i/$SEARCH_FOR; then
dnl MYOVERPASS_DIR=$i
dnl AC_MSG_RESULT(found in $i)
dnl fi
dnl done
dnl fi
dnl
dnl if test -z “$MYOVERPASS_DIR”; then
dnl AC_MSG_RESULT([not found])
dnl AC_MSG_ERROR([Please reinstall the myoverpass distribution])
dnl fi
dnl # –with-myoverpass -> add include path
dnl PHP_ADD_INCLUDE($MYOVERPASS_DIR/include)
dnl # –with-myoverpass -> check for lib and symbol presence
dnl LIBNAME=myoverpass # you may want to change this
dnl LIBSYMBOL=myoverpass # you most likely want to change this
dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
dnl [
dnl PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $MYOVERPASS_DIR/lib, MYOVERPASS_SHARED_LIBADD)
dnl AC_DEFINE(HAVE_MYOVERPASSLIB,1,[ ])
dnl ],[
dnl AC_MSG_ERROR([wrong myoverpass lib version or lib not found])
dnl ],[
dnl -L$MYOVERPASS_DIR/lib -lm
dnl ])
dnl
PHP_SUBST(MYEXT_SHARED_LIBADD)
PHP_ADD_LIBRARY_WITH_PATH(a, /usr/lib, MYEXT_SHARED_LIBADD)
PHP_NEW_EXTENSION(myext, myext.c, $ext_shared)
fi
上面的:
PHP_SUBST(MYEXT_SHARED_LIBADD)
PHP_ADD_LIBRARY_WITH_PATH(a, /usr/lib, MYEXT_SHARED_LIBADD)
用来指定第三方库liba.so放在了/usr/lib库中
编辑:php_myext.h
PHP_FUNCTION(my_test); /* For testing, remove later. */
编辑:myext.c
const zend_function_entry myoverpass_functions[] = {
PHP_FE(my_test, NULL) /* For testing, remove later. */
PHP_FE_END /* Must be the last line in myoverpass_functions[] */
};
PHP_FUNCTION(my_test)
{
long a;
char *str;
int str_len;
long int result;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “ls”, &a, &str, &str_len) == FAILURE) {
return;
}
result = my_test(a, str);
RETURN_LONG(result);
}
将第三方库的头文件拷贝到myext目录,并在myext.c包含该目录:#include “a.h”。
zend_parse_parameters负责C语言函数与PHP参数的传递
zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “ls”, &a, &str, &str_len)
类型说明见下表:
Boolean b zend_bool
Long l long
Double d double
String s char*, int
Resource r zval*
Array a zval*
Object o zval*
zval z zval*
那么返回值怎么办呢?
使用下面一组宏来表示:
RETURN_STRING
RETURN_LONG
RETURN_DOUBLE
RETURN_BOOL
RETURN_NULL
注意RETURN_STRING有两个参数
当你需要复制一份字符串时使用
RETURN_STRING(“Hello World”, 1);
否则使用
RETURN_STRING(str, 0);
如果C语言函数里有结构体或者其他指针,用zval类型,具体参见下面这篇文章:
http://qgjie456.blog.163.com/blog/static/35451367201241021826903/
编辑好之后,在ext/myext目录下:
/usr/local/php/bin/phpize
./configure –with-php-config=/usr/local/php/bin/php-config –enable-myext
make
然后将myext目录下:modules/myext.so拷贝到/usr/local/php/lib/php/extensions/no-xxxx/
将第三方库拷贝a.so到:/usr/lib/下,然后运行/sbin/ldconfig
测试:
hi.php
<? dl(“myext.so”); my_test(10, “hello world”); ?>
/usr/local/php/bin/php hi.php
静态方式:
PHP_ARG_ENABLE(myext, whether to enable myext support,
[ –enable-myext Enable myext support])
if test “$PHP_MYEXT” = “yes”; then
AC_DEFINE(HAVE_MYEXT, 1, [Whether you have MYEXT])
if test -f ./liba.a; then
PHP_ADD_LIBRARY_WITH_PATH(a, ./, MYEXT_SHARED_LIBADD)
PHP_SUBST(MYEXT_SHARED_LIBADD)
AC_MSG_RESULT(checking for liba.a is OK)
else
AC_MSG_RESULT(liba.a not found)
fi
PHP_NEW_EXTENSION(myext, myext.c, $ext_shared)
fi
编辑:php_myext.h
PHP_FUNCTION(my_test); /* For testing, remove later. */
编辑:myext.c
const zend_function_entry myoverpass_functions[] = {
PHP_FE(my_test, NULL) /* For testing, remove later. */
PHP_FE_END /* Must be the last line in myoverpass_functions[] */
};
PHP_FUNCTION(my_test)
{
long a;
char *str;
int str_len;
long int result;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “ls”, &a, &str, &str_len) == FAILURE) {
return;
}
result = my_test(a, str);
RETURN_LONG(result);
}
将第三方库的头文件拷贝到myext目录,并在myext.c包含该目录:#include “a.h”。
zend_parse_parameters负责C语言函数与PHP参数的传递 zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “ls”, &a, &str, &str_len)
类型说明见下表:
Boolean b zend_bool
Long l long
Double d double
String s char*, int
Resource r zval*
Array a zval*
Object o zval*
zval z zval*
那么返回值怎么办呢?
使用下面一组宏来表示:
RETURN_STRING
RETURN_LONG
RETURN_DOUBLE
RETURN_BOOL
RETURN_NULL
注意RETURN_STRING有两个参数
当你需要复制一份字符串时使用
RETURN_STRING(“Hello World”, 1);
否则使用
RETURN_STRING(str, 0);
将第三方库的头文件和a.a拷贝到myext目录,并在myext.c包含该目录:#include “a.h”。
编辑好之后,在ext/myext目录下:
/usr/local/php/bin/phpize
./configure –with-php-config=/usr/local/php/bin/php-config –enable-myext
make
然后将myext目录下:modules/myext.so拷贝到/usr/local/php/lib/php/extensions/no-xxxx/
测试:
hi.php
<? dl(“myext.so”); my_test(100, “hello world”); ?>
/usr/local/php/bin/php hi.php