home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Writing Apache Modules with Perl and C
By:   Lincoln Stein and Doug MacEachern
Published:   O'Reilly & Associates, Inc.  - March 1999

Copyright © 1999 by O'Reilly & Associates, Inc.


 


   Show Contents   Previous Page   Next Page

Appendix C - Building Multifile C API Modules

In this section...

Introduction
Statically Linked Modules That Need External Libraries
Dynamically Linked Modules That Need External Libraries
Building Modules from Several Source Files

Introduction

   Show Contents   Go to Top   Previous Page   Next Page

In This Appendix

If you need to build a C module from several object files, or if the module requires functions defined in external library files, then you need to go beyond the simple build mechanism described in Chapter 2, A First Module. This appendix describes how to do so.

Statically Linked Modules That Need External Libraries

   Show Contents   Go to Top   Previous Page   Next Page

If you have a module that requires one or more external library files and you wish to link it into the httpd binary statically, then you have to arrange for the library to be added to the LIBS variable that the httpd makefile uses for the link phase. The most straightforward way to achieve this is to provide a "hint" to Apache's configuration system. You can embed configuration hints directly in the module source file, or you can place them in separate files located in the same directory as the source file.

For the purposes of this example, we'll assume we're implementing a module named mod_compress which requires some of the data compression/decompression functions located in the system libz library. We need to arrange for -lz to be added to the LIBS makefile variable. One way to do this is to add the following comment somewhere toward the top of the source file mod_compress.c:

/* Module configuration hints
MODULE-DEFINITION-START
Name: compress_module
ConfigStart
 LIBS="$LIBS -lz"
 echo " + using -lz for compression support"
ConfigEnd
MODULE-DEFINITION-END
*/

When the configure script runs, it scans through a module looking for lines containing the MODULE-DEFINITION-START and MODULE-DEFINITION-END keywords and passes everything between the two lines to the configuration system. Within the configuration section, the Name: keyword specifies the name of the module, which should be the same as the name given in the module declaration. This is followed by a section bracketed by the keywords ConfigStart and Config-End. Everything between these two keywords is treated as a shell script and passed to /bin/sh for evaluation. You are free to do anything in this section that you wish, including calling other shell scripts. In this case, we simply augment the LIBS variable by appending -lz to it; we then call echo to display a message indicating that we've done so.

An alternate way to achieve the same thing is to place the configuration information in a separate file named .module located in the same directory as the module's source code. In this example, we would want to create a file named mod_compress.module containing the following text:

Name: compress_module
ConfigStart
 LIBS="$LIBS -lz"
 echo " + using -lz for compression support"
ConfigEnd

The contents of the file is identical to the text between the MODULE-DEFINITION-START and MODULE-DEFINITION-END lines. In either case, running configure with the option --enable-module=modules/site/mod_compress.c should now give output similar to the following:

Configuring for Apache, Version 1.3.3
+ activated compress module (modules/site/mod_compress.c)
Creating Makefile
Creating Configuration.apaci in src
+ enabling mod_so for DSO support
Creating Makefile in src
+ configured for Linux platform
+ setting C compiler to gcc
+ setting C pre-processor to gcc -E
+ checking for system header files
+ adding selected modules
   o rewrite_module uses ConfigStart/End
+ using -ldbm for DBM support
     enabling DBM support for mod_rewrite
   o compress_module uses ConfigStart/End
+ using -lz for compression support
+ using -ldl for vendor DSO support
+ doing sanity check on compiler and options
Creating Makefile in src/support
Creating Makefile in src/main
Creating Makefile in src/ap
Creating Makefile in src/regex
Creating Makefile in src/os/unix
Creating Makefile in src/modules/standard
Creating Makefile in src/modules/proxy
Creating Makefile in src/modules/extra

The relevant lines here are compress_module uses ConfigStart/End and use -lz for compression support. Together they show that the configuration hints have been correctly recognized and processed by the configuration system. If we were to go on to build httpd, we would see -lz included among the list of libraries brought in during the link phase.

