Thursday 20 November 2008

How to add mod_deflate to apache without recompiling

Apache version: 2.0.63
mod_deflate version: from here
Operating System: Solaris 10 (Generic_125100-10 on Sun T2000) non-global zone
Error keywords seen:
Cannot load mod_deflate.so into server: ld.so.1: httpd: fatal: relocation error: file mod_deflate.so: symbol deflate: referenced symbol not found
gcc: command not found

A requirement came up today to add the mod_deflate module to Apache. (From apache.org: The mod_deflate module provides the DEFLATE output filter that allows output from your server to be compressed before being sent to the client over the network.)

This shouldn't be tricky, and as I generally compile apache with mod_so enabled, it shouldn't be a problem to add it in as a Dynamic Shared Object (DSO), following the process described here.

So let's have a go and see what happens:

# cp mod_deflate.c /tmp
# cd /app/apache/bin
# ./apxs -c /tmp/mod_deflate.c

/app/apache_2.0.63/build/libtool --silent --mode=compile gcc -prefer-pic -DAP_HAVE_DESIGNATED_INITIALIZER -DSOLARIS2=10 -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT -g -O2 -I/app/apache_2.0.63/include -I/app/apache_2.0.63/include -I/app/apache_2.0.63/include -I/usr/local/include -c -o /tmp/mod_deflate.lo /tmp/mod_deflate.c && touch /tmp/mod_deflate.slo
/app/apache_2.0.63/build/libtool: line 1279: gcc: command not found
apxs:Error: Command failed with rc=65536


----------------------------------------------------------------------------------------------------------------------

Okay - this is my fault, I'm an idiot, and I always do this. I've forgotten that the root PATH doesn't include /usr/sfw/bin by default. Again.

# which gcc
no gcc in /usr/sbin /usr/bin
# PATH=$PATH:/usr/sfw/bin

# ./apxs -c /tmp/mod_deflate.c

/app/apache_2.0.63/build/libtool --silent --mode=compile gcc -prefer-pic -DAP_HAVE_DESIGNATED_INITIALIZER -DSOLARIS2=10 -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT -g -O2 -I/app/apache_2.0.63/include -I/app/apache_2.0.63/include -I/app/apache_2.0.63/include -I/usr/local/include -c -o /tmp/mod_deflate.lo /tmp/mod_deflate.c && touch /tmp/mod_deflate.slo
/app/apache_2.0.63/build/libtool --silent --mode=link gcc -o /tmp/mod_deflate.la -rpath /app/apache_2.0.63/modules -module -avoid-version /tmp/mod_deflate.lo


----------------------------------------------------------------------------------------------------------------------

That's more like it.

APXS is the Apache Extension Tool. Sorry, I mean the APache eXtenSion tool, and here it has compiled mod_deflate.c into a libtool control file, mod_deflate.la, which we'll now turn into an Apache shared object. (If you're not following this, don't worry, neither am I.)

So we follow the process:

# ./apxs -i -a -n deflate /tmp/mod_deflate.la
/app/apache_2.0.63/build/instdso.sh SH_LIBTOOL='/app/apache_2.0.63/build/libtool' /tmp/mod_deflate.la /app/apache_2.0.63/modules
/app/apache_2.0.63/build/libtool --mode=install cp /tmp/mod_deflate.la /app/apache_2.0.63/modules/
cp /tmp/.libs/mod_deflate.so /app/apache_2.0.63/modules/mod_deflate.so
chmod +x /app/apache_2.0.63/modules/mod_deflate.so
cp /tmp/.libs/mod_deflate.lai /app/apache_2.0.63/modules/mod_deflate.la
cp /tmp/.libs/mod_deflate.a /app/apache_2.0.63/modules/mod_deflate.a
chmod 644 /app/apache_2.0.63/modules/mod_deflate.a
ranlib /app/apache_2.0.63/modules/mod_deflate.a
----------------------------------------------------------------------
Libraries have been installed in:
/app/apache_2.0.63/modules

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
- add LIBDIR to the `LD_LIBRARY_PATH' environment variable
during execution
- use the `-RLIBDIR' linker flag

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
chmod 755 /app/apache_2.0.63/modules/mod_deflate.so
[activating module `deflate' in /app/apache_2.0.63/conf/httpd.conf]


----------------------------------------------------------------------------------------------------------------------

And yep, here we can see the module has been created and added to the modules subdirectory, and the appropriate LoadModule line is present in httpd.conf:


# cd ../modules
# ls

httpd.exp mod_deflate.so mod_jk.so

# cd ../conf
# cat httpd.conf


LoadModule deflate_module modules/mod_deflate.so



----------------------------------------------------------------------------------------------------------------------

Restart apache, and we’re in business, right? Wrong.


# ../bin/apachectl restart
Syntax error on line 1056 of /app/apache_2.0.63/conf/httpd.conf:
Cannot load /app/apache_2.0.63/modules/mod_deflate.so into server: ld.so.1: httpd: fatal: relocation error: file /app/apache_2.0.63/modules/mod_deflate.so: symbol deflate: referenced symbol not found


----------------------------------------------------------------------------------------------------------------------

Oh dear. What does that mean? Well, with a bit of googling – and most credit goes to Matty at prefetch.net – it becomes clear that mod_deflate is missing the library with the zip compression tools, libz.so, which is present on the system.

We can easily confirm that mod_deflate.so is not being linked to this library with ldd:


# ldd /app/apache/modules/mod_deflate.so
libc.so.1 => /lib/libc.so.1
libgcc_s.so.1 => /usr/sfw/lib/libgcc_s.so.1
libm.so.2 => /lib/libm.so.2
/platform/SUNW,Sun-Fire-T200/lib/libc_psr.so.1


----------------------------------------------------------------------------------------------------------------------

According to gnu.org (here), we need to call gcc with -lz (just as to link to libxml2.so we would need to call gcc with -lxml2, and so on) – and we can do this with the variable LDFLAGS (“flags to be used by libtool when it links a program”). Armed with this information, let’s see what happens:

# export LDFLAGS="-lz";./apr-config –ldflags

#
#


----------------------------------------------------------------------------------------------------------------------

We get nothing. Apache ignores the LDFLAGS parameter. Diving into the apr-config file, we can se that this is because the following line wipes anything we pass to it:

LDFLAGS=""

Well, it’s a small deal to change this to,

LDFLAGS="-lz"

And now we get the expected response:

# ./apr-config –ldflags
-lz


----------------------------------------------------------------------------------------------------------------------

So we go through the procedure again:

# ./apxs –c /tmp/mod_deflate.c

# ./apxs -i -a -n deflate /tmp/mod_deflate.la


----------------------------------------------------------------------------------------------------------------------

Let’s check to see that this has now linked to the desired libz.so:

# ldd /app/apache_2.0.63/modules/mod_deflate.so
libz.so.1 => /usr/lib/libz.so.1
libc.so.1 => /lib/libc.so.1
libgcc_s.so.1 => /usr/sfw/lib/libgcc_s.so.1
libm.so.2 => /lib/libm.so.2
/platform/SUNW,Sun-Fire-T200/lib/libc_psr.so.1


----------------------------------------------------------------------------------------------------------------------

It has, and happily we now see no errors:

# ./apachectl restart
#

1 comment:

Anonymous said...

You can make linkage in the same apxs command:
./apxs -c -i -Wl,-lz /app/httpd-2.4.12/modules/filters/mod_deflate.c