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

Comments are closed.

Post Navigation