Difference between revisions of "FPC and Apache Modules"

From Free Pascal wiki
Jump to navigationJump to search
Line 116: Line 116:
  
 
Be careful when using apr_pstrcat and other string function. Note that the unlike c, you have to enclose the extra parameters with a [ ]. Also note that you must cast all strings to PChar when using c string functions, otherwise your module may crash the server.
 
Be careful when using apr_pstrcat and other string function. Note that the unlike c, you have to enclose the extra parameters with a [ ]. Also note that you must cast all strings to PChar when using c string functions, otherwise your module may crash the server.
 +
 +
3 - '''Loading 2 or more pascal Apache modules'''
 +
 +
By default, Free Pascal (actually, the linker used by Free Pascal) creates libraries that are not relocatable. This means that if two Free Pascal generated libraries are loaded by a program, there will be a conflict, and the second library will fail to be loaded.
 +
 +
To fix this you must pass the -WR option to the compiler. On Lazarus you can add this option on "Compiler Options" -> "Other" -> "Custom Options". Using Lazarus 0.9.16 and FPC 2.0.2 that comes with it on Windows XP, even passing -WR option the libraries will fail to load at the same time. Using Free Pascal 2.0.2 installed separately from Lazarus, and compiling from the command line, the libraries will work correctly. This problem may be solved with the release of 2.0.4, or not.
 +
 +
There is more detailed information [http://www.freepascal.org/docs-html/prog/progse53.html#x226-22800012.5 here].
  
 
=== Screenshot ===
 
=== Screenshot ===

Revision as of 17:41, 14 July 2006

Documentation

How the bindings work

A basic apache module created with Free Pascal will have a code similar to this:

library mod_hello;

{$ifndef win32}
  {$l hello_module.o}
{$endif}

uses httpd;

var
 hello_module: module; {$ifdef Unix}cvar; external; {$endif}
 default_module_ptr: Pmodule;

{$ifdef Win32}
exports
 hello_module name 'hello_module';
{$endif}

begin
  default_module_ptr := @hello_module;
  FillChar(default_module_ptr^, SizeOf(default_module_ptr^), 0);
  with default_module_ptr^ do
  begin
    version := MODULE_MAGIC_NUMBER_MAJOR;
    minor_version := MODULE_MAGIC_NUMBER_MINOR;
    module_index := -1;
    name := 'mod_hello.so';
    magic := MODULE_MAGIC_COOKIE;
  end;
end.

Apache uses a non-standard way to exchange information between the module and the library. Normally libraries export functions, but Apache instead expects a library that exports a variable. The variable is a structure with the module information. This variable needs to be filled with information as soon as the module is loaded.

Now, on Windows we can easely export a variable with Free Pascal. Just put it on the exports section. On Linux, Free Pascal doesn´t yet support exporting variables, so we need a alternative. To work around this we can create a assembler file that will export the variable and then link it into our code.

The file will look like this:

[SECTION .data]
global hello_module
hello_module dd 0

And the command line to compile this assembler code is: "nasm -f elf hello_module.asm"

How the bindings were created

The translated headers follow some simple guidelines. First all translated declarations remain at the exact same position as they were on the .h files, unless there is a incompatibility and they have to be moved. This is to make it easier to compare the .h files with the pascal translation and find possible mistakes on translation. Second, most files become include files, and some units are created to hold them. In particular, one unit was created for each apache library (httpd, apr, aprutil and apriconv).


The translation was all done manually with the help of "Replace All" from the Lazarus IDE. This is because automatic translators cannot deal with the heavy use of macros by apache headers, and passing the c preprocessor produces a code that is unrecognizably different from the original headers.


The Apache headers heavily rely on macros to work. In fact, almost every single declaration is a macro. Bellow are some of the most common macros and appropriate translations:


1 - AP_DECLARE

AP_DECLARE(void) ap_add_version_component(apr_pool_t *pconf, const char *component);


procedure ap_add_version_component(pconf: Papr_pool_t; const component: PChar);
 {$IFDEF WINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
 external LibHTTPD name LibNamePrefix + 'ap_add_version_component' + LibSuff8;

The AP_DECLARE macro says that the calling convention for the function is stdcall on Windows and cdecl on other operating systems, so we need an IFDEF for this. It also says that the function name will have a prefix and a suffix on Windows. The prefix is "_" and the suffix is "@N", where N is a number multiple of 4. Tipically, the number is 4 times the number of parameters on the function, but there are some exceptions. To find out possible conflics on the function names, a software to list all exported functions of a dll was created.

2 - AP_DECLARE_NONSTD

AP_DECLARE_NONSTD(const char *) ap_set_string_slot(cmd_parms *cmd, 
                                                   void *struct_ptr,
                                                   const char *arg);


function ap_set_string_slot(cmd: Pcmd_parms; struct_ptr: Pointer; const arg: PChar): PChar;
 cdecl; external LibHTTPD name 'ap_set_string_slot';

This is the same as AP_DECLARE, but the calling convention is cdecl and no suffix or preffix is present on the function name.

3 - Other combinations

APR_DECLARE_NONSTD(int) apr_file_printf(apr_file_t *fptr, 
                                        const char *format, ...)


function apr_file_printf(fptr: Papr_file_t; const format: PChar;
 othres: array of const): Integer;
 cdecl; external LibAPR name 'apr_file_printf';

Another possible combination are macros starting with APR. AP means libhttpd, APR is libapr, APU is libaprutil and API is for libapriconv. Also notice that this function has a variable number of parameters, that in pascal is represented by an array of const.

Possible problems

1 - Apache version number

Apache expects that the module is compiled specifically for the exact same version as the server. Because we have a single translation for all 2.0.x versions, you can just change the MODULE_MAGIC_NUMBER_MAJOR to what Apache expects and it should work. On the file ap_mmn.inc you can find a list of apache magic numbers for almost all 2.0.x Apache versions.

2 - Using string functions

note := apr_pstrcat(p, [PChar('x_child_init('), sname, PChar(')'), nil]);

Be careful when using apr_pstrcat and other string function. Note that the unlike c, you have to enclose the extra parameters with a [ ]. Also note that you must cast all strings to PChar when using c string functions, otherwise your module may crash the server.

3 - Loading 2 or more pascal Apache modules

By default, Free Pascal (actually, the linker used by Free Pascal) creates libraries that are not relocatable. This means that if two Free Pascal generated libraries are loaded by a program, there will be a conflict, and the second library will fail to be loaded.

To fix this you must pass the -WR option to the compiler. On Lazarus you can add this option on "Compiler Options" -> "Other" -> "Custom Options". Using Lazarus 0.9.16 and FPC 2.0.2 that comes with it on Windows XP, even passing -WR option the libraries will fail to load at the same time. Using Free Pascal 2.0.2 installed separately from Lazarus, and compiling from the command line, the libraries will work correctly. This problem may be solved with the release of 2.0.4, or not.

There is more detailed information here.

Screenshot

Authors

Felipe Monteiro de Carvalho

License

Download

Status: Under development

Installation

Hello World Module

CVS

Not yet available.


Bug Reporting

Tests are necessary to verify if all functions and structures are declared properly.

You can post Bug Reports here:

Change Log

Help

Please send help requests to the Free Pascal mailling list.