Tutorial One |
Note: Someone has linked to this tutorial from the Apache 2.0 Developer Documentation. This is but one in an upcoming series of tutorials - check the main tutorial page for others. For that matter, check out the main threebit site. -- Cheers, Kevin.
This tutorial guides the reader through the minimal tasks involved in writing a module for Apache 2. The module developed here has almost no functionality - it's only impact is the generation of a static message to logs/errorlog for each HTTP request.
This tutorial is not intended to showcase Apache's module API. Instead, it guides the reader through the other tasks that must be done to properly develop, compile and install a custom module - namely autoconf and automake.
Further tutorials will build from this one and explore the advanced module API. Drop a message to kevino at threebit.net if you feel the need.
# Throughout the tutorial, look for links to Apache's # LXR website http://lxr.webperf.org/ # For example, clink on AP_MODULE_DECLARE_DATA below. module AP_MODULE_DECLARE_DATA tut2_module;
Preparation
If you don't actually want to run or test the code in this tutorial, then feel free to skip this step. Otherwise, you'll want to perform the following actions so your work area prepared for compiling and running the tutorial.I have assumed in this tutorial that you have an account on a Linux (or Unix) machine and you have installed the GNU build tools (autoconf, automake, etc). If you haven't then you're not going to get very far - consult your OS documentation.
# Prepare the temporary directory cd $HOME mkdir threebit-tutorials cd threebit-tutorials # Remember the tutorial home directory for later. export TUTORIAL_HOME=`pwd`Download via HTTP
cd $TUTORIAL_HOME wget "http://threebit.net/tutorials/tutorials.tar.gz" tar zxvf tutorials.tar.gzDownload via Anonymous CVS
cd $TUTORIAL_HOME CVSROOT=:pserver:anonymous@threebit.net:/usr/local/cvs # use "anonymous" as the password. cvs login cvs co tutorials/apache2_modules mv tutorials/* . rm -rf tutorialsApache Note: You will get a "404 - Not Found" error if 2.0.43 is no longer the newest version of Apache. Just substitute the current version tag if that is the case.
cd $TUTORIAL_HOME wget http://www.apache.org/dist/httpd/httpd-2.0.43.tar.gz tar zxf httpd-2.0.43.tar.gz cd httpd-2.0.43 ./configure --prefix=$TUTORIAL_HOME/apache2 --enable-so make make installNow we will fix the ServerName and Listen configuration directives so that we can run this installation as an unpriviledged user.
# store the location of the apache configuration file. HTTPCONF=$TUTORIAL_HOME/apache2/conf/httpd.conf # replace the ServerName directive cat $HTTPCONF | \ sed 's/#ServerName new.host.name:80/ServerName localhost/' \ > $HTTPCONF.new mv $HTTPCONF.new $HTTPCONF # replace the Listen directive. cat $HTTPCONF | sed 's/^Listen 80/Listen 21000/' > $HTTPCONF.new mv $HTTPCONF.new $HTTPCONFAnd test the configuration:
$TUTORIAL_HOME/apache2/bin/apachectl configtest Syntax OK
mod_tut1.c
As stated above, the purpose of this module is to write data to the error log for each HTTP request. We are obviously building a useless module - but by limiting what the module does it becomes easier to explain what everything is doing.The source code to the module is pretty much self documenting but let us examine each block independently.
/* * Include the core server components. */ #include "httpd.h" #include "http_config.h"Obviously an Apache module will require information about structures, macros and functions from Apache's core. These two header files are all that is required for this module, but real modules will need to include other header files relating to request handling, logging, protocols, etc.
/* * Declare and populate the module's data structure. The * name of this structure ('tut1_module') is important - it * must match the name of the module. This structure is the * only "glue" between the httpd core and the module. */ module AP_MODULE_DECLARE_DATA tut1_module = { // Only one callback function is provided. Real // modules will need to declare callback functions for // server/directory configuration, configuration merging // and other tasks. STANDARD20_MODULE_STUFF, NULL, NULL, NULL, NULL, NULL, mod_tut1_register_hooks, /* callback for registering hooks */ };Every module must declare it's data structure as shown above. Since this module does not require any configuration most of the callback locations have been left blank, except for the last one - that one is invoked by the HTTPD core so that the module can declare other functions that should be invoked to handle various events (like an HTTP request).
/* * This function is a callback and it declares what * other functions should be called for request * processing and configuration requests. This * callback function declares the Handlers for * other events. */ static void mod_tut1_register_hooks (apr_pool_t *p) { // I think this is the call to make to register a // handler for method calls (GET PUT et. al.). // We will ask to be last so that the comment // has a higher tendency to go at the end. ap_hook_handler(mod_tut1_method_handler, NULL, NULL, APR_HOOK_LAST); }When this function is called by the HTTPD core, it registers a handler that should be invoked for all HTTP requests.
/* * This function is registered as a handler for HTTP methods and will * therefore be invoked for all GET requests (and others). Regardless * of the request type, this function simply sends a message to * STDERR (which httpd redirects to logs/error_log). A real module * would do *alot* more at this point. */ static int mod_tut1_method_handler (request_rec *r) { // Send a message to stderr (apache redirects this to the error log) fprintf(stderr,"apache2_mod_tut1: A request was made.\n"); // We need to flush the stream for messages to appear right away. // Performing an fflush() in a production system is not good for // performance - don't do this for real. fflush(stderr); // Return DECLINED so that the Apache core will keep looking for // other modules to handle this request. This effectively makes // this module completely transparent. return DECLINED; }This is the function that will be invoked for every HTTP request. This is where the meat of an Apache module should go.
GNU Build Tools
Looking in TODO $TUTORIAL_HOME/tut1, you will find some familiar files that are included with most GNU applications.
Makefile.am | An input file for automake |
---|---|
configure.in | An inputfile to autoconf. |
mod_tut1.c | The source code to the tutorial module. |
tutorial1.html | This file. |
The remaining files can safely be ignored. | |
AUTHORS | automake will produce warnings if this file is not present. |
COPYING | The GPL license. automake will complain if this file is not present. |
CVS/ | CVS state directory. Ignore it. If you downloaded the tutorial using the tar ball then it won't even exist. |
ChangeLog | Another automake file. |
INSTALL | Standard install instructions. In this case, it points the reader to this file. |
NEWS | Another automake file. |
README | Another automake file. |
This tutorial does not aim to be a complete reference for the GNU build tools. See the following references for information.
- GNU Autoconf, Automake and Libtool
http://sources.redhat.com/autobook/ - GNU Autoconf
http://www.gnu.org/manual/autoconf/ - GNU Automake
http://www.gnu.org/manual/automake/ - GNU Libtool
http://www.gnu.org/manual/libtool/
configure.in is an input file to autoconf and is used to configure the module source code and dependencies for each target platform. Running autoconf creates the configure script we are all so familiar with.
Makefile.am is an input file to automake and is used to create a Makefile.in file. The Makefile.in file is then used by configure to create real Makefile's.
If you're confused - have no fear because I still am! You probably don't need to understand everything - just plug away through the tutorial. If you want to understand what's going on, I suggest you read the references cited above.
configure.in
I would be lying to you if I told you that I understand everything in this file. However, it seems to work so I'll tell you what I know. :) See configure.in for raw file.AC_INITThe mandatory autoconf initialization macro.
# Automake initialization AM_INIT_AUTOMAKE(mod_tut1, 1.0)This macro is provided by automake and is required when automake is used. The arguments are the package name and version number. I have provided reasonable values for the parameters but still haven't figured out what their impact is.
AC_PROG_CC AM_PROG_LIBTOOLThese two macros add checks for suitable cc and libtool programs.
AC_DEFUN([APACHE_DIR],[ AC_ARG_WITH( apache, [ --with-apache[=DIR] Apache server directory], , [with_apache="no"] ) AC_MSG_CHECKING(for Apache directory) if test "$with_apache" = "no"; then AC_MSG_ERROR( Specify the apache using --with-apache) else # make sure that a well known include file exists if test -e $with_apache/include/httpd.h; then apache_dir=$with_apache AC_MSG_RESULT(APACHE found!) else AC_MSG_ERROR( $with_apache not found. ) fi fi ])This declares a new autoconf macro named APACHE_DIR. It is used to handle the --with-apache=/usr/local/apache2 argument to configure.
APACHE_DIRThis runs the APACHE_DIR macro that was just defined. When successfull, the directory location is stored in apache_dir.
AC_SUBST(apache_dir)Not all variables that are set in shell snippets are persisted to the configuration status file (config.status). This call to AC_SUBST persists the value of apache_dir.
AC_OUTPUT(Makefile)Finally, AC_OUTPUT() saves the results of the configuration and causes a real Makefile to be generated.
Makefile.am
This file is used by automake to generate a Makefile.in file. As stated earlier, Makefile.in is then parsed using an invocation of configure to create an actual Makefile.Since writing an Apache module is the same as writing, compiling and linking any standard shared library, automake is well suited to the task.
Again, consult the full automake documentation for all the info. See the raw Makefile.am.
lib_LTLIBRARIES = libmodtut1.laThis tells automake that we are creating a shared library named libmottut1.la.
libmodtut1_la_SOURCES = mod_tut1.cThis tells automake what source files should be compiled as part of the library. In this case there is only one, but there could be serveral.
INCLUDES = -I@apache_dir@/includeHeader files from the apache distribution are required when compiling the module. This directive provides a list of include directories to pass on to gcc. Does apache_dir look familiar? If you said yes, then step to the front of the class - configure will subsitute the value that was passed in with --with-apache when the Makefile is written.
aclocal, autoconf, automake
Now that you have some idea of what those files mean we can run the utilities that use them.aclocal is used to import macros defined by automake so that autoconf can understand what's going on.
cd $TUTORIAL_HOME/apache2_modules/tut1 # import automake m4 macros. aclocal # create configure based on configure.in autoconf # create Makefile.in based on Makefile.am and configure.in automake -a
[注]这一步会提示“ltmain.sh”找不到,后来是用libtool --copy阿什么的运行了一下就好了,具体网上找找。反正把ltmain.sh弄出来就行。
configure
Now we can run configure to prepare the module's Makefile.# The ubiquitous configure script ./configure --with-apache=$TUTORIAL_HOME/apache2
[注]在这里的$TUTORIAL_HOME/apache2其实就是要apache的头文件,我用的是apache-2.2.4,
没有configure,直接把系统/usr/include/apr-1下的头文件复制过来了。据说在用.configure配置
apache时会生成apr.h等,不管它,复制过来也能用。但是apr.h中有一个地方要改一下:apr.h的270行内容是
typedef off64_t apr_off_t;将其更改为
typedef long long apr_off_t;
make
And now we can run make to compile the module. Note: don't run make install. We'll handle the module installation later.make
apxs
** DO NOT RUN make install ** Ordinarially you would, but the install step for an Apache module is different. Instead, apxs is used to register the module in httpd.conf and move the shared object into the apache lib directory.$TUTORIAL_HOME/apache2/bin/apxs -i -a -n tut1 libmodtut1.laapxs also addes the following line to httpd.conf:
LoadModule tut1_module modules/libmodtut1.so
Run Apache
Now we are ready to run Apache and test the module.# Change to the apache directory cd $TUTORIAL_HOME/apache2 # Start Apache bin/apachectl start # Use Lynx to hit the web server. lynx --source http://localhost:21000 | grep success # Look for the module's message in the error log cat logs/error_log | grep tut1 apache2_mod_tut1: A request was made.
Success!
The tutorial one module has been successfully compiled and installed into the Apache 2 runtime.Updates
Dmitry: ... on the aclocal step it said that "macro AM_PROG_LIBTOOL not found in library", After some looking around I've discovered that AM_PROG_LIBTOOL is changed to AC_PROG_LIBTOOL, so I did and aclocal went fine. Then when I launched autoconf it said to me:
configure.in:9: error: possibly undefined macro: AC_PROG_LIBTOOL If this token and others are legitimate, please use m4_pattern_allow. See the Autoconf documentation.As far as I see possibly you used another version of these utilites. I use automake 1.7.2 and autoconf 2.57. What version have you used? Or if this isn't the problem can you point me what it is?
Kevin: automake (GNU automake) 1.4-p4
Dmitry:The problem was that libtool.m4 must be included at the end of aclocal.m4, and ltmain.sh must be in that directory. Both files were taken from latest libtool package(for now it is 1.2.5).
$Id: tutorial1.html,v 1.18 2002/10/28 07:24:08 kevino Exp $