程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP綜合 >> php源代碼的配置和鏈接

php源代碼的配置和鏈接

編輯:PHP綜合

配置和鏈接

所有前面示例中的代碼, 都是你曾經在php用戶空間編寫過代碼的C語言的獨立版本. 如果你做的項目需要和php擴展進行粘合, 那麼你就至少需要鏈接一個外部庫.

autoconf

在一個簡單的應用中, 你可能已經在你的Makefile中增加了下面這樣的CFLAGS和LDFLAGS.

CFLAGS = ${CFLAGS} -I/usr/local/foobar/include  
LDFLAGS = ${LDFLAGS} -lfoobar -L/usr/local/foobar/lib

想要構建你的應用卻沒有libfoobar的人, 或將libfoobar安裝到其他位置的人, 將會得到一個處理過的錯誤消息, 用於幫助他找到錯誤原因.

在過去十年開發的多數開發源代碼軟件(OSS)以及PHP都利用了一個實用工具autoconf, 通過一些簡單的宏來生成復雜的configure腳本. 這個產生的腳本會執行查找依賴庫已經頭文件是否安裝的工作. 基於這些信息, 一個包可以自定義構建代碼行, 或在編譯的時間被浪費之前提供一個有意義的錯誤消息.

在構建php擴展時, 無論你是否計劃公開發布, 都需要利用這個autoconf機制. 即便你對autoconf已經很熟悉了, 也請花幾分鐘時間閱讀本章, php中引入了一些一般安裝的autoconf沒有的自定義宏.

和傳統的autoconf步驟(集中的configure.in文件包含了包的所有配置宏)不同, php只是用configure.in管理許多位域源碼樹下小的config.m4腳本的協調, 包括各個擴展, SAPI, 核心自身, 以及ZendEngine.

你已經在前面的章節看到了一個簡單版本的config.m4. 接下來, 我們將在這個文件中增加其他的autoconf語法, 讓你的擴展可以收集到更多的配置時信息.

庫的查找

config.m4腳本最多是用於檢查依賴庫是否已安裝. 擴展比如mysql, ldap, gmp以及其他設計為php用戶空間和c庫實現的其他功能之間的粘合層的擴展. 如果它們的依賴庫沒有安裝, 或者安裝的版本太舊, 要麼會編譯錯誤, 要麼會導致產生的二進制無法運行.

頭文件掃描

對依賴庫掃描中最簡單的一步就是檢查你的腳本中的包含文件, 它們將在鏈接時使用. 下面的代碼嘗試在一些常見位置查找zlib.h:

PHP_ARG_WITH(zlib,[for zlib Support]  
[  with-zlib              Include ZLIB Support])  
      
if test "$PHP_ZLIB" != "no"; then  
  for i in /usr /usr/local /opt; do
    if test -f $i/include/zlib/zlib.h; then  
      ZLIB_DIR=$i  
    fi  
  done  
      
  if test -z "$ZLIB_DIR"; then  
    AC_MSG_ERROR([zlib not installed (http://www.zlib.org)])  
  fi  
      
  PHP_ADD_LIBRARY_WITH_PATH(z,$ZLIB_DIR/lib, ZLIB_SHARED_LIBADD)  
  PHP_ADD_INCLUDE($ZLIB_DIR/include)  
      
  AC_MSG_RESULT([found in $ZLIB_DIR])  
  AC_DEFINE(HAVE_ZLIB,1,[libz found and included])  
      
  PHP_NEW_EXTENSION(zlib, zlib.c, $ext_shared)  
  PHP_SUBST(ZLIB_SHARED_LIBADD)  
fi

config.m4文件很明顯比你迄今為止使用的要大. 幸運的是, 它的語法非常的簡單易懂並且如果你熟悉bash腳本, 對它也就不會陌生.

文件和第5章"你的第一個擴展"中第一次出現的一樣, 都是以PHP_ARG_WITH()宏開始. 這個宏的行為和你用過的PHP_ARG_ENABLE()宏一樣, 不過它將導致./configure時的選項是--with-extname/--without-extname而不再是--enable-extname/--disable-extname.

回顧這些宏, 它們的功能是等同的, 不同僅在於是否讓終端用戶給你的包一些暗示. 你可以在自己創建的私有擴展上使用任意一種方式. 不過, 如果你計劃公開發布, 那就應該知道php正式的編碼標准, 它指出enable/disable用於哪些不需要鏈接外部庫的擴展, with/without則反之.

由於我們這裡假設的擴展將鏈接zlib庫, 因此你的config.m4腳本要以查找擴展源代碼中將包含的zlib.h頭文件. 這通過檢查一些標准位置/usr, /usr/local, /opt中include/zlib目錄下的zlib.h完成對其下兩個目錄的定位.

如果找到了zlib.h, 則將基路徑設置到臨時變量ZLIB_DIR中. 一旦循環完成, config.m4腳本檢查ZLIB_DIR是否包含內容來確定是否找到了zlib.h. 如果沒有找到, 則產生一個有意義的錯誤讓用戶知道./configure不能繼續.

此刻, 腳本假設頭文件存在, 對應的庫也必須存在, 因此在下面的兩行使用它修改構建環境, 最終增加-lz -L$ZLIB_DIR/lib到LDFLAGS以及-I$ZLIB_DIR/include到CFLAGS.

最終, 輸出一個確認消息指示zlib安裝已經找到, 並且在編譯期間使用它的路徑. config.m4的其他部分從前面部分的學習中你應該已經熟悉了. 為config.h定義一個#define, 定義擴展並指定它的源代碼文件, 同時標識一個變量完成將擴展附加到構建系統的工作.

功能測試

迄今為止, 這個config.m4示例指示查找了需要的頭文件. 盡管這已經夠用了, 但它仍然不能確保產生的二進制正確的進行鏈接, 因為可能不存在匹配的庫文件, 或者版本不正確.

最簡單的檢查zlib.h對應的libz.so庫文件是否存在的方式就是檢查文件是否存在:

if ! test -f $ZLIB_DIR/lib/libz.so; then  
  AC_MSG_ERROR([zlib.h found, but libz.so not present!])  
fi

當然, 這僅僅是問題的一面. 如果安裝了其他的同名庫但和你要查找的庫不兼容怎麼辦呢? 確保你的擴展可以成功編譯的最好方式是測試找到的庫實際編譯所需的內容. 要這樣做就需要在config.m4中PHP_ADD_LIBRARY_WITH_PATH調用之前加入下面代碼:

PHP_CHECK_LIBRARY(z, deflateInit,,[  
  AC_MSG_ERROR([Invalid zlib extension, gzInit() not found])  
],-L$ZLIB_DIR/lib)

這個工具宏將展開輸出一個完整的程序, ./configure將嘗試編譯它. 如果編譯成功, 表示第二個參數定義的符號在第一個參數指定的庫中存在. 成功後, 第三個參數中指定的autoconf腳本將會執行; 失敗後, 第四個參數中指定的autoconf腳本將執行. 在這個例子中, 第三個參數為空, 因為沒有消息就是最好的消息(譯注: 應該是unix哲學之一), 第五個參數也就是左後一個參數, 用於指定額外的編譯器和鏈接器標記, 這裡, 使用-L致命了一個額外的用於查找庫的路徑.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved