构建PHP扩展
在了解了如何编译 PHP 本身之后,我们将开始编译其他扩展。我们将讨论编译过程是如何工作的,以及有哪些不同的选项。
加载共享扩展
如前所述,PHP 扩展既可以静态联入 PHP 二进制文件,也可以编译成共享对象(.so
)。静态链接是大多数捆绑扩展的默认方式,而共享对象可以通过在 ./configure
中明确传递 --enable-EXTNAME=shared
或 --with-EXTNAME=shared
来创建。
静态扩展总是可用的,而共享扩展则需要使用 extension
或 zend_extension
ini 选项加载。这两个选项要么使用 .so
文件的绝对路径,要么使用 extension_dir
设置的相对路径。
举例来说,使用以下配置行编译 PHP 代码:
~/php-src> ./configure --prefix=$HOME/myphp \
--enable-debug --enable-maintainer-zts \
--enable-opcache --with-gmp=shared
在这种情况下,opcache
扩展和 GMP
扩展都被编译成共享对象,位于 modules/
目录下。您可以通过更改 extension_dir
或传递绝对路径来加载这两个扩展:
~/php-src> sapi/cli/php -dzend_extension=`pwd`/modules/opcache.so \
-dextension=`pwd`/modules/gmp.so
# or
~/php-src> sapi/cli/php -dextension_dir=`pwd`/modules \
-dzend_extension=opcache.so -dextension=gmp.so
# or (since PHP 7.2 the .so is optional)
~/php-src> sapi/cli/php -dextension_dir=`pwd`/modules \
-dzend_extension=opcache -dextension=gmp
在 make install
步骤中,两个 .so
文件都将被移入 PHP 安装的扩展目录,可以使用 php-config --extension-dir
命令找到该目录。在上述构建选项中,该目录将是 /home/myuser/myphp/lib/php/extensions/no-debug-non-zts-MODULE_API
。该值也将是 extension_dir
ini 选项的默认值,因此无需明确指定,可以直接加载扩展:
~/myphp> bin/php -dzend_extension=opcache -dextension=gmp
这就给我们留下了一个问题: 应该使用哪种机制?共享对象允许你拥有一个基本的 PHP 二进制文件,并通过 php.ini 加载额外的扩展。发行版就是利用了这一点,提供了一个基本的 PHP 包,并将扩展作为单独的包发行。另一方面,如果你正在编译自己的 PHP 二进制文件,你可能不需要这样做,因为你已经知道自己需要哪些扩展。
根据经验,PHP 本身捆绑的扩展会使用静态链接,而其他扩展则使用共享链接。原因很简单,将外部扩展构建为共享对象更容易(或至少不那么麻烦),稍后就会明白。另一个好处是可以更新扩展而无需重建 PHP。
如果你需要了解扩展和 Zend 扩展之间的区别, 可以参阅专门章节。 |
从PECL安装扩展
PECL 是 PHP 扩展社区库,为 PHP 提供了大量扩展。当扩展从主要的 PHP 发行版中移除时,它们通常会继续存在于 PECL 中。同样,现在与 PHP 捆绑的许多扩展以前也是 PECL 扩展。
如果在构建 PHP 的配置阶段指定了 --with-pear
,make install
将下载并安装作为 PEAR 一部分的 PECL。您可以在 $PREFIX/bin
目录中找到 pecl
脚本。现在,安装扩展只需运行 pecl install EXTNAME
即可,例如:
~/myphp> bin/pecl install apcu
该命令将下载、编译并安装 APCu 扩展。其结果是在扩展目录下生成 apcu.so
文件,然后通过 extension=apcu
ini 选项加载该文件。
虽然 pecl install
对于最终用户来说非常方便,但对于扩展开发人员来说却并不重要。下面,我们将介绍两种手动构建扩展的方法: 一种是将其导入主 PHP 源代码树(允许静态链接),另一种是进行外部编译(只能共享)。
增加扩展到PHP源码树
第三方扩展与捆绑在 PHP 中的扩展没有本质区别。因此,只需将外部扩展复制到 PHP 源代码树中,然后使用通常的构建过程,就可以构建外部扩展。我们将以 APCu 为例进行演示。
首先,您需要将扩展的源代码放到 PHP 源代码树的 ext/EXTNAME
目录中。如果扩展是通过 git 提供的,则只需从 ext/
目录中克隆源代码即可:
~/php-src/ext> git clone https://github.com/krakjoe/apcu.git
或者,您也可以下载源代码压缩包并解压缩:
/tmp> wget http://pecl.php.net/get/apcu-4.0.2.tgz
/tmp> tar xzf apcu-4.0.2.tgz
/tmp> mkdir ~/php-src/ext/apcu
/tmp> cp -r apcu-4.0.2/. ~/php-src/ext/apcu
扩展将包含一个 config.m4
文件,其中指定了供 autoconf 使用的特定扩展编译指令。要将其纳入 ./configure
脚本,必须再次运行 ./buildconf
。为确保 configure 文件真正重新生成,建议事先将其删除:
~/php-src> rm configure && ./buildconf
现在,您可以使用 ./config.nice
脚本将 APCu 添加到现有配置中,或使用全新的 configure 行重新开始:
~/php-src> ./config.nice --enable-apcu
# or
~/php-src> ./configure --enable-apcu # --other-options
最后运行 make -jN
执行实际构建。由于我们没有使用 --enable-apcu=shared
,扩展会静态链接到 PHP 二进制文件中,也就是说,不需要额外的操作就可以使用它。当然,也可以使用 make install
安装生成的二进制文件。
使用phpize构建扩展
通过使用在构建 PHP 部分已经提到过的 phpize
脚本,也可以在 PHP 之外单独构建扩展。
phpize
的作用与用于 PHP 构建的 ./buildconf
脚本类似: 首先,它将从 $PREFIX/lib/php/build
中复制文件,将 PHP 编译系统导入到扩展中。这些文件包括 php.m4
(PHP 的 M4 宏)、phpize.m4
(在扩展中将更名为 configure.ac
,包含主要的构建说明)和 run-tests.php
。
然后,phpize
将调用 autoconf
生成 ./configure
文件,该文件可用于自定义扩展的构建。请注意,无需向其传递 --enable-apcu
,因为它会隐含地假定这一点。相反,你应该使用 --with-php-config
来指定 php-config
脚本的路径:
/tmp/apcu-4.0.2> ~/myphp/bin/phpize
Configuring for:
PHP Api Version: 20121113
Zend Module Api No: 20121113
Zend Extension Api No: 220121113
/tmp/apcu-4.0.2> ./configure --with-php-config=$HOME/myphp/bin/php-config
/tmp/apcu-4.0.2> make -jN && make install
在构建扩展时,应始终指定 --with-php-config
选项(除非只安装了一个PHP的全局安装),否则 ./configure
将无法正确确定要构建的PHP版本和标志。指定 php-config
脚本还能确保 make install
将生成的 .so
文件(可在 modules/
目录中找到)移动到正确的扩展目录。
由于 run-tests.php
文件也在 phpize
阶段被复制,因此可以使用 make test
(或明确调用 run-tests.php
)运行扩展测试。
make clean
目标也可用于删除已编译的对象,如果增量构建在更改后失败,它允许你强制重建扩展。此外,phpize 还提供了 phpize --clean
清理选项。这将删除 phpize
导入的所有文件,以及 ./configure
脚本生成的文件。
显示关于扩展的信息
PHP CLI 二进制程序提供了几个选项来显示有关扩展的信息。您已经知道 -m
,它会列出所有已加载的扩展。您可以用它来验证扩展是否已正确加载:
~/myphp/bin> ./php -dextension=apcu -m | grep apcu
apcu
还有几种以 --r
开头的开关可以显示 Reflection 功能。例如,你可以使用 --ri
来显示扩展的配置:
~/myphp/bin> ./php -dextension=apcu --ri apcu
apcu
APCu Support => disabled
Version => 4.0.2
APCu Debugging => Disabled
MMAP Support => Enabled
MMAP File Mask =>
Serialization Support => broken
Revision => $Revision: 328290 $
Build Date => Jan 1 2014 16:40:00
Directive => Local Value => Master Value
apc.enabled => On => On
apc.shm_segments => 1 => 1
apc.shm_size => 32M => 32M
apc.entries_hint => 4096 => 4096
apc.gc_ttl => 3600 => 3600
apc.ttl => 0 => 0
# ...
选项 --re
会列出扩展添加的所有 ini 设置、常量、函数和类:
~/myphp/bin> ./php -dextension=apcu --re apcu
Extension [ <persistent> extension #27 apcu version 4.0.2 ] {
- INI {
Entry [ apc.enabled <SYSTEM> ]
Current = '1'
}
Entry [ apc.shm_segments <SYSTEM> ]
Current = '1'
}
# ...
}
- Constants [1] {
Constant [ boolean APCU_APC_FULL_BC ] { 1 }
}
- Functions {
Function [ <internal:apcu> function apcu_cache_info ] {
- Parameters [2] {
Parameter #0 [ <optional> $type ]
Parameter #1 [ <optional> $limited ]
}
}
# ...
}
}
--re
开关只适用于普通扩展,Zend 扩展则使用 --rz
。你可以在 opcache 上试试:
~/myphp/bin> ./php -dzend_extension=opcache --rz "Zend OPcache"
Zend Extension [ Zend OPcache 7.0.3-dev Copyright (c) 1999-2013 by Zend Technologies <http://www.zend.com/> ]
正如你所看到的,这不会显示任何有用的信息。原因是 opcache 注册了普通扩展和 Zend 扩展,前者包含所有 ini 设置、常量和函数。因此,在这种特殊情况下,你仍然需要使用 --re
。 不过,其他 Zend 扩展可以通过 --rz
获取信息。