Running php 5.2 fpm on ARM processor

Compiling from sources

Since there is no old php releases in modern linux distros we’re obviously going to compile everything from scratch. For our purposes we’ll use ubuntu 15.04, let’s download php sources from PHP museum: $ mkdir -p /mnt/build/ && cd /mnt/build/ $ wget http://museum.php.net/php5/php-5.2.17.tar.gz && tar -xf php-5.2.17.tar.gz $ apt-get install -y build-essential nano wget curl libbz2-dev libncurses5-dev autoconf libxml2-dev

PHP-FPM patch

For historical reasons, Fast Process Manager(FPM) for 5.2.X branch exists only in the form of patch. Let’s download this patch and apply it the most recent 5.2 version: $ cd php-5.2.17/ $ wget http://php-fpm.org/downloads/php-5.2.17-fpm-0.5.14.diff.gz && gzip -d php-5.2.17-fpm-0.5.14.diff.gz $ patch -p1 < php-5.2.17-fpm-0.5.14.diff patching file configure Hunk #7 succeeded at 110645 (offset 1324 lines). Hunk #8 succeeded at 118930 (offset 1324 lines). Hunk #9 succeeded at 119634 (offset 1324 lines). Hunk #10 succeeded at 119689 (offset 1324 lines). patching file configure.in patching file libevent/ChangeLog patching file libevent/Makefile.am patching file libevent/Makefile.in patching file libevent/README patching file libevent/aclocal.m4 After this operation --enable-fpm option becomes available in ./configure script: $ ./configure --help | grep "fpm" --enable-fpm FastCGI: If this is enabled, the fastcgi support --with-fpm-conf=PATH Set the path for php-fpm configuration file [PREFIX/etc/php-fpm.conf] --with-fpm-log=PATH Set the path for php-fpm log file [PREFIX/logs/php-fpm.log] --with-fpm-pid=PATH Set the path for php-fpm pid file [PREFIX/logs/php-fpm.pid] Let’s try to compile php with FPM support: $ ./configure --prefix=/opt/php52 --enable-fastcgi --enable-fpm loading cache ./config.cache checking for Cygwin environment... no checking for mingw32 environment... no checking for egrep... grep -E checking for a sed that does not truncate output... /bin/sed checking host system type... armv7l-unknown-linux-gnueabi checking target system type... armv7l-unknown-linux-gnueabi checking for gcc... gcc checking whether the C compiler (gcc ) works... yes checking whether the C compiler (gcc ) is a cross-compiler... no checking whether we are using GNU C... yes .... Thank you for using PHP. So far, everything is looking fine. Let’s try to build it by running make using 4 ARM cores to speedup process: $ make -j4 /bin/sh /mnt/build/php-5.2.17/libtool --silent --preserve-dup-deps --mode=compile gcc -Iext/date/lib -Iext/date/ -I/mnt/build/php-5.2.17/ext/date/ -DPHP_ATOM_ INC -I/mnt/build/php-5.2.17/include -I/mnt/build/php-5.2.17/main -I/mnt/build/php-5.2.17 -I/mnt/build/php-5.2.17/ext/date/lib -I/usr/include/libxml2 -I/mnt/bu ild/php-5.2.17/TSRM -I/mnt/build/php-5.2.17/Zend -I/usr/include -g -O2 -c /mnt/build/php-5.2.17/ext/date/php_date.c -o ext/date/php_date.lo /bin/sh /mnt/build/php-5.2.17/libtool --silent --preserve-dup-deps --mode=compile gcc -Iext/date/lib -Iext/date/ -I/mnt/build/php-5.2.17/ext/date/ -DPHP_ATOM_ INC -I/mnt/build/php-5.2.17/include -I/mnt/build/php-5.2.17/main -I/mnt/build/php-5.2.17 -I/mnt/build/php-5.2.17/ext/date/lib -I/usr/include/libxml2 -I/mnt/bu ild/php-5.2.17/TSRM -I/mnt/build/php-5.2.17/Zend -I/usr/include -g -O2 -c /mnt/build/php-5.2.17/ext/date/lib/astro.c -o ext/date/lib/astro.lo .......... /mnt/build/php-5.2.17/ext/dom/node.c: In function ‘dom_canonicalization’: /mnt/build/php-5.2.17/ext/dom/node.c:1953:21: error: dereferencing pointer to incomplete type ‘xmlBuf {aka struct _xmlBuf}’ ret = buf->buffer->use; ^ Makefile:553: recipe for target 'ext/dom/node.lo' failed make: *** [ext/dom/node.lo] Error 1

