首先聲明:我們要構建的是擴展或者模塊名為hello_module.該模塊提供一個方法:hello_word.
1、php環境的搭建
我們一般使用源碼包編譯安裝,而不是binary包安裝。因為使用PHP的二進制分發包安裝有些冒險,這些版本傾向于忽略./configure的兩個重要選項,它們在開發過程中很便利:
第一個–enable-debug。這個選項將把附加的符號信息編譯進PHP的執行文件,以便如果發生段錯誤,你能從中得到一個內核轉儲文件,使用gdb追蹤并發現什么地方以及為什么會發生段錯誤。
另一個選項依賴于你的PHP版本。在PHP 4.3中該選項名為–enable-experimental-zts,在PHP 5及以后的版本中為–enable-maintainer-zts。這個選項使PHP以為自己執行于多線程環境,并且使你能捕獲通常的程序錯誤,然而它們在非多線程環境中是無害的,卻使你的擴展不可安全用于多線程環境。一旦你已經使用這些額外的選項編譯了PHP并安裝于你的開發服務器(或者工作站)中,你就可以把你的第一個擴展加入其中了。
Zend 引擎提供了一個內存管理器,有在擴展中跟蹤內存泄漏的能力并提供詳盡的調試信息。跟蹤在默認情況下是被禁用的,同時也是線程安全的。要打開的話,應將 –enable-debug 和 –enable-maintainer-zts 選項與其他常用選項一起傳給 configure。要獲得從源代碼構建 PHP 的說明,請看位于 安裝前需要考慮的事項 的說明。
典型的 configure 命令行可能看起來象這樣:
$ ./configure --prefix=/usr/local/php --enable-debug --enable-maintainer-zts --enable-cgi --enable-cli --with-mysql=/path/to/mysql1)一般可以把php安裝在/usr/local/php目錄下。
2)php的二進制可執行文件都在/usr/local/php/bin目錄,包括php自帶工具phpize.
phpize實際上是個shell腳本,可以用vi phpize來查看其內容.
注意:使用phpize需要安裝autoconf 宏。
因為config.m4 文件使用 GNU autoconf 語法編寫。簡而言之,就是用強大的宏語言增強的 shell 腳本。注釋用字符串 dnl 分隔,字符串則放在左右方括號中間(例如,[ 和 ])。字符串可按需要多次嵌套引用。完整的語法參考可參見位于http://www.gnu.org/software/autoconf/manual/
安裝autoconf 宏最簡單的方法:apt-get install autoconf
2、ext_skel腳本
PHP 擴展由幾個文件組成,這些文件對所有擴展來說都是通用的。不同擴展之間,這些文件的很多細節是相似的,只是要費力去復制每個文件的內容。幸運的是,有腳本可以做所有的初始化工作,名為 ext_skel,自 PHP 4.0 起與其一起分發。
不帶參數運行 ext_skel 在 PHP 5.3.2 中會產生以下輸出:
php-5.3.2/ext$ ./ext_skel ./ext_skel --extname=module [--proto=file] [--stubs=file] [--xml[=file]] [--skel=dir] [--full-xml] [--no-help] --extname=module module is the name of your extension --proto=file file contains prototypes of functions to create --stubs=file generate only function stubs in file --xml generate xml documentation to be added to phpdoc-cvs --skel=dir path to the skeleton directory --full-xml generate xml documentation for a self-contained extension (not yet implemented) --no-help don't try to be nice and create comments in the code and helper functions to test if the module compiled通常來說,開發一個新擴展時,僅需關注的參數是 –extname 和 –no-help。除非已經熟悉擴展的結構,不要想去使用 –no-help; 指定此參數會造成 ext_skel 不會在生成的文件里省略很多有用的注釋。
剩下的 –extname 會將擴展的名稱傳給 ext_skel。"name" 是一個全為小寫字母的標識符,僅包含字母和下劃線,在 PHP 發行包的 ext/ 文件夾下是唯一的。
–proto選項允許開發人員指定一個頭文件,由此創建一系列 PHP 函數,表面上看就是要開發基于一個函數庫的擴展,但對大多數頭現代的文件來說很少能起作用。如果用 zlib.h 頭文件來做測試,就會導致在 ext_skel 的輸出文件中存在大量的空的和無意義的原型文件。–xml 和 –full-xml 選項當前完全不起作用。–skel 選項可用于指定用一套修改過的框架文件來工作,這是本節范圍之外的話題了。
3、擴展組成文件
不管是通過手工,通過
ext_skel ,還是通過另外的擴展生成器,所有的擴展都會有以下個文件:
1)
config.m4:phpize用來準備構建系統哪些擴展的配置文件configure 選項 ,是UNIX 構建系統配置。對應的win系統是config.w32: http://www.php.net/manual/zh/internals2.buildsys.configunix.php
2) php_hello_module.h
:包含引用的頭文件當將擴展作為靜態模塊構建并放入PHP 二進制包時,構建系統要求用 php_ 加擴展的名稱命名的 頭文件包含一個對擴展模塊結構的指針定義。就象其他頭文件,此文件經常包含附加的宏、原型和全局量。當然你可以把頭文件內容放在源文件hello_module.c頂部。分開只是讓代碼組織更清晰,而且是個很好的習慣。
3) hello_module.c :
包含模塊函數的源碼文件
擴展應包含任意數量的頭文件、源文件、單元測試和其他支持文件,此四個文件僅夠組成最小的擴展。hello_module擴展的文件列表如下所示:
ext/ hello_module/ config.m4 config.w32 CREDITS EXPERIMENTAL php_hello_module.h hello_module.c tests/ 001.phpt
4、與 UNIX 構建系統交互: config.m4
config.m4文件負責在配置時解析configure的命令行選項。這就是說它將檢查所需的外部文件并且要做一些類似配置與安裝的任務。config.m4 文件告訴 UNIX 構建系統哪些擴展 configure 選項是支持的,你需要哪些擴展庫,以及哪些源文件要編譯成它的一部分。對所有經常使用的 autoconf 宏,包括 PHP 特定的及 autoconf 內建的,
config.m4 文件舉例 dnl $Id$ dnl config.m4 for extension example PHP_ARG_WITH(example, for example support, [ --with-example[=FILE] Include example support. File is the optional path to example-config]) PHP_ARG_ENABLE(example-debug, whether to enable debugging support in example, [ --enable-example-debug example: Enable debugging support in example], no, no) PHP_ARG_WITH(example-extra, for extra libraries for example, [ --with-example-extra=DIR example: Location of extra libraries for example], no, no) dnl 檢測擴展是否已啟用 if test "$PHP_EXAMPLE" != "no"; then dnl 檢測 example-config。首先嘗試所給出的路徑,然后在 $PATH 中尋找 AC_MSG_CHECKING([for example-config]) EXAMPLE_CONFIG="example-config" if test "$PHP_EXAMPLE" != "yes"; then EXAMPLE_PATH=$PHP_EXAMPLE else EXAMPLE_PATH=`$php_shtool path $EXAMPLE_CONFIG` fi dnl 如果找到可用的 example-config,就使用它 if test -f "$EXAMPLE_PATH" && test -x "$EXAMPLE_PATH" && $EXAMPLE_PATH --version > /dev/null 2>&1; then AC_MSG_RESULT([$EXAMPLE_PATH]) EXAMPLE_LIB_NAME=`$EXAMPLE_PATH --libname` EXAMPLE_INCDIRS=`$EXAMPLE_PATH --incdirs` EXAMPLE_LIBS=`$EXAMPLE_PATH --libs` dnl 檢測擴展庫是否工作正常 PHP_CHECK_LIBRARY($EXAMPLE_LIB_NAME, example_critical_function, [ dnl 添加所需的 include 目錄 PHP_EVAL_INCLINE($EXAMPLE_INCDIRS) dnl 添加所需的擴展庫及擴展庫所在目錄 PHP_EVAL_LIBLINE($EXAMPLE_LIBS, EXAMPLE_SHARED_LIBADD) ],[ dnl 跳出 AC_MSG_ERROR([example library not found. Check config.log for more information.]) ],[$EXAMPLE_LIBS] ) else dnl 沒有可用的 example-config,跳出 AC_MSG_RESULT([not found]) AC_MSG_ERROR([Please check your example installation.]) fi dnl 檢測是否啟用調試 if test "$PHP_EXAMPLE_DEBUG" != "no"; then dnl 是,則設置 C 語言宏指令 AC_DEFINE(USE_EXAMPLE_DEBUG,1,[Include debugging support in example]) fi dnl 檢測額外的支持 if test "$PHP_EXAMPLE_EXTRA" != "no"; then if test "$PHP_EXAMPLE_EXTRA" == "yes"; then AC_MSG_ERROR([You must specify a path when using --with-example-extra]) fi PHP_CHECK_LIBRARY(example-extra, example_critical_extra_function, [ dnl 添加所需路徑 PHP_ADD_INCLUDE($PHP_EXAMPLE_EXTRA/include) PHP_ADD_LIBRARY_WITH_PATH(example-extra, $PHP_EXAMPLE_EXTRA/lib, EXAMPLE_SHARED_LIBADD) AC_DEFINE(HAVE_EXAMPLEEXTRALIB,1,[Whether example-extra support is present and requested]) EXAMPLE_SOURCES="$EXAMPLE_SOURCES example_extra.c" ],[ AC_MSG_ERROR([example-extra lib not found. See config.log for more information.]) ],[-L$PHP_EXAMPLE_EXTRA/lib] ) fi dnl 最后,將擴展及其所需文件等信息傳給構建系統 PHP_NEW_EXTENSION(example, example.c $EXAMPLE_SOURCES, $ext_shared) PHP_SUBST(EXAMPLE_SHARED_LIBADD) fi
注意:凡是帶有dnl前綴的都是注釋,注釋是不被解析的。
4.1 PHP_ARG_*: 賦予用戶可選項
在以上的
config.m4 例子中,兩條注釋后,最先見到的 3 行代碼,使用了 PHP_ARG_WITH() 和 PHP_ARG_ENABLE()。這些給 configure 提供了可選項,和在運行 ./configure –help 時顯示的幫助文本。就象名稱所暗示的,其兩者的不同點在于是創建 –with-* 選項還是 –enable-* 選項。每個擴展應提供至少一個以上的選項以及擴展名稱,以便用戶可選擇是否將擴展構建至 PHP 中。按慣例,PHP_ARG_WITH() 用于取得參數的選項,例如擴展所需庫或程序的位置;而 PHP_ARG_ENABLE() 用于代表簡單標志的選項。
不管你使用哪一個指令,你都應該注釋掉另外一個。也就是說,如果你使用了–enable-my_module,那就應該去掉–with-my_module。反之亦然。
configue使用例子:./configure –enable-hello_module
則將
dnl PHP_ARG_ENABLE(hello_module, whether to enablehello_module support, dnl Make sure that the comment is aligned: dnl [ --enable-hello_module Enablehello_module support])修改成
PHP_ARG_ENABLE(hello_module, whether to enablehello_module support, [ --enable-hello_module Enablehello_module support])4.2 處理用戶選擇
config.m4
可給用戶提供一些做什么的選擇,現在就是做出選擇的時候了。在上例中,三個選項在未指定時顯然默認為 "no"。習慣上,最好用此值作為用于啟用擴展的選項的默認值,為了擴展與 PHP 分開構建則用 phpize 覆蓋此值,而要構建在 PHP 中時則不應被默認值將擴展空間弄亂。處理這三個選項的代碼要復雜得多。
處理 –with-example[=FILE] 選項
首先檢測是否設置了 –with-example[=FILE] 選項。如此選項未被指定,或使用否定的格式(–without-example ),或賦值為 "no" 時,它會控制整個擴展的含有物其他任何事情都不會發生。在上面的例子中所指定的值為 /some/library/path/example-config,所以第一個 test 成功了。
接下來,代碼調用 AC_MSG_CHECKING(),這是一個 autoconf 宏,輸出一行標準的如 "checking for …" 的信息,并檢測用戶假定的 example-config 是否是一個明確的路徑。在這個例子中,PHP_EXAMPLE 所取到的值為 /some/library/path/example-config,現已復制到 EXAMPLE_PATH 變量中了。只有用戶指定了 –with-example ,才會執行代碼 $php_shtool path $EXAMPLE_CONFIG,嘗試使用用戶當前的 PATH 環境變量推測 example-config 的位置。無論如何,下一步都是檢測所選的EXAMPLE_PATH 是否是正常文件,是否可執行,及是否執行成功。如成功,則調用 AC_MSG_RESULT(),結束由 AC_MSG_CHECKING() 開始的輸出行。否則,調用 AC_MSG_ERROR(),打印所給的信息并立即中斷執行 configure。
代碼現在執行幾次 example-config 以確定一些站點特定的配置信息。下一步調用的是 PHP_CHECK_LIBRARY(),這是 PHP 構建系統提供的一個宏,包裝了 autoconf 的 AC_CHECK_LIB() 函數。PHP_CHECK_LIBRARY() 嘗試編譯、鏈接和執行程序,在第一個參數指定的庫中調用由第二個參數指定的符號,使用第五個參數給出的字符串作為額外的鏈接選項。如果嘗試成功了,則運行第三個參數所給出的腳本。此腳本從 example-config 所提供的原始的選項字符串中取出頭文件路徑、庫文件路徑和庫名稱,告訴 PHP 構建系統。如果嘗試失敗,腳本則運行第四個參數中的腳本。此時調用 AC_MSG_ERROR() 來中斷程序執行。
處理 –enable-example-debug 選項
處理 –enable-example-debug 很簡單。只簡單地檢測其真實值。如果檢測成功,則調用 AC_DEFINE() 使 C 語言宏指令 USE_EXAMPLE_DEBUG 可用于擴展的源代碼。第三個參數是給 config.h 的注釋字符串,通??煞判牡牧艨铡?/p>
處理 –with-example-extra=DIR 選項
對于此例子來說,由 –with-example-extra=DIR 選項所請求的假定的“額外”功能操作不會與假定的 example-config 程序共享,也沒有默認的搜索路徑。因此,用戶需要在所需的庫之前提供設置程序。有點不象現實中的擴展,在這里的設置僅僅起說明性的作用。
代碼開始用已熟知的方式來檢測 PHP_EXAMPLE_EXTRA 的真實值。如果所提供的為否定形式,則不會進行其他處理,用戶也不會請求額外的功能。如果所提供的為未提供參數的肯定形式,則調用 AC_MSG_ERROR() 中止處理。下一步則再次調用PHP_CHECK_LIBRARY()。這一次,因為沒有提供預定義編譯選項,PHP_ADD_INCLUDE() 和 PHP_ADD_LIBRARY_WITH_PATH() 用于構建額外功能所需的頭文件路徑、庫文件路徑和庫標志。也調用 AC_DEFINE() 來指示所請求的額外功能代碼是可用的,設置變量來告訴以后的代碼,有額外的源代碼要構建。如果檢測失敗,則調用所熟悉的 AC_MSG_ERROR()。另一種不同的處理失敗的方式是更換為調用 AC_MSG_WARNING(),例如:
4.3 PHP_NEW_EXTENSION宏
默認情況下,通過ext_skel創建的config.m4都能接受指令,并且會自動啟用該擴展。啟用該擴展是通過PHP_EXTENSION這個宏進行的。如果你要改變一下默認的情況,想讓用戶明確的使用 –enable-my_module或 –with-my_module指令來把擴展包含在PHP二進制文件當中,那么將 “if test "$PHP_MY_MODULE" != "no"”改為“if test "$PHP_MY_MODULE" == "yes"”即可。
if test "$PHP_MY_MODULE" == "yes"; thendnl PHP_EXTENSION(hello_module, $ext_shared) fi這樣就會導致在每次重新配置和編譯PHP時都要求用戶使用 –enable-my_module指令。
PHP_NEW_EXTENSION()
就是宏告訴構建系統去構建擴展本身和被其用到的文件。
PHP_NEW_EXTENSION()參數:
第一個參數是擴展的名稱,和包含它的目錄同名。
第二個參數是做為擴展的一部分的所有源文件的列表
。參見 PHP_ADD_BUILD_DIR() 以獲取將在子目錄中源文件添加到構建過程的相關信息。
第三個參數總是 $ext_shared, 當為了 –with-example[=FILE] 而調用 PHP_ARG_WITH()時,由 configure 決定參數的值。
第四個參數指定一個“SAPI 類”,僅用于專門需要 CGI 或 CLI SAPI 的擴展。其他情況下應留空。
第五個參數指定了構建時要加入 CFLAGS 的標志列表。
第六個參數是一個布爾值,為 "yes" 時會強迫整個擴展使用 $CXX 代替 $CC 來構建。第三個以后的所有參數都是可選的。最后,調用 PHP_SUBST() 來啟用擴展的共享構建。
例如我們要構建擴展是hello_module
dnl $Id$ dnl config.m4 for extension hello PHP_ARG_ENABLE(hello, whether to enable hello support, [ --enable-hello Enable hello support]) if test "$PHP_HELLO" != "no"; then PHP_NEW_EXTENSION(hello_module, hello_module.c, $ext_shared) fi
5、擴展模塊代碼的
模塊結構
所有的PHP模塊通常都包含以下幾個部分:
· 包含頭文件(引入所需要的宏、API定義等);
· 聲明導出函數(用于Zend函數塊的聲明);
· 聲明Zend函數塊;
· 聲明Zend模塊;
· 實現get_module()函數;
· 實現導出函數。
詳解請看:
PHP擴展代碼結構詳解
6、創建擴展的詳細步驟
我們創建擴展最好放在php的源碼包的ext目錄下。如/opt/php-5.3.2/ext/下
1) ext_skel來建立一個php擴展的一個框架
root@ubuntu:/# cd /opt/php-5.3.2/ext/
root@ubuntu:opt/php-5.3.2/ext/]# ./ext_skel –extname=hello_module
執行了這個步驟以后看到這樣的結果:
Creating directory hello_module Creating basic files: config.m4 config.w32 .cvsignore hello_module.c php_hello_module.h CREDITS EXPERIMENTAL tests/001.phpt hello_module.php [done]. To use your new extension, you will have to execute the following steps: 1. $ cd .. 2. $ vi ext/hello_module/config.m4 3. $ ./buildconf 4. $ ./configure --[with|enable]-hello_module 5. $ make 6. $ ./php -f ext/hello_module/hello_module.php 7. $ vi ext/hello_module/hello_module.c 8. $ make Repeat steps 3-6 until you are satisfied with ext/hello_module/config.m4 and step 6 confirms that your module is compiled into PHP. Then, start writing code and repeat the last two steps as often as necessary.在這個目錄下生成一個目錄叫hello_module
進入這里面我們看看
root@ubuntu:opt/php-5.3.2/ext# #cd hello_module root@ubuntu:/opt/php-5.3.2/ext/hello_module# ls config.m4 config.w32 CREDITS EXPERIMENTAL hello_module.c hello_module.php php_hello_module.h tests然后我們要修改文件順序是
configue.m4 hello_module.c php_hello_module.h2)編輯config.m4文件,我們使用enable-hello_module選項:
dnl PHP_ARG_ENABLE(hello_module, whether to enablehello_module support, dnl Make sure that the comment is aligned: dnl [ --enable-hello_module Enable hello_module support])修改成
PHP_ARG_ENABLE(hello_module, whether to enable hello_module support, [ --enable-hello_module Enable hello_module support])3)vi hello_module.c
主要是給模塊添加函數:
/* Every user visible function must have an entry in my_module_functions[].*/ function_entry hello_module_functions[] = { PHP_FE(hello_world, NULL) /* 添加著一行代碼 */ PHP_FE(confirm_my_module_compiled, NULL) /* For testing, remove later. */ {NULL, NULL, NULL} /* Must be the last line in my_module_functions[] */ };在文件的最后添加下列代碼
定義函數:
PHP_FUNCTION(hello_world) { zend_printf("hello sdomain!"); }4)修改php_hello_module.h
在PHP_FUNCTION(confirm_my_module_compiled ); /* For testing, remove later. */ 這行的下面添加一行:
PHP_FUNCTION(hello_world); /* 函數的聲明 */
5) 執行phpize并編譯
root@ubuntu:/opt/php-5.3.2/ext/hello_module# /usr/local/php/bin/phpize
執行以后會看到下面的
Configuring for:
PHP Api Version: 20090626
Zend Module Api No: 20090626
Zend Extension Api No: 220090626然后執行:
root@ubuntu:/opt/php-5.3.2/ext/hello_module#./configure –enable-hello_module –with-php-config=/usr/local/php/bin/php-config
root@ubuntu:/opt/php-5.3.2/ext/hello_module# make
這個時候會在當前的目錄下生成一個目錄叫modules先存放著hello_module.so文件
cp modules/hello_module.so /usr/local/php/ext/
然后再把hello_module.so文件拷到php.ini里面的extension_dir所指定的位置
6)開啟擴展
php.ini文件中打開這個擴展
extension=hello_module.so
重新起動apache
用phpinfo來察看一下ok了
我們看看安裝php memcached的擴展:
安裝分兩步
安裝libmemcached,目標是so和header文件
安裝memcached php extensions
libmemcaced 分為兩大版本0.x和1.x, 1.x的版本從2011-09-28開始,編譯很麻煩,需要gcc4.0以上的專門配置,compile無比慢. 0.x版本就簡單很多,最高版本是0.53,所以選擇安裝0.53
極品總是成對出現,php的memcahed也從2.1.0開始,要求libmemcached 必須是1.0.x版本
安裝libmemcached
下載:https://launchpad.net/libmemcached/+download
wget https://launchpadlibrarian.net/135986673/libmemcached-1.0.17.tar.gz
tar xvfz libmemcached-1.0.17.tar.gz
cdlibmemcached-1.0.17
./configure –prefix=/usr/local/libmemcached
make && make install
安裝php擴展,
使用php官網的源碼安裝
wget http://pecl.php.net/get/memcached-2.0.0.tgz
(https://github.com/php-memcached-dev/php-memcached)
tar zvxf memcached-2.0.0.tgz
cd memcached-2.0.0/
ls ,你會看到只是源碼。然后:
/usr/local/php/bin/phpize
./configure –enable-memcached –with-php-config=/usr/local/php/bin/php-config –with-libmemcached-dir=/usr/local/libmemcached/
make && make install
make install 是 把memcached.so 安裝到 ${php install dir}/extensions/no-debug-non-zts-20090626/,這個目錄隨著php的版本不同而不同
最后一步,修改php.ini,加上 extension=memcached.so
(使用bin/php –ini 查看php.ini所在目錄)
轉自:http://blog.csdn.net/hguisu/article/details/7381978
原創文章,作者:s19930811,如若轉載,請注明出處:http://www.www58058.com/3055