Configurations and Links
All the code in the previous example is a standalone version of the C language that you have written in PHP user space. If your project needs to be bonded to the PHP extension, then you need to link at least one external library.
Autoconf
In a simple application, you may have added the following cflags and Ldflags to your makefile.
CFLAGS = ${cflags}-i/usr/local/foobar/includeldflags = ${ldflags}-lfoobar-l/usr/local/foobar/lib
Anyone who wants to build your app without Libfoobar, or installs Libfoobar to another location, will get a processed error message to help him find the cause of the error.
Most of the developed source code software (OSS) and PHP developed over the past decade have used a utility, autoconf, to generate complex configure scripts with a few simple macros. This generated script performs the work of locating the dependent libraries that have header files installed. Based on this information, a package can customize the build line of code, or provide a meaningful error message before the compile time is wasted.
When building PHP extensions, whether you plan to publish publicly or not, you need to use this autoconf mechanism. Even if you are familiar with autoconf, take a few minutes to read this chapter, and PHP introduces some custom macros that are generally installed autoconf not.
Unlike the traditional autoconf step (the centralized Configure.in file contains all the configuration macros for the package), PHP uses configure.in to manage the coordination of small CONFIG.M4 scripts under many bit domain source trees, including the various extensions, SAPI, core itself, and Zendengine.
You have seen a simple version of CONFIG.M4 in the previous section. Next, we'll add additional autoconf syntax to this file, allowing your extension to collect more configuration-time information.
Find a library
The config.m4 script is used at most to check whether the dependent libraries are installed. Extensions such as MySQL, LDAP, GMP, and other features designed for PHP user space and C libraries to implement the glue layer extension. If their dependent libraries are not installed, or if the installed version is too old, either compiles the error or causes the resulting binary to not run.
Header file Scan
The simplest step in a dependent library scan is to examine the included files in your script, which will be used when linking. The following code tries to find zlib.h in some common locations:
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 doing if test-z "$ZLIB _dir"; Then Ac_msg_error ([Zlib not Installed (http://www.php.cn/)]) 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
The CONFIG.M4 file is significantly larger than you have used so far. Fortunately, its syntax is very simple and easy to understand, and if you are familiar with the bash script, it is no stranger to it.
The first occurrence of the file and the 5th chapter "Your first extension" begins with the Php_arg_with () macro. This macro behaves the same as the php_arg_enable () macro you used, but it will cause./configure when the option is--with-extname/--without-extname and no longer--enable-extname/-- Disable-extname.
Looking back at these macros, they are functionally equivalent, depending only on whether the end user gives your package some hint. You can use either method on a private extension that you create. However, if you plan to publish publicly, you should be aware of PHP's formal coding standards, which indicate that enable/disable is used for extensions that do not need to link to external libraries, whereas with/without is not.
Since the extensions we assume here will link the zlib library, your CONFIG.M4 script will be looking for zlib.h header files that will be included in the extension source code. This is done by checking some of the standard locations in/usr,/usr/local,/opt in the Include/zlib directory under Zlib.h to complete the positioning of their next two directories.
If Zlib.h is found, the base path is set to the temporary variable Zlib_dir. Once the loop is complete, the Config.m4 script checks whether Zlib_dir contains content to determine if zlib.h is found. If not found, a meaningful error is generated to let the user know./configure cannot continue.
At this point, the script assumes that the header file exists and that the corresponding library must exist, so use it in the following two lines to modify the build environment, eventually adding-lz-l$zlib_dir/lib to Ldflags and-i$zlib_dir/include to Cflags.
Finally, the output of a confirmation message indicates that the zlib installation has been found and uses its path during compilation. Other parts of config.m4 you should have been familiar with the previous part of the study. Defines a # define for Config.h, defines the extension and specifies its source code file, and identifies a variable that completes the work of attaching the extension to the build system.
Functional Testing
To date, this CONFIG.M4 example indicates that the desired header file was found. Although this is sufficient, it still does not ensure that the resulting binary is properly linked, because there may not be a matching library file, or the version is incorrect.
The simplest way to check if the zlib.h corresponding libz.so library file exists is to check if the file exists:
if! Test-f $ZLIB _dir/lib/libz.so; Then ac_msg_error ([zlib.h found, but libz.so not present!]) Fi
Of course, this is only one side of the problem. What if another library with the same name is installed but not compatible with the library you are looking for? The best way to ensure that your extension compiles successfully is to test what is needed to actually compile the found library. To do this, you need to add the following code before the Php_add_library_with_path call in CONFIG.M4:
Php_check_library (z, deflateinit,,[ ac_msg_error ([Invalid zlib extension, gzinit () not found])],-l$zlib_dir/lib)
This tool macro will expand the output of a complete program,./configure will attempt to compile it. If the compilation succeeds, the symbol that represents the second parameter definition exists in the library specified by the first parameter. After success, the autoconf script specified in the third parameter will be executed; After the failure, the autoconf script specified in the fourth parameter executes. In this example, the third argument is null, because no message is the best message (it should be one of the Unix philosophies), the fifth parameter is the left-hand argument, which specifies the additional compiler and linker tags, where the use of-L is fatal to an additional path to find the library.
Optional features
So now that you have the correct library and header file, but what version of the library are you relying on? You may need certain features or exclude certain features. Because this type of change usually involves the addition or deletion of certain entry points, you can reuse the Php_check_library () macro to check some of the library's capabilities.
Php_check_library (z, gzgets,[ ac_define (have_zlib_gets,1,[having gzgets indicates ZLIB >= 1.0.9])],[ AC_ Msg_warn ([Zlib < 1.0.9 installed, Gzgets () won't be available])],-l$zlib_dir/lib)
Test the actual behavior
It is possible to know that a symbol exists and does not ensure that your code compiles correctly; Certain versions of some libraries may have bugs that need to run some test code to check.
Ac_try_run () macros can compile a small source code file for the executable program and execute it. Depending on the return code passed back to the./configure, your script can set an optional # define statement or direct output message (such as prompting for escalation if a bug causes a failure to work) to safely exit. Consider the following code (excerpt from EXT/STANDARD/CONFIG.M4):
Ac_try_run ([#include <math.h>double somefn (double n) { return floor (N*pow (10,2) + 0.5);} int main () { return Somefn (0.045)/10.0! = 0.5;}],[ php_round_fuzz=0.5 ac_msg_result (yes)],[ php_ round_fuzz=0.50000000001 Ac_msg_result (NO)],[ php_round_fuzz=0.50000000001 Ac_msg_result (cross Compile)] ac_define_unquoted (Php_round_fuzz, $PHP _round_fuzz, [is double precision imprecise?])
As you can see, the first parameter of Ac_try_run () is a C language code that will be compiled and executed. If the exit code for this code is 0, the autoconf script located in the second parameter is executed, which identifies the round () function as expected and returns 0.5.
If the code block returns a value other than 0, the autoconf script for the third parameter of the bit field is executed. The fourth parameter (the last one) is used when PHP is cross-compiling. In this case, it is meaningless to try to run the sample code because the target platform is different from the one used when the extension was compiled.
Force module Dependencies
In PHP 5.1, the internal dependencies between extensions can be mandatory. Because extensions can be statically built into PHP, they can also be built to load dynamically for shared objects, so forcing dependencies needs to be implemented in two places.
module dependencies when configuring
The first position is in the Config.m4 file you just saw in this chapter's course. You can use PHP_ADD_EXTENSION_DEP (Extname, depname[, optional]) Macro Identity extname This extension relies on the depname extension. When Extname is statically constructed into PHP, the./configure script will use this line of code to confirm that the Depname must be initialized first. The optional parameter is a token that is used to identify if the depname is statically constructed and should be loaded before extname, but it is not a required dependency.
One use example of this macro is the PDO driver, such as Pdo_mysql, which is predictable depending on the PDO extension:
Ifdef ([php_add_extendion_dep],[ PHP_ADD_EXTENSION_DEP (Pdo_mysql, PDO)])
Note that the PHP_ADD_EXTENSION_DEP () macro is wrapped in a ifdef () structure. This is because PDO and its drivers exist when compiling PHP greater than or equal to version 5.0, whereas the PHP_ADD_EXTENSION_DEP () macro is not present until the 5.1.0 version.
Run-time module dependencies
Another place where you need to register depends on the zend_module_entry structure. Consider the zend_module_entry structure you defined in the 5th chapter below:
Zend_module_entry sample_module_entry = {#if zend_module_api_no >= 20010901 Standard_module_header, #endif Php_sample_extname, php_sample_functions, null,/* Minit */ NULL,/* Mshutdown */ NULL,/* Rinit * / NULL,/* Rshutdown */ NULL,/* MINFO */#if zend_module_api_no >= 20010901 php_sample_extver, #endif standard_module_properties};
Increasing the runtime module dependency information requires some minor modifications to the Standard_moudle_header section:
Zend_module_entry sample_module_entry = {#if zend_module_api_no >= 220050617 standard_module_header_ex, NULL, php_sample_deps, #elif zend_module_api_no >= 20010901 Standard_module_header, #endif php_sample_extname, php_sample_functions, null,/* Minit */ NULL,/* Mshutdown */ NULL,/* Rinit */ NULL,/* Rshutdown */ NULL,/* MINFO */#if zend_module_api_no >= 20010901
php_sample_extver, #endif standard_module_properties};
Now, if Zend_module_api_no is higher than the PHP 5.1.0 beta release, then Standard_module_header (here's the original clerical error is standard_module_properties) will be replaced by a slightly more complex structure that will contain a reference to the module dependency information.
This target structure can be defined on your Zend_module_entry structure as follows:
#if zend_module_api_no >= 220050617static zend_module_dep php_sample_deps[] = { zend_module_required ("zlib") {null,null,null}}; #endif
Similar to zend_function_entry vectors, this list can have multiple dependencies, which are checked in order. If an attempt to load a dependent module is not met, Zend will break the load and the report does not meet the dependent name so that the end user can solve the problem by loading the other modules first.
Windows dialect
Because the translator is unfamiliar with the Windows environment, skip this section.
Summary
If your extension will be built in an unknown or uncontrollable environment, it is important to make it smart enough to cope with a strange environment. Using PHP's powerful scripting capabilities on UNIX and Windows, you should be able to detect trouble and give her a solution before an unknown administrator needs to call for help.
Now that you have the basic ability to build PHP extensions from scratch using the PHP API, you are ready to learn how to use the extended development tools provided by PHP to liberate yourself from heavy repetitive work, and use them to quickly and accurately build new, expanded prototypes.
The above is [translation][php extension development and Embedded] 17th Chapter-php Source code configuration and link content, more relevant content please pay attention to topic.alibabacloud.com (www.php.cn)!