libxml2 patching

And boom! We’re stuck with the first error: dereferencing pointer to incomplete type xmlBuf {aka struct _xmlBuf}. After googling around, the problem seems to be related to libxml2 incompatibility and is well documented. Let’s fix that error by applying yet another patch: $ wget https://github.com/bananos/dockerized/raw/master/armbuild-php52/patches/libxml29_compat.patch $ patch -p1 < libxml29_compat.patch patching file ext/dom/node.c Hunk #1 succeeded at 1950 (offset 55 lines). patching file ext/dom/documenttype.c Hunk #1 succeeded at 215 (offset 10 lines). patching file ext/simplexml/simplexml.c Hunk #1 succeeded at 1343 (offset -74 lines). And run make once again: $ make -j4 ...... In file included from /mnt/build/php-5.2.17/sapi/cgi/fpm/fpm_shm_slots.h:8:0, from /mnt/build/php-5.2.17/sapi/cgi/fpm/fpm_children.c:28: /mnt/build/php-5.2.17/sapi/cgi/fpm/fpm_atomic.h:62:2: error: #error unsupported processor. please write a patch and send it to me #error unsupported processor. please write a patch and send it to me ^ /mnt/build/php-5.2.17/sapi/cgi/fpm/fpm_atomic.h:66:32: error: unknown type name ‘atomic_t’ static inline int fpm_spinlock(atomic_t *lock, int try_once) ^ In file included from /mnt/build/php-5.2.17/sapi/cgi/fpm/fpm_children.c:28:0: /mnt/build/php-5.2.17/sapi/cgi/fpm/fpm_shm_slots.h:16:3: error: unknown type name ‘atomic_t’ atomic_t lock; ^ In file included from /mnt/build/php-5.2.17/sapi/cgi/fpm/fpm_shm_slots.h:8:0, from /mnt/build/php-5.2.17/sapi/cgi/fpm/fpm_worker_pool.c:15: /mnt/build/php-5.2.17/sapi/cgi/fpm/fpm_atomic.h:62:2: error: #error unsupported processor. please write a patch and send it to me #error unsupported processor. please write a patch and send it to me ^ /mnt/build/php-5.2.17/sapi/cgi/fpm/fpm_atomic.h:66:32: error: unknown type name ‘atomic_t’ static inline int fpm_spinlock(atomic_t *lock, int try_once) ^ In file included from /mnt/build/php-5.2.17/sapi/cgi/fpm/fpm_worker_pool.c:15:0: /mnt/build/php-5.2.17/sapi/cgi/fpm/fpm_shm_slots.h:16:3: error: unknown type name ‘atomic_t’ atomic_t lock; ^ Makefile:433: recipe for target 'sapi/cgi/fpm/fpm_worker_pool.lo' failed make: *** [sapi/cgi/fpm/fpm_worker_pool.lo] Error 1 make: *** Waiting for unfinished jobs.... Makefile:431: recipe for target 'sapi/cgi/fpm/fpm_children.lo' failed make: *** [sapi/cgi/fpm/fpm_children.lo] Error 1 Well, this is embarrassing. As we can see from compiler logs, the FPM author suggests us to write a patch and send it to him because current CPU type is not supported. Obviously, the first thing I did was to try google yet another patch to solve this problem, but unfortunately, there is no one — people moved on to newer PHP versions and no one cared enough to write a fix. Therefore, we’re going to write our own patch. Let’s take a look at /mnt/build/php-5.2.17/sapi/cgi/fpm/fpm_atomic.h:62:2 /* $Id: fpm_atomic.h,v 1.3 2008/09/18 23:34:11 anight Exp $ */ /* (c) 2007,2008 Andrei Nigmatulin */ #ifndef FPM_ATOMIC_H #define FPM_ATOMIC_H 1 #include <stdint.h> #include <sched .h> #if ( __i386__ || __i386 ) typedef int32_t atomic_int_t; typedef uint32_t atomic_uint_t; typedef volatile atomic_uint_t atomic_t; static inline atomic_int_t atomic_fetch_add(atomic_t *value, atomic_int_t add) { __asm__ volatile ( "lock;" "xaddl %0, %1;" : "+r" (add) : "m" (*value) : "memory"); return add; } static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, atomic_uint_t set) { unsigned char res; __asm__ volatile ( "lock;" "cmpxchgl %3, %1;" "sete %0;" : "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "memory"); return res; } #elif ( __amd64__ || __amd64 ) // definitions of the same functions for AMD64 #else #error unsupported processor. please write a patch and send it to me #endif

Atomic types

