免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6185 | 回复: 5
打印 上一主题 下一主题

请教Linux下用C++作php扩展的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-12-19 15:16 |只看该作者 |倒序浏览
配置如下:
PHP_ARG_WITH(sysfile, for sysfile support,
[  --with-sysfile             Include sysfile support])

if test "$PHP_SYSFILE" == "yes"; then
  PHP_REQUIRE_CXX()
  PHP_ADD_LIBRARY(stdc++)
  PHP_NEW_EXTENSION(sysfile, sysfile.cpp c_sysfile/check.cpp c_sysfile/constraint.cpp c_sysfile/create.cpp c_sysfile/define.cpp c_sysfile/getdata.cpp c_sysfile/load.cpp c_sysfile/save.cpp c_sysfile/setdata.cpp c_sysfile/utility.cpp, $ext_shared)
fi


./configure --disable-all --with-sysfile=shared --with-apxs2=/usr/local/apache2/bin/apxs

make

顺利得到了一个sysfile.so,但是在测试的时候报错,说这是一个invalid PHP library.
我用的是PHP-4.4.4,这可能是什么原因呢?

谢谢!

论坛徽章:
0
2 [报告]
发表于 2006-12-19 17:16 |只看该作者

这个问题可能描述的不够精确,我缩小一下范围

用ext_skel创建一个扩展的框架,比如myext
然后把myext.c改成myext.cpp,并且把对php.h等的#include用extern "C"修饰起来。
然后我就没有再增加任何C/C++代码了。

修改config.m4如下:
PHP_ARG_WITH(myext, for sysfile support,
[  --with-myext            Include myext support])

if test "$PHP_MYEXT" == "yes"; then
  PHP_REQUIRE_CXX()
  PHP_ADD_LIBRARY(stdc++)
  PHP_NEW_EXTENSION(myext, myext.cpp, $ext_shared)
fi

./configure --disable-all --with-myext=shared

make

得到的myext.so 用./sapi/cli/php ext/myext/myext.php 测试显示正确。
但是把myext.so复制到php的安装目录里并且在php.ini里用
extension=myext.so装载,就会出错,从Apache的日志里看到如下错误信息:
PHP Warning: Unknow(): Unable to load dynamic library '/usr/local/php/exts/myext.so' - /usr/local/php/exts/myext.so: undefined symbol: _Znaj in Unknown on line 0

_Znaj是C++标准库里的东西吧?我明明在config.m4里申明了
  PHP_ADD_LIBRARY(stdc++)了呀。这是什么原因呢?

是不是用C++作PHP扩展的特别少?我们的项目应该要使用模版库,不得不
使用C++.

如果我使用C来做这个myext扩展,就一切正常。
谢谢~

[ 本帖最后由 goodtaste 于 2006-12-19 17:17 编辑 ]

论坛徽章:
0
3 [报告]
发表于 2006-12-19 17:36 |只看该作者

myext的问题我解决了,但是sysfile那个实际的扩展还是有问题

myext的问题只要修改config.m4成:
PHP_ARG_WITH(myext, for sysfile support,
[  --with-myext            Include myext support])

if test "$PHP_MYEXT" == "yes"; then
  PHP_REQUIRE_CXX()
  PHP_SUBST(MYEXT_SHARED_LIBADD)
  PHP_ADD_LIBRARY(stdc++,"",MYEXT_SHARED_LIBADD)
  PHP_NEW_EXTENSION(myext, myext.cpp, $ext_shared)
fi

就可以了。
但是我的实际工程sysfile在装载的时候还是报错:
Warning: dl(): Invalid library (maybe not a PHP library) 'sysfile.so'

帮帮我吧.

论坛徽章:
0
4 [报告]
发表于 2006-12-19 18:19 |只看该作者

最后的原因也找到了

我的ZEND_GET_MODULE前后忘记加extern "C"了,通过nm看导出函数名发现的.
呵呵,谢谢大家.

论坛徽章:
0
5 [报告]
发表于 2006-12-19 22:02 |只看该作者
楼主品格好啊

