ホームページ >バックエンド開発 >PHPチュートリアル >PHP 拡張機能をコンパイルする方法
[関連する学習の推奨事項: php プログラミング (ビデオ)]
すでにご存知でしょうPHP自体をコンパイルする方法、次に外部拡張機能をコンパイルします。拡張されたビルド プロセスと利用可能なコンパイル オプションについて説明します。
前の章ですでにご存知のとおり、PHP 拡張機能は静的ライブラリまたは動的ライブラリ (.so
) のいずれかに組み込むことができます。ほとんどの静的ライブラリは PHP にバンドルされてコンパイルされており、動的ライブラリはパラメータ --enable-EXTNAME=shared
または --with-EXTNAME=shared
を ./ に明示的に渡すことができます。構成、設定###。
~/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
make install ステップで、これら 2 つの
.so ファイルこれは、PHP インストールの拡張ディレクトリに移動されます。
php-config --extension-dir コマンドを使用して見つけることができる場合があります。上記のビルド オプションの場合、
/home/myuser/myphp/lib/php/extensions/no-debug-non-zts-MODULE_API になります。この値は、
extension_dir 構成オプションのデフォルト値でもあるため、明示的に指定せずに拡張機能を直接ロードできます:
~/myphp> bin/php -dzend_extension=opcache.so -dextension=gmp.soこれにより、どのメカニズムを使用する必要があるかという疑問が残ります。 ?共有オブジェクトを使用すると、ベースの PHP バイナリを取得し、php.ini を介して追加の拡張機能を読み込むことができます。ディストリビューションは、元の PHP パッケージを通じて、または拡張機能を別個のパッケージとして配布することによって、この機能を利用します。一方、独自の PHP バイナリをコンパイルする場合は、どの拡張機能が必要かすでにわかっているため、おそらくこれは必要ありません。 経験則として、PHP 自体にバンドルされている拡張機能には静的リンクを使用し、他の場所では共有拡張機能を使用します。理由は簡単で、後で説明するように、共有オブジェクトへの外部拡張機能を構築する方が簡単 (または少なくとも煩わしさが少ない) です。もう 1 つの利点は、PHP を再構築せずに拡張機能を更新できることです。
注拡張機能と Zend 拡張機能の違いに関する情報が必要な場合は、専用のセクションを参照してください。PECL から拡張機能をインストールするPECL、
PHP 拡張機能コミュニティ ライブラリ では、多数の PHP 拡張機能が提供されています。拡張機能がメインの PHP ディストリビューションから削除されても、通常は PECL 内に残ります。同様に、現在 PHP にバンドルされている拡張機能の多くは、以前は PECL 拡張機能でした。
PHP ビルドの構成ステップで--without-pear を指定しない限り、
make install は PEAR の一部として PECL をダウンロードしてインストールします。
pecl スクリプトは
$PREFIX/bin ディレクトリにあります。拡張機能のインストールは、
pecl install EXTNAME を実行するだけで簡単になります。例:
~/myphp> bin/pecl install apcuこのコマンドは、APCu 拡張機能をダウンロード、コンパイル、インストールします。結果として、拡張機能ディレクトリに
apcu.so ファイルが作成されます。このファイルは、
extension=apcu.so 構成オプションを渡すことでロードできます。
pecl install はエンド ユーザーにとっては非常に便利ですが、拡張機能開発者の間ではほとんど関心がありません。以下では、拡張機能を手動で構築する 2 つの方法について説明します。拡張機能をメインの PHP ソース ツリーにインポートする (静的リンクを許可する) 方法と、外部で構築する (共有のみ) 方法です。
ext/EXTNAME ディレクトリに配置する必要があります。拡張機能が Git 経由で利用可能な場合は、
ext/:
~/php-src/ext> git clone https://github.com/krakjoe/apcu.gitからリポジトリのクローンを作成するのと同じくらい簡単です。または、ソース tarball をダウンロードして解凍することもできます:
/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拡張機能には、autoconf ファイルで使用される特定の拡張機能のビルド手順を指定する
config.m4 ファイルが含まれます。これらを
/configure スクリプトに含めるには、
./buildconf を再度実行する必要があります。構成ファイルが確実に再生成されるように、事前に構成ファイルを削除することをお勧めします。
~/php-src> rm configure && ./buildconf --forceこれで、
./config.nice スクリプトを使用して、既存の構成に APCu を追加できるようになります。または、新しい構成行から始まります:
~/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
的作用与 ./buildconf
用于 PHP 构建的脚本相似:第一,通过$PREFIX/lib/php/build
复制文件导入 PHP 构建系统到你的扩展中。这些文件是 acinclude.m4
(PHP 的 M4宏)、phpize.m4
(它会在你的扩展中重命名为 configure.in
并包含主要的构建说明)和 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/
目录找到)到正确的扩展目录。
由于在 phpize
阶段还复制了 run-tests.php
文件,因此你可以使用 make test
(或显示调用 run-tests)运行扩展测试。
删除已编译对象的 make clean
也是可用的,并且允许你增量构建失败时强制重新构建扩展。 另外 phpize 提供了一个清理选项 phpize --clean
。该命令将删除所有 phpize
导入的文件和通过 /configure
脚本生成的文件。
PHP CLI 二进制文件提供了几个选项来显示关于扩展的信息。你已经知道 -m
,该命令会列出所有已经下载的扩展。你可以利用它来确定扩展是否正确下载了:
~/myphp/bin> ./php -dextension=apcu.so -m | grep apcu apcu
还有其他一些以 --r
开头的参数都是具有 Reflection 功能。例如,你可以使用 --ri
去显示扩展的配置:
~/myphp/bin> ./php -dextension=apcu.so --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
参数列出扩展添加的所有初始设置、常数、函数和类:
~/myphp/bin> ./php -dextension=apcu.so --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.so --rz "Zend OPcache" Zend Extension [ Zend OPcache 7.0.3-dev Copyright (c) 1999-2013 by Zend Technologies <http://www.zend.com/> ]
如你所见, 该命令没有显示有用的信息。因为 opcache 同时注册了普通扩展和 Zend 扩展, 前者包含所有初始配置、常量和函数。因此在这个特殊的案例中,你仍然需要使用 --re
。其他 Zend 扩展通过 --rz
可得到信息。
扩展对5个主要因素非常敏感。如果它们不合适,则该扩展将不会加载到 PHP中,并将无用:
- PHP Api 版本
- Zend 模块 Api 编号
- Zend 扩展 Api 编号
- 调试模式
- 线程安全
phpize 工具可让你回想它们的一些信息。所以,如果你在调试模式下构建 PHP,并试图加载和使用非调试模式构建的扩展,那它将无法工作。其他检查也一样。
PHP Api 版本 是内部 API 版本号,Zend 模块 Api 编号 和 Zend 扩展 Api 编号 分别与 PHP 扩展和 Zend 扩展 API 有关。
那些编号随后作为 C 宏传递给正在构建的扩展,以便它本身可以检查那些参数,并在 C 预处理器 #ifdef
的基础上采用不同的代码路径。当那些编号作为宏传给扩展代码,它们会被写在扩展结构中,以便你每次尝试在 PHP 二进制文件中加载该扩展时,都将对照 PHP 二进制文件本身的编号进行检查。如果不匹配,那么该扩展不会被加载,并显示一条错误信息。
如果我们看一下扩展的 C 结构,它看起来像这样:
zend_module_entry foo_module_entry = { STANDARD_MODULE_HEADER, "foo", foo_functions, PHP_MINIT(foo), PHP_MSHUTDOWN(foo), NULL, NULL, PHP_MINFO(foo), PHP_FOO_VERSION, STANDARD_MODULE_PROPERTIES };
至今,对我们来说有趣的是 STANDARD_MODULE_HEADER
宏。如果我们扩展它,我们可以看到:
#define STANDARD_MODULE_HEADER_EX sizeof(zend_module_entry), ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS #define STANDARD_MODULE_HEADER STANDARD_MODULE_HEADER_EX, NULL, NULL
注意 ZEND_MODULE_API_NO
、ZEND_DEBUG
、 USING_ZTS
是如何使用的。
如果查看 PHP 扩展的默认目录,它应该像 no-debug-non-zts-20090626
。如你所料,该目录由不同的部分组成:调试模式,其次是线程安全信息,然后是Zend 模块 Api 编号。所以默认情况下,PHP 试图帮你浏览扩展。
注意
通常,当你成为一位内部开发人员或扩展开发人员,必须使用调试参数,并且如果必须处理 Windows 平台,线程也会显示出来。你可以针对那些参数的多种情况多次编译同一扩展。
记住,每次新的 PHP 主要/次要版本都会更改参数,比如 PHP Api 版本,这就是为什么你需要针对新的 PHP 版本重新编译的原因。
> /path/to/php70/bin/phpize -v Configuring for: PHP Api Version: 20151012 Zend Module Api No: 20151012 Zend Extension Api No: 320151012 > /path/to/php71/bin/phpize -v Configuring for: PHP Api Version: 20160303 Zend Module Api No: 20160303 Zend Extension Api No: 320160303 > /path/to/php56/bin/phpize -v Configuring for: PHP Api Version: 20131106 Zend Module Api No: 20131226 Zend Extension Api No: 220131226
注意
Zend 模块 Api 编号 本身是使用 年 月 日 的日期格式构建。这是 API 更改和并被标记的日期。Zend 扩展 Api 编号 是 Zend 版本,其次是 Zend 模块 Api 编号。
注意
数字太多?是的,一个 API 编号绑定一个 PHP 版本,对任何人来说都足够了,并且可以简化对 PHP 的理解。不幸的是,除了 PHP 版本本身,还增加了3种不同的 API 编号。你应该找哪一个?答案是任何一个:当 PHP 版本演变时,它们三种同时演变。由于历史原因,我们有三种不同编号。
但是,你是一位 C开发人员,不是吗?为什么不根据这些数字构建一个“兼容的”头文件?我们在我们的扩展中使用了类似这些:
#include "php.h" #include "Zend/zend_extensions.h" #define PHP_5_5_X_API_NO 220121212 #define PHP_5_6_X_API_NO 220131226 #define PHP_7_0_X_API_NO 320151012 #define PHP_7_1_X_API_NO 320160303 #define PHP_7_2_X_API_NO 320160731 #define IS_PHP_72 ZEND_EXTENSION_API_NO == PHP_7_2_X_API_NO #define IS_AT_LEAST_PHP_72 ZEND_EXTENSION_API_NO >= PHP_7_2_X_API_NO #define IS_PHP_71 ZEND_EXTENSION_API_NO == PHP_7_1_X_API_NO #define IS_AT_LEAST_PHP_71 ZEND_EXTENSION_API_NO >= PHP_7_1_X_API_NO #define IS_PHP_70 ZEND_EXTENSION_API_NO == PHP_7_0_X_API_NO #define IS_AT_LEAST_PHP_70 ZEND_EXTENSION_API_NO >= PHP_7_0_X_API_NO #define IS_PHP_56 ZEND_EXTENSION_API_NO == PHP_5_6_X_API_NO #define IS_AT_LEAST_PHP_56 (ZEND_EXTENSION_API_NO >= PHP_5_6_X_API_NO && ZEND_EXTENSION_API_NO < PHP_7_0_X_API_NO) #define IS_PHP_55 ZEND_EXTENSION_API_NO == PHP_5_5_X_API_NO #define IS_AT_LEAST_PHP_55 (ZEND_EXTENSION_API_NO >= PHP_5_5_X_API_NO && ZEND_EXTENSION_API_NO < PHP_7_0_X_API_NO) #if ZEND_EXTENSION_API_NO >= PHP_7_0_X_API_NO #define IS_PHP_7 1 #define IS_PHP_5 0 #else #define IS_PHP_7 0 #define IS_PHP_5 1 #endif
看见了?
或者更简单(更好)的是使用 PHP_VERSION_ID
,这你可能更熟悉:
#if PHP_VERSION_ID >= 50600
想了解更多编程学习,敬请关注php培训栏目!
以上がPHP 拡張機能をコンパイルする方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。