blob: 06d2d2f14c8e6c1a6da855abe72b086b040c0a1e [file] [log] [blame]
<!-- Published by Quadralay WebWorks HTML Lite 1.5.1 -->
<!-- And munged by Dave's special Python script -->
<html>
<head>
<title>Extending SWIG</title>
</head>
<body bgcolor="#ffffff">
<a name="n0"></a><h1>12 Extending SWIG</h1><p><ul>
<li> <a href="#n1">Introduction</a>
<li> <a href="#n2">Compiling a SWIG extension</a>
<li> <a href="#n3">SWIG output</a>
<li> <a href="#n4">The Language class (simple version)</a>
<li> <a href="#n5">A tour of SWIG datatypes</a>
<li> <a href="#n6">Typemaps (from C)</a>
<li> <a href="#n7">File management</a>
<li> <a href="#n8">Naming Services</a>
<li> <a href="#n9">Code Generation Functions</a>
<li> <a href="#n10">Writing a Real Language Module</a>
<li> <a href="#n11">C++ Processing</a>
<li> <a href="#n12">Documentation Processing</a>
<li> <a href="#n13">The Future of SWIG</a>
</ul>
<a name="n1"></a><h2> Introduction</h2>
This chapter attempts to describe the process of extending SWIG to support new target languages and documentation methods. First a word of warning--SWIG started out being a relatively simple system for building interfaces to ANSI C programs. Since then, it has grown into something much more than that (although I'm still trying to figure out what). As a result, it is undergoing a number of growing pains. Certain parts of the code have been rewritten and others can probably be described as a hackish nightmare. I'm always working on ways to improve the implementation, but expect to find a few warts and inconsistencies.<p>
<a name="n14"></a><h3> Prerequisites</h3>
In order to develop or modify a SWIG module, I assume the following :<p>
<p>
<ul>
<li>That you understand the C API for the scripting language of interest.
<li>You have a good understanding of how SWIG operates and a good idea of how typemaps work.
<li>That you have some experience with C++. SWIG is written in C++, but doesn't use it maximally. However, familiarity with classes, inheritance, and operator overloading will help.
<li>That you're just a little crazy (this will help alot).
</ul>
<a name="n15"></a><h3> SWIG Organization</h3>
SWIG is built around a central core of functions and classes responsible for parsing interface files, managing documentation, handling datatypes, and utility functions. This code is contained in the "SWIG" directory of the distribution, but contains no information specific to any one scripting language. The various scripting language modules are implemented as C++ classes and found in the "Modules" directory of the distribution. The basic idea behind writing a module is that you write a language class containing about a dozen methods for creating wrapper functions, variables, constants, etc.... To use the language, you simply create a language "object", pass it on the parser and you magically get wrapper code. Documentation modules are written in a similar manner.<p>
<p>
An important aspect of the design is the relationship between ANSI C and C++. The original version of SWIG was developed to support ANSI C programs. To add C++ support, an additional "layer" was added to the system---that is, all of the C++ support is really built on top of the ANSI C support. Language modules can take advantage of both C and C++ although a module written only for C can still work with C++ (due to the layered implementation). <p>
<p>
As for making modifications to SWIG, all files in the "SWIG" directory should be considered "critical." Making changes here can cause serious problems in all SWIG language modules. When making customizations, one should only consider files in the "Modules" directory if at all possible.<p>
<a name="n16"></a><h3> The organization of this chapter</h3>
The remainder of this chapter is a bottom-up approach is to building SWIG modules. It will start with the basics and gradually build up a working language module, introducing new concepts as needed.<p>
<a name="n2"></a><h2> Compiling a SWIG extension</h2>
The first order of business is that of compiling an extension to SWIG and using it. This is the easy part.<p>
<a name="n17"></a><h3> Required files</h3>
To build any SWIG extension you need to locate the files "<tt>swig.h</tt>" and "<tt>libswig.a</tt>". In a typical installation, these will usually be found in <tt>/usr/local/include</tt> and <tt>/usr/local/lib</tt> respectively. All extension modules will need to include the "<tt>swig.h</tt>" header file and link against the <tt>libswig.a</tt> library. <p>
<a name="n18"></a><h3> Required C++ compiler</h3>
Due to name-mangling in the C++ compiler (which is different between compiler implementations), you will need to use the same C++ compiler used to compile SWIG. If you don't know which C++ compiler was used, typing `<tt>swig -version</tt>' will cause SWIG to print out its version number and the C++ compiler that was used to build it.<p>
<a name="n19"></a><h3> Writing a main program</h3>
To get any extension to work, it is necessary to write a small <tt>main()</tt> program to create a language object and start the SWIG parser. For example :<br><p>
<blockquote><pre>#include &lt;swig.h&gt;
#include "swigtcl.h" // Language specific header
extern int SWIG_main(int, char **, Language *, Documentation *);
int main(int argc, char **argv) {
TCL *l = new Tcl; // Create a new Language object
init_args(argc, argv); // Initialize args
return SWIG_main(argc, argv, l, 0);
}
</pre></blockquote>
<a name="n20"></a><h3> Compiling</h3>
To compile your extension, do the following :<p>
<p>
<blockquote><pre>% c++ tcl.cxx main.cxx -lswig -o myswig
</pre></blockquote>
In this case we get a special version of SWIG that compiles Tcl extensions.<p>
<a name="n3"></a><h2> SWIG output</h2>
The output of SWIG is a single file that is organized as follows :<p>
<center><img src="ch12.1.png"></center><p>
<p>
<p>
During code generation, the three sections are created as separate files that are accessed using the following file handles :<p>
<p>
<blockquote><pre>FILE *f_header; // Header section
FILE *f_wrappers; // Wrapper section
FILE *f_init; // Initialization function
</pre></blockquote>
On exit, the three files are merged into a single output file.<p>
<p>
When generating code, your language module should use the I/O functions in the C <tt>&lt;stdio.h&gt;</tt> library. SWIG does not use the C++ streams library.<p>
<p>
The use of each output section can be roughly described as follows :<p>
<p>
<ul>
<li>The header section contains forward declarations, header files, helper functions, and run-time functions (such as the pointer type-checker). All code included with %{,%} also ends up here.
<li>The wrapper section contains all of the SWIG generated wrapper functions.
<li>The initialization section is a single C function used to initialize the module. For large modules, this function can be quite large. In any case, output to <tt>f_init</tt> should be treated with some care considering that the file is essentially one big C function.
</ul>
<a name="n4"></a><h2> The Language class (simple version)</h2>
Writing a new language module involves inheriting from the SWIG <tt>Language</tt> class and implementing methods for a few virtual functions. A minimal definition of a new Language module is as follows :<p>
<p>
<blockquote><pre>// File : mylang.h
// A minimal SWIG Language module
class MYLANG : public Language {
private:
char *module;
public :
MYLANG() {
module = 0;
};
// Virtual functions required by the SWIG parser
void parse_args(int, char *argv[]);
void parse();
void create_function(char *, char *, DataType *, ParmList *);
void link_variable(char *, char *, DataType *);
void declare_const(char *, char *, DataType *, char *);
void initialize(void);
void headers(void);
void close(void);
void set_module(char *,char **);
void create_command(char *, char *);
};
</pre></blockquote>
<p>
Given the above header file, we can create a very simplistic language module as follows :<p>
<p>
<blockquote><pre>// ---------------------------------------------------------------------
// A simple SWIG Language module
// ---------------------------------------------------------------------
#include "swig.h"
#include "mylang.h"
// ---------------------------------------------------------------------
// MYLANG::parse_args(int argc, char *argv[])
//
// Parse command line options and initializes variables.
// ---------------------------------------------------------------------
void MYLANG::parse_args(int argc, char *argv[]) {
printf("Getting command line options\n");
typemap_lang = "mylang";
}
// ---------------------------------------------------------------------
// void MYLANG::parse()
//
// Start parsing an interface file.
// ---------------------------------------------------------------------
void MYLANG::parse() {
fprintf(stderr,"Making wrappers for My Language\n");
headers();
yyparse(); // Run the SWIG parser
}
// ---------------------------------------------------------------------
// MYLANG::set_module(char *mod_name,char **mod_list)
//
// Sets the module name. Does nothing if it's already set (so it can
// be overridden as a command line option).
//
// mod_list is a NULL-terminated list of additional modules. This
// is really only useful when building static executables.
//----------------------------------------------------------------------
void MYLANG::set_module(char *mod_name, char **mod_list) {
if (module) return;
module = new char[strlen(mod_name)+1];
strcpy(module,mod_name);
}
// ----------------------------------------------------------------------
// MYLANG::headers(void)
//
// Generate the appropriate header files for MYLANG interface.
// ----------------------------------------------------------------------
void MYLANG::headers(void) {
emit_banner(f_header); // Print the SWIG banner message
fprintf(f_header,"/* Implementation : My Language */\n\n");
}
// ---------------------------------------------------------------------
// MYLANG::initialize(void)
//
// Produces an initialization function. Assumes that the module
// name has already been specified.
// ---------------------------------------------------------------------
void MYLANG::initialize() {
if (!module) module = "swig"; // Pick a default name
// Start generating the initialization function
fprintf(f_init,"int %s_initialize() {\n", module);
}
// ---------------------------------------------------------------------
// MYLANG::close(void)
//
// Finish the initialization function. Close any additional files and
// resources in use.
// ---------------------------------------------------------------------
void MYLANG::close(void) {
// Finish off our init function
fprintf(f_init,"}\n");
}
// ---------------------------------------------------------------------
// MYLANG::create_command(char *cname, char *iname)
//
// Creates a new command from a C function.
// cname = Name of the C function
// iname = Name of function in scripting language
// ---------------------------------------------------------------------
void MYLANG::create_command(char *cname, char *iname) {
fprintf(f_init,"\t Creating command %s\n", iname);
}
// ---------------------------------------------------------------------
// MYLANG::create_function(char *name, char *iname, DataType *d, ParmList *l)
//
// Create a function declaration and register it with the interpreter.
// name = Name of real C function
// iname = Name of function in scripting language
// d = Return datatype
// l = Function parameters
// ---------------------------------------------------------------------
void MYLANG::create_function(char *name, char *iname, DataType *d, ParmList *l) {
fprintf(f_wrappers,"\nwrap_%s() { }\n\n", name);
create_command(name,iname);
}
// ---------------------------------------------------------------------
// MYLANG::link_variable(char *name, char *iname, DataType *t)
//
// Create a link to a C variable.
// name = Name of C variable
// iname = Name of variable in scripting language
// t = Datatype of the variable
// ---------------------------------------------------------------------
void MYLANG::link_variable(char *name, char *iname, DataType *t) {
fprintf(f_init,"\t Linking variable : %s\n", iname);
}
// ---------------------------------------------------------------------
// MYLANG::declare_const(char *name, char *iname, DataType *type, char *value)
//
// Makes a constant.
// name = Name of the constant
// iname = Scripting language name of constant
// type = Datatype of the constant
// value = Constant value (as a string)
// ---------------------------------------------------------------------
void MYLANG::declare_const(char *name, char *iname, DataType *type, char *value) {
fprintf(f_init,"\t Creating constant : %s = %s\n", name, value);
}
</pre></blockquote>
<p>
To compile our new language, we write a main program (as described previously) and do this :<p>
<p>
<blockquote><pre>% g++ main.cxx mylang.cxx -I/usr/local/include -L/usr/local/lib -lswig -o myswig
</pre></blockquote>
Now, try running this new version of SWIG on a few interface files to see what happens. The various <tt>printf()</tt> statements will show you where output appears and how it is structured. For example, if we run this module on the following interface file :<p>
<p>
<blockquote><pre>/* File : example.i */
%module example
%{
/* Put headers and other declarations here */
%}
// A function
extern double foo(double a, double b);
// A variable
extern int bar;
// A constant
#define SPAM 42
</pre></blockquote>
We get the following output :<p>
<p>
<blockquote><pre>/*
* FILE : example_wrap.c
*
* This file was automatically generated by :
* Simplified Wrapper and Interface Generator (SWIG)
* Version 1.1 (Final)
*
* Portions Copyright (c) 1995-1997
* The University of Utah and The Regents of the University of California.
* Permission is granted to distribute this file in any manner provided
* this notice remains intact.
*
* Do not make changes to this file--changes will be lost!
*
*/
#define SWIGCODE
/* Implementation : My Language */
/* Put headers and other declarations here */
extern double foo(double ,double );
extern int bar;
wrap_foo() { }
int example_initialize() {
Creating command foo
Linking variable : bar
Creating constant : SPAM = 42
}
</pre></blockquote>
Looking at the language module and the output gives some idea of how things are structured. The first part of the file is a banner message printed by the <tt>emit_banner()</tt> function. The "extern" declarations are automatically supplied by the SWIG compiler when use an extern modifier. The wrapper functions appear after all of the headers and forward declarations. Finally, the initialization function is written.<p>
<p>
It is important to note that this minimal module is enough to use virtually all aspects of SWIG. If we feed SWIG a C++ file, we will see our low-level module functions being called even though we have not explicitly defined any C++ handling (this is due to the layered approach of implementing C++ on top of C). For example, the following interface file <p>
<blockquote><pre>
%module example
struct Vector {
double x,y,z;
Vector();
~Vector();
double magnitude();
};
</pre></blockquote>
<p>
produces accessor functions and the following output :<p>
<p>
<blockquote><pre>/*
* FILE : example_wrap.c
*
* This file was automatically generated by :
* Simplified Wrapper and Interface Generator (SWIG)
* Version 1.1 (Final)
*
* Portions Copyright (c) 1995-1997
* The University of Utah and The Regents of the University of California.
* Permission is granted to distribute this file in any manner provided
* this notice remains intact.
*
* Do not make changes to this file--changes will be lost!
*
*/
#define SWIGCODE
/* Implementation : My Language */
static double Vector_x_set(Vector *obj, double val) {
obj-&gt;x = val;
return val;
}
wrap_Vector_x_set() { }
static double Vector_x_get(Vector *obj) {
double result;
result = (double ) obj-&gt;x;
return result;
}
wrap_Vector_x_get() { }
static double Vector_y_set(Vector *obj, double val) {
obj-&gt;y = val;
return val;
}
wrap_Vector_y_set() { }
static double Vector_y_get(Vector *obj) {
double result;
result = (double ) obj-&gt;y;
return result;
}
wrap_Vector_y_get() { }
static double Vector_z_set(Vector *obj, double val) {
obj-&gt;z = val;
return val;
}
wrap_Vector_z_set() { }
static double Vector_z_get(Vector *obj) {
double result;
result = (double ) obj-&gt;z;
return result;
}
wrap_Vector_z_get() { }
static Vector *new_Vector() {
return new Vector();
}
wrap_new_Vector() { }
static void delete_Vector(Vector *obj) {
delete obj;
}
wrap_delete_Vector() { }
static double Vector_magnitude(Vector *obj) {
double _result = (double )obj-&gt;magnitude();
return _result;
}
wrap_Vector_magnitude() { }
int example_initialize() {
Creating command Vector_x_set
Creating command Vector_x_get
Creating command Vector_y_set
Creating command Vector_y_get
Creating command Vector_z_set
Creating command Vector_z_get
Creating command new_Vector
Creating command delete_Vector
Creating command Vector_magnitude
}
</pre></blockquote>
<p>
With just a little work, we already see that SWIG does quite alot for us. Now our task is to fill in the various Language methods with the real code needed to produce a working module. Before doing that, we first need to take a tour of some important SWIG datatypes and functions.<p>
<a name="n5"></a><h2> A tour of SWIG datatypes</h2>
While SWIG has become somewhat complicated over the last year, its internal operation is based on just a few fundamental datatypes. These types are described now although examples of using the various datatypes are shown later.<p>
<a name="n21"></a><h3> The DataType class</h3>
All C datatypes are represented by the following structure :<p>
<blockquote><pre>
class DataType {
public:
DataType();
DataType(DataType *);
~DataType();
int type; // SWIG Type code
char name[MAXNAME]; // Name of type
char is_pointer; // Is this a pointer?
char implicit_ptr; // Implicit ptr
char is_reference; // A C++ reference type
char status; // Is this datatype read-only?
char *qualifier; // A qualifier string (ie. const).
char *arraystr; // String containing array part
int id; // type identifier (unique for every type).
// Output methods
char *print_type(); // Return string containing datatype
char *print_full(); // Return string with full datatype
char *print_cast(); // Return string for type casting
char *print_mangle(); // Return mangled version of type
char *print_mangle_default(); // Default mangling scheme
char *print_real(); // Print the real datatype
char *print_arraycast(); // Prints an array cast
// Array query functions
int array_dimensions(); // Return number of array dimensions (if any)
char *get_dimension(int); // Return string for a particular dimension
};
</pre></blockquote>
The fundamental C datatypes are given a unique numerical code which is stored in the <tt>type</tt> field. The current list of types is as follows :<p>
<p>
<blockquote><pre>C Datatype SWIG Type Code
int T_INT
short T_SHORT
long T_LONG
char T_CHAR
float T_FLOAT
double T_DOUBLE
void T_VOID
unsigned int T_UINT
unsigned short T_USHORT
unsigned long T_ULONG
unsigned char T_UCHAR
signed char T_SCHAR
bool T_BOOL
&lt;user&gt; T_USER
error T_ERROR
</pre></blockquote>
<p>
The <tt>T_USER</tt> type is used for all derived datatypes including structures and classes. The <tt>T_ERROR</tt> type indicates that a parse/type error has occurred and went undetected (as far as I know this doesn't happen).<p>
<p>
The <tt>name[]</tt> field contains the actual name of the datatype as seen by the parser and is currently limited to a maximum of 96 bytes (more than enough for most applications). If a typedef has been used, the name field contains the actual name used, not the name of the primitive C datatype. Here are some examples :<p>
<p>
<blockquote><pre>C Datatype type name[]
double T_DOUBLE double
unsigned int T_UINT unsigned int
signed long T_LONG signed long
struct Vector T_USER struct Vector
Real T_DOUBLE Real
</pre></blockquote>
C qualifiers such as "<tt>const</tt>" or "<tt>volatile</tt>" are stored separately in the <tt>qualifier</tt> field. In order to produce usable wrapper code, SWIG often needs to strip the qualifiers. For example, trying to assign a passed function argument into a type of "<tt>const int</tt>" will irritate most compilers. Unfortunately, this kind of assignment is unavoidable when converting arguments between a scripting and C representation.<p>
<p>
The <tt>is_pointer</tt> field indicates whether or not a particular datatype is a pointer. The value of <tt>is_pointer</tt> determines the level of indirection used. For example :<p>
<p>
<blockquote><pre>C Datatype type is_pointer
double * T_DOUBLE 1
int *** T_INT 3
char * T_CHAR 1
</pre></blockquote>
The <tt>implicit_ptr</tt> field is an internally used parameter that is used to properly handle the use of pointers in typedef statements. However, for the curious, in indicates the level of indirection implicitly defined in a datatype. For example :<p>
<p>
<blockquote><pre>typedef char *String;
</pre></blockquote>
is represented by a datatype with the following parameters :<p>
<p>
<blockquote><pre>type = T_CHAR;
name[] = "String";
is_pointer = 1;
implicit_ptr = 1;
</pre></blockquote>
Normally, language modules do not worry about the <tt>implicit_ptr </tt>field.<p>
<p>
C++ references are indicated by the <tt>is_reference</tt> field. By default, the parser converts references into pointers which makes them indistinguishable from other pointer datatypes. However, knowing that something is a reference effects some code generation procedures so this field can be checked to see if a datatype really is a C++ reference.<p>
<p>
The <tt>arraystr</tt> field is used to hold the array dimensions of array datatypes. The dimensions are simply represented by a string. For example :<p>
<p>
<blockquote><pre>C Datatype type is_pointer arraystr
double a[50] T_DOUBLE 1 [50]
int b[20][30][50] T_INT 1 [20][30][50]
char *[MAX] T_CHAR 2 [MAX]
</pre></blockquote>
SWIG converts all arrays into pointers. Thus a "<tt>double [50]</tt>" is really just a special version of "<tt>double *</tt>". If a datatype is not declared as an array, the <tt>arraystr</tt> field contains the NULL pointer.<p>
<p>
A collection of "output" methods are available for datatypes. The names of these methods are mainly "historical" in that they don't actually "print" anything, but now return character strings instead. Assuming that <tt>t</tt> is a datatype representing the C datatype "<tt>const int *</tt>", here's what the methods produce :<p>
<p>
<blockquote><pre>Operation Output
t-&gt;print_type() int *
t-&gt;print_full() const int *
t-&gt;print_cast() (int *)
t-&gt;print_mangle() &lt; language dependent &gt;
t-&gt;print_mangle_default() _int_p
</pre></blockquote>
<p>
A few additional output methods are provided for dealing with arrays :<p>
<p>
<blockquote><pre>type Operation Output
int a[50] t-&gt;print_type() int *
int a[50] t-&gt;print_real() int [50]
int a[50] t-&gt;print_arraycast() (int *)
int a[50][50] t-&gt;print_arraycast() (int (*)[50])
</pre></blockquote>
Additional information about arrays is also available using the following functions :<p>
<p>
<blockquote><pre>type Operation Result
int a[50] t-&gt;array_dimension() 1
int a[50] t-&gt;get_dimension(0) 50
int b[MAXN][10] t-&gt;array_dimension() 2
int b[MAXN][10] t-&gt;get_dimension(0) MAXN
int b[MAXN][10] t-&gt;get_dimension(1) 10
</pre></blockquote>
The <tt>DataType</tt> class contains a variety of other methods for managing typedefs, scoping, and other operations. These are usually only used by the SWIG parser. While available to language modules too, they are never used (at least not in the current implementation), and should probably be avoided unless you absolutely know what you're doing (not that this is a strict requirement of course).<p>
<a name="n22"></a><h3> Function Parameters</h3>
Each argument of a function call is represented using the <tt>Parm</tt> structure :<p>
<p>
<blockquote><pre>struct Parm {
Parm(DataType *type, char *name);
Parm(Parm *p);
~Parm();
DataType *t; // Datatype of this parameter
int call_type; // Call type (value or reference or value)
char *name; // Name of parameter (optional)
char *defvalue; // Default value (as a string)
int ignore; // Ignore flag
};
</pre></blockquote>
<tt>t</tt> is the datatype of the parameter, <tt>name</tt> is an optional parameter name, and <tt>defvalue</tt> is a default argument value (if supplied). <p>
<p>
<tt>call_type</tt> is an integer code describing any special processing. It can be one of two values :<p>
<p>
<ul>
<li><tt>CALL_VALUE</tt>. This means that the argument is a pointer, but we should make it work like a call-by-value argument in the scripting interface. This value used to be set by the <tt>%val</tt> directive, but this approach is now deprecated (since the same effect can be achieved by typemaps).
<li><tt>CALL_REFERENCE</tt>. This is set when a complex datatype is being passed by value to a function. Since SWIG can't handle complex datatypes by value, the datatype is implicitly changed into a pointer and<tt> call_type</tt> set to <tt>CALL_REFERENCE</tt>. Many of SWIG's internals look at this when generating code. A common mistake is forgetting that all complex datatypes in SWIG are pointers. This is even the case when writing a language-module---the conversion to pointers takes place in the parser before data is even passed into a particular module.
</ul>
<p>
The <tt>ignore</tt> field is set when SWIG detects that a function parameter is to be "ignored" when generating wrapper functions. An "ignored" parameter is usually set to a default value and effectively disappears when a function call is made from a scripting language (that is, the function is called with fewer arguments than are specified in the interface file). The <tt>ignore</tt> field is normally only set when an "ignore" typemap has been used.<p>
<p>
All of the function parameters are passed in the structure <tt>ParmList</tt>. This structure has the following user-accesible methods available :<p>
<p>
<blockquote><pre>class ParmList {
public:
int nparms; // Number of parms in list
void append(Parm *p); // Append a parameter to the end
void insert(Parm *p, int pos); // Insert a parameter into the list
void del(int pos); // Delete a parameter at position pos
int numopt(); // Get number of optional arguments
int numarg(); // Get number of active arguments
Parm *get(int pos); // Get the parameter at position pos
};
</pre></blockquote>
The methods operate in the manner that you would expect. The most common operation that will be performed in a language module is walking down the parameter list and processing individual parameters. This can be done as follows :<p>
<p>
<blockquote><pre>// Walk down a parameter list
ParmList *l; // Function parameter list (already created)
Parm *p;
for (int i = 0; i &lt; l-&gt;nparms; i++) {
p = l-&gt;get(i); // Get ith parameter
// do something with the parameter
...
}
</pre></blockquote>
<a name="n23"></a><h3> The String Class</h3>
The process of writing wrapper functions is mainly just a tedious exercise in string manipulation. To make this easier, the <tt>String</tt> class provides relatively simple mechanism for constructing strings, concatenating values, replacing symbols, and so on. <p>
<p>
<blockquote><pre>class String {
public:
String();
String(const char *s);
~String();
char *get() const;
friend String&amp; operator&lt;&lt;(String&amp;,const char *s);
friend String&amp; operator&lt;&lt;(String&amp;,const int);
friend String&amp; operator&lt;&lt;(String&amp;,const char);
friend String&amp; operator&lt;&lt;(String&amp;,String&amp;);
friend String&amp; operator&gt;&gt;(const char *s, String&amp;);
friend String&amp; operator&gt;&gt;(String&amp;,String&amp;);
String&amp; operator=(const char *);
operator char*() const { return str; }
void untabify();
void replace(char *token, char *rep);
void replaceid(char *id, char *rep);
};
</pre></blockquote>
<p>
Strings can be manipulated in a manner that looks similar to C++ I/O operations. For example :<p>
<p>
<blockquote><pre>String s;
s &lt;&lt; "void" &lt;&lt; " foo() {\n"
&lt;&lt; tab4 &lt;&lt; "printf(\"Hello World\");\n"
&lt;&lt; "}\n";
fprintf(f_wrappers,"%s", (char *) s);
</pre></blockquote>
produces the output :<p>
<p>
<blockquote><pre>void foo() {
printf("Hello World");
}
</pre></blockquote>
The <tt>&lt;&lt;</tt> operator always appends to the end of a string while <tt>&gt;&gt;</tt> can be used to insert a string at the beginning. Strings may be used anywhere a <tt>char *</tt> is expected. For example :<p>
<p>
<blockquote><pre>String s1,s2;
...
if (strcmp(s1,s2) == 0) {
printf("Equal!\n");
}
</pre></blockquote>
The <tt>get()</tt> method can be used to explicitly return the <tt>char *</tt> containing the string data. The <tt>untabify()</tt> method replaces tabs with whitespace. The <tt>replace()</tt> method can be used to perform substring replacement and is used by typemaps. For example :<p>
<p>
<blockquote><pre>s.replace("$target","_arg3");
</pre></blockquote>
The <tt>replaceid()</tt> method can be used to replace valid C identifiers with a new value. C identifiers must be surrounded by white-space or other non-identifier characters. The <tt>replace()</tt> method does not have this restriction.<p>
<a name="n24"></a><h3> Hash Tables</h3>
Hash tables can be created using the <tt>Hash</tt> class :<p>
<p>
<blockquote><pre>class Hash {
public:
Hash();
~Hash();
int add(const char *key, void *object);
int add(const char *key, void *object, void (*del)(void *));
void *lookup(const char *key);
void remove(const char *key);
void *first();
void *next();
char *firstkey();
char *nextkey();
};
</pre></blockquote>
Hash tables store arbitrary objects (cast to <tt>void *</tt>) with string keys. An optional object deletion function may be registered with each entry to delete objects when the hash is destroyed. Hash tables are primarily used for managing internal symbol tables although language modules may also use them to keep track of special symbols and other state.<p>
<p>
The following hash table shows how one might keep track of real and renamed function names.<p>
<p>
<blockquote><pre>Hash wrapped_functions;
int add_function(char *name, char *renamed) {
char *nn = new char[strlen(renamed)+1];
strcpy(nn,renamed);
if (wrapped_functions.add(name,nn) == -1) {
printf("Function multiply defined!\n");
delete [] nn;
return -1;
}
}
char *get_renamed(char *name) {
char *rn = (char *) wrapped_functions.lookup(name);
return rn;
}
</pre></blockquote>
The <tt>remove()</tt> method removes a hash-table entry. The <tt>first()</tt> and <tt>next()</tt> methods are iterators for extracting all of the hashed objects. They return NULL when no more objects are found in the hash. The <tt>firstkey()</tt> and <tt>nextkey() </tt>methods are iterators that return the hash keys. NULL is returned when no more keys are found.<p>
<a name="n25"></a><h3> The WrapperFunction class</h3>
Finally, a <tt>WrapperFunction</tt> class is available for simplifying the creation of wrapper functions. The class is primarily designed to organize code generation and provide a few supporting services. The class is defined as follows :<p>
<p>
<blockquote><pre>class WrapperFunction {
public:
String def;
String locals;
String code;
void print(FILE *f);
void print(String &amp;f);
void add_local(char *type, char *name, char *defvalue = 0);
char *new_local(char *type, char *name, char *defvalue = 0);
};
</pre></blockquote>
Three strings are available. The <tt>def</tt> string contains the actual function declaration, the <tt>locals</tt> string contain local variable declarations, and the <tt>code</tt> string contains the resulting wrapper code.<p>
<p>
The method <tt>add_local()</tt> creates a new local variable which is managed with an internal symbol table (that detects variable conflicts and reports potential errors). The <tt>new_local()</tt> method can be used to create a new local variable that is guaranteed to be unique. Since a renaming might be required, this latter method returns the name of the variable that was actually selected for use (typically, this is derived from the original name).<p>
<p>
The <tt>print()</tt> method can be used to emit the wrapper function to a file. The printing process consolidates all of the strings into a single result.<p>
<p>
Here is a very simple example of the wrapper function class :<p>
<p>
<blockquote><pre>WrapperFunction f;
f.def &lt;&lt; "void count_n(int n) {";
f.add_local("int","i");
f.code &lt;&lt; tab4 &lt;&lt; "for (i = 0; i &lt; n; i++) {\n"
&lt;&lt; tab8 &lt;&lt; "printf(\"%d\\n\",i);\n"
&lt;&lt; tab4 &lt;&lt; "}\n"
&lt;&lt; "}\n";
f.print(f_wrappers);
</pre></blockquote>
This produces the following output :<p>
<p>
<blockquote><pre>void count_n(int n) {
int i;
for (i = 0; i &lt; n; i++) {
printf("%d\n",i);
}
}
</pre></blockquote>
Of course, as you can guess, the functions actually generated by your language module will be more complicated than this.<p>
<a name="n6"></a><h2> Typemaps (from C)</h2>
The typemapper plays a big role in generating code for all of SWIG's modules. Understanding the <tt>%typemap</tt> directive and how it works is probably a good starting point for understanding this section.<p>
<a name="n26"></a><h3> The typemap C API.</h3>
There is a relatively simple C API for managing typemaps in language modules.<p>
<p>
<h6> <b>void typemap_register(char *op, char *lang, DataType *type, char *pname,</b> <b> char *code, ParmList *l = 0);</b></h6>
<dl>
<dt><dd>
<dt><dd>Registers a new typemap with the typemapper. This is the C equivalent of the <tt>%typemap </tt>directive. For example :
<dt><dd>
<blockquote><pre> %typemap(lang,op) type pname { ... code ... };
%typemap(lang,op) type pname(ParmList) { ... code ... };
</pre></blockquote>
<dt><dd><tt>code</tt> contains the actual typemap code, while <tt>l</tt> is a parameter list containing local variable declarations. Normally, it is not necessary to execute this function from language modules.
<dt><dd>
</dl>
<h6> void typemap_register_default(char *op, char *lang, int type, int ptr, char *arraystr, char *code, ParmList *args)</h6>
<dl>
<dt><dd>
<dt><dd>Registers a default typemap. This works in the same way as the normal registration function, but takes a type code (an integer) instead. Default typemaps are more general than normal typemaps (see below).
<dt><dd>
</dl>
<h6> char *typemap_lookup(char *op, char *lang, DataType *type, char *pname, char *source, char *target, WrapperFunction *f = 0);</h6>
<dl>
<dt><dd>
<dt><dd>Looks up a typemap, performs variable substitutions, and returns a string with the corresponding typemap code. The tuple <tt>(op, lang, type, pname)</tt> determine which typemap to find. <tt>source</tt> contains the string to be assigned to the <tt>$source</tt> variable, <tt>target</tt> contains the string to be assigned to the<tt> $target</tt> variable. <tt>f</tt> is an optional wrapper function object. It should be supplied to support parameterized typemaps (ie. typemaps that declare additional local variables).
<dt><dd>
<dt><dd><tt>typemap_lookup()</tt> returns NULL is no typemap is found. Otherwise it returns a string containing the updated typemap code. This code has a number of variables substituted including <tt>$source</tt>, <tt>$target</tt>, <tt>$type</tt>, <tt>$mangle</tt>, and <tt>$basetype</tt>.
<dt><dd>
</dl>
<h6> char *typemap_check(char *op, char *lang, DataType *type, char *pname)</h6>
<p>
<dl>
<dt><dd>Checks to see if a typemap exists. The tuple <tt>(op, lang, type, pname)</tt> determine which typemap to find. If the typemap exists, the raw typemap code is returned. Otherwise, NULL is returned. While <tt>typemap_lookup()</tt> could be used to accomplish the same thing, this function is more compact and is significantly faster since it does not perform any variable substitutions.
<dt><dd>
</dl>
<a name="n27"></a><h3> What happens on typemap lookup?</h3>
When looking for a typemap, SWIG searches for a match in a series of steps.<p>
<p>
<ul>
<li>Explicit typemaps. These are specified directly with the <tt>%typemap()</tt> directive. Named typemaps have the highest precedence while arrays have higher precedence than pointers (see the typemap chapter for more details).
<li>If no explicit typemap is found, mappings applied with the <tt>%apply </tt>directive are checked. Basically, <tt>%apply </tt>is nothing more than a glorified renaming operation. We rename the datatype and see if there are any explicit typemaps that match. If so, we use the typemap that was found.
<li>Default typemaps. If no match is found with either explicit typemaps or apply directives, we make a final search using the default typemap. Unlike other typemaps, default typemaps are applied to the raw SWIG internal datatypes (<tt>T_INT</tt>, <tt>T_DOUBLE</tt>, <tt>T_CHAR</tt>, etc...). As a result, they are insentive to typedefs and renaming operations. If nothing is found here, a NULL pointer is returned indicating that no mapping was found for that particular datatype.
</ul>
<p>
Another way to think of the typemap mechanism is that it always tries to apply the most specific typemap that can be found for any particular datatype. When searching, it starts with the most specific and works its way out to the most general specification. If nothing is found it gives up and returns a NULL pointer.<p>
<a name="n28"></a><h3> How many typemaps are there?</h3>
All typemaps are identified by an operation string such as "in", "out", "memberin", etc... A number of typemaps are defined by other parts of SWIG, but you can create any sort of typemap that you wish by simply picking a new name and using it when making calls to <tt>typemap_lookup()</tt> and <tt>typemap_check()</tt>. <p>
<a name="n7"></a><h2> File management</h2>
The following functions are provided for managing files within SWIG. <p>
<p>
<h6> void add_directory(char *dirname);</h6>
<dl>
<dt><dd>
<dt><dd>Adds a new directory to the search path used to locate SWIG library files. This is the C equivalent of the <tt>swig</tt> <tt>-I</tt> option.
<dt><dd>
</dl>
<h6> int insert_file(char *filename, FILE *output);</h6>
<dl>
<dt><dd>
<dt><dd>Searches for a file and copies it into the given output stream. The search process goes through the SWIG library mechanism which first checks the current directory, then in various parts of the SWIG library for a match. Returns -1 if the file is not found. Language modules often use this function to insert supporting code. Usually these code fragments are given a `<tt>.swg</tt>' suffix and are placed in the SWIG library.
<dt><dd>
</dl>
<h6> int get_file(char *filename, String &amp;str);</h6>
<dl>
<dt><dd>
<dt><dd> Searches for a file and returns its contents in the String <tt>str.</tt>Returns a -1 if the file is not found.
</dl>
<p>
<h6> int checkout_file(char *source, char *dest);</h6>
<dl>
<dt><dd>
<dt><dd>Copies a file from the SWIG library into the current directory. <tt>dest </tt>is the filename of the desired file. This function will not replace a file that already exists. The primary use of this function is to give the user supporting code. For example, we could check out a Makefile if none exists. Returns -1 on failure.
<dt><dd>
</dl>
<h6> int include_file(char *filename);</h6>
<dl>
<dt><dd>
<dt><dd>The C equivalent of the SWIG <tt>%include</tt> directive. When called, SWIG will attempt to open <tt>filename</tt> and start parsing all of its contents. If successful, parsing of the new file will take place immediately. When the end of the file is reached, the parser switches back to the input file being read prior to this call. Returns -1 if the file is not found.
</dl>
<a name="n8"></a><h2> Naming Services</h2>
The naming module provides methods for generating the names of wrapper functions, accessor functions, and other aspects of SWIG. Each function returns a new name that is a syntactically correct C identifier where invalid characters have been converted to a "_". <p>
<p>
<h6> char *name_wrapper(char *fname, char *prefix);</h6>
<dl>
<dt><dd>Returns the name of a wrapper function. By default, it will be "<tt>_wrap_prefixfname</tt>".
<dt><dd>
</dl>
<h6> char *name_member(char *mname, char *classname;</h6>
<dl>
<dt><dd>Returns the name of a C++ accessor function. Normally, this is "<tt>classname_mname</tt>".
<dt><dd>
</dl>
<h6> char *name_get(char *vname);</h6>
<dl>
<dt><dd>Returns the name of a function to get the value of a variable or class data member. Normally "<tt>vname_get</tt>" is returned.
<dt><dd>
</dl>
<h6> char *name_set(char *vname);</h6>
<dl>
<dt><dd>Returns the name of a function to set the value of a variable or class data member. Normally, "<tt>vname_set</tt>" is returned.
<dt><dd>
</dl>
<h6> char *name_construct(char *classname);</h6>
<dl>
<dt><dd>Returns the name of a constructor function. Normally returns "<tt>new_classname</tt>".
<dt><dd>
</dl>
<h6> char *name_destroy(char *classname);</h6>
<dl>
<dt><dd>Returns the name of a destructor function. Normally returns "<tt>delete_classname</tt>".
<dt><dd>
</dl>
Each function may also accept an optional parameter of <tt>AS_IS</tt>. This suppresses the conversion of illegal characters (a process that is sometimes required). For example :<p>
<p>
<blockquote><pre>char *name = name_member("foo","bar",AS_IS); // Produce a name, but don't change
// illegal characters.
</pre></blockquote>
It is critical that language modules use the naming functions. These function are used throughout SWIG and provide a centralized mechanism for keeping track of functions that have been generated, managing multiple files, and so forth. In future releases, it may be possible to change the naming scheme used by SWIG. Using these functions should insure future compatibility.<p>
<a name="n9"></a><h2> Code Generation Functions</h2>
The following functions are used to emit code that is generally useful and used in essentially every SWIG language module.<p>
<p>
<h6> int emit_args(DataType *t, ParmList *l, WrapperFunction &amp;f);</h6>
<dl>
<dt><dd>Creates all of the local variables used for function arguments and return value. <tt>t</tt> is the return datatype of the function, <tt>l</tt> is the parameter list holding all of the function arguments. <tt>f</tt> is a WrapperFunction object where the local variables will be created.
<dt><dd>
</dl>
<h6> void emit_func_call(char *name, DataType *t, ParmList *l, WrapperFunction &amp;f);</h6>
<dl>
<dt><dd>Creates a function call to a C function. <tt>name</tt> is the name of the C function, <tt>t</tt> is the return datatype, <tt>l</tt> is the function parameters and <tt>f</tt> is a WrapperFunction object. The code generated by this function assumes that one has first called <tt>emit_args()</tt>.
<dt><dd>
</dl>
<h6> void emit_banner(FILE *file);</h6>
<dl>
<dt><dd>Emits the SWIG banner comment to the output file.
</dl>
<p>
<h6> void emit_set_get(char *name, char *rename, DataType *t);</h6>
<dl>
<dt><dd>Given a variable of type <tt>t</tt>, this function creates two functions to set and get the value. These functions are then wrapped like normal C functions. <tt>name</tt> is the real name of the variable. <tt>rename</tt> is the renamed version of the variable.
<dt><dd>
</dl>
<h6> void emit_ptr_equivalence(FILE *file);</h6>
<dl>
<dt><dd>To keep track of datatypes, SWIG maintains an internal table of "equivalent" datatypes. This table is updated by typedef, class definitions, and other C constructs. This function emits code compatible with the type-checker that is needed to make sure pointers work correctly. Typically this function is called after an interface file has been parsed completely.
</dl>
<a name="n10"></a><h2> Writing a Real Language Module</h2>
Whew, assuming you've made it this far, we're ready to write a real language module. In this example, we'll develop a simple Tcl module. Tcl has been chosen because it has a relatively simple C API that is well documented and easy to understand. The module developed here is not the same as the real SWIG Tcl module (which is significantly more complicated). <p>
<a name="n29"></a><h3> The header file</h3>
We will start with the same header file as before :<p>
<p>
<blockquote><pre>// File : mylang.h
// A simple SWIG Language module
class MYLANG : public Language {
private:
char *module;
public :
MYLANG() {
module = 0;
};
// Virtual functions required by the SWIG parser
void parse_args(int, char *argv[]);
void parse();
void create_function(char *, char *, DataType *, ParmList *);
void link_variable(char *, char *, DataType *);
void declare_const(char *, char *, DataType *, char *);
void initialize(void);
void headers(void);
void close(void);
void set_module(char *,char **);
void create_command(char *, char *);
};
</pre></blockquote>
<a name="n30"></a><h3> Command Line Options and Basic Initialization</h3>
Command line options are parsed using the <tt>parse_args()</tt> method :<p>
<blockquote><pre>
// ------------------------------------------------------------------------
// A simple SWIG Language module
//
// ------------------------------------------------------------------------
#include "swig.h"
#include "mylang.h"
static char *usage = "\
My Language Options\n\
-module name - Set name of module\n\n";
// ---------------------------------------------------------------------
// MYLANG::parse_args(int argc, char *argv[])
//
// Parse my command line options and initialize by variables.
// ---------------------------------------------------------------------
void MYLANG::parse_args(int argc, char *argv[]) {
// Look for certain command line options
for (int i = 1; i &lt; argc; i++) {
if (argv[i]) {
if (strcmp(argv[i],"-module") == 0) {
if (argv[i+1]) {
set_module(argv[i+1],0);
mark_arg(i);
mark_arg(i+1);
i++;
} else {
arg_error();
}
} else if (strcmp(argv[i],"-help") == 0) {
fprintf(stderr,"%s\n", usage);
}
}
}
// Set location of SWIG library
strcpy(LibDir,"tcl");
// Add a symbol to the parser for conditional compilation
add_symbol("SWIGTCL",0,0);
// Add typemap definitions
typemap_lang = "tcl";
}
</pre></blockquote>
Parsing command line options follows the same conventions as for writing a C++ main program with one caveat. For each option that your language module parses, you need to call the function <tt>mark_arg()</tt>. This tells the SWIG main program that your module found a valid option and used it. If you don't do this, SWIG will exit with an error message about unrecognized command line options.<p>
<p>
After processing command line options, you next need to set the variable <tt>LibDir</tt> with the name of the subdirectory your language will use to find files in the SWIG library. Since we are making a new Tcl module, we'll just set this to "<tt>tcl</tt>".<p>
<p>
Next, we may want to add a symbol to SWIG's symbol table. In this case we're adding "<tt>SWIGTCL</tt>" to indicate that we're using Tcl. SWIG modules can use this for conditional compilation and detecting your module using <tt>#ifdef</tt>. <p>
<p>
Finally, we need to set the variable <tt>typemap_lang</tt>. This should be assigned a name that you would like to use for all typemap declarations. When a user gives a typemap, they would use this name as the target language.<p>
<a name="n31"></a><h3> Starting the parser</h3>
To start the SWIG parser, the <tt>parse()</tt> method is used :<p>
<p>
<blockquote><pre>// ---------------------------------------------------------------------
// void MYLANG::parse()
//
// Start parsing an interface file for MYLANG.
// ---------------------------------------------------------------------
void MYLANG::parse() {
fprintf(stderr,"Making wrappers for Tcl\n");
headers(); // Emit header files and other supporting code
// Tell the parser to first include a typemap definition file
if (include_file("lang.map") == -1) {
fprintf(stderr,"Unable to find lang.map!\n");
SWIG_exit(1);
}
yyparse(); // Run the SWIG parser
}
</pre></blockquote>
<p>
This function should print some kind of message to the user indicating what language is being targeted. The <tt>headers()</tt> method is called (see below) to emit support code and header files. Finally, we make a call to <tt>yyparse()</tt>. This starts the SWIG parser and does not return until the entire interface file has been read. <p>
<p>
In our implementation, we have also added code to immediately include a file `<tt>lang.map</tt>'. This file will contain typemap definitions to be used by our module and is described in detail later. <p>
<a name="n32"></a><h3> Emitting headers and support code</h3>
Prior to emitting any code, our module should emit standard header files and support code. This is done using the <tt>headers()</tt> method :<p>
<blockquote><pre>// ---------------------------------------------------------------------
// MYLANG::headers(void)
//
// Generate the appropriate header files for MYLANG interface.
// ----------------------------------------------------------------------
void MYLANG::headers(void)
{
emit_banner(f_header); // Print the SWIG banner message
fprintf(f_header,"/* Implementation : My TCL */\n\n");
// Include header file code fragment into the output
if (insert_file("header.swg",f_header) == -1) {
fprintf(stderr,"Fatal Error. Unable to locate 'header.swg'.\n");
SWIG_exit(1);
}
// Emit the default SWIG pointer type-checker (for strings)
if (insert_file("swigptr.swg",f_header) == -1) {
fprintf(stderr,"Fatal Error. Unable to locate 'swigptr.swg'.\n");
SWIG_exit(1);
}
}
</pre></blockquote>
In this implementation, we emit the standard SWIG banner followed by a comment indicating which language module is being used. After that, we are going to include two different files. `<tt>header.swg'</tt> is a file containing standard declarations needed to build a Tcl extension. For our example, it will look like this :<p>
<p>
<blockquote><pre>/* File : header.swg */
#include &lt;tcl.h&gt;
</pre></blockquote>
The file `<tt>swigptr.swg'</tt> contains the standard SWIG pointer-type checking library. This library contains about 300 lines of rather nasty looking support code that define the following 3 functions :<p>
<p>
<h6> void SWIG_RegisterMapping(char *type1, char *type, void *(*cast)(void *))</h6>
<dl>
<dt><dd>Creates a mapping between C datatypes <tt>type1</tt> and <tt>type2</tt>. This is registered with the runtime type-checker and is similiar to a typedef. <tt>cast</tt> is an optional function pointer defining a method for proper pointer conversion (if needed). Normally, cast is only used when converting between base and derived classes in C++ and is needed for proper implementation of multiple inheritance.
</dl>
<p>
<h6> void SWIG_MakePtr(char *str, void *ptr, char *type);</h6>
<dl>
<dt><dd>Makes a string representation of a C pointer. The result is stored in <tt>str</tt> which is assumed to be large enough to hold the result. <tt>ptr</tt> contains the pointer value and <tt>type</tt> is a string code corresponding to the datatype.
<dt><dd>
</dl>
<h6> char *SWIG_GetPtr(char *str, void **ptr, char *type);</h6>
<dl>
<dt><dd>Extracts a pointer from its string representation, performs type-checking, and casting. <tt>str</tt> is the string containing the pointer-value representation, <tt>ptr</tt> is the address of the pointer that will be returned, and <tt>type </tt>is the string code corresponding to the datatype. If a type-error occurs, the function returns a <tt>char *</tt> corresponding to the part of the input string that was invalid, otherwise the function returns NULL. If a NULL pointer is given for <tt>type</tt>, the function will accept a pointer of any type.
</dl>
<p>
We will use these functions later.<p>
<a name="n33"></a><h3> Setting a module name</h3>
The <tt>set_module()</tt> method is used whenever the <tt>%module</tt> directive is encountered.<p>
<blockquote><pre>
// ---------------------------------------------------------------------
// MYLANG::set_module(char *mod_name,char **mod_list)
//
// Sets the module name. Does nothing if it's already set (so it can
// be overriddent as a command line option).
//
// mod_list is a NULL-terminated list of additional modules to initialize
// and is only provided if the user specifies something like this :
// %module foo, mod1, mod2, mod3, mod4
//----------------------------------------------------------------------
void MYLANG::set_module(char *mod_name, char **mod_list) {
if (module) return;
module = new char[strlen(mod_name)+1];
strcpy(module,mod_name);
// Make sure the name conforms to Tcl naming conventions
for (char *c = module; (*c); c++)
*c = tolower(*c);
toupper(module);
}
</pre></blockquote>
This function may, in fact, be called multiple times in the course of processing. Normally, we only allow a module name to be set once and ignore all subsequent calls however.<p>
<a name="n34"></a><h3> Final Initialization</h3>
The initialization of a module takes several steps--parsing command line options, printing standard header files, starting the parser, and setting the module name. The final step in initialization is calling the <tt>initialize()</tt> method :<p>
<p>
<blockquote><pre>// --------------------------------------------------------------------
// MYLANG::initialize(void)
//
// Produces an initialization function. Assumes that the module
// name has already been specified.
// ---------------------------------------------------------------------
void MYLANG::initialize()
{
// Check if a module has been defined
if (!module) {
fprintf(stderr,"Warning. No module name given!\n");
module = "swig";
}
// Generate a CPP symbol containing the name of the initialization function
fprintf(f_header,"#define SWIG_init %s_Init\n\n\n", module);
// Start generating the initialization function
fprintf(f_init,"int SWIG_init(Tcl_Interp *interp) {\n");
fprintf(f_init,"\t if (interp == 0) return TCL_ERROR;\n");
}
</pre></blockquote>
The <tt>initialize()</tt> method should create the module initialization function by emitting code to <tt>f_init</tt> as shown. By this point, we should already know the name of the module, but should check just in case. The preferred style of creating the initialization function is to create a C preprocessor symbol <tt>SWIG_init</tt>. Doing so may look weird, but it turns out that many SWIG library files may want to know the name of the initialization function. If we define a symbol for it, these files can simply assume that it's called <tt>SWIG_init()</tt> and everything will work out (okay, so it's a hack).<p>
<a name="n35"></a><h3> Cleanup </h3>
When an interface file has finished parsing, we need to clean everything up. This is done using the <tt>close()</tt> method :<p>
<p>
<blockquote><pre>// ---------------------------------------------------------------------
// MYLANG::close(void)
//
// Wrap things up. Close initialization function.
// ---------------------------------------------------------------------
void MYLANG::close(void)
{
// Dump the pointer equivalency table
emit_ptr_equivalence(f_init);
// Finish off our init function and print it to the init file
fprintf(f_init,"\t return TCL_OK;\n");
fprintf(f_init,"}\n");
}
</pre></blockquote>
The <tt>close()</tt> method should first call <tt>emit_ptr_equivalence()</tt> if the SWIG pointer type checker has been used. This dumps out support code to make sure the type-checker works correctly. Afterwards, we simply need to terminate our initialization function as shown. After this function has been called, SWIG dumps out all of its documentation files and exits.<p>
<a name="n36"></a><h3> Creating Commands</h3>
Now, we're moving into the code generation part of SWIG. The first step is to make a function to create scripting language commands. This is done using the <tt>create_command()</tt> function :<p>
<p>
<blockquote><pre>// ----------------------------------------------------------------------
// MYLANG::create_command(char *cname, char *iname)
//
// Creates a Tcl command from a C function.
// ----------------------------------------------------------------------
void MYLANG::create_command(char *cname, char *iname) {
// Create a name for the wrapper function
char *wname = name_wrapper(cname,"");
// Create a Tcl command
fprintf(f_init,"\t Tcl_CreateCommand(interp,\"%s\",%s, (ClientData) NULL,
(Tcl_CmdDeleteProc *) NULL);\n", iname, wname);
}
</pre></blockquote>
<p>
For our Tcl module, this just calls Tcl_CreateCommand to make a new scripting language command. <p>
<a name="n37"></a><h3> Creating a Wrapper Function</h3>
The most complicated part of writing a language module is the process of creating wrapper functions. This is done using the <tt>create_function()</tt> method as shown here :<p>
<blockquote><pre>
// ----------------------------------------------------------------------
// MYLANG::create_function(char *name, char *iname, DataType *d, ParmList *l)
//
// Create a function declaration and register it with the interpreter.
// ----------------------------------------------------------------------
void MYLANG::create_function(char *name, char *iname, DataType *t, ParmList *l)
{
String source, target;
char *tm;
String cleanup, outarg;
WrapperFunction f;
// Make a wrapper name for this function
char *wname = name_wrapper(iname,"");
// Now write the wrapper function itself
f.def &lt;&lt; "static int " &lt;&lt; wname &lt;&lt; "(ClientData clientData, Tcl_Interp *interp, int
argc, char *argv[]) {\n";
// Emit all of the local variables for holding arguments.
int pcount = emit_args(t,l,f);
// Get number of optional/default arguments
int numopt = l-&gt;numopt();
// Emit count to check the number of arguments
f.code &lt;&lt; tab4 &lt;&lt; "if ((argc &lt; " &lt;&lt; (pcount-numopt) + 1 &lt;&lt; ") || (argc &gt; "
&lt;&lt; l-&gt;numarg()+1 &lt;&lt; ")) {\n"
&lt;&lt; tab8 &lt;&lt; "Tcl_SetResult(interp, \"Wrong # args.\",TCL_STATIC);\n"
&lt;&lt; tab8 &lt;&lt; "return TCL_ERROR;\n"
&lt;&lt; tab4 &lt;&lt; "}\n";
// Now walk the function parameter list and generate code to get arguments
int j = 0; // Total number of non-optional arguments
for (int i = 0; i &lt; pcount ; i++) {
Parm &amp;p = (*l)[i]; // Get the ith argument
source = "";
target = "";
// Produce string representation of source and target arguments
source &lt;&lt; "argv[" &lt;&lt; j+1 &lt;&lt; "]";
target &lt;&lt; "_arg" &lt;&lt; i;
if (!p.ignore) {
if (j &gt;= (pcount-numopt)) // Check if parsing an optional argument
f.code &lt;&lt; tab4 &lt;&lt; "if argc &gt;" &lt;&lt; j+1 &lt;&lt; ") {\n";
// Get typemap for this argument
tm = typemap_lookup("in",typemap_lang,p.t,p.name,source,target,&amp;f);
if (tm) {
f.code &lt;&lt; tm &lt;&lt; "\n";
f.code.replace("$arg",source); // Perform a variable replacement
} else {
fprintf(stderr,"%s : Line %d. No typemapping for datatype %s\n",
input_file,line_number, p.t-&gt;print_type());
}
if (j &gt;= (pcount-numopt))
f.code &lt;&lt; tab4 &lt;&lt; "} \n";
j++;
}
// Check to see if there was any sort of a constaint typemap
if ((tm = typemap_lookup("check",typemap_lang,p.t,p.name,source,target))) {
f.code &lt;&lt; tm &lt;&lt; "\n";
f.code.replace("$arg",source);
}
// Check if there was any cleanup code (save it for later)
if ((tm = typemap_lookup("freearg",typemap_lang,p.t,p.name,target,
"interp-&gt;result"))) {
cleanup &lt;&lt; tm &lt;&lt; "\n";
cleanup.replace("$arg",source);
}
if ((tm = typemap_lookup("argout",typemap_lang,p.t,p.name,target,
"interp-&gt;result"))) {
outarg &lt;&lt; tm &lt;&lt; "\n";
outarg.replace("$arg",source);
}
}
// Now write code to make the function call
emit_func_call(name,t,l,f);
// Return value if necessary
if ((t-&gt;type != T_VOID) || (t-&gt;is_pointer)) {
if ((tm = typemap_lookup("out",typemap_lang,t,name,"_result","interp-&gt;result"))) {
// Yep. Use it instead of the default
f.code &lt;&lt; tm &lt;&lt; "\n";
} else {
fprintf(stderr,"%s : Line %d. No return typemap for datatype %s\n",
input_file,line_number,t-&gt;print_type());
}
}
// Dump argument output code;
f.code &lt;&lt; outarg;
// Dump the argument cleanup code
f.code &lt;&lt; cleanup;
// Look for any remaining cleanup. This processes the %new directive
if (NewObject) {
if ((tm = typemap_lookup("newfree",typemap_lang,t,iname,"_result",""))) {
f.code &lt;&lt; tm &lt;&lt; "\n";
}
}
// Special processing on return value.
if ((tm = typemap_lookup("ret",typemap_lang,t,name,"_result",""))) {
f.code &lt;&lt; tm &lt;&lt; "\n";
}
// Wrap things up (in a manner of speaking)
f.code &lt;&lt; tab4 &lt;&lt; "return TCL_OK;\n}";
// Substitute the cleanup code (some exception handlers like to have this)
f.code.replace("$cleanup",cleanup);
// Emit the function
f.print(f_wrappers);
// Now register the function with the language
create_command(iname,iname);
}
</pre></blockquote>
<p>
Creating a wrapper function really boils down to 3 components :<p>
<p>
<ul>
<li>Emit local variables and handling input arguments.
<li>Call the real C function.
<li>Convert the return value to a scripting language representation.
</ul>
<p>
In our implementation, most of this work is done using typemaps. In fact, the role of the C++ code is really just to process typemaps in the appropriate order and to combine strings in the correct manner. The following typemaps are used in this procedure :<p>
<p>
<ul>
<li>"in". This is used to convert function arguments from Tcl to C.
<li>"out". This is used to convert the return value from C to Tcl.
<li>"check". This is used to apply constraints to the input values.
<li>"argout". Used to return values through function parameters.
<li>"freearg". Used to clean up arguments after a function call (possibly to release memory, etc...)
<li>"ret". Used to clean up the return value of a C function (possibly to release memory).
<li>"newfree" this is special processing applied when the <tt>%new</tt> directive has been used. Usually its used to clean up memory.
</ul>
<p>
It may take awhile for this function to sink in, but its operation will hopefully become more clear shortly. <p>
<a name="n38"></a><h3> Manipulating Global Variables</h3>
To provide access to C global variables, the <tt>link_variable()</tt> method is used. In the case of Tcl, only <tt>int</tt>, <tt>double</tt>, and <tt>char * </tt>datatypes can be safely linked.<p>
<p>
<blockquote><pre>// -----------------------------------------------------------------------
// MYLANG::link_variable(char *name, char *iname, DataType *t)
//
// Create a Tcl link to a C variable.
// -----------------------------------------------------------------------
void MYLANG::link_variable(char *name, char *iname, DataType *t) {
char *tm;
// Uses a typemap to stick code into the module initialization function
if ((tm = typemap_lookup("varinit",typemap_lang,t,name,name,iname))) {
String temp = tm;
if (Status &amp; STAT_READONLY)
temp.replace("$status"," | TCL_LINK_READ_ONLY");
else
temp.replace("$status","");
fprintf(f_init,"%s\n",(char *) temp);
} else {
fprintf(stderr,"%s : Line %d. Unable to link with variable type %s\n",
input_file,line_number,t-&gt;print_type());
}
}
</pre></blockquote>
<p>
In this case, the procedure is looking for a typemap "varinit". We'll use the code specified with this typemap to create variable links. If no typemap is supplied or the user gives an unsupported datatypes, a warning message will be generated.<p>
<p>
It is also worth noting that the <tt>Status</tt> variable contains information about whether or not a variable is read-only or not. To test for this, use the technique shown in the code above. Read-only variables may require special processing as shown.<p>
<a name="n39"></a><h3> Constants</h3>
Finally, creating constants is accomplished using the <tt>declare_const()</tt> method. For Tcl, we could do this :<p>
<p>
<blockquote><pre>// -----------------------------------------------------------------------
// MYLANG::declare_const(char *name, char *iname, DataType *type, char *value)
//
// Makes a constant.
// ------------------------------------------------------------------------
void MYLANG::declare_const(char *name, char *iname, DataType *type, char *value) {
char *tm;
if ((tm = typemap_lookup("const",typemap_lang,type,name,name,iname))) {
String str = tm;
str.replace("$value",value);
fprintf(f_init,"%s\n", (char *) str);
} else {
fprintf(stderr,"%s : Line %d. Unable to create constant %s = %s\n",
input_file, line_number, type-&gt;print_type(), value);
}
}
</pre></blockquote>
We take the same approach used to create variables. In this case, the `<tt>const</tt>' typemap specifies the special processing.<p>
<p>
The value of a constant is a string produced by the SWIG parser. It may contain an arithmetic expression such as "3 + 4*(7+8)". Because of this, it is critical to use this string in a way that allows it to be evaluated by the C compiler (this will be apparent when the typemaps are given).<p>
<a name="n40"></a><h3> A Quick Intermission</h3>
We are now done writing all of the methods for our language class. Of all of the methods, <tt>create_function()</tt> is the most complicated and tends to do most of the work. We have also ignored issues related to documentation processing and C++ handling (although C++ will work with the functions we have defined so far).<p>
<p>
While our C++ implementation is done, we still do not have a working language module. In fact, if we run SWIG on the following interface file :<p>
<p>
<blockquote><pre>/* File : example.i */
%module example
%{
/* Put headers and other declarations here */
%}
// A function
extern double foo(double a, double b);
// A variable
extern int bar;
// A constant
#define SPAM 42
</pre></blockquote>
we get the following errors :<p>
<p>
<blockquote><pre>[beazley@guinness lang]$ ./myswig example.i
Making wrappers for My Tcl
example.i : Line 9. No typemapping for datatype double
example.i : Line 9. No typemapping for datatype double
example.i : Line 9. No return typemap for datatype double
example.i : Line 12. Unable to link with variable type int
example.i : Line 16. Unable to create constant int = 42
[beazley@guinness lang]$
</pre></blockquote>
The reason for this is that we have not yet defined any processing for real datatypes. For example, our language module has no idea how to convert doubles into Tcl strings, how to link with C variables and so on. To do this, we need to write a collection of typemaps.<p>
<a name="n41"></a><h3> Writing the default typemaps</h3>
In our earlier <tt>parse()</tt> method, there is a statement to include the file `<tt>lang.map</tt>'. We will use this file to write typemaps for our new language module. The `<tt>lang.map</tt>' file will actually go through the SWIG parser so we can write our typemaps using the normal <tt>%typemap</tt> directive. This approach makes it easy for us to debug and test our module because the typemaps can be developed and tested without having to repeatedly recompile the C++ part of the module. <p>
<p>
Without further delay, here is the typemap file for our module (you might want to sit down) :<p>
<p>
<blockquote><pre>// ----------------------------------------------------------------------
// lang.map
//
// This file defines all of the type-mappings for our language (TCL).
// A typemap of 'SWIG_DEFAULT_TYPE' should be used to create default
// mappings.
// ----------------------------------------------------------------------
/**************************** FUNCTION INPUTS ****************************/
// Integers
%typemap(in) int SWIG_DEFAULT_TYPE,
short SWIG_DEFAULT_TYPE,
long SWIG_DEFAULT_TYPE,
unsigned int SWIG_DEFAULT_TYPE,
unsigned short SWIG_DEFAULT_TYPE,
unsigned long SWIG_DEFAULT_TYPE,
signed char SWIG_DEFAULT_TYPE,
unsigned char SWIG_DEFAULT_TYPE
{
int temp;
if (Tcl_GetInt(interp, $source, &amp;temp) == TCL_ERROR) return TCL_ERROR;
$target = ($type) temp;
}
// Floating point
%typemap(in) float SWIG_DEFAULT_TYPE,
double SWIG_DEFAULT_TYPE
{
double temp;
if (Tcl_GetDouble(interp, $source, &amp;temp) == TCL_ERROR) return TCL_ERROR;
$target = ($type) temp;
}
// Strings
%typemap(in) char * SWIG_DEFAULT_TYPE
{
$target = $source;
}
// void *
%typemap(in) void * SWIG_DEFAULT_TYPE
{
if (SWIG_GetPtr($source,(void **) &amp;$target, (char *) 0)) {
Tcl_SetResult(interp,"Type error. Expected a pointer",TCL_STATIC);
return TCL_ERROR;
}
}
// User defined types and all other pointers
%typemap(in) User * SWIG_DEFAULT_TYPE
{
if (SWIG_GetPtr($source,(void **) &amp;$target, "$mangle")) {
Tcl_SetResult(interp,"Type error. Expected a $mangle",TCL_STATIC);
return TCL_ERROR;
}
}
/**************************** FUNCTION OUTPUTS ****************************/
// Signed integers
%typemap(out) int SWIG_DEFAULT_TYPE,
short SWIG_DEFAULT_TYPE,
long SWIG_DEFAULT_TYPE,
signed char SWIG_DEFAULT_TYPE
{
sprintf($target,"%ld", (long) $source);
}
// Unsigned integers
%typemap(out) unsigned SWIG_DEFAULT_TYPE,
unsigned short SWIG_DEFAULT_TYPE,
unsigned long SWIG_DEFAULT_TYPE,
unsigned char SWIG_DEFAULT_TYPE
{
sprintf($target,"%lu", (unsigned long) $source);
}
// Floating point
%typemap(out) double SWIG_DEFAULT_TYPE,
float SWIG_DEFAULT_TYPE
{
Tcl_PrintDouble(interp,(double) $source,interp-&gt;result);
}
// Strings
%typemap(out) char *SWIG_DEFAULT_TYPE
{
Tcl_SetResult(interp,$source,TCL_VOLATILE);
}
// Pointers
%typemap(out) User *SWIG_DEFAULT_TYPE
{
SWIG_MakePtr($target,(void *) $source, "$mangle");
}
/**************************** VARIABLE CREATION ****************************/
// Integers
%typemap(varinit) int SWIG_DEFAULT_TYPE,
unsigned int SWIG_DEFAULT_TYPE
{
Tcl_LinkVar(interp, "$target", (char *) &amp;$source, TCL_LINK_INT $status);
}
// Doubles
%typemap(varinit) double SWIG_DEFAULT_TYPE {
Tcl_LinkVar(interp,"$target", (char *) &amp;$source, TCL_LINK_DOUBLE $status);
}
// Strings
%typemap(varinit) char * SWIG_DEFAULT_TYPE {
Tcl_LinkVar(interp,"$target", (char *) &amp;$source, TCL_LINK_STRING $status);
}
/****************************** CONSTANTS **********************************/
// Signed Integers
%typemap(const) int SWIG_DEFAULT_TYPE,
short SWIG_DEFAULT_TYPE,
long SWIG_DEFAULT_TYPE,
signed char SWIG_DEFAULT_TYPE
{
static char *_wrap_$target;
_wrap_$target = (char *) malloc(40);
sprintf(_wrap_$target,"%ld",$value);
Tcl_LinkVar(interp,"$target", (char *) &amp;_wrap_$target, TCL_LINK_STRING |
TCL_LINK_READ_ONLY);
}
// Unsigned integers
%typemap(const) unsigned SWIG_DEFAULT_TYPE,
unsigned short SWIG_DEFAULT_TYPE,
unsigned long SWIG_DEFAULT_TYPE,
unsigned char SWIG_DEFAULT_TYPE
{
static char *_wrap_$target;
_wrap_$target = (char *) malloc(40);
sprintf(_wrap_$target,"%lu",$value);
Tcl_LinkVar(interp,"$target", (char *) &amp;_wrap_$target, TCL_LINK_STRING |
TCL_LINK_READ_ONLY);
}
// Doubles and floats
%typemap(const) double SWIG_DEFAULT_TYPE,
float SWIG_DEFAULT_TYPE
{
static char *_wrap_$target;
_wrap_$target = (char *) malloc(40);
sprintf(_wrap_$target,"%f",$value);
Tcl_LinkVar(interp,"$target", (char *) &amp;_wrap_$target, TCL_LINK_STRING |
TCL_LINK_READ_ONLY);
}
// Strings
%typemap(const) char *SWIG_DEFAULT_TYPE
{
static char *_wrap_$target = "$value";
Tcl_LinkVar(interp,"$target", (char *) &amp;_wrap_$target, TCL_LINK_STRING |
TCL_LINK_READ_ONLY);
}
// Pointers
%typemap(const) User *SWIG_DEFAULT_TYPE
{
static char *_wrap_$target;
_wrap_$target = (char *) malloc(20+strlen("$mangle"));
SWIG_MakePtr(_wrap_$target, (void *) $value, "$mangle");
Tcl_LinkVar(interp,"$target", (char *) &amp;_wrap_$target, TCL_LINK_STRING |
TCL_LINK_READ_ONLY);
}
</pre></blockquote>
Now that we have our typemaps file, we are done and can start producing a variety of interesting Tcl extension modules. Should errors arrise, one will either have to pry into the C++ module or the typemaps file for a correction. <p>
<a name="n42"></a><h3> The SWIG library and installation issues</h3>
To make a new SWIG module generally usable, you will want to perform the following steps :<p>
<p>
<ul>
<li>Put the new binary in a publicly accessible location (ie. <tt>/usr/local/bin</tt>).
<li>Make a subdirectory for your language in the SWIG library. The library should match up with the name you assigned to the <tt>LibDir</tt> variable in <tt>parse_args()</tt>.
<li>Copy the file `<tt>lang.map</tt>' to the SWIG library directory. Your new version of SWIG will now be able to find it no matter what directory SWIG is executed from.
<li>Provide some documentation about how your module works.
</ul>
<p>
SWIG extensions are only able to target a single scripting language. If you would like to make your module part of the full version of SWIG, you will need to modify the file `<tt>swigmain.cxx</tt>' in the <tt>SWIG1.1/Modules</tt> directory. To do this, follow these steps :<p>
<p>
<ul>
<li>Add a <tt>#include "lang.h"</tt> to the<tt> swigmain.cxx</tt> file.
<li>Create a command line option for your module and write code to create an instance of your language (just copy the technique used for the other languages).
<li>Modify <tt>Modules/Makefile</tt> to include your module as part of its compilation process.
<li>Rebuild SWIG by typing `make'.
</ul>
<a name="n11"></a><h2> C++ Processing</h2>
Language modules have the option to provide special processing for C++ classes. Usually this is to provide some sort of object-oriented interface such as shadow classes. The process of developing these extensions is highly technical and the best approach may be to copy pieces from other SWIG modules that provide object oriented support.<p>
<a name="n43"></a><h3> How C++ processing works</h3>
The wrapping of C++ classes follows a "file" metaphor. When a class is encountered, the following steps are performed :<p>
<p>
<ul>
<li>Open a new class.
<li>Inherit from base classes.
<li>Add members to the class (functions, variables, constants, etc...)
<li>Close the class and emit object-oriented code.
</ul>
<p>
As a class is constructed, a language module may need to keep track of a variety of data such as whether constructors or destructors have been given, are there any data members, have datatypes been renamed, and so on. It is not always a clear-cut process.<p>
<a name="n44"></a><h3> Language extensions</h3>
Providing additional support for object-oriented programming requires the use of the following Language extensions. These are additional methods that can be defined for the Language class.<p>
<p>
<h6> void cpp_open_class(char *name, char *rename, char *ctype, int strip);</h6>
<dl>
<dt><dd>Opens a new class. <tt>name</tt> is the name of the class, <tt>rename</tt> is the renamed version of the class (or NULL if not renamed), <tt>ctype</tt> is the class type (<tt>struct</tt>, <tt>class</tt>, <tt>union</tt>), and <tt>strip</tt> is a flag indicating whether or not its safe to drop the leading type specifier (this is often unsafe for ANSI C).
<dt><dd>
</dl>
<h6> void cpp_inherit(char **baseclass, int mode = INHERIT_ALL);</h6>
<dl>
<dt><dd>Inherits from base classes. <tt>baseclass</tt> is a NULL terminated array of class names corresponding to all of the base classes of an object. <tt>mode</tt> is an inheritance mode that is the or'd value of <tt>INHERIT_FUNC</tt> , <tt>INHERIT_VAR</tt>, <tt>INHERIT_CONST</tt>, or <tt>INHERIT_ALL</tt>.
<dt><dd>
</dl>
<h6> void cpp_member_func(char *name, char *iname, DataType *t, ParmList *l);</h6>
<dl>
<dt><dd>Creates a member function. <tt>name</tt> is the real name of the member, <tt>iname</tt> is the renamed version (NULL if not renamed), <tt>t</tt> is the return datatype, and <tt>l</tt> is the function parameter list.
<dt><dd>
</dl>
<h6> void cpp_static_func(char *name, char *iname, DataType *t, ParmList *l);</h6>
<dl>
<dt><dd>Create a static member function. The calling conventions are the same as for <tt>cpp_member_func()</tt>.
<dt><dd>
</dl>
<h6> void cpp_variable(char *name, char *iname, DataType *t);</h6>
<dl>
<dt><dd>Creates a member variable. <tt>name</tt> is the real name of the member, <tt>iname</tt> is the renamed version (NULL is not renamed). <tt>t</tt> is the type of the member.
<dt><dd>
</dl>
<h6> void cpp_static_var(char *name, char *iname, DataType *t);</h6>
<dl>
<dt><dd>Creates a static member variable. The calling convention is the same as for <tt>cpp_variable()</tt>.
<dt><dd>
</dl>
<h6> void cpp_declare_const(char *name, char *iname, DataType *type, char *value);</h6>
<dl>
<dt><dd>Creates a constant inside a C++ class. Normally this is an enum or member declared as const. <tt>name</tt> is the real name, <tt>iname</tt> is the renamed version (NULL if not renamed), <tt>type</tt> is the type of the constant, and <tt>value</tt> is a string containing the value.
<dt><dd>
</dl>
<h6> void cpp_constructor(char *name, char *iname, ParmList *l);</h6>
<dl>
<dt><dd>Creates a constructor. <tt>name</tt> is the name of the constructor, <tt>iname</tt> is the renamed version, and <tt>l</tt> is the function parameter list. Normally, <tt>name</tt> is the same name as the class. If not, this may actually be a member function with no declared return type (assumed to be an int in C++).
<dt><dd>
</dl>
<h6> void cpp_destructor(char *name, char *newname);</h6>
<dl>
<dt><dd>Creates a destructor. <tt>name</tt> is the real name of the destructor (usually the same name as the class), and <tt>newname</tt> is the renamed version (NULL if not renamed).
<dt><dd>
</dl>
<h6> void cpp_close_class();</h6>
<dl>
<dt><dd>Closes the current class. Language modules should finish off code generation for a class once this has been called.
<dt><dd>
</dl>
<h6> void cpp_cleanup();</h6>
<dl>
<dt><dd>Called after all C++ classes have been generated. Only used to provide some kind of global cleanup for all classes.
</dl>
<a name="n45"></a><h3> Hints</h3>
Special C++ code generation is not for the weak of heart. Most of SWIG's built in modules have been developed for well over a year and object oriented support has been in continual development. If writing a new language module, looking at the implementation for Python, Tcl, or Perl5 would be a good start.<p>
<a name="n12"></a><h2> Documentation Processing</h2>
The documentation system operates (for the most part), independently of the language modules. However, language modules are still responsible for generating a "usage" string describing how each function, variable, or constant is to be used in the target language.<p>
<a name="n46"></a><h3> Documentation entries</h3>
Each C/C++ declaration in an interface file gets assigned to a "Documentation Entry" that is described by the <tt>DocEntry</tt> object :<p>
<p>
<blockquote><pre>class DocEntry {
public:
String usage; // Short description
String cinfo; // Information about C interface (optional).
String text; // Supporting text (optional)
};
</pre></blockquote>
The <tt>usage</tt> string is used to hold the calling sequence for the function. The <tt>cinfo</tt> field is used to provide additional information about the underlying C code. <tt>text</tt> is filled in with comment text.<p>
<p>
The global variable <tt>doc_entry</tt> always contains the documentation entry for the current declaration being processed. Language modules can choose to update the documentation by referring to and modifying its fields.<p>
<a name="n47"></a><h3> Creating a usage string</h3>
To create a documentation usage string, language modules need to modify the `usage' field of <tt>doc_entry</tt>. This can be done by creating a function like this :<p>
<p>
<blockquote><pre>// ---------------------------------------------------------------------------
// char *TCL::usage_string(char *iname, DataType *t, ParmList *l),
//
// Generates a generic usage string for a Tcl function.
// ---------------------------------------------------------------------------
char * TCL::usage_string(char *iname, DataType *, ParmList *l) {
static String temp;
Parm *p;
int i, numopt,pcount;
temp = "";
temp &lt;&lt; iname &lt;&lt; " ";
/* Now go through and print parameters */
i = 0;
pcount = l-&gt;nparms;
numopt = l-&gt;numopt();
p = l-&gt;get_first();
while (p != 0) {
if (!p-&gt;ignore) {
if (i &gt;= (pcount-numopt))
temp &lt;&lt; "?";
/* If parameter has been named, use that. Otherwise, just print a type */
if ((p-&gt;t-&gt;type != T_VOID) || (p-&gt;t-&gt;is_pointer)) {
if (strlen(p-&gt;name) &gt; 0) {
temp &lt;&lt; p-&gt;name;
}
else {
temp &lt;&lt; "{ " &lt;&lt; p-&gt;t-&gt;print_type() &lt;&lt; " }";
}
}
if (i &gt;= (pcount-numopt))
temp &lt;&lt; "?";
temp &lt;&lt; " ";
i++;
}
p = l-&gt;get_next();
}
return temp;
}
</pre></blockquote>
<p>
Now, within the function to create a wrapper function, include code such as the following :<p>
<p>
<blockquote><pre>// Fill in the documentation entry
doc_entry-&gt;usage &lt;&lt; usage_string(iname,t,l);
</pre></blockquote>
To produce full documentation, each language module needs to fill in the documentation usage string for all declarations. Looking at existing SWIG modules can provide more information on how this should be implemented.<p>
<a name="n48"></a><h3> Writing a new documentation module</h3>
Writing a new documentation module is roughly the same idea as writing a new Language class. To do it, you need to implement a "Documentation Object" by inheriting from the following base class and defining all of the virtual methods :<p>
<p>
<blockquote><pre>class Documentation {
public:
virtual void parse_args(int argc, char **argv) = 0;
virtual void title(DocEntry *de) = 0;
virtual void newsection(DocEntry *de, int sectnum) = 0;
virtual void endsection() = 0;
virtual void print_decl(DocEntry *de) = 0;
virtual void print_text(DocEntry *de) = 0;
virtual void separator() = 0;
virtual void init(char *filename) = 0;
virtual void close(void) = 0;
virtual void style(char *name, char *value) = 0;
};
</pre></blockquote>
<h6> void parse_args(int argc, char **argv);</h6>
<dl>
<dt><dd>Parses command line options. Any special options you want to provide should be placed here.
<dt><dd>
</dl>
<h6> void title(DocEntry *de;</h6>
<dl>
<dt><dd>Produces documentation output for a title.
<dt><dd>
</dl>
<h6> void newsection(DocEntry *de, int sectnum;</h6>
<dl>
<dt><dd>Called whenever a new section is created. The documentation system is hierarchical in nature so each call to this function goes down one level in the hierarchy.
<dt><dd>
</dl>
<h6> void endsection();</h6>
<dl>
<dt><dd>Ends the current section. Moves up one level in the documentation hierarchy.
<dt><dd>
</dl>
<h6> void print_decl(DocEntry *de);</h6>
<dl>
<dt><dd>Creates documentation for a C declaration (function, variable, or constant).
<dt><dd>
</dl>
<h6> void print_text(DocEntry *de);</h6>
<dl>
<dt><dd>Prints documentation that has been given with the <tt>%text %{ %}</tt> directive.
<dt><dd>
</dl>
<h6> void separator();</h6>
<dl>
<dt><dd>Prints an optional separator between sections.
<dt><dd>
</dl>
<h6> void init(char *filename);</h6>
<dl>
<dt><dd>Initializes the documentation system. This function is called after command line options have been parsed. <tt>filename</tt> is the file where documentation should be placed.
<dt><dd>
</dl>
<h6> void close(void);</h6>
<dl>
<dt><dd>Closes the documentation file. All remaining output should be complete and files closed upon exit.
<dt><dd>
</dl>
<h6> void style(char *name, char *value);</h6>
<dl>
<dt><dd>Called to set style parameters. This function is called by the <tt>%style</tt> and <tt>%localstyle</tt> directives. It is also called whenever style parameters are given after a section directive.
</dl>
<a name="n49"></a><h3> Using a new documentation module</h3>
Using a new documentation module requires a change to SWIG's main program. If you are writing your own main() program, you can use a new documentation module as follows :<p>
<p>
<blockquote><pre>#include &lt;swig.h&gt;
#include "swigtcl.h" // Language specific header
#include "mydoc.h" // New Documentation module
extern int SWIG_main(int, char **, Language *, Documentation *);
int main(int argc, char **argv) {
TCL *l = new TCL; // Create a new Language object
MyDoc *d = new MyDoc; // New documentation object
init_args(argc, argv); // Initialize args
return SWIG_main(argc, argv, l, d);
}
</pre></blockquote>
<a name="n50"></a><h3> Where to go for more information</h3>
To find out more about documentation modules, look at some of the existing SWIG modules contained in the <tt>SWIG1.1/SWIG</tt> directory. The ASCII and HTML modules are good starting points for finding more information. <p>
<a name="n13"></a><h2> The Future of SWIG</h2>
SWIG's C++ API is the most rapidly evolving portion of SWIG. While interface-file compatibility will be maintained as much as possible in future releases, the internal structure of SWIG is likely to change significantly in the future. This will possibly have many ramifications on the construction of language modules. Here are a few significant changes that are coming :<p>
<p>
<dl>
<dt>1. A complete reorganization of the SWIG type system. Datatypes will be represented in a more flexible manner that provide full support for arrays, function pointers, classes, structures, and types possibly coming from other languages (such as Fortran).
<dt>2. Objectification of functions, variables, constants, classes, etc... Currently many of SWIG's functions take multiple arguments such as functions being described by name, return datatype, and parameters. These attributes will be consolidated into a single "Function" object, "Variable" object, "Constant" object, and so forth.
<dt>3. A complete rewrite of the SWIG parser. This will be closely tied to the change in datatype representation among other things.
<dt>4. Increased reliance on typemaps. Many of SWIG's older modules do not rely on typemaps, but this is likely to change. Typemaps provide a more concise implementation and are easier to maintain. Modules written for 1.1 that adopt typemaps now will be much easier to integrate into future releases.
<dt>5. A possible reorganization of object-oriented code generation. The layered approach will probably remain in place however.
<dt>6. Better support for multiple-files (exporting, importing, etc...)
</dl>
<p>
In planning for the future, much of a language's functionality can be described in terms of typemaps. Sticking to this approach will make it significantly easier to move to new releases. I anticipate that there will be few drastic changes to the Language module presented in this section (other than changes to many of the calling mechanisms).<p>
<p><hr>
<address>SWIG 1.1 - Last Modified : Mon Aug 4 10:47:17 1997</address>
</body>
</html>