论坛徽章:
0
6 [报告]
发表于 2007-01-31 09:41 |只看该作者

谢谢大家,问题解决了,我写了个备忘

免得以后忘记了,也给其他一些帮助。

原文在
http://jason.rocklv.net/techdoc/PHPExt.html

在Linux上创建PHP4的C++扩展
Jason

1. 必须的工具
2. 主要步骤

    2.1. 创建
    2.2. 编译
    2.3. 调试

3. 总结

1. 必须的工具

如下工具是必须的:

   1.

      gcc. 我使用的是3.4.3
   2.

      autoconf. 我使用的是 2.13-5. 奇怪的是2.59是不能用的,如果你的系统里安装的是这个版本,要先卸载,然后安装2.13
   3.

      PHP4的源代码。我使用的是PHP-4.4.4。在PHP的网站上可以下载到

2. 主要步骤

创建PHP的扩展很麻烦。熟悉其它脚本语言的人会觉得开发PHP的扩展真是罗嗦到了极点。不过给脚本写扩展的原理都是一样的:

导出一个特定名字的函数,然后通过这个函数返回关于这个扩展的全部信息,其中重要的有:

   1.

      名字,描述,版本信息
   2.

      模块所提供的功能,这个一般都是一个函数名和函数指针成对的数组
   3.

      通过一些函数实现脚本和扩展之间的数据交换.这方面各个语言都不相同,TCL是直接传递字符串,Python提供了PyArg_ParseTuple,Py_BuildValue等函数,Lua则通过一个堆栈来交换数据.

PHP提供了一系列的工具和宏来封装这个过程,可惜的是在我看来这反而让它更加复杂。
2.1. 创建

   1.

      将PHP-4 的源代码解压缩。下文将这个目录称为PHPSRC.
   2.

      进入PHPSRC/ext目录,执行./ext_skel 扩展名。假设我们的扩展名字叫testext,那就是输入./ext_skel testext. 这个程序将会为你在ext目录下创建如下内容:
         1.

            testext目录
         2.

            在testext目录下又包括:
               1.

                  testext.c - 这是扩展模块的源文件
               2.

                  php_testext.h - 头文件
               3.

                  config.m4 - 用于autoconf的配置文件,autoconf会通过这个文件的内容决定应该如何编译链接这个模块。
               4.

                  testext.php - 自动产生的测试脚本
               5.

                  tests 目录 - 忽略
   3.

      然后我们必须简单的理解一下config.m4这个文件。

      m4 is a macro processor, in the sense that it copies its input to the output, expanding macros as it goes. Macros are either builtin or user-defined, and can take any number of arguments. Besides just doing macro expansion, m4 has builtin functions for including named files, running shell commands, doing integer arithmetic, manipulating text in various ways, performing recursion, etc.... m4 can be used either as a front-end to a compiler, or as a macro processor in its own right.

      The m4 macro processor is widely available on all UNIXes, and has been standardized by POSIX. Usually, only a small percentage of users are aware of its existence. However, those who find it often become committed users. The popularity of GNU Autoconf, which requires GNU m4 for generating configure scripts, is an incentive for many to install it, while these people will not themselves program in m4. GNU m4 is mostly compatible with the System V, Release 3 version, except for some minor differences. See Compatibility, for more details.

      Some people find m4 to be fairly addictive. They first use m4 for simple problems, then take bigger and bigger challenges, learning how to write complex sets of m4 macros along the way. Once really addicted, users pursue writing of sophisticated m4 applications even to solve simple problems, devoting more time debugging their m4 scripts than doing real work. Beware that m4 may be dangerous for the health of compulsive programmers.

      以上内容来自http://www.gnu.org,所以我就不多说了. 总之PHP使用了这种技术来帮助我们构建扩展.

      只记录一下对我们有用的东西:
         1.

            dnl是注释.好怪
         2.

            PHP_ARG_WITH或者PHP_ARG_ENABLE指定了PHP模块的工作方式,任选一种,我选择的是WITH
         3.

            PHP_REQUIRE_CXX()用于指定这个扩展用到了C++
         4.

            PHP_SUBST(SYSFILE_SHARED_LIBADD)用于说明这个扩展编译成动态链接库的形式
         5.

            PHP_ADD_LIBRARY(stdc++,"",SYSFILE_SHARED_LIBADD)用于将标准C++库链接进入扩展
         6.

            PHP_NEW_EXTENSION用于指定有哪些源文件应该被编译,文件和文件之间用空格隔开.

      ext_skel默认生成的模块框架是针对C的,我们要使用C++,那以上的3,5两个宏就是必须的.另外还要把testext.c改名成testext.cpp,所以PHP_NEW_EXTENSION原本包括的testext.c也要修改.

      在使用C++之后要注意一个小问题,那就是php_testext.h这个文件可能被PHP的其他部分所引用到,而引用者很可能是一个.c文件,所以不能在php_testext.h里包含任何C++所独有的东西.比如标准模版库,类,或者bool类型等等.
   4.

      默认生成的testext.c(现在改名为testext.cpp)了,已经包含了一个测试性质的导出函数,通过那个例子就可以大概明白怎么添加自己的函数了. zend_function_entry是导出函数列表, zend_module_entry描述了模块的信息. 不过因为是C++了,还是有几点要修改的:
         1.

            #include "php.h" #include "php_ini.h" #include "ext/standard/info.h"

            要用extern "C" 修饰.
         2.

            ZEND_GET_MODULE也要用extern "C"修饰
         3.

            zend_module_entry就是用于描述模块信息的类型,其实就是一个结构,其中第二项不知道是什么含意.在Windows上,这好像是一个描述信息,可以是一个长长的字符串,但是在Linux上似乎只能是跟模块名相同.
   5.

      之后的工作就是写自己的代码了.根据设计,提供对外的接口函数,然后写C/C++代码来实现.

