php扩展中使用动态链接库

整理下大概知识点:

  • C的编译、链接、安装过程
  • autoconf基本语法
  • config.m4中的PHP_XX系列宏(在aclocal.m4中)

具体例子:
以使用taglib(https://github.com/taglib/taglib)编写一个操作mp3的id3标签的PHP扩展为例,按照默认编译安装taglib,头文件在/usr/local/include/taglib/tag_c.h,共享库文件在/usr/local/lib/libtag_c.so
我用到了taglib这个库的c语言版,安装后taglib-config –libs命令得到的是它的c++版的库,所以要在config.m4里自己写。

config.m4的关键代码:

PHP_ARG_WITH(taglib, for taglib support, [  --with-taglib             Include taglib support])

if test "$PHP_TAGLIB" != "no"; then

SEARCH_PATH="/usr/local /usr"
SEARCH_FOR="/include/taglib/tag_c.h"
if test -r $PHP_TAGLIB/$SEARCH_FOR; then # path given as parameter
TAGLIB_DIR=$PHP_TAGLIB
else # search default path list
AC_MSG_CHECKING([for taglib files in default path])
for i in $SEARCH_PATH ; do
if test -r $i/$SEARCH_FOR; then
TAGLIB_DIR=$i
AC_MSG_RESULT(found in $i)
fi
done
fi

if test -z "$TAGLIB_DIR"; then
AC_MSG_RESULT([not found])
AC_MSG_ERROR([Please reinstall the taglib distribution])
fi

PHP_ADD_INCLUDE($TAGLIB_DIR/include)

dnl #库文件 libtag_c.so
LIBNAME=tag_c

dnl #库函数
LIBSYMBOL=taglib_file_tag

dnl 第三个参数要设置成EXTRA_LDFLAGS时,链接的时候才会加上 -ltag_c 参数...这个PHP_ADD_LIBRARY_WITH_PATH的原型还没看明白...
dnl 貌似还有好几种解决方案,PHP_EVAL_LIBLINE?
PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $TAGLIB_DIR/lib, EXTRA_LDFLAGS)

PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
[
AC_DEFINE(HAVE_TAGLIB,1,[ ])
],[
AC_MSG_ERROR()
],[
-L$TAGLIB_DIR/lib -lm
])

PHP_NEW_EXTENSION(php_taglib, php_taglib.c, $ext_shared)
PHP_SUBST(TAGLIB_SHARED_LIBADD)
fi

接下来是

configure [--with-taglib[=/path]]
make
make install

顺利的话可以到php.ini里面加载扩展。

期间可能会出现tag_c.h文件找不到的问题,注意下头文件的路径是由 config.m4 文件里的 PHP_ADD_INCLUDE($TAGLIB_DIR/include) 加上 扩展源码里 #include “taglib/tag_c.h” 组成的。

然后,即使扩展编译安装成功,php_info()里看到加载成功,但是cli执行php 扩展测试代码的时候出现 symbol lookup error的话,应该是扩展链接的时候没有找到libtag_c.so, 注意下PHP_ADD_LIBRARY_WITH_PATH() 的第三个参数即可。