首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

將 PHP 5 移植到 ARM Linux 完整指南:動態擴展載入 (dlopen) 啟用與交叉編譯技巧

     編輯:PHP 綜合知識

問題背景

在 ARM 嵌入式 Linux (如路由器、開發板) 上交叉編譯 PHP 5 後,`phpinfo()` 顯示:

Dynamic Library support => not available

導致 `dl()`、 `extension=xxx.so` 失效,無法載入任何動態擴展 (PDO、GD、MongoDB 等)。

根本原因

PHP `configure` 階段自動檢測 `dlopen`、`dlsym` 等符號 (通常在 `libdl.so`)。交叉編譯時,**目標板上的庫路徑與編譯機不同**,導致 `configure` 以為目標系統不支援動態載入,將 `HAVE_LIBDL` 設為 0,進而禁用整個動態擴展機制。

解決方案:強制啟用 libdl

  1. 修改主 Makefile (configure 產生後),在 `LDFLAGS` 追加 `-ldl`:
# Makefile 頂部
LDFLAGS = -ldl $(LDFLAGS)
  1. 修改 main/php_config.h (或 `main/php.h`),強制定義宏:
#define HAVE_LIBDL 1
#define HAVE_DLOPEN 1
#define HAVE_DLSYM 1
#define HAVE_DLERROR 1
#define HAVE_DLCLOSE 1
  1. 修改 ext/standard/dl.c,確保包含 ``:
#if defined(HAVE_LIBDL) || defined(HAVE_MACH_O_DYLD_H)
#include 
#include 
#include    // 關鍵:dlopen 系列函數宣告
#endif
  1. 重新編譯安裝:
make clean
make -j$(nproc)
make install

交叉編譯完整流程 (以 arm-linux-gnueabihf 為例)

# 1. 準備工具鏈與 sysroot
export CROSS_COMPILE=arm-linux-gnueabihf-
export SYSROOT=/opt/arm-linux-gnueabihf/sysroot
export CC=${CROSS_COMPILE}gcc
export CXX=${CROSS_COMPILE}g++
export AR=${CROSS_COMPILE}ar
export RANLIB=${CROSS_COMPILE}ranlib
export STRIP=${CROSS_COMPILE}strip
export CFLAGS="--sysroot=$SYSROOT -O2 -pipe"
export LDFLAGS="--sysroot=$SYSROOT -Wl,-rpath-link=$SYSROOT/lib -Wl,-rpath-link=$SYSROOT/usr/lib"

# 2. 依賴庫交叉編譯 (zlib, libxml2, openssl, libcurl, libpng, libjpeg, freetype, libicu 等)
#    建議使用 Buildroot / Yocto / OpenWrt SDK 統一產生 sysroot,避免手動編譯依賴地獄。

# 3. PHP configure
./configure \
  --host=arm-linux-gnueabihf \
  --target=arm-linux-gnueabihf \
  --prefix=/usr/local/php \
  --with-config-file-path=/etc/php \
  --enable-fpm \
  --with-fpm-user=www \
  --with-fpm-group=www \
  --disable-cgi \
  --disable-cli \
  --disable-phpdbg \
  --with-zlib-dir=$SYSROOT/usr \
  --with-libxml-dir=$SYSROOT/usr \
  --with-openssl-dir=$SYSROOT/usr \
  --with-curl=$SYSROOT/usr \
  --with-gd \
  --with-jpeg-dir=$SYSROOT/usr \
  --with-png-dir=$SYSROOT/usr \
  --with-freetype-dir=$SYSROOT/usr \
  --enable-mbstring \
  --enable-sockets \
  --enable-pdo \
  --with-pdo-mysql=mysqlnd \
  --with-mysqli=mysqlnd \
  --enable-bcmath \
  --enable-json \
  --enable-opcache \
  --disable-rpath \
  --disable-debug \
  --without-pear \
  --disable-short-tags \
  --disable-ipv6 \
  --disable-all \
  --enable-libdl   # 部分版本支援此選項,若無則靠後續強制宏

驗證動態擴展載入

# 目標板上
php -m | grep -E 'pdo|gd|mbstring|json'
# 應列出已編譯為 shared 的擴展

php -r "dl('pdo_mysql.so'); echo extension_loaded('pdo_mysql') ? 'OK' : 'FAIL';"
# 輸出 OK 即成功

常見坑點與對策

現象原因解決
configure 报错 `cannot run test program while cross compiling`AC_RUN_IFELSE 試圖在編譯機執行目標二進制設定 `ac_cv_func_dlopen=yes ac_cv_func_dlsym=yes` 等快取變數,或使用 `--cache-file=config.cache` 預填
編譯通過但目標板 `dlopen` 失敗 `libphp5.so: cannot open shared object file`RPATH 未正確指向庫目錄編譯時加 `-Wl,-rpath=/usr/local/php/lib`;運行時 `LD_LIBRARY_PATH=/usr/local/php/lib`
啟用擴展後 PHP-FPM 啟動 segfault擴展與 PHP 核心 API 版本不匹配 (ZEND_MODULE_API_NO)確保擴展與 PHP 同源碼編譯,或使用 `phpize` 重新編譯擴展
靜態編譯擴展 (--enable-xxx=static) 卻仍需 dlopen誤解:static 意味著編入 php 二進制,無需 dlopen嵌入式建議核心擴展 (pdo, mbstring, json) 全部 static,減少 .so 依賴

現代替代:PHP 7/8 + 靜態編譯 + OPcache

PHP 5 已停止維護 (EOL 2018-12-31)。新專案**強烈建議直接交叉編譯 PHP 8.2+**;預設啟用 `libdl`、OPcache JIT、Fiber、JIT 編譯,效能與安全性大幅提升。嵌入式場景可 `--disable-all` 只啟用必要擴展,並全部 `--enable-xxx=static` 產出單一 `php` 二進制,部署極簡。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved