| <html> |
| <title> SWIG : An Easy to Use Tool For Integrating Scriptint Languages |
| with C and C++ </title> |
| <body bgcolor="#ffffff"> |
| <h1> |
| SWIG : An Easy to Use Tool for Integrating Scripting Languages with C and C++ |
| </h1> |
| |
| <b> David M. Beazley </b> <br> |
| <em> Department of Computer Science <br> |
| University of Utah <br> |
| Salt Lake City, Utah 84112 <br> |
| beazley@cs.utah.edu <br> </em> |
| |
| <br> <br> |
| (Presented at the 4th Annual Tcl/Tk Workshop, Monterey, CA. July 6-10, 1996. ) |
| |
| <h2> Abstract </h2> |
| |
| <em> |
| I present SWIG (Simplified Wrapper and Interface Generator), a |
| program development tool that automatically generates the bindings |
| between C/C++ code and common scripting languages including |
| Tcl, Python, Perl and Guile. SWIG supports most C/C++ datatypes |
| including pointers, structures, and classes. |
| Unlike many other approaches, SWIG |
| uses ANSI C/C++ declarations and requires the user to make virtually |
| no modifications to the underlying C code. |
| In addition, SWIG automatically |
| produces documentation in HTML, LaTeX, or ASCII format. |
| SWIG has been primarily designed for scientists, engineers, and application |
| developers who would like to use scripting languages with their C/C++ programs |
| without worrying about the underlying implementation details |
| of each language or using a complicated software development tool. |
| This paper concentrates on SWIG's use with Tcl/Tk. |
| </em> |
| |
| <h2> 1. Introduction </h2> |
| SWIG (Simplified Wrapper and Interface Generator) |
| is a software |
| development tool that I never intended to develop. At the time, |
| I was trying to add a data analysis and visualization capability to |
| a molecular dynamics (MD) code I had helped develop for massively |
| parallel supercomputers at Los Alamos National Laboratory [Beazley,Lomdahl]. I wanted |
| to provide a simple, yet flexible user interface that could be used |
| to glue various code modules together and an extensible scripting |
| language seemed like an ideal solution. Unfortunately there were constraints. |
| First, I didn't want to hack up 4-years of code development trying to |
| fit our MD code into yet another interface scheme (having done so several |
| times already). Secondly, this code |
| was routinely run on systems ranging from Connection Machines and Crays to |
| workstations and I didn't want to depend on any one |
| interface language---out of fear that it might not be supported on |
| all of these platforms. Finally, the users were constantly adding |
| new code and making modifications. I needed a flexible, yet easy to use |
| system that did not get in the way of the physicists. <br> <br> |
| |
| SWIG is my solution to this problem. Simply stated, SWIG automatically generates all |
| of the code |
| needed to bind C/C++ functions with scripting languages using only |
| a simple input file containing C function and variable declarations. |
| At first, I supported |
| a scripting language I had developed specifically for use |
| on massively parallel systems. Later I decided to rewrite SWIG in C++ and extend it to support |
| Tcl, Python, Perl, Guile and other languages that interested me. I also |
| added more data-types, support for pointers, C++ classes, documentation generation, and |
| a few other features. <br> <br> |
| |
| This paper provides a brief overview of SWIG |
| with a particular emphasis on Tcl/Tk. However, the reader should |
| remain aware that SWIG works equally well with |
| Perl and other languages. It is not my intent to provide |
| a tutorial or a user's guide, but rather to show |
| how SWIG can be used to do interesting things such as |
| adding Tcl/Tk interfaces to existing C applications, |
| quickly debugging and prototyping C code, |
| and building interface-language-independent C applications. |
| |
| <h2> 2. Tcl and Wrapper Functions </h2> |
| |
| In order to add a new C or C++ function to Tcl, it is necessary to |
| write a special ``wrapper'' function that parses the function arguments |
| presented as ASCII strings by the Tcl interpreter into a representation |
| that can be used to call the C function. For example, if you wanted |
| to add the factorial function to Tcl, a wrapper function might |
| look like the following : <br> |
| |
| <blockquote> |
| <tt> <pre> |
| int wrap_fact(ClientData clientData, |
| Tcl_Interp *interp, |
| int argc, char *argv[]) { |
| int result; |
| int arg0; |
| if (argc != 2) { |
| interp->result = "wrong # args"; |
| return TCL_ERROR; |
| } |
| arg0 = atoi(argv[1]); |
| result = fact(arg0); |
| sprintf(interp->result,"%d",result); |
| return TCL_OK; |
| } |
| </pre> |
| </tt> |
| </blockquote> |
| |
| In addition to writing the wrapper function, a user will also need to |
| write code to add this function to the Tcl interpreter. In the case of |
| Tcl 7.5, this could be done by writing an initialization function to |
| be called when the extension is loaded dynamically. While writing |
| a wrapper function usually is not too difficult, the process quickly |
| becomes tedious and error prone as the number of functions increases. |
| Therefore, automated approaches for producing wrapper functions are |
| appealing--especially when working with a large number of C functions |
| or with C++ (in which case the wrapper code tends to get more complicated). |
| |
| <h2> 3. Prior Work </h2> |
| |
| The idea of automatically generating wrapper code is certainly not new. |
| Some efforts such as |
| Itcl++, Object Tcl, or the XS language included with Perl5, provide a mechanism for |
| generating wrapper code, but require the user to provide detailed |
| specifications, type conversion rules, or use a specialized |
| syntax [heidrich,Wetherall,perl5]. Large packages |
| such as the Visualization Toolkit (vtk) may use their own C/C++ translators, |
| but these almost always tend to be somewhat special purpose (in fact, SWIG started |
| out in this manner) [vtk]. |
| If supporting multiple languages is the ultimate goal, a programmer might |
| consider a package such as ILU [Janssen]. |
| Unfortunately, |
| this requires the user to provide specifications in IDL--a process which |
| is unappealing to many users. |
| SWIG is not necessarily intended to compete with |
| these approaches, but rather is designed to be a no-nonsense tool that |
| scientists and engineers can use to easily add Tcl and other scripting |
| languages to their own applications. SWIG is also |
| very different than Embedded Tk (ET) which also aims to |
| simplify code development [ET]. Unlike ET, SWIG is designed to |
| integrate C functions into Tcl/Tk as opposed to integrating Tcl/Tk into |
| C programs. |
| |
| <h2> 4. A Quick Tour of SWIG </h2> |
| |
| <h3> 4.1 Organization </h3> |
| |
| <center> |
| <img alt = "SWIG Organization" src="fig1.gif"> <br> |
| Figure 1 : SWIG Organization <br> <br> |
| </center> |
| |
| Figure 1 shows the structure of SWIG. At the core is a YACC parser |
| for reading input files along with some utility functions. |
| To generate code, |
| the parser calls about a dozen functions from a generic language |
| class to do things like write a wrapper function, link a |
| variable, wrap a C++ member function, etc... Each target language is |
| implemented as a C++ class containing the functions that emit |
| the resulting C code. If an ``empty'' language definition is given |
| to SWIG, it will produce no output. Thus, each language class can |
| be implemented in almost any manner. |
| The documentation system is implemented in a similar manner and can |
| currently produce ASCII, LaTeX, or HTML output. As output, |
| SWIG produces a C file that should be compiled and linked with the rest |
| of the code and a documentation file that can be used for later reference. |
| |
| <h3> 4.2. Interface Files </h3> |
| |
| As input, SWIG takes a single input file referred to as an ``interface file.'' |
| This file contains a few SWIG specific directives, but otherwise contains |
| ANSI C function and variable declarations. Unlike the approach in [Heidrich], no type conversion rules are needed and all declarations are made |
| using familiar ANSI C/C++ prototypes. The following code shows an |
| interface file for wrapping a few C file I/O and memory management functions. |
| |
| <blockquote> |
| <tt> <pre> |
| /* File : file.i */ |
| %module fileio |
| %{ |
| #include <stdio.h> |
| %} |
| |
| FILE *fopen(char *filename, char *type); |
| int fclose(FILE *stream); |
| typedef unsigned int size_t |
| size_t fread(void *ptr, size_t size, |
| size_t nobj, FILE *stream); |
| size_t fwrite(void *ptr, size_t size, |
| size_t nobj,FILE *stream); |
| void *malloc(size_t nbytes); |
| void free(void *); |
| </pre> </tt> </blockquote> |
| |
| The <tt> %module </tt> directive |
| sets the name of the initialization function. This is optional, but is |
| recommended if building a Tcl 7.5 module. |
| Everything inside the <tt> %{, %} </tt> |
| block is copied directly into the output, allowing the inclusion of |
| header files and additional C code. |
| Afterwards, C/C++ function and variable declarations are listed in any |
| order. |
| Building a new Tcl module is usually as |
| easy as the following : |
| |
| <blockquote> |
| <tt> <pre> |
| unix > swig -tcl file.i |
| unix > gcc file_wrap.c -I/usr/local/include |
| unix > ld -shared file_wrap.o -o Fileio.so |
| </pre> </tt> |
| </blockquote> |
| |
| |
| <h3> 4.3. A Tcl Example </h3> |
| |
| Newly added functions work like ordinary Tcl procedures. For |
| example, the following Tcl script copies a file using the binary |
| file I/O functions added in the previous example : |
| |
| <blockquote> |
| <tt> <pre> |
| proc filecopy {name1 name2} { |
| set buffer [malloc 8192]; |
| set f1 [fopen $name1 r]; |
| set f2 [fopen $name2 w]; |
| set nbytes [fread $buffer 1 8192 $f1]; |
| while {$nbytes > 0} { |
| fwrite $buffer 1 $nbytes $f2; |
| set nbytes [fread $buffer 1 8192 $f1]; |
| } |
| fclose $f1; |
| fclose $f2; |
| free $buffer |
| } |
| </pre> </tt> |
| </blockquote> |
| |
| <h3> 4.4. Datatypes and Pointers </h3> |
| |
| SWIG supports the basic datatypes of <tt> int, short, |
| long, float, double, char, </tt> and <tt> void </tt> |
| as well as signed and unsigned integers. SWIG |
| also allows derived types such as pointers, structures, and classes, |
| but these are all encoded as pointers. |
| If an unknown type is encountered, SWIG assumes |
| that it is a complex datatype that has been defined earlier. |
| No attempt is made to figure out what data that datatype actually contains |
| or how it should be used. Of course, this this is only possible |
| since SWIG's mapping of complex types into pointers allows them |
| to be handled in a uniform manner. |
| As a result, SWIG does not normally need any sort |
| of type-mapping, but <tt> typedef </tt> can be used to map any of the built-in |
| datatypes to new types if desired. <br> <br> |
| |
| SWIG encodes pointers as hexadecimal strings with type-information. This |
| type information is used to provide a run-time type checking mechanism. |
| Thus, a typical SWIG pointer looks something like the following : <br> <br> |
| |
| <center> |
| <tt> _1008e614_Vector_p </tt> <br> <br> |
| </center> |
| |
| If this pointer is passed into a function requiring some other kind of |
| pointer, SWIG will generate a Tcl error and return an error message. |
| The NULL pointer is represented by the string "NULL". The SWIG run-time |
| type checker is saavy to typedefs and the relationship between base classes |
| and derived classes in C++. Thus if a |
| user specifies <br> <br> |
| |
| <center> |
| <tt> typedef double Real; </tt> <br> <br> |
| </center> |
| |
| the type checker knows that <tt> Real * </tt> and <tt> double * </tt> |
| are equivalent (more on C++ in a minute). |
| From the point of view of other Tcl extensions, |
| SWIG pointers should be seen as special "handles" except that they |
| happen to contain the pointer value and its type. <br> <br> |
| |
| To some, this approach may seem horribly restrictive (or error prone), |
| but keep in mind that SWIG was primarily designed to work with |
| existing C applications. Since most C programs pass complex datatypes |
| around by reference this technique works remarkably well in practice. |
| Run time type-checking also eliminates most common crashes by catching |
| stupid mistakes such as using a wrong variable name or forgetting the |
| "$" character in a Tcl script. While it is still possible to crash Tcl by forging a |
| SWIG pointer value (or making a call to buggy C code), it is worth |
| emphasizing that existing Tcl extensions |
| may also crash if given an invalid handle. |
| |
| <h3> 4.5. Global Variables and Constants </h3> |
| |
| SWIG can install global C variables and constants using Tcl's variable linkage |
| mechanism. |
| Variables may also be declared as ``read only'' |
| within the Tcl interpreter. The following example shows |
| how variables and constants can be added to Tcl : |
| |
| <blockquote> |
| <tt> <pre> |
| // SWIG file with variables and constants |
| %{ |
| %} |
| |
| // Some global variables |
| extern int My_variable; |
| extern char *default_path; |
| extern double My_double; |
| |
| // Some constants |
| #define PI 3.14159265359 |
| #define PI_4 PI/4.0 |
| enum colors {red,blue,green}; |
| const int SIZEOF_VECTOR = sizeof(Vector); |
| |
| // A read only variable |
| %readonly |
| extern int Status; |
| %readwrite |
| |
| </pre> |
| </tt> |
| </blockquote> |
| |
| <h3> 4.6. C++ Support </h3> |
| |
| The SWIG parser can handle simple C++ class definitions and supports public |
| inheritance, virtual functions, static functions, constructors and |
| destructors. Currently, C++ translation is performed |
| by politely tranforming C++ code into C code and generating wrappers for the |
| C functions. For example, consider the following SWIG interface file |
| containing a C++ class definition: |
| |
| <blockquote> |
| <tt> <pre> |
| %module tree |
| %{ |
| #include "tree.h" |
| %} |
| |
| class Tree { |
| public: |
| Tree(); |
| ~Tree(); |
| void insert(char *item); |
| int search(char *item); |
| int remove(char *item); |
| static void print(Tree *t); |
| }; |
| </pre> |
| </tt> |
| </blockquote> |
| |
| When translated, the class will be access used the following set of |
| functions (created automatically by SWIG). |
| |
| <blockquote> |
| <tt> |
| <pre> |
| Tree *new_Tree(); |
| void delete_Tree(Tree *this); |
| void Tree_insert(Tree *this, char *item); |
| int Tree_search(Tree *this, char *item); |
| int Tree_remove(Tree *this, char *item); |
| void Tree_print(Tree *t); |
| </pre> |
| </tt> |
| </blockquote> |
| |
| |
| All C++ functions wrapped by SWIG explicitly require the <tt> this </tt> pointer |
| as shown. This approach has the advantage of working for all of the target |
| languages. It also makes it easier to pass objects between |
| other C++ functions since every C++ object is simply represented as a SWIG pointer. SWIG does not support function overloading, but overloaded functions |
| can be resolved by renaming them with the SWIG <tt> %name </tt> directive as follows: |
| |
| <blockquote> |
| <tt> <pre> |
| class List { |
| public: |
| List(); |
| %name(ListMax) List(int maxsize); |
| ... |
| }; |
| </pre> </tt> </blockquote> |
| |
| The approach used by SWIG is |
| quite different than that used in systems such as |
| Object Tcl or vtk [vtk,Wetherall]. As a result, users of those systems |
| may find it to be confusing. However, |
| It is important to note that the modular design of |
| SWIG allows the user to completely redefine the output behavior of |
| the system. Thus, while the current C++ implementation is quite different |
| than other systems supporting C++, it would be entirely possible |
| write a new SWIG module that wrapped C++ classes into a representation |
| similar to that used by Object Tcl (in fact, in might even be possible |
| to use SWIG to produce the input files used for Object Tcl). |
| |
| <h3> 4.7. Multiple Files and Code Reuse </h3> |
| |
| An essential feature of SWIG is its support for multiple files |
| and modules. A SWIG interface file may include another interface |
| file using the "<tt> %include </tt>" directive. Thus, an interface |
| for a large system might be broken up into a collection of smaller |
| modules as shown |
| |
| <blockquote> |
| <tt> <pre> |
| %module package |
| %{ |
| #include "package.h" |
| %} |
| |
| %include geometry.i |
| %include memory.i |
| %include network.i |
| %include graphics.i |
| %include physics.i |
| |
| %include wish.i |
| </pre> </tt> </blockquote> |
| |
| Common operations can be placed into a SWIG library for use in |
| all applications. For example, the <tt> %include wish.i </tt> directive |
| tells SWIG to include code for the <tt> Tcl_AppInit() </tt> function |
| needed to rebuild the <tt> wish </tt> program. The library can also be |
| used to build modules |
| allowing SWIG to be used with common Tcl extensions such |
| as Expect [Expect]. Of course, the primary use of the library is with |
| large applications such as Open-Inventor which contain hundreds of |
| modules and a substantial class hierarchy [Invent]. In this case a user |
| could use SWIG's include mechanism to selectively pick which modules |
| they wanted to use for a particular problem. |
| |
| <h3> 4.8. The Documentation System </h3> |
| |
| SWIG produces documentation in ASCII, LaTeX, or HTML |
| format describing everything that was wrapped. The documentation |
| follows the syntax rules of the target language and can |
| can be further enhanced by adding descriptions in a C/C++ comment |
| immediately following a declaration. These comments may also contain |
| embedded LaTeX or HTML commands. For example: |
| |
| <blockquote> |
| <tt> <pre> |
| extern size_t fread(void *ptr, size_t size, |
| size_t nobj, FILE *stream); |
| /* {\tt fread} reads from {\tt stream} into |
| the array {\tt ptr} at most {\tt nobj} objects |
| of size {\tt size}. {\tt fread} returns |
| the number of objects read. */ |
| </pre> </tt> </blockquote> |
| |
| When output by SWIG and processed by LaTeX, this appears as follows : |
| |
| <ul> |
| <tt> size_t : fread ptr size nobj stream </tt> <br> |
| <ul> |
| <tt> fread </tt> reads from <tt> stream </tt> into the array <tt> ptr </tt> at |
| most <tt> nobj </tt> objects of size <tt> size </tt>. <tt> fread </tt> |
| returns |
| the number of objects read. |
| </ul> |
| </ul> |
| |
| <h3> 4.9. Extending the SWIG System </h3> |
| |
| Finally, SWIG itself can be extended by the user to provide new |
| functionality. This is done by modifying an existing or creating a |
| new language class. A typical class must specify the following |
| functions that determine the behavior of the parser output : |
| |
| <blockquote> |
| <tt> <pre> |
| // File : swigtcl.h |
| class TCL : public Language { |
| private: |
| // Put private stuff here |
| public : |
| TCL(); |
| int main(int, char *argv[]); |
| void create_function(char *,char *,DataType*, |
| ParmList *); |
| void link_variable(char *,char *,DataType *); |
| void declare_const(char *,int,char *); |
| void initialize(void); |
| void headers(void); |
| void close(void); |
| void usage_var(char *,DataType*,char **); |
| void usage_func(char *,DataType*,ParmList*, |
| char **); |
| void usage_const(char *,int,char*,char**); |
| void set_module(char *); |
| void set_init(char *); |
| }; |
| </pre> </tt> </blockquote> |
| |
| Descriptions of these functions can be found in the SWIG |
| users manual. To build a new version of SWIG, the user |
| only needs to provide the function definitions and a main |
| program which looks something like the following : |
| |
| <blockquote> |
| <tt> <pre> |
| |
| // SWIG main program |
| |
| #include "swig.h" |
| #include "swigtcl.h" |
| |
| int main(int argc, char **argv) { |
| |
| Language *lang; |
| |
| lang = new TCL; |
| SWIG_main(argc,argv,lang,(Documentation *) 0); |
| |
| } |
| </pre> </tt> </blockquote> |
| |
| When linked with a library file, any extensions and |
| modifications can now be used with the SWIG parser. While |
| writing a new language definition is not entirely trivial, |
| it can usually be done by just copying one of the existing |
| modules and modifying it appropriately. |
| |
| <h2> 5. Examples </h2> |
| |
| <h3> 5.1. A C-Tcl Linked List </h3> |
| |
| SWIG can be used to build simple data structures that are usuable in |
| both C and Tcl. The following code shows a SWIG interface file for |
| building a simple linked list. |
| |
| <blockquote> |
| <tt> <pre> |
| /* File : list.i */ |
| %{ |
| struct Node { |
| Node(char *n) { |
| name = new char[strlen(n)+1]; |
| strcpy(name,n); |
| next = 0; |
| }; |
| char *name; |
| Node *next; |
| }; |
| %} |
| |
| // Just add struct definition to |
| // the interface file. |
| |
| struct Node { |
| Node(char *); |
| char *name; |
| Node *next; |
| }; |
| |
| </pre> </tt> </blockquote> |
| |
| When used in a Tcl script, we can now create new nodes and access |
| individual members of the <tt> Node </tt> structure. In fact, we can |
| write code to convert between Tcl lists and linked lists entirely |
| in Tcl as shown : |
| |
| <blockquote> |
| <tt> <pre> |
| # Builds linked list from a Tcl list |
| proc buildlist {list head} { |
| set nitems [llength $list]; |
| for {set i 0} {$i < $nitems} {incr i -1} { |
| set item [lrange $list $i $i] |
| set n [new_Node $item] |
| Node_set_next $n $head |
| set head $n |
| } |
| return $head |
| } |
| # Builds a Tcl list from a linked list |
| proc get_list {llist} { |
| set list {} |
| while {$llist != "NULL"} { |
| lappend list [Node_name_get $llist] |
| set llist [Node_get_next $llist] |
| } |
| return $list |
| } |
| </pre> </tt> </blockquote> |
| |
| When run interactively, we could now use our Tcl functions as |
| follows. |
| |
| <blockquote> |
| <tt> <pre> |
| % set l {John Anne Mary Jim} |
| John Anne Mary Jim |
| % set ll [buildlist $l _0_Node_p] |
| _1000cab8_Node_p |
| % get_list $ll |
| Jim Mary Anne John |
| % set ll [buildlist {Mike Peter Dave} $ll] |
| _1000cc38_Node_p |
| % get_list $ll |
| Dave Peter Mike Jim Mary Anne John |
| % |
| </pre> </tt> </blockquote> |
| Aside from the pointer values, our script acts like any other |
| Tcl script. However, we have built up a real |
| C data structure that could be easily passed to other C functions |
| if needed. |
| |
| <h3> 5.2. Using C Data-Structures with Tk </h3> |
| |
| In manner similar to the linked list example, Tcl/Tk can be used |
| to build complex C/C++ data structures. For example, suppose we |
| wanted to interactively build a graph of ``Nodes'' for use in a C |
| application. |
| A typical interface file might include the following functions: |
| |
| <blockquote> <tt> <pre> |
| %{ |
| #include "nodes.h" |
| %} |
| |
| %include wish |
| extern Node *new_node(); |
| extern void AddEdge(Node *n1, Node *n2); |
| </pre> </tt> </blockquote> |
| |
| Within a Tcl/Tk script, loosely based on one to make ball and stick graphs |
| in [Ousterhout], a graph could be built as follows: |
| |
| <blockquote> <tt> <pre> |
| proc makeNode {x y} { |
| global nodeX nodeY nodeP edgeFirst edgeSecond |
| set new [.create oval [expr $x-15] \ |
| [expr $y-15] [expr $x+15] \ |
| [expr $y+15] -outline black \ |
| -fill white -tags node] |
| set newnode [new_node] |
| set nodeX($new) $x |
| set nodeY($new) $y |
| set nodeP($new) $newnode |
| set edgeFirst($new) {} |
| set edgeSecond($new) {} |
| } |
| proc makeEdge {first second} { |
| global nodeX nodeY nodeP edgeFirst edgeSecond |
| set x1 $nodeX($first); set y1 $nodeY($first) |
| set x2 $nodeX($second); set y2 $nodeY($second) |
| set edge [.c create line $x1 $y1 $x2 $y2 \ |
| -tags edge} |
| .c lower edge |
| lappend edgeFirst($first) $edge |
| lappend edgeSecond($first) $edge |
| AddEdge $nodeP($first) $nodeP($second) |
| } |
| </pre> </tt> </blockquote> |
| |
| These functions create |
| Tk canvas items, but also attach a pointer to a C data structure to each one. |
| This is done by maintaining an associative array mapping |
| item identifiers to pointers (with the <tt> nodeP() </tt> array). |
| When a |
| particular ``node'' is referenced later, we can use this to |
| get its pointer use it in calls to C functions. |
| |
| <h3> 5.3. Parsing a C++ Simple Class Hierarchy </h3> |
| |
| As mentioned earlier, SWIG can handle C++ classes and public |
| inheritance. The following example provides a few classes |
| and illustrates how this is accomplished (some code has been |
| ommitted for readability). |
| |
| <blockquote> <tt> <pre> |
| // A SWIG inheritance example |
| %module shapes |
| %{ |
| #include "shapes.h" |
| %} |
| |
| class Shape { |
| private: |
| double xc, yc; |
| public: |
| virtual double area() = 0; |
| virtual double perimeter() = 0; |
| void set_position(double x, double y); |
| void print_position(); |
| }; |
| |
| class Circle: public Shape { |
| private: |
| double radius; |
| public: |
| Circle(double r); |
| double area(); |
| double perimeter(); |
| }; |
| |
| class Square : public Shape { |
| private: |
| double width; |
| public: |
| Square(double w); |
| double area(); |
| double perimeter(); |
| }; |
| |
| </pre> </tt> </blockquote> |
| |
| Now, when wrapped by SWIG (note : |
| When parsing C++ classes, SWIG throws away everything declared as private, |
| inline code, and alot of the other clutter found in C++ header files. |
| Primarily this is provided only to make it easier to build interfaces from |
| existing C++ header files.), we can use our class structure as follows: |
| |
| <blockquote> <tt> <pre> |
| % set c [new_Circle 4] |
| _1000ad70_Circle_p |
| % set s [new_Square 10] |
| _1000adc0_Square_p |
| % Shape_area $c |
| 50.26548246400000200 |
| % Shape_area $s |
| 100.00000000000000000 |
| % Shape_set_position $c -5 10 |
| % Circle_print_position $c |
| xc = -5, yc = 10 |
| % |
| </pre> </tt> </blockquote> |
| |
| In our example, we have created new <tt> Circle </tt> and <tt> Square </tt> objects, |
| but these can be used interchangably in any functions defined in the <tt> Shape </tt> |
| base class. The SWIG type checker is encoded with the class hierarchy and |
| knows the relationship between the different classes. Thus, while an |
| object of type <tt> Circle </tt> is perfectly acceptable to a function operating |
| on shapes, it would be unacceptable to a function operating only on the |
| <tt> Square </tt> type. As in C++, any functions in the base class can be |
| called in the derived class as shown by the <tt> Circle_print_position </tt> |
| function above. |
| |
| <h2> 6. Using SWIG in Real Applications </h2> |
| |
| So far only a few simple toy examples have been presented to illustrate |
| the operation of SWIG in general. |
| This section will describe how SWIG can be used |
| with larger applications. |
| |
| <h3> 6.1. Use in Scientific Applications </h3> |
| |
| Many users, especially within the scientific and engineering |
| community, have spent years developing simulation codes. |
| While many of these users appreciate the |
| power that a scripting language can provide, they don't want to |
| completely rewrite their applications or spend all of their time |
| trying to build a user-interface (most users would rather be working |
| on the scientific problem at hand). While SWIG certainly won't do everything, |
| it can dramatically simplify this process. <br> <br> |
| |
| As an example, the first SWIG application was the SPaSM molecular |
| dynamics code developed at Los Alamos National Laboratory |
| [Beazley,Lomdahl]. This code is currently being used for materials |
| science problems and consists of more than 200 C functions and about 20000 lines |
| of code. |
| In order to use SWIG, only the <tt> main() </tt> function had to be |
| rewritten along with a few other minor modifications. |
| The full user interface is built using a collection of modules for |
| simulation, graphics, memory management, etc... |
| A user may also supply their own interface modules--allowing the code to |
| be easily extended with new functionality capabilities as needed. |
| All of the interface files, containing a few hundred lines of |
| function declarations, are automatically translated into more than |
| 2000 lines of wrapper code at compile time. As a result, many users |
| of the system know how to extend it, but are unaware of the actual |
| wrapping procedure. <br> <br> |
| |
| After modifying the SPaSM code to use SWIG, most of the C code remained |
| unchanged. In fact, in subsequent work, we were able to eliminate |
| more than 25% of the source code--almost all of which was related to the |
| now obsolete interface method that we replaced. More importantly, we |
| were able to turn a code that was difficult to use and modify into a |
| flexible package that was easy to use and extend. This has had a |
| huge impact, which can not be understated, on the use of the SPaSM |
| code to solve real problems. |
| |
| <h3> 6.2. Open-GL and Inventor </h3> |
| |
| While SWIG was primarily designed to work with application codes, it |
| can also be used to wrap large libraries. At the University of Utah, |
| Peter-Pike Sloan used SWIG to wrap the entire contents of the Open-GL |
| library into Tcl for use with an Open-GL Tk widget. The process of |
| wrapping Open-GL with SWIG was as simple as the following : |
| |
| <ul> |
| <li> Make a copy of the <tt> gl.h </tt> header file. |
| <li> Clean it up by taking a few C preprocessor directives out |
| of it. Fix a few typedefs. |
| <li> Insert the following code into the beginning |
| <blockquote> <tt> <pre> |
| %module opengl |
| %{ |
| #include <GL/gl.h> |
| %} |
| ... Copy edited gl.h here ... |
| </pre> </tt> </blockquote> |
| |
| <li> Modify the Open-GL widget to call <tt> Opengl_Init </tt>. |
| <li> Recompile |
| </ul> |
| |
| The entire process required only about 10 minutes of work, but resulted |
| in more than 500 constants and 360 functions being added to Tcl. Furthermore, |
| this extension allows Open-GL commands to be issued directly from Tcl's |
| interpreted environment as shown in this example |
| (from the Open-GL manual [OpenGL]). |
| |
| <blockquote> <tt> <pre> |
| % ... open GL widget here ... |
| % glClearColor 0.0 0.0 0.0 0.0 |
| % glClear $GL_COLOR_BUFFER_BIT |
| % glColor3f 1.0 1.0 1.0 |
| % glOrtho -1.0 1.0 -1.0 1.0 -1.0 1.0 |
| % glBegin $GL_POLYGON |
| % glVertex2f -0.5 -0.5 |
| % glVertex2f -0.5 0.5 |
| % glVertex2f 0.5 0.5 |
| % glVertex2f 0.5 -0.5 |
| % glEnd |
| % glFlush |
| </pre> </tt> </blockquote> |
| |
| Early work has also been performed on using SWIG to wrap portions |
| of the Open-Inventor package [Invent]. This is a more ambitious project |
| since Open-Inventor consists of a very large collection of header |
| files and C++ classes. However, the SWIG library mechanism can be |
| used effective in this case. For each Inventor header, we can create |
| a sanitized SWIG interface file (removing alot of the clutter found in |
| the header files). These interface files can then be organized to mirror the |
| structure of the Inventor system. To build a module for Tcl, a user |
| could simply specify which modules they wanted to use as follows : |
| |
| <blockquote> <tt> <pre> |
| %module invent |
| %{ |
| ... put headers here ... |
| %} |
| |
| %include "Inventor/Xt/SoXt.i" |
| %include "Inventor/Xt/SoXtRenderArea.i" |
| %include "Inventor/nodes/SoCone.i" |
| %include "Inventor/nodes/SoDirectionalLight.i" |
| %include "Inventor/nodes/SoMaterial.i" |
| %include "Inventor/nodes/SoPerspectiveCamera.i" |
| %include "Inventor/nodes/SoSeparator.i" |
| </pre> </tt> </blockquote> |
| |
| While wrapping the Inventor library will require significantly |
| more work than Open-GL, SWIG can be used effectively with such |
| systems. |
| |
| <h3> 6.3. Building Interesting Applications by Cut and Paste </h3> |
| |
| SWIG can be used to construct tools out of dissimiliar |
| packages and libraries. |
| In contrast to combining packages at an input level as one might |
| do with with Expect, SWIG can be used to build applications at a |
| function level [Expect]. |
| For example, using |
| a simple interface file, you can wrap the |
| C API of MATLAB 4.2 [MATLAB]. |
| This in turn lets you build a Tcl/Tk interface for controlling |
| MATLAB programs. Separately, you could wrap a numerical simulation |
| code. Now, a few translation functions could be written and both |
| packages combined into a single Tcl/Tk application. You have |
| now built a simple ``computational steering'' system that allows you |
| to run a simulation code, visualize data in MATLAB, and control the |
| entire system with a Tcl/Tk based interface. Figure 2 shows |
| a screen snapshot from such a simulation in which the SPaSM molecular |
| dynamics code, a visualization module library, image server (using xv), |
| and MATLAB have been |
| combined. Under this system, the user can interactively set up |
| and run simulations while watching the results evolve in real-time. |
| <br> <br> |
| <center> |
| <img alt = "Tcl/Tk/MATLAB/SPASM Figure" src="steer2.gif"> <br> |
| Figure 2: Simple Tcl/Tk Steering Application Built with SWIG <br> |
| </center> |
| |
| <h3> 6.4. Language Independent Applications </h3> |
| |
| |
| Each scripting language has it's own strengths and weaknesses. |
| Rather |
| than trying to choose the language that is the best at everything (which |
| is probably impossible), |
| SWIG allows a user to use the best language for the job at hand. I'm |
| always finding myself writing little utilities and programs to support |
| my scientific computing work. Why should I be forced to use only one |
| language for everything? With SWIG, I can put a Perl interface on a |
| tool and switch over to Tcl/Tk at anytime by just changing a few |
| Makefile options. <br> <br> |
| |
| Since SWIG provides a language-independent interface specification, |
| it is relatively easy to use SWIG generated modules in a variety of |
| interesting applications. For example, the identical MATLAB |
| module used in the last Tcl example could be imported as Perl5 module |
| and combined with a Perl script to produce graphical displays from |
| Web-server logs as shown in Figure 3. <br> <br> |
| |
| <center> |
| <img alt="Perl5 web stats example" src="hits.gif"> <br> |
| Figure 3:Web-server activity graph. Generated from a Perl script, but |
| uses an unmodified SWIG generated module for integrating MATLAB with Tcl/Tk. <br> <br> |
| </center> |
| |
| Some have promoted the idea of encapsulating several languages into |
| a higher level language as has been proposed with Guile [Lord]. |
| This may be fine if one wants to write code that uses different languages |
| all at once, but when I want to use only Tcl or Perl for an application, |
| I almost always prefer using the real versions instead of an encapsulated |
| variant. SWIG makes this possible without much effort. |
| |
| <h3> 6.5. Using Tcl as a debugger </h3> |
| |
| Since SWIG can work with existing C code, it can be used quite effectively |
| as a debugger. |
| You can wrap C functions and interact |
| with them from <tt> tclsh </tt> or <tt> wish </tt>. |
| Unlike most traditional debuggers, you |
| can create objects, buffers, arrays, and other things on the fly |
| by putting appropriate definitions in the interface file. |
| Since <tt> tclsh </tt> or <tt> wish </tt> provides a <tt> main() </tt> function, you |
| can even rip small pieces out of a larger package without including |
| that package's main program. |
| Scripts can be written to test out different parts of your |
| code as it is developed. When you are satisfied with the module, |
| removing the interface is as easy as discarding the SWIG interface |
| file. I have used SWIG as a debugger for developing graphics libraries, |
| network servers, simulation codes, and a wide range of other projects--some |
| of which didn't even use a scripting language when completed. |
| |
| <h2> 7. Limitations </h2> |
| |
| SWIG represents a balance of flexibility and ease of use. |
| I have always felt that the tool shouldn't be more complicated than |
| the original problem. Therefore, SWIG certainly won't do everything. |
| While I believe the pointer representation of complex datatypes works |
| well in practice, some users have found this to be too general or |
| confusing. SWIG's |
| support for C++ is also limited by the fact that SWIG does not support |
| operator overloading, multiple inheritance, templates, and a number |
| of other more advanced C++ features. SWIG also lacks support for |
| default or variable length function arguments, array notation, |
| pointers to functions (unless hidden by a typedef) and an exception |
| mechanism. |
| Finally, SWIG |
| does |
| not support all of the features of Tcl such as associative arrays. |
| These aren't an inherent part of the C language so it is difficult |
| to generalize how they should be handled or generated. I prefer to |
| keep the tool simple while leaving these issues up to the individual |
| programmer. <br> <br> |
| |
| |
| Fortunately, it is almost always possible to work around |
| many problems by writing special library functions or making |
| modifications to the SWIG language modules to produce the desired effect. |
| For example, when wrapping Open-GL, SWIG installed all of the Open-GL |
| constants as Tcl global variables. Unfortunately, none of these |
| variables were accessible inside Tcl procedures unless they were explicitly |
| declared global. By making a modification to the Tcl language module, |
| it was possible to put the GL constants into hash table and perform |
| a hidden ``lookup'' inside all of the GL-related functions. Similarly, |
| much of the functionality of SWIG can be placed into library |
| files for use in other modules. |
| |
| <h2> 8. Conclusions </h2> |
| |
| SWIG has been in use for approximately one year. At Los Alamos National Laboratory, its use with the SPaSM code has |
| proven to |
| be a remarkably simple, stable, and bug-free way to build and modify user |
| interfaces. At the University of Utah, SWIG is being used in a variety |
| of other applications where the users have quickly come to appreciate its |
| ease of use and flexibility. <br> <br> |
| |
| While SWIG may be inappropriate for certain applications, I feel that it |
| opens up Tcl/Tk, Python, Perl, Guile, and other languages to |
| users who would like to develop interesting user interfaces for their codes, |
| but who don't want to worry about the low-level details or figuring |
| out how to use a complicated tool. <br> <br> |
| |
| Future directions for SWIG include support for other scripting languages, |
| and a library of extensions. SWIG may also be extended to support packages |
| such as incremental Tcl. Work is also underway to port SWIG to non-unix |
| platforms. |
| |
| <h2> Acknowledgments </h2> |
| |
| This project would not have been possible without the support of a number |
| of people. Peter Lomdahl, Shujia Zhou, Brad Holian, Tim Germann, and Niels |
| Jensen at Los Alamos National Laboratory were the first users and were |
| instrumental in testing out the first designs. Patrick Tullmann at |
| the University of Utah suggested the idea of automatic documentation |
| generation. John Schmidt, Kurtis |
| Bleeker, Peter-Pike Sloan, and Steve Parker at the University of Utah tested out some of the newer versions and |
| provided valuable feedback. John Buckman suggested many interesting |
| improvements and has been instrumental the recent development of SWIG. |
| Finally |
| I'd like to thank Chris Johnson and the members of the Scientific |
| Computing and Imaging group at the University of Utah for their continued |
| support and for putting up with my wrapping every software package |
| I could get my hands on. SWIG was developed in part under the |
| auspices of the US Department of Energy, the National Science Foundation, |
| and National Institutes of Health. |
| |
| <h2> Availability </h2> |
| |
| SWIG is free software and available via anonymous FTP at <br> <br> |
| |
| <center> |
| <tt> ftp.cs.utah.edu/pub/beazley/SWIG </tt> <br> <br> |
| </center> |
| |
| More information is also available on the SWIG homepage at <br> <br> |
| |
| <center> |
| <a href="http://www.cs.utah.edu/~beazley/SWIG"> <tt> http://www.cs.utah.edu/~beazley/SWIG </tt> </a> |
| </center> <br> <br> |
| |
| <h2> References </h2> |
| |
| [Beazley] D.M. Beazley and P.S. Lomdahl, |
| <em> Message-Passing Multi-Cell Molecular Dynamics on the Connection |
| Machine 5 </em>, Parallel Computing 20 (1994) p. 173-195. <br> <br> |
| |
| [ET] Embedded Tk, <br> |
| <tt> ftp://ftp.vnet.net/pub/users/drh/ET.html </tt> <br> <br> |
| |
| [Expect] Don Libes, <em> Exploring Expect </em>, O'Reilly & Associates, Inc. (1995). <br> <br> |
| |
| [Heidrich] Wolfgang Heidrich and Philipp Slusallek, <em> |
| Automatic Generation of Tcl Bindings for C and C++ Libraries.</em>, |
| USENIX 3rd Annual Tcl/Tk Workshop (1995). <br> <br> |
| |
| [Janssen] Bill Janssen, Mike Spreitzer, <em> ILU : Inter-Language Unification via Object Modules </em>, OOPSLA 94 Workshop on Multi-Language |
| Object Models. <br> <br> |
| |
| [Lomdahl] P.S. Lomdahl, P. Tamayo, |
| N.Gronbech-Jensen, and D.M. Beazley, |
| <em> Proc. of Supercomputing 93 </em>, IEEE Computer Society (1993), p. 520-527. |
| <br> <br> |
| |
| [Lord] Thomas Lord, <em> An Anatomy of Guile, The Interface to |
| Tcl/Tk </em>, Proceedings of the USENIX 3rd Annual Tcl/Tk Workshop (1995). <br> <br> |
| |
| [MATLAB] <em> MATLAB External Interface Guide </em>, The Math Works, Inc. (1993). |
| <br> <br> |
| |
| [Ousterhout] John K. Ousterhout, <em> Tcl and the Tk Toolkit </em>, Addison-Wesley Publishers (1994). <br> <br> |
| |
| [Perl5] Perl5 Programmers reference, <br> |
| <tt> http://www.metronet.com/perlinfo/doc </tt>, (1996). <br> <br> |
| |
| [vtk] W. Schroeder, K. Martin, and B. Lorensen, <em> The |
| Visualization Toolkit </em>, Prentice Hall (1995). <br> <br> |
| |
| [Invent] J. Wernecke,<em> The Inventor Mentor </em>, Addison-Wesley Publishing (1994). <br> <br> |
| |
| [Wetherall] D. Wetherall, C. J. Lindblad, <em> Extending Tcl for |
| Dynamic Object-Oriented Programming </em>, Proceedings of the USENIX 3rd Annual Tcl/Tk Workshop (1995). <br> <br> |
| |
| [OpenGL] J. Neider, T. Davis, M. Woo, <em> OpenGL Programming Guide </em>, Addison-Wesley Publishing (1993). <br> <br> |
| |
| </body> |
| </html> |
| |
| |
| |
| |
| |
| |
| |
| |