The moto language, like most web programming languages, was designed primarily for webmasters with some technical ability
to intersperse programmatic constructs within web pages to create web applications. Moto was built with performance in mind
because the history of web programming languages such as Coldfusion, ASP, and PHP, shows that they are used more often than
not as the entire platform for rapid web application development. Nonetheless, the preferred way of using moto is for the
user interface and form handling aspects of your web applications alone. Business logic, where possible, should be
implemented in a classical programming language such as C.
To this end, an API has been provided for the creation of new moto objects and functions from your own C libraries.
Moto extensions are organized into libraries that can be used in your moto pages via the $use construct. These libraries
reside under the mx directory of your moto home directory. The structure of the mx directory is loosly modelled after a java
class library structure. It is heirarchical with the top level subdirectories conventionally named after the source company
that maintains the moto extensions within. Underneath each top level directory there may be further subdirectories
dividing the contained extensions into frameworks by function. Entensions are made available to the a moto page one folder
at a time.
To add a new extension library you should begin by creating a new directory underneath the mx directory. You should then copy
the makefile file from one of the existing extensions folders into your new folder. You can now begin creating interface files that map extension functions and object methods to C functions in your own C libraries.
For each new object or set of related functions you wish to expose to your moto application, you should create one interface
file (.i) . The convention is that this interface file be given the same name as the extension which it contains and thus
start with a capital letter. Interface files have the following general structure:
Extension: 1st Extension / Class Name
LibraryPath: 1st library path needed to locate shared libs this extension depends upon
LibraryPath: 2nd library path needed to locate shared libs this extension depends upon
...
IncludePath: 1st path to header files needed to compile this extension
IncludePath: 2nd path to header files needed to compile this extension
...
Library: 1st shared library file needed for this extension
Library: 2nd shared library file needed for this extension
...
Archive: 1st archive needed for this extension
Archive: 2nd archive needed for this extension
...
Include: 1st C header file needed to compile this extension
Include: 2nd C header file needed to compile this extension
...
Interface:
prototype mapping ;
prototype mapping ;
prototype mapping ;
...
| |
The prototype mapping is where moto functions and methods get translated to their C counterparts. A prototype mapping
begins with the return type of the moto function or method preceded by the keyword tracked if the return value
is an object created on the heap by the function or method call. If the function or method returns nothing then
void should be specified as it's return value. Following the return type is the function or method name. In the
case of a method name, the C++ style qualified name should be used
After the method name there is an open paren '(' followed by a comma delimeted list of argument type argument name pairs
followed by a close paren ')'. After the argument list comes the mapping symbol => and finally the C function
prototype. A complete example of an interface file taken from the codex.util library for the SymbolTable class follows:
Extension: SymbolTable
Include: "symboltable.h"
Include: "enumeration.h"
Interface:
tracked SymbolTable SymbolTable::SymbolTable() =>
SymbolTable *stab_createDefault();
void SymbolTable::~SymbolTable() =>
void *stab_free(SymbolTable *this);
void SymbolTable::put(String key, Object value) =>
void stab_put(SymbolTable *this, char *key, void *value);
Object SymbolTable::get(String key) =>
void *stab_get(SymbolTable *this, char *key);
void SymbolTable::remove(String key) =>
void *stab_remove(SymbolTable *this, char *key);
void SymbolTable::clear() =>
void *stab_clear(SymbolTable *this);
tracked Enumeration SymbolTable::keys() =>
Enumeration *stab_getKeys(SymbolTable *this);
int SymbolTable::size() =>
int stab_size(SymbolTable *table);
| |
There are three important times when the dependencies for an extension must be known.
- When the extension is compiled with mxc into .a and .so libraries
- When the extension is dynamically loaded by the moto interpreter
- When the extension is linked to a binary or apache module with mmc
At compilation time when the .a and .so files are created, header files that declare C prototypes
used in .i files must be listed using the Include keyword so that they can be included when building extension object
files. If these headers aren't in a standard location such as /usr/include the path to the
directory containing these header files must also be specified using the IncludePath keyword
so that mxc and mmc know where to look for them.
Using IncludePath to add the path to the moto include directory is not necessary as it is automatically
included by mxc and mmc.
The Library keyword in an interface file allows you to specify that your extension depends on a third party
library. This keyword should only be used for linking to shared libraries. It will generate a runtime dependency from the
extension (and therefore from modules compiled with that extension) to that library.
Libraries you should never link to via the library keyword include libmotom and libcodex. All the symbols
from these libraries are included in the command line interpreter and in mod_moto and are automatically linked
by mmc. Linking to these libraries will cause duplicate symbol errors on some platforms.
If the shared library you depend on is not in a standard location such as /usr/lib then you must specify the path
to the directory containing the shared library by using the LibraryPath keyword.
Often times it is preferable to actually copy the necessary symbols out of a library directly into an extension.
This is the case when you do not wish to have the runtime dependency on that library. Specifying a full path
to an archive that contains the necessary symbols (a .a file) using the Archive keyword will tell both mxc and mmc
to statically link to that archive (copy out symbols).
Sometimes archives and shared libraries may themselved be dependant on symbols in other libraries. These dependencies
should also be listed with the Library or Archive keywords.
Often times there will be a choice to link to either a shared library or an archive.
The general rule should be to link to common shared libraries that are guarenteed to be present in the same location
on platforms where binaries compiled with your extension will be deployed.
If you cannot guarentee that, then statically link to an archive if possible.
This diagram shows the current design of the libraries that are distributed with moto.
Always include "memsw.h" this is very important because this header redefines malloc, realloc, and free to
allocate memory on the shared heap. If your methods in your extension return Objects (a constructor for
example) than that memory needs to be allocated on the shared heap. If it is allocated with the plain
old system malloc than that memory will leak and never get cleaned up. Worse, your object won't be promotable.
That is, moto programmers won't be able to persist it in the session or context and if they try to, Apache will
likely segfault when they next try to access it. Bottom line ... include memsw.h .
Usually include "excpfn.h" and "exception.h". With these you will be able to throw and catch exceptions using the
macros TRY, CATCH, CATCH_ALL and END_TRY. This is much better than segfaulting (or returning error codes ... yuck)
when something goes wrong inside your extension. Moreover excpfn.h defines a number of usefull function that mimic
their C stdlib counterparts but allocate memory on the shared heap and throw exceptions when the arguments passed
to them are bad. These functions include emalloc, erealloc, estrdup, and estrcmp.
Always create a destructor. Without a destructor moto will just call plain old free on your object and if you
have any member objects those won't get cleaned up.
Copyright © 2000 - 2003 David Hakim