summaryrefslogtreecommitdiff
path: root/swigweb/papers/Tcl96/tcl96.html
blob: c2bdbdc2688d90c74222dd3c6d7e0b4411b40dc3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
<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 &lt;stdio.h&gt;
%}

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 &lt; $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 &lt;GL/gl.h&gt;
%}
... 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 &amp; 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>