diff options
Diffstat (limited to 'swigweb/papers/Tcl96/tcl96.html')
-rwxr-xr-x | swigweb/papers/Tcl96/tcl96.html | 1084 |
1 files changed, 0 insertions, 1084 deletions
diff --git a/swigweb/papers/Tcl96/tcl96.html b/swigweb/papers/Tcl96/tcl96.html deleted file mode 100755 index c2bdbdc26..000000000 --- a/swigweb/papers/Tcl96/tcl96.html +++ /dev/null @@ -1,1084 +0,0 @@ -<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> - - - - - - - - |