Other makefile variables that you can adjust in this way are INCLUDES, the list of directory paths to search for header files, CFLAGS, the list of flags to pass to the compiler during compile phase, and LDFLAGS, the list of flags to pass to the linker during link phase.

This same technique can be used to create DSO modules, but there's a catch, as we explain in the next section.

Dynamically Linked Modules That Need External Libraries

   Show Contents   Go to Top   Previous Page   Next Page

Things get slightly more complicated when you want to build your module as a dynamic shared object (DSO) for loading at runtime. This is because not all Unix architectures allow you to link one shared object to another. Because both the module and the external library are shareable, this restriction causes LoadModule to fail at runtime with "symbol not found" errors.

Most Unix architectures don't suffer this problem, including all ELF-based systems. However, older systems that use the a.out binary architecture, including most BSD-derived systems, do suffer from this limitation. If this is the case with your system, you have the choice of statically linking the module with the httpd binary, as described in the previous section, or statically linking the whole external library into the DSO module.

Regardless of whether your system allows linking of DSOs to each other, its easiest to create modules that depend on external libraries using the APache eXtenSion (apxs) tool. Start out by running apxs with the -g and -n switches in order to create a skeleton build directory for your module:

 % apxs -g -n compress
Creating [DIR]  compress
Creating [FILE] compress/Makefile
Creating [FILE] compress/mod_compress.c

Now edit the stub .c file to contain the handlers you need. In the case of mod_compress.c, we would add code to invoke libz's file compression and decompression routines. To get the DSO module to link correctly, you must now edit Makefile so that the LIBS definition refers to -lz. For platforms that allow DSOs to be linked together, uncomment the LIBS line and edit it to read like this:

LIBS = -lz

If your platform doesn't support linking between DSOs, you have a few options. One option is to compile the library statically. The easiest way to do this is to locate the archive version of the library, for example, libz.a, and add the full path of the library file to the LIBS definition:

LIBS = /usr/local/lib/libz.a

This will cause the contents of libz.a to be linked in statically, just like an ordinary object file. However, there is one very large caveat! This will only work if the library archive was originally compiled with position-independent code, using the -fpic compiler flag or equivalent. If this was not the case, then the DSO module will fail, either when it is first built or when you first attempt to load it. If you really want to pursue this option, you can attempt to obtain the source code for the library and recompile it with the correct compiler flags.

Another option is to load the necessary shared libraries manually using mod_so's LoadFile directive. This instructs Apache to load the symbols of any shared object file on the system, including shared libraries. You should call this directive before you attempt to load any DSO modules that require shared libraries that aren't linked into httpd itself. For example, to make mod_compress work on a system that doesn't allow shared libraries to be linked to DSOs, you could modify httpd.conf as follows (changing the paths as appropriate for your system):

LoadFile   /usr/lib/libz.so
LoadModule compress_module libexec/mod_compress.so

The last variant we will consider is when you are using a system that allows DSOs to be linked to shared libraries and you wish to build a DSO module in the Apache source tree with the Apache configuration system rather than with apxs. You can do so using the configuration techniques described in the previous section. However, the configuration system ordinarily won't allow a DSO module to be linked to a shared library because it is forbidden on some systems. In order to allow this to happen, you must recompile Apache with the SHARED_CHAIN compilation rule. This makes the way that Apache compiles and links DSO modules a little bit smarter. At configure time, the Apache configuration system examines the contents of the LIBS makefile definition. Any shared libraries in LIBS are remembered and used later when linking against DSO-based modules. To enable this feature, reconfigure Apache with the --enable-rule=SHARED_CHAIN option, as follows:

% ./configure --enable-rule=SHARED_CHAIN \
            

This feature is only useful when creating DSO modules within the Apache source tree. It has no effect on modules created with apxs.

Shared library support is quite variable between different flavors of Unix. Be prepared to experiment a bit with loadable modules, and be aware that some combinations of loadable modules and shared libraries may just not work on certain platforms. A lengthier discussion can be found in the Apache documentation under manual/dso.html.

   Show Contents   Go to Top   Previous Page   Next Page
Copyright © 1999 by O'Reilly & Associates, Inc.