Saturday, January 9, 2016

Shoehorning Development Headers Into PHP for Windows

Introduction

In years past, I've had trouble building PHP modules on Windows because, though PHP packages are available for Windows, they lack the necessary header files to build PHP modules. One solution is to build and install PHP from source, but that takes forever, uses a ton of space, and has a long list of prerequisites. It turns out that it's actually faster and easier to shoehorn in a set of development headers into the already-installed PHP package.

Here's how.

Prerequisites

You will need the following items:

  • A Linux or Unix machine, with a working compiler toolchain. (Actually, a cygwin installation with a working compiler toolchain might suffice but I've never tried it.)
  • The PHP package for Windows.
  • The source code for the same version of PHP as the package.
  • The same version of Microsoft Visual Studio that was used to build the PHP package. The version of VS is discernible in the package filename. For example, php-7.0.2-Win32-VC14-x64.zip was built with Visual Studio 14 (aka Visual Studio 2015).
  • Several bits of software from the gnuwin32 project:

On the Windows machine, install the PHP package into C:\PHP and install Visual Studio.

Install the gnuwin32 software:

  • Create C:\gnuwin32
  • Extract each zip file by right-clicking on it and selecting Extract All.
  • Move the contents of the folders created during the extraction into C:\gnuwin32
  • Add C:\gnuwin32\bin to the PATH environment variable.
    • Open the Control Panel
    • Search for Environment
    • Click the link for "Edit the system environment variables"
    • Click "Environment Variables"
    • In the System Variables pane, scroll down and click on Path
    • Click Edit...
    • Append: ;C:\gnuwin\bin to the Variable Value.
    • Click OK
    • Click OK
    • Click OK

If you can run bison or flex from the command prompt, then it worked.

Building the Headers

Copy the source code to the Linux/Unix machine and extract it. Then build and install the headers somewhere convenient, like your home directory. In this example, we'll use /home/dmuse/php though it could be anywhere.


tar xf php-5.6.17.tar.bz2
cd php-5.6.17
./configure --prefix=/home/dmuse/php
make
make install-headers

Now, copy the entire /home/dmuse/php/include directory to the Windows machine. If the linux/unix machine is visible as a Windows share then you can just drag the directory across the network. Otherwise you can zip or tar it up, contrive to copy it over using scp, ftp, http, or something else, and then extract it by right-clicking on it and selecting Extract All.

Move the includes folder to C:\PHP\dev such that there is now a C:\PHP\dev\include folder. Verify that C:\PHP\dev\include\php exists and that C:\PHP\dev\include\include didn't get created by accident, as sometimes the top-level folder gets duplicated during extraction.

The PHP package now contains most of the headers necessary to develop PHP modules, but a few windows-specific files need to be generated and installed.

Extract the PHP source somewhere convenient on the Windows machine.

Open a Visual Studio command prompt. Make sure to open a prompt for the same architecture as the PHP binary package. For example, if the package is an x86 package, then make sure to open the x86 prompt. If the package is an x64 package, then make sure to open the x64 prompt.

Change directories to the folder that was created when you extracted the PHP source and run the following commands.


buildconf.bat
cscript /nologo configure.js

Then, copy the Windows-specific headers that were built by those commands into the PHP tree:


copy main\config.w32.h C:\PHP\dev\include\php\main
copy TSRM\tsrm_config.w32.h C:\PHP\dev\include\php\TSRM
copy Zend\zend_config.w32.h C:\PHP\dev\include\php\Zend

And that's it. You have now shoehorned development headers into the PHP package for Windows. Good luck building your PHP module!