Chapter 3. Packaging

PHP Packaging

General information

Below we describe the process of creating a portable executable of PHP on a Fedora Core 3 x86-64 host.

We are going to test the portability on Fedora 12 x86-64.

Is PHP packaging really needed?

Maybe we could just copy the php binary from Fedora Core 3 to Fedora 12 and be done with it?

Well, let's try. First just to be sure run the php on Fedora Core 3:

[magicErmine@Fedora3]$ php -v
PHP 4.3.9 (cgi) (built: Oct 20 2004 14:07:20)
Copyright (c) 1997-2004 The PHP Group
Zend Engine v1.3.0, Copyright (c) 1998-2004 Zend Technologies

Looks good.

Now, let's copy the executable to Fedora 12 and try to run it there:

[magicErmine@Fedora12]$ php -v
./php: error while loading shared libraries: libexpat.so.0: cannot open shared object file: No such file or directory

Uh oh! That's not so good. Our simple approach of just copying the executable and hoping it would work has failed -- there is a portability problem.

Packaging -- first attempt

Let's pack php with the following command:

[magicErmine@Fedora3]$ ErminePro /usr/bin/php -o php.ermine.1

then copy php.ermine.1 to the Fedora12 box and run it there:

[magicErmine@Fedora12]$ ./php.ermine.1 -v
PHP Warning:  Unknown(): Unable to load dynamic library '/usr/lib64/php4/curl.so' - /usr/lib64/php4/curl.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning:  Unknown(): Unable to load dynamic library '/usr/lib64/php4/fileinfo.so' - /usr/lib64/php4/fileinfo.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning:  Unknown(): Unable to load dynamic library '/usr/lib64/php4/json.so' - /usr/lib64/php4/json.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning:  Unknown(): Unable to load dynamic library '/usr/lib64/php4/ldap.so' - /usr/lib64/php4/ldap.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning:  Unknown(): Unable to load dynamic library '/usr/lib64/php4/mbstring.so' - /usr/lib64/php4/mbstring.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning:  Unknown(): Unable to load dynamic library '/usr/lib64/php4/mcrypt.so' - /usr/lib64/php4/mcrypt.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning:  Unknown(): Unable to load dynamic library '/usr/lib64/php4/mysql.so' - /usr/lib64/php4/mysql.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning:  Unknown(): Unable to load dynamic library '/usr/lib64/php4/mysqli.so' - /usr/lib64/php4/mysqli.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning:  Unknown(): Unable to load dynamic library '/usr/lib64/php4/pdo.so' - /usr/lib64/php4/pdo.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning:  Unknown(): Unable to load dynamic library '/usr/lib64/php4/pdo_mysql.so' - /usr/lib64/php4/pdo_mysql.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning:  Unknown(): Unable to load dynamic library '/usr/lib64/php4/pdo_sqlite.so' - /usr/lib64/php4/pdo_sqlite.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning:  Unknown(): Unable to load dynamic library '/usr/lib64/php4/phar.so' - /usr/lib64/php4/phar.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning:  Unknown(): Unable to load dynamic library '/usr/lib64/php4/sqlite3.so' - /usr/lib64/php4/sqlite3.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning:  Unknown(): Unable to load dynamic library '/usr/lib64/php4/zip.so' - /usr/lib64/php4/zip.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP 4.3.9 (cgi) (built: Oct 20 2004 14:07:20)
Copyright (c) 1997-2004 The PHP Group
Zend Engine v1.3.0, Copyright (c) 1998-2004 Zend Technologies

Now at least php is able to run. But where do all those warnings come from?

Packaging with php config

php.ermine.1 tried (and failed) to load a bunch of dynamic libraries. How does php know what libraries should be loaded?

As can be seen from php's man page (or from strace -e open /usr/bin/php output) php uses /etc/php.ini as config file.

Here is the relevant part of this file from Fedora Core 3:

;;;;
; Note: packaged extension modules are now loaded via the .ini files
; found in the directory /etc/php.d; these are loaded by default.
;;;;

Our first packaging attempt left out two important things:

  • the php configuration file
  • the php extensions directory