2.2. 编译

   1.

      代码写好以后,到PHPSRC目录,运行./buildconf --force,除非m4文件有错或者autoconf安装有问题,否则这个步骤不会有什么错误,时间也不长. 通过删除configure文件,可以强迫buildconf重新生成一遍.
   2.

      运行./configure --disable-all --with-testext=shared

      --disable-all是为了减少配置和下一步编译的时间,因为我们只需要自己的模块

      --with-testext=shared指明了讲这个模块编译成动态链接库,而不是集成到PHP内部
   3.

      运行make

      这个过程时间比较长,如果你的代码有问题,就会出现编译或者链接错误,根据提示自己修改就是了. 如果没什么问题,就会在PHPSRC/modules下面生成扩展文件testext.so,同时也会生成PHPSRC/sapi/cli/php. 可以运行./sapi/cli/app ext/testext/testext.php来测试模块是否正常. 不过这之前要先把testext.so复制到某个特定的目录下,这个目录不同的系统不一样,你可以根据运行/sapi/cli/app ext/testext/testext.php得到的错误信息来知道这个目录.
   4.

      如果测试没有问题,就可以安装到正式的PHP里去了,通过修改php.ini文件然后重起Apache就可以.

2.3. 调试

用gdb可以调试PHP的扩展.首先要写一个php脚本用来测试你想测试的功能, 把它放到PHPSRC目录下,比如叫test.php. 然后按如下步骤进行:

   1.

      gdb
   2.

      file ./sapi/cli/php
   3.

      用b命令下断点.因为是C++程序,所以扩展的导出函数名并不是我们输入的名字,可以用nm命令查看扩展的所有导出函数,找到编译器最终分配的名字.这个名字是肯定包含了你原本输入的名字的,所以很好找.

      gdb会提示说这个符号在当前程序(php)里找不到,问你要不要在以后的shared library里找,回答Yes
   4.

      run test.php,之后就会停在断点上了. 用n,s,display之类的命令调试的.

3. 总结

一句话,PHP的模块扩展比谁都麻烦,规则太多.其实我希望它提供一个文档,提供我在第二节开头描述的那些信息就够了. 不过也许是我学艺不精吧,对本来挺正常的事深恶痛绝,
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP