PHP 擴展若依賴外部 C 庫 (如 libxml2, OpenSSL, zlib, libcurl),需在 config.m4 中實作依賴檢測、頭文件掃描、庫功能測試與建構旗標注入。本文以 zlib 為例完整示範標準流程。
| 宏 | 用途 | 產生 configure 選項 |
|---|---|---|
PHP_ARG_ENABLE | 無外部依賴的功能開關 | --enable-extname / --disable-extname |
PHP_ARG_WITH | 有外部依賴的功能開關 | --with-extname / --without-extname |
PHP_ADD_INCLUDE | 加入 CFLAGS (-I 路徑) | — |
PHP_ADD_LIBRARY_WITH_PATH | 加入 LDFLAGS (-l 庫 -L 路徑) | — |
PHP_CHECK_LIBRARY | 編譯測試庫符號是否存在 | — |
PHP_SUBST | 變數替換到 Makefile | — |
PHP_NEW_EXTENSION | 宣告擴展源檔 | — |
AC_DEFINE | 定義 config.h 巨集 | — |
AC_MSG_ERROR | 輸出錯誤並中止 configure | — |
AC_MSG_RESULT | 輸出檢測結果 | — |
PHP_ARG_WITH(zlib, [for zlib Support],
[ --with-zlib Include ZLIB Support])
if test "$PHP_ZLIB" != "no"; then
# 1. 掃描頭文件路徑
ZLIB_DIR=""
for i in /usr /usr/local /opt; do
if test -f $i/include/zlib/zlib.h; then
ZLIB_DIR=$i
break
fi
done
# 2. 未找到 → 報錯
if test -z "$ZLIB_DIR"; then
AC_MSG_ERROR([zlib not installed (https://www.zlib.org)])
fi
# 3. 註冊建構旗標
PHP_ADD_LIBRARY_WITH_PATH(z, $ZLIB_DIR/lib, ZLIB_SHARED_LIBADD)
PHP_ADD_INCLUDE($ZLIB_DIR/include)
# 4. 定義 config.h 巨集
AC_DEFINE(HAVE_ZLIB, 1, [libz found and included])
# 5. 功能測試:確認關鍵符號存在
PHP_CHECK_LIBRARY(z, deflateInit, , [
AC_MSG_ERROR([Invalid zlib extension, deflateInit() not found])
], -L$ZLIB_DIR/lib)
# 6. 宣告擴展
PHP_NEW_EXTENSION(zlib, zlib.c, $ext_shared)
PHP_SUBST(ZLIB_SHARED_LIBADD)
fi
--with-zlib 選項。/usr, /usr/local, /opt) 下的 include/zlib/zlib.h。LDFLAGS (加入 -lz -L$ZLIB_DIR/lib) 並設定 ZLIB_SHARED_LIBADD 變數供共享模組鏈接。CFLAGS (加入 -I$ZLIB_DIR/include)。deflateInit 符號存在。防止「頭文件有但庫版本不符/缺失」導致鏈接失敗或運行崩潰。PHP_CHECK_LIBRARY(library, symbol, action-if-found, action-if-not-found, extra-flags)
# library: 庫名 (不含 lib 前綴,如 "z" 對應 libz)
# symbol: 要測試的函式/變數名稱
# action-if-found: 成功時執行的 autoconf 代碼 (通常為空)
# action-if-not-found: 失敗時執行 (通常 AC_MSG_ERROR)
# extra-flags: 額外編譯/鏈接旗標 (如 -L 路徑)
# OpenSSL
PHP_ARG_WITH(openssl, [for OpenSSL support], [--with-openssl])
if test "$PHP_OPENSSL" != "no"; then
# 掃描 openssl/ssl.h
# PHP_ADD_LIBRARY_WITH_PATH(ssl, $OPENSSL_DIR/lib, OPENSSL_SHARED_LIBADD)
# PHP_ADD_LIBRARY_WITH_PATH(crypto, $OPENSSL_DIR/lib, OPENSSL_SHARED_LIBADD)
# PHP_CHECK_LIBRARY(ssl, SSL_library_init, , [AC_MSG_ERROR([OpenSSL too old])])
# AC_DEFINE(HAVE_OPENSSL, 1, [OpenSSL support])
# PHP_NEW_EXTENSION(openssl, openssl.c, $ext_shared)
# PHP_SUBST(OPENSSL_SHARED_LIBADD)
fi
# libcurl
PHP_ARG_WITH(curl, [for cURL support], [--with-curl])
if test "$PHP_CURL" != "no"; then
# 掃描 curl/curl.h
# PHP_ADD_LIBRARY_WITH_PATH(curl, $CURL_DIR/lib, CURL_SHARED_LIBADD)
# PHP_CHECK_LIBRARY(curl, curl_easy_init, , [AC_MSG_ERROR([libcurl >= 7.10.0 required])])
# ...
fi
現代庫多提供 .pc 檔案,可簡化路徑掃描:
if test "$PHP_ZLIB" != "no"; then
if pkg-config --exists zlib; then
ZLIB_CFLAGS=$(pkg-config --cflags zlib)
ZLIB_LIBS=$(pkg-config --libs zlib)
PHP_EVAL_INCLINE($ZLIB_CFLAGS)
PHP_EVAL_LIBLINE($ZLIB_LIBS, ZLIB_SHARED_LIBADD)
AC_DEFINE(HAVE_ZLIB, 1, [zlib found via pkg-config])
PHP_NEW_EXTENSION(zlib, zlib.c, $ext_shared)
PHP_SUBST(ZLIB_SHARED_LIBADD)
else
AC_MSG_ERROR([zlib not found via pkg-config])
fi
fi
PHP_ARG_WITH (有外部依賴) / PHP_ARG_ENABLE (無依賴)。PHP_CHECK_LIBRARY**,僅掃描頭文件不足以保證鏈接成功。AC_MSG_ERROR 訊息 (含官網連結、最低版本要求)。--with-libname=/custom/path 讓使用者指定自訂安裝路徑。php_sample.h 中 #ifdef HAVE_LIBNAME 保護相關代碼。