Let's add these to Ermine's configuration file config.2:

# config.2
/etc/php.ini internal
/etc/php.d   internal

And then pack them:

[magicErmine@Fedora3]$ ErminePro /usr/bin/php --config=config.2 --output=php.ermine.2

We copy php.ermine.2 to our Fedora 12 machine and run it:

[magicErmine@Fedora12]$ ./php.ermine.2 -v
PHP Warning:  Unknown(): Unable to load dynamic library '/usr/lib64/php4/ldap.so' - /usr/lib64/php4/ldap.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP 4.3.9 (cgi) (built: Oct 20 2004 14:07:20)
Copyright (c) 1997-2004 The PHP Group
Zend Engine v1.3.0, Copyright (c) 1998-2004 Zend Technologies

Now it looks less scary. If we tak a look at /etc/php.d on the Fedora Core 3 machine, there is only one entry:

[magicErmine@Fedora3]$ ls /etc/php.d/
ldap.ini

While /etc/php.d on our Fedora 12 machine has a bit more:

[magicErmine@Fedora12]$ ls /etc/php.d/
curl.ini      json.ini  mbstring.ini  mysqli.ini  pdo.ini        pdo_sqlite.ini  sqlite3.ini
fileinfo.ini  ldap.ini  mcrypt.ini    mysql.ini   pdo_mysql.ini  phar.ini        zip.ini

Yes - it's better, but the extensions still can't be loaded.

Packaging with extension directory

Lets have a closer look at /etc/php.ini on Fedora Core 3:

; Directory in which the loadable extensions (modules) reside.
extension_dir = /usr/lib64/php4

This directory should be packed too, so we add it to the config file:

# config.3
/etc/php.ini    internal
/etc/php.d      internal
/usr/lib64/php4 internal

And now let's package it again:

[magicErmine@Fedora3]$ ErminePro /usr/bin/php --config=config.3 --output=php.ermine.3

Once more we copy php.ermine.3 to our Fedora 12 machine and run it:

[magicErmine@Fedora12]$ ./php.ermine.3 -v
PHP Warning:  Unknown(): Unable to load dynamic library '/usr/lib64/php4/ldap.so' - libldap-2.2.so.7: cannot open shared object file: No such file or directory in Unknown on line 0
PHP 4.3.9 (cgi) (built: Oct 20 2004 14:07:20)
Copyright (c) 1997-2004 The PHP Group
Zend Engine v1.3.0, Copyright (c) 1998-2004 Zend Technologies

php.ermine.3, like php.ermine.2 is unable to load ldap.so, but the reason is different: php.ermine.2 was unable to find ldap.so itself, while php.ermine.3 is unable to find ldap's dependencies.

Packaging with extension directory and dependencies

While it's possible to chase down the dependencies of all extensions and add them to the config file it is tedious and error-prone. A better solution is to just specify all of those libraries with --ld_preload switch:

[magicErmine@Fedora3]$ ld_preload=`echo /usr/lib64/php4/*.so` && ErminePro /usr/bin/php --config=config.3 --ld_preload="$ld_preload" --output=php.ermine.4

Now we copy php.ermine.4 to our Fedora 12 machine and run it:

[magicErmine@Fedora12]$ ./php.ermine.4 -v
PHP 4.3.9 (cgi) (built: Oct 20 2004 14:07:20)
Copyright (c) 1997-2004 The PHP Group
Zend Engine v1.3.0, Copyright (c) 1998-2004 Zend Technologies

That's perfect!

Perfect?

Obviously php.ermine.4 will now run (and that's a good thing), but php, like a lot of others programs, makes use of NSS (Network Switch Service) libraries. Those libraries weren't packed, so php.ermine.4 is now only running by chance. Let's add the --with-nss='internal' switch.

Finally, here is the command to pack php:

[magicErmine@Fedora3]$ ld_preload=`echo /usr/lib64/php4/*.so` && ErminePro /usr/bin/php --config=config.3 --ld_preload="$ld_preload" --with-nss='internal' --output=php.ermine.5

Now it's really perfect.