$Header$
(Note : This is a work in progress.)
First a little background: SWIG was started in 1995 as a one-person project and continued in this mode of operation until about 1998. Most of this development was driven by ideas submitted by early SWIG users as opposed to being motivated by a grand design. As a result, the code ended up being a pretty horrible C++ coding disaster. A mostly working disaster perhaps, but a disaster nonetheless.
With that said, the primary goal of future SWIG development is to reengineer the original system, fix most of its inherent design flaws, and to produce what I hope will become a highly extensible and modular interface compiler framework. To this do this, there are a few critical areas of work. First, I want to restructure SWIG as a collection of loosely coupled modules written in either ANSI C or an scripting language. Second, I want the system to be minimalistic in its use of data structures and interconnections. The primary reason for this is that the fewer data structures there are, the less users will have to remember. This will also make the system more accessible to non-experts. Finally, I want to reevaluate the whole idea of a SWIG module is and expand the definition to include just about anything from parsers, preprocessors, optimizers, interface editors, and code generators.
The rest of this document outlines a few general rules of how code should be developed within the SWIG project. These rules are primarily drawn from my own experience developing software and observing the practices of other successful projects.
Module writers should make every attempt to use only those functions described in the POSIX.1 standard. This includes most of the functions contained the Kernighan and Ritchie C programming book. Use of operating system dependent functionality such as socket libraries should always be included inside a conditional compilation block so that it can be omitted on problematic platforms. If you are unsure about a library call, check the man page or contact Dave.
When choosing a module name, please pick a name that is not currently in use. As a general convention, the first letter of a module name is capitalized such as "Perl". Alternatives such as "perl" or "PERL" should be avoided. In certain instances, the first two letters may be capitalized as in "CParse." The exact usage of this is somewhat inconsistent and isn't terribly important--just make sure the first letter is capitalized. Also, module names should not start with numbers, include underscores or any other special non-alphanumeric characters.
All header files should include a short description, author information, copyright message, CVS version, include guards, and be C++ aware. For example:
/* -------------------------------------------------------------------------
* swigperl.h
*
* All of the externally visible functions in the Perl module.
*
* Author(s) : David Beazley (beazley@cs.uchicago.edu)
*
* Copyright (C) 1999-2000, The University of Chicago.
* See the file LICENSE for information on usage and redistribution.
*
* $Header$
* ------------------------------------------------------------------------- */
#ifndef _SWIGPERL_H
#define _SWIGPERL_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* Your declarations here */
...
#ifdef __cplusplus
}
#endif
#endif /* _SWIGPERL_H */
To minimize compilation time, please include as few other header files as possible.
Each file should include a short abstract, author information, copyright information, and a CVS revision tag like this:
/* -----------------------------------------------------------------------------
* include.c
*
* This file implements the functions used to locate and include files in
* the SWIG library. Functions for maintaining the library search path are
* also located here.
*
* Author(s) : David Beazley (beazley@cs.uchicago.edu)
*
* Copyright (C) 1999-2000, The University of Chicago.
* See the file LICENSE for information on usage and redistribution.
* ----------------------------------------------------------------------------- */
static char cvsroot[] = "$Header$";
#include "swig.h"
/* Declarations */
typedef struct {
int x, y;
} Foo;
...
/* Private Declarations (used only in this file) */
static int avariable;
...
/* Functions */
...
The CVS revision tag should be placed into a static string as shown
above. This adds the revision information to the SWIG executable and
makes it possible to extract version information from a raw binary
(sometimes useful in debugging).
As a general rule, files start to get unmanagable once they exceed about 2000 lines. Files larger than this should be broken up into multiple files. Similarly, you should avoid the temptation to create many small files as this increases compilation time and makes the directory structure too complicated.
/* Simple bottom-up program */
#include <stdio.h>
int foo(int x, int y) {
/* Implement foo */
...
}
int bar() {
...
foo(i,j);
...
}
...
int main(int argc, char **argv) {
...
bar();
...
}
This choice of design is somewhat arbitrary however it has a number of
benefits particular to C. In particular, a bottom-up design generally
eliminates the need to include forward references--resulting in
cleaner code and fewer compilation errors.
/* -------------------------------------------------------------------------
* Swig_add_directory()
*
* Adds a directory to the SWIG search path.
* ------------------------------------------------------------------------- */
void
Swig_add_directory(DOH *dirname) {
...
}
In the function declaration, the return type and any specifiers
(extern or static) should appear on a separate line followed by the
function name and arguments as shown above. The left curly brace
should appear on the same line as the function name.
Function declarations should NOT use the pre-ANSI function declaration syntax. The ANSI standard has been around long enough for this to be a non-issue.
In general, the module name should match the name of the module subdirectory and the function name should be in all lowercase with words separated by underscores.Preprocessor_define() Swig_add_directory()
typedef struct SwigScanner {
...
} SwigScanner;
typedef struct LParseType {
...
} LParseType;
In this case, both the name of the module and the type should be capitalized. Also, whenever
possible, you should use the "typedef struct Name { ... } Name" form when defining new
data structures.
Separate words in a constant should be separated by underscores as with functions.#define SWIG_TOKEN_LPAREN 1
typedef struct SwigScanner {
DOH *text; /* Current token value */
DOH *scanobjs; /* Objects being scanned */
DOH *str; /* Current object being scanned */
char *idstart; /* Optional identifier start characters */
int next_token; /* Next token to be returned */
int start_line; /* Starting line of certain declarations */
int yylen; /* Length of text pushed into text */
DOH *file; /* Current file name */
} SwigScanner;
typedef struct Foo {
int line;
} Foo;
It is better to hide the implementation of Foo and provide an
function-call interface like this:
Although this results in worse performance, there are many practical reasons for doing this. The most important reason is that it allows you to change the internal representation of Foo without breaking all of the other modules or having to recompile the entire universe after making your changes.typedef struct Foo Foo; extern int Foo_getline(Foo *f); extern void Foo_setline(Foo *f, int line);
There are three different concepts of "module" involved, defined separately for SWIG, Guile, and Libtool. To avoid horrible confusion, we explicitly prefix the context, e.g., "guile-module".
Guile support is complicated by a lack of user community cohesiveness, which manifests in multiple shared-library usage conventions. A set of policies implementing a usage convention is called a linkage. The default linkage is the simplest; nothing special is done. In this case `SWIG_init()' is provided and users must do something like this:
At this time, the name `SWIG_init' is hardcoded; this approach does not work with multiple swig-modules.(define my-so (dynamic-link "./example.so")) (dynamic-call "SWIG_init" my-so)
A second linkage creates "libtool dl module" wrappers, and currently is broken. Whoever fixes this needs to track Guile's libtool dl module convention, since that is not finalized.
The only other linkage supported at this time creates shared object libraries suitable for use by hobbit's `(hobbit4d link)' guile module. This is called the "hobbit" linkage, and requires also using the "-package" command line option to set the part of the module name before the last symbol. For example, both command lines: [checkme:ttn]
would create module `(my lib foo)' (assuming in the first case foo.i declares the module to be "foo"). The installed files are my/lib/libfoo.so.X.Y.Z and friends. This scheme is still very experimental; the (hobbit4d link) conventions are not well understood.swig -guile -package my/lib foo.i swig -guile -package my/lib -module foo foo.i
There are no other linkage types planned, but that could change... To add a new type, add the name to the enum in guile.h and add the case to `GUILE::emit_linkage()'.
Underscores are converted to dashes in identifiers. Guile support may grow an option to inhibit this folding in the future, but no one has complained so far.
It used to be that the mappings for "native" types were included in guile.cxx. This information is now in Lib/guile/typemaps.i, which presents a new challenge: how to have SWIG include typemaps.i before processing the user's foo.i. At this time, we must say:
in foo.i. This may change in the future.%include guile/typemaps.i
For pointer types, SWIG can use Guile smobs if given the command-line option "-with-smobs". Ultimately this will be the default (and only) behavior and the command-line option will no longer be supported. Ideally, "-with-smobs" will not even make it to beta.
[insert smob implementation overview here (Matthias Koeppe?)]