Looks like we need to define those 2 functions for ARM platform. But how do we do it without proper knowledge of C and specifics of armhf architecture? Luckily, we may steal some code from newer PHP versions, which do work in FPM mode on ARM platform. Go to https://github.com/php/php-src/blob/PHP-5.3/sapi/fpm/fpm/fpm_atomic.h and take a look at source code: /* $Id: fpm_atomic.h,v 1.3 2008/09/18 23:34:11 anight Exp $ */ /* (c) 2007,2008 Andrei Nigmatulin */ #ifndef FPM_ATOMIC_H #define FPM_ATOMIC_H 1 #if HAVE_INTTYPES_H # include <inttypes .h> #else # include <stdint .h> #endif #include <sched .h> #ifdef HAVE_BUILTIN_ATOMIC /** * all the cases below (as provided by upstream) define: * word as atomic_int_t, and * unsigned word as atomic_uint_t * and only use volatile atomic_uint_t as atomic_t */ typedef volatile unsigned long atomic_t; #define atomic_cmp_set(a,b,c) __sync_bool_compare_and_swap(a,b,c) #elif ( __i386__ || __i386 ) /// a lot of platform-speicific definitions of above mentioned functions #if (__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)) #elif ( __arm__ || __arm ) /* W-Mark Kubacki */ /// other code we're not interested in Although, it does contain the mention of ARM, the code defined for this case won’t be executed, since this is not our case: $ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/5/lto-wrapper Target: arm-linux-gnueabihf Configured with: ../src/configure -v --with-pkgversion='Ubuntu 5.2.1-22ubuntu2' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libitm --disable-libquadmath --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-armhf/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-armhf --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-armhf --with-arch-directory=arm --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --enable-multilib --disable-sjlj-exceptions --with-arch=armv7-a --with-fpu=vfpv3-d16 --with-float=hard --with-mode=thumb --disable-werror --enable-multilib --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf Thread model: posix gcc version 5.2.1 20151010 (Ubuntu 5.2.1-22ubuntu2) What we’re going to do is leveraging built-in atomic types, which are controlled by HAVE_BUILTIN_ATOMIC flag. But first, let’s do a drop-in replacement of fpm_atomic.h from 5.3 branch: $ cd /mnt/build/php-5.2.17/sapi/cgi/fpm $ rm fpm_atomic.h && wget "https://github.com/php/php-src/raw/PHP-5.3/sapi/fpm/fpm/fpm_atomic.h" Another magic step is in fact, fix configure system to be able to enable above mentioned flag. Open /mnt/build/php-5.2.17/sapi/cgi/fpm/acinclude.m4 and add at the top: AC_DEFUN([AC_FPM_BUILTIN_ATOMIC], [ AC_MSG_CHECKING([if gcc supports __sync_bool_compare_and_swap]) AC_TRY_LINK(, [ int variable = 1; return (__sync_bool_compare_and_swap(&variable, 1, 2) && __sync_add_and_fetch(&variable, 1)) ? 1 : 0; ], [ AC_MSG_RESULT([yes]) AC_DEFINE(HAVE_BUILTIN_ATOMIC, 1, [Define to 1 if gcc supports __sync_bool_compare_and_swap() a.o.]) ], [ AC_MSG_RESULT([no]) ]) ]) After this is done, everything should compile just fine.

TL;DR

For those lazy folks who don’t want all the investigation details here’s an updated patch which I prepared: https://github.com/bananos/dockerized/blob/master/armbuild-php52/patches/php-5.2.17-fpm-arm-0.5.14.diff In order to use it, just download vanilla php-5.2.17 sources and apply the patch: mkdir -p /tmp/build cd /tmp/build && wget http://museum.php.net/php5/php-5.2.17.tar.gz && tar -xf php-5.2.17.tar.gz cd /tmp/build && wget https://github.com/bananos/dockerized/raw/master/armbuild-php52/patches/php-5.2.17-fpm-arm-0.5.14.diff cd /tmp/build && patch -p1 -d php-5.2.17/ < /tmp/build/php-5.2.17-fpm-arm-0.5.14.diff If you’re familiar with Docker you may might also check precompiled and flattened PHP-5.2.17 ARMHF image with some most popular PECL packages pre-built. Happy running your old legacy PHP code!

Sources

http://php-fpm.org/ https://github.com/bananos/dockerized/tree/master/armbuild-php52/ https://github.com/php/php-src/ https://code.google.com/archive/p/php52-backports/issues/16 http://saravananlinux.blogspot.com/2014/01/libxml-error-while-compiling-dual-php.html

Page 2 of 2 | Previous page