/tags/ttn-post-libtool-1-4-3-upgrade/SWIG/Doc/Manual/Tcl.html
# · HTML · 2502 lines · 2005 code · 495 blank · 2 comment · 0 complexity · e642de8b1f6f7a237cb9c86049dbd277 MD5 · raw file
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <html>
- <head>
- <title>SWIG and Tcl</title>
- </head>
- <body bgcolor="#ffffff">
- <a name="n1"></a><H1>21 SWIG and Tcl</H1>
- <!-- INDEX -->
- <ul>
- <li><a href="#n2">Preliminaries</a>
- <ul>
- <li><a href="#n3">Getting the right header files</a>
- <li><a href="#n4">Compiling a dynamic module</a>
- <li><a href="#n5">Static linking</a>
- <li><a href="#n6">Using your module</a>
- <li><a href="#n7">Compilation of C++ extensions</a>
- <li><a href="#n8">Compiling for 64-bit platforms</a>
- <li><a href="#n9">Setting a package prefix</a>
- <li><a href="#n10">Using namespaces</a>
- </ul>
- <li><a href="#n11">Building Tcl/Tk Extensions under Windows 95/NT</a>
- <ul>
- <li><a href="#n12">Running SWIG from Developer Studio</a>
- <li><a href="#n13">Using NMAKE</a>
- </ul>
- <li><a href="#n14">A tour of basic C/C++ wrapping</a>
- <ul>
- <li><a href="#n15">Modules</a>
- <li><a href="#n16">Functions</a>
- <li><a href="#n17">Global variables</a>
- <li><a href="#n18">Constants and enums</a>
- <li><a href="#n19">Pointers</a>
- <li><a href="#n20">Structures</a>
- <li><a href="#n21">C++ classes</a>
- <li><a href="#n22">C++ inheritance</a>
- <li><a href="#n23">Pointers, references, values, and arrays</a>
- <li><a href="#n24">C++ overloaded functions</a>
- <li><a href="#n25">C++ operators</a>
- <li><a href="#n26">C++ namespaces</a>
- <li><a href="#n27">C++ templates</a>
- <li><a href="#n28">C++ Smart Pointers</a>
- </ul>
- <li><a href="#n29">Further details on the Tcl class interface</a>
- <ul>
- <li><a href="#n30">Proxy classes</a>
- <li><a href="#n31">Memory management</a>
- </ul>
- <li><a href="#n32">Input and output parameters</a>
- <li><a href="#n33">Exception handling </a>
- <li><a href="#n34">Typemaps</a>
- <ul>
- <li><a href="#n35">What is a typemap?</a>
- <li><a href="#n36">Tcl typemaps</a>
- <li><a href="#n37">Typemap variables</a>
- <li><a href="#n38">Converting a Tcl list to a char ** </a>
- <li><a href="#n39">Returning values in arguments</a>
- <li><a href="#n40">Useful functions</a>
- <li><a href="#n41">Standard typemaps</a>
- <li><a href="#n42">Pointer handling</a>
- </ul>
- <li><a href="#n43">Turning a SWIG module into a Tcl Package.</a>
- <li><a href="#n44">Building new kinds of Tcl interfaces (in Tcl)</a>
- <ul>
- <li><a href="#n45">Shadow classes</a>
- </ul>
- </ul>
- <!-- INDEX -->
- <b>Caution: This chapter is under repair!</b>
- <p>
- This chapter discusses SWIG's support of Tcl. SWIG currently requires
- Tcl 8.0 or a later release. Earlier releases of SWIG supported Tcl 7.x, but
- this is no longer supported.
- <a name="n2"></a><H2>21.1 Preliminaries</H2>
- To build a Tcl module, run SWIG using the <tt>-tcl</tt> option :<p>
- <p>
- <blockquote><pre>$ swig -tcl example.i
- </pre></blockquote>
- If building a C++ extension, add the <tt>-c++</tt> option:
- <p>
- <blockquote><pre>$ swig -c++ -tcl example.i
- </pre></blockquote>
- <p>
- This creates a file <tt>example_wrap.c</tt> or
- <tt>example_wrap.cxx</tt> that contains all of the code needed to
- build a Tcl extension module. To finish building the module, you
- need to compile this file and link it with the rest of your program.
- <a name="n3"></a><H3>21.1.1 Getting the right header files</H3>
- In order to compile the wrapper code, the compiler needs the <tt>tcl.h</tt> header file.
- This file is usually contained in the directory
- <p>
- <blockquote><pre>/usr/local/include
- </pre></blockquote>
- Be aware that some Tcl versions install this header file with a version number attached to it. If
- this is the case, you should probably make a symbolic link so that <tt>tcl.h</tt> points to the correct
- header file.
- <a name="n4"></a><H3>21.1.2 Compiling a dynamic module</H3>
- The preferred approach to building an extension module is to compile it into
- a shared object file or DLL. To do this, you will need to compile your program
- using comands like this (shown for Linux):
- <p>
- <blockquote><pre>$ swig -tcl example.i
- $ gcc -c example.c
- $ gcc -c example_wrap.c -I/usr/local/include
- $ gcc -shared example.o example_wrap.o -o example.so
- </pre></blockquote>
- The exact commands for doing this vary from platform to platform.
- SWIG tries to guess the right options when it is installed. Therefore,
- you may want to start with one of the examples in the <tt>SWIG/Examples/tcl</tt>
- directory. If that doesn't work, you will need to read the man-pages for
- your compiler and linker to get the right set of options. You might also
- check the <a href="http://swig.cs.uchicago.edu/cgi-bin/wiki.pl">SWIG Wiki</a> for
- additional information.
- <p>
- When linking the module, the name of the output file has to match the name
- of the module. If the name of your SWIG module is "<tt>example</tt>", the
- name of the corresponding object file should be
- "<tt>example.so</tt>".
- The name of the module is specified using the <tt>%module</tt> directive or the
- <tt> -module</tt> command line option.<p>
- <a name="n5"></a><H3>21.1.3 Static linking</H3>
- An alternative approach to dynamic linking is to rebuild the Tcl
- interpreter with your extension module added to it. In the past,
- this approach was sometimes necesssary due to limitations in dynamic loading
- support on certain machines. However, the situation has improved greatly
- over the last few years and you should not consider this approach
- unless there is really no other option.
- <p>
- The usual procedure for adding a new module to Tcl involves writing a
- special function <tt>Tcl_AppInit()</tt> and using it to initialize the interpreter and
- your module. With SWIG, the <tt>tclsh.i</tt> and <tt>wish.i</tt> library files
- can be used to rebuild the <tt>tclsh</tt> and <tt>wish</tt> interpreters respectively.
- For example:
- <p>
- <blockquote><pre>%module example
- extern int fact(int);
- extern int mod(int, int);
- extern double My_variable;
- %include tclsh.i // Include code for rebuilding tclsh
- </pre></blockquote>
- The <tt>tclsh.i</tt> library file includes supporting code that
- contains everything needed to rebuild tclsh. To rebuild the interpreter,
- you simply do something like this:
- <p>
- <blockquote><pre>$ swig -tcl example.i
- $ gcc example.c example_wrap.c \
- -Xlinker -export-dynamic \
- -DHAVE_CONFIG_H -I/usr/local/include/ \
- -L/usr/local/lib -ltcl -lm -ldl \
- -o mytclsh
- </pre></blockquote>
- You will need to supply the same libraries that were used to build Tcl the first
- time. This may include system libraries such as <tt>-lsocket</tt>, <tt>-lnsl</tt>,
- and <tt>-lpthread</tt>. If this actually works, the new version of Tcl
- should be identical to the default version except that your extension module will be
- a built-in part of the interpreter.
- <p>
- <b>Comment:</b> In practice, you should probably try to avoid static
- linking if possible. Some programmers may be inclined
- to use static linking in the interest of getting better performance.
- However, the performance gained by static linking tends to be rather
- minimal in most situations (and quite frankly not worth the extra
- hassle in the opinion of this author).
- <a name="n6"></a><H3>21.1.4 Using your module</H3>
- To use your module, simply use the Tcl <tt>load</tt> command. If
- all goes well, you will be able to this:
- <p>
- <blockquote><pre>$ tclsh
- % load ./example.so
- % fact 4
- 24
- %
- </pre></blockquote>
- A common error received by first-time users is the following:
- <blockquote>
- <pre>
- % load ./example.so
- couldn't find procedure Example_Init
- %
- </pre>
- </blockquote>
- This error is almost always caused when the name of the shared object file doesn't
- match the name of the module supplied using the SWIG <tt>%module</tt> directive.
- Double-check the interface to make sure the module name and the shared object
- file match. Another possible cause of this error is forgetting to link the SWIG-generated
- wrapper code with the rest of your application when creating the extension module.
- <p>
- Another common error is something similar to the following:
- <blockquote>
- <pre>
- % load ./example.so
- couldn't load file "./example.so": ./example.so: undefined symbol: fact
- %
- </pre>
- </blockquote>
- This error usually indicates that you forgot to include some object
- files or libraries in the linking of the shared library file. Make
- sure you compile both the SWIG wrapper file and your original program
- into a shared library file. Make sure you pass all of the required libraries
- to the linker.
- <p>
- Sometimes unresolved symbols occur because a wrapper has been created
- for a function that doesn't actually exist in a library. This usually
- occurs when a header file includes a declaration for a function that
- was never actually implemented or it was removed from a library
- without updating the header file. To fix this, you can either edit
- the SWIG input file to remove the offending declaration or you can use
- the <tt>%ignore</tt> directive to ignore the declaration.
- <p>
- Finally, suppose that your extension module is linked with another library like this:
- <blockquote>
- <pre>
- $ gcc -shared example.o example_wrap.o -L/home/beazley/projects/lib -lfoo \
- -o example.so
- </pre>
- </blockquote>
- If the <tt>foo</tt> library is compiled as a shared library, you might get the following
- problem when you try to use your module:
- <blockquote>
- <pre>
- % load ./example.so
- couldn't load file "./example.so": libfoo.so: cannot open shared object file:
- No such file or directory
- %
- </pre>
- </blockquote>
- This error is generated because the dynamic linker can't locate the
- <tt>libfoo.so</tt> library. When shared libraries are loaded, the
- system normally only checks a few standard locations such as
- <tt>/usr/lib</tt> and <tt>/usr/local/lib</tt>. To fix this problem,
- there are several things you can do. First, you can recompile your extension
- module with extra path information. For example, on Linux you can do this:
- <blockquote>
- <pre>
- $ gcc -shared example.o example_wrap.o -L/home/beazley/projects/lib -lfoo \
- -Xlinker -rpath /home/beazley/projects/lib \
- -o example.so
- </pre>
- </blockquote>
- Alternatively, you can set the <tt>LD_LIBRARY_PATH</tt> environment variable to
- include the directory with your shared libraries.
- If setting <tt>LD_LIBRARY_PATH</tt>, be aware that setting this variable can introduce
- a noticeable performance impact on all other applications that you run.
- To set it only for Tcl, you might want to do this instead:
- <blockquote>
- <pre>
- $ env LD_LIBRARY_PATH=/home/beazley/projects/lib tclsh
- </pre>
- </blockquote>
- Finally, you can use a command such as <tt>ldconfig</tt> to add additional search paths
- to the default system configuration (this requires root access and you will need to read
- the man pages).
- <a name="n7"></a><H3>21.1.5 Compilation of C++ extensions</H3>
- Compilation of C++ extensions has traditionally been a tricky problem.
- Since the Tcl interpreter is written in C, you need to take steps to
- make sure C++ is properly initialized and that modules are compiled
- correctly.
- <p>
- On most machines, C++ extension modules should be linked using the C++
- compiler. For example:
- <p>
- <blockquote><pre>% swig -c++ -tcl example.i
- % g++ -c example.cxx
- % g++ -c example_wrap.cxx -I/usr/local/include
- % g++ -shared example.o example_wrap.o -o example.so
- </pre></blockquote>
- In addition to this, you may need to include additional library
- files to make it work. For example, if you are using the Sun C++ compiler on
- Solaris, you often need to add an extra library <tt>-lCrun</tt> like this:
- <p>
- <blockquote><pre>% swig -c++ -tcl example.i
- % CC -c example.cxx
- % CC -c example_wrap.cxx -I/usr/local/include
- % CC -G example.o example_wrap.o -L/opt/SUNWspro/lib -o example.so -lCrun
- </pre></blockquote>
- Of course, the extra libraries to use are completely non-portable---you will
- probably need to do some experimentation.
- <p>
- Sometimes people have suggested that it is necessary to relink the
- Tcl interpreter using the C++ compiler to make C++ extension modules work.
- In the experience of this author, this has never actually appeared to be
- necessary. Relinking the interpreter with C++ really only includes the
- special run-time libraries described above---as long as you link your extension
- modules with these libraries, it should not be necessary to rebuild Tcl.
- <p>
- If you aren't entirely sure about the linking of a C++ extension, you
- might look at an existing C++ program. On many Unix machines, the
- <tt>ldd</tt> command will list library dependencies. This should give
- you some clues about what you might have to include when you link your
- extension module. For example:
- <blockquote>
- <pre>
- $ ldd swig
- libstdc++-libc6.1-1.so.2 => /usr/lib/libstdc++-libc6.1-1.so.2 (0x40019000)
- libm.so.6 => /lib/libm.so.6 (0x4005b000)
- libc.so.6 => /lib/libc.so.6 (0x40077000)
- /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
- $
- </pre>
- </blockquote>
- <p>
- As a final complication, a major weakness of C++ is that it does not
- define any sort of standard for binary linking of libraries. This
- means that C++ code compiled by different compilers will not link
- together properly as libraries nor is the memory layout of classes and
- data structures implemented in any kind of portable manner. In a
- monolithic C++ program, this problem may be unnoticed. However, in Tcl, it
- is possible for different extension modules to be compiled with
- different C++ compilers. As long as these modules are self-contained,
- this probably won't matter. However, if these modules start sharing data,
- you will need to take steps to avoid segmentation faults and other
- erratic program behavior. If working with lots of software components, you
- might want to investigate using a more formal standard such as COM.
- <a name="n8"></a><H3>21.1.6 Compiling for 64-bit platforms</H3>
- On platforms that support 64-bit applications (Solaris, Irix, etc.),
- special care is required when building extension modules. On these
- machines, 64-bit applications are compiled and linked using a different
- set of compiler/linker options. In addition, it is not generally possible to mix
- 32-bit and 64-bit code together in the same application.
- <p>
- To utilize 64-bits, the Tcl executable will need to be recompiled
- as a 64-bit application. In addition, all libraries, wrapper code,
- and every other part of your application will need to be compiled for
- 64-bits. If you plan to use other third-party extension modules, they
- will also have to be recompiled as 64-bit extensions.
- <p>
- If you are wrapping commercial software for which you have no source
- code, you will be forced to use the same linking standard as used by
- that software. This may prevent the use of 64-bit extensions. It may
- also introduce problems on platforms that support more than one
- linking standard (e.g., -o32 and -n32 on Irix).
- <a name="n9"></a><H3>21.1.7 Setting a package prefix</H3>
- To avoid namespace problems, you can instruct SWIG to append a package
- prefix to all of your functions and variables. This is done using the
- -prefix option as follows :<p>
- <p>
- <blockquote><pre>swig -tcl -prefix Foo example.i
- </pre></blockquote>
- If you have a function "<tt>bar</tt>" in the SWIG file, the prefix
- option will append the prefix to the name when creating a command and
- call it "<tt>Foo_bar</tt>". <p>
- <a name="n10"></a><H3>21.1.8 Using namespaces</H3>
- Alternatively, you can have SWIG install your module into a Tcl
- namespace by specifying the <tt>-namespace</tt> option :<p>
- <p>
- <blockquote><pre>swig -tcl -namespace example.i
- </pre></blockquote>
- By default, the name of the namespace will be the same as the module
- name, but you can override it using the <tt>-prefix</tt> option.<p>
- <p>
- When the<tt> -namespace</tt> option is used, objects in the module
- are always accessed with the namespace name such as <tt>Foo::bar</tt>.
- <a name="n11"></a><H2>21.2 Building Tcl/Tk Extensions under Windows 95/NT</H2>
- Building a SWIG extension to Tcl/Tk under Windows 95/NT is roughly
- similar to the process used with Unix. Normally, you will want to
- produce a DLL that can be loaded into tclsh or wish. This section
- covers the process of using SWIG with Microsoft Visual C++.
- although the procedure may be similar with other compilers.<p>
- <a name="n12"></a><H3>21.2.1 Running SWIG from Developer Studio</H3>
- If you are developing your application within Microsoft developer
- studio, SWIG can be invoked as a custom build option. The process
- roughly follows these steps :<p>
- <p>
- <ul>
- <li>Open up a new workspace and use the AppWizard to select a DLL project.
- <li>Add both the SWIG interface file (the .i file), any supporting C
- files, and the name of the wrapper file that will be created by SWIG
- (ie. <tt>example_wrap.c</tt>). Note : If using C++, choose a
- different suffix for the wrapper file such as
- <tt>example_wrap.cxx</tt>. Don't worry if the wrapper file doesn't
- exist yet--Developer studio will keep a reference to it around.
- <li>Select the SWIG interface file and go to the settings menu. Under
- settings, select the "Custom Build" option.
- <li>Enter "SWIG" in the description field.
- <li>Enter "<tt>swig -tcl -o $(ProjDir)\$(InputName)_wrap.c
- $(InputPath)</tt>" in the "Build command(s) field"
- <li>Enter "<tt>$(ProjDir)\$(InputName)_wrap.c</tt>" in the "Output files(s) field".
- <li>Next, select the settings for the entire project and go to
- "C++:Preprocessor". Add the include directories for your Tcl
- installation under "Additional include directories".
- <li>Finally, select the settings for the entire project and go to
- "Link Options". Add the Tcl library file to your link libraries. For
- example "<tt>tcl80.lib</tt>". Also, set the name of the output file
- to match the name of your Tcl module (ie. example.dll).
- <li>Build your project.
- </ul>
- <p>
- Now, assuming all went well, SWIG will be automatically invoked when
- you build your project. Any changes made to the interface file will
- result in SWIG being automatically invoked to produce a new version of
- the wrapper file. To run your new Tcl extension, simply run
- <tt>tclsh</tt> or <tt>wish</tt> and use the <tt>load</tt> command.
- For example :<p>
- <p>
- <blockquote><pre>
- MSDOS > tclsh80
- % load example.dll
- % fact 4
- 24
- %
- </pre></blockquote>
- <a name="n13"></a><H3>21.2.2 Using NMAKE</H3>
- Alternatively, SWIG extensions can be built by writing a Makefile for
- NMAKE. To do this, make sure the environment variables for MSVC++ are
- available and the MSVC++ tools are in your path. Now, just write a
- short Makefile like this :<p>
- <p>
- <blockquote><pre># Makefile for building various SWIG generated extensions
- SRCS = example.c
- IFILE = example
- INTERFACE = $(IFILE).i
- WRAPFILE = $(IFILE)_wrap.c
- # Location of the Visual C++ tools (32 bit assumed)
- TOOLS = c:\msdev
- TARGET = example.dll
- CC = $(TOOLS)\bin\cl.exe
- LINK = $(TOOLS)\bin\link.exe
- INCLUDE32 = -I$(TOOLS)\include
- MACHINE = IX86
- # C Library needed to build a DLL
- DLLIBC = msvcrt.lib oldnames.lib
- # Windows libraries that are apparently needed
- WINLIB = kernel32.lib advapi32.lib user32.lib gdi32.lib comdlg32.lib
- winspool.lib
- # Libraries common to all DLLs
- LIBS = $(DLLIBC) $(WINLIB)
- # Linker options
- LOPT = -debug:full -debugtype:cv /NODEFAULTLIB /RELEASE /NOLOGO /
- MACHINE:$(MACHINE) -entry:_DllMainCRTStartup@12 -dll
- # C compiler flags
- CFLAGS = /Z7 /Od /c /nologo
- TCL_INCLUDES = -Id:\tcl8.0a2\generic -Id:\tcl8.0a2\win
- TCLLIB = d:\tcl8.0a2\win\tcl80.lib
- tcl::
- ..\..\swig -tcl -o $(WRAPFILE) $(INTERFACE)
- $(CC) $(CFLAGS) $(TCL_INCLUDES) $(SRCS) $(WRAPFILE)
- set LIB=$(TOOLS)\lib
- $(LINK) $(LOPT) -out:example.dll $(LIBS) $(TCLLIB) example.obj example_wrap.obj
- </pre></blockquote>
- To build the extension, run NMAKE (you may need to run vcvars32
- first). This is a pretty minimal Makefile, but hopefully its enough
- to get you started. With a little practice, you'll be making lots of
- Tcl extensions.<p>
- <a name="n14"></a><H2>21.3 A tour of basic C/C++ wrapping</H2>
- By default, SWIG tries to build a very natural Tcl interface to your
- C/C++ code. Functions are wrapped as functions, classes are wrapped
- in an interface that mimics the style of Tk widgets and [incr Tcl]
- classes. This section briefly covers the essential aspects of this
- wrapping.
- <a name="n15"></a><H3>21.3.1 Modules</H3>
- The SWIG <tt>%module</tt> directive specifies the name of the Tcl
- module. If you specify `<tt>%module example</tt>', then everything is
- compiled into an extension module <tt>example.so</tt>. When choosing a
- module name, make sure you don't use the same name as a built-in
- Tcl command.
- <p>
- One pitfall to watch out for is module names involving numbers. If
- you specify a module name like <tt>%module md5</tt>, you'll find that the
- load command no longer seems to work:
- <blockquote>
- <pre>
- % load ./md5.so
- couldn't find procedure Md_Init
- </pre>
- </blockquote>
- To fix this, supply an extra argument to <tt>load</tt> like this:
- <blockquote>
- <pre>
- % load ./md5.so md5
- </pre>
- </blockquote>
- <a name="n16"></a><H3>21.3.2 Functions</H3>
- Global functions are wrapped as new Tcl built-in commands. For example,
- <p>
- <blockquote><pre>%module example
- int fact(int n);
- </pre></blockquote>
- creates a built-in function <tt>fact</tt> that works exactly
- like you think it does:<p>
- <p>
- <blockquote><pre>
- % load ./example.so
- % fact 4
- 24
- % set x [fact 6]
- %
- </pre></blockquote>
- <a name="n17"></a><H3>21.3.3 Global variables</H3>
- C/C++ global variables are wrapped by Tcl global variables. For example:
- <blockquote><pre>
- // SWIG interface file with global variables
- %module example
- ...
- extern double density;
- ...
- </pre></blockquote>
- <p>
- Now look at the Tcl interface:<p>
- <p>
- <blockquote><pre>
- % puts $density # Output value of C global variable
- 1.0
- % set density 0.95 # Change value
- </pre></blockquote>
- <p>
- If you make an error in variable assignment, you will get an
- error message. For example:
- <blockquote><pre>
- % set density "hello"
- can't set "density": Type error. expected a double.
- %
- </pre></blockquote>
- <p>
- If a variable is declared as <tt>const</tt>, it is wrapped as a
- read-only variable. Attempts to modify its value will result in an
- error.
- <p>
- To make ordinary variables read-only, you can use the <tt>%immutable</tt> directive. For example:
- <blockquote>
- <pre>
- %immutable;
- extern char *path;
- %mutable;
- </pre>
- </blockquote>
- The <tt>%immutable</tt> directive stays in effect until it is explicitly disabled using
- <tt>%mutable</tt>.
- <p>
- If you just want to make a specific variable immutable, supply a declaration name. For example:
- <blockquote>
- <pre>
- %immutable path;
- ...
- extern char *path; // Read-only (due to %immutable)
- </pre>
- </blockquote>
- <a name="n18"></a><H3>21.3.4 Constants and enums</H3>
- C/C++ constants are installed as global Tcl variables containing the
- appropriate value. To create a constant, use <tt>#define</tt>, <tt>enum</tt>, or the
- <tt>%constant</tt> directive. For example:
- <blockquote>
- <pre>
- #define PI 3.14159
- #define VERSION "1.0"
- enum Beverage { ALE, LAGER, STOUT, PILSNER };
- %constant int FOO = 42;
- %constant const char *path = "/usr/local";
- </pre>
- </blockquote>
- For enums, make sure that the definition of the enumeration actually appears in a header
- file or in the wrapper file somehow---if you just stick an enum in a SWIG interface without
- also telling the C compiler about it, the wrapper code won't compile.
- <p>
- Note: declarations declared as <tt>const</tt> are wrapped as read-only variables and
- will be accessed using the <tt>cvar</tt> object described in the previous section. They
- are not wrapped as constants. For further discussion about this, see the <a href="SWIG.html">SWIG Basics</a> chapter.
- <p>
- Constants are not guaranteed to remain constant in Tcl---the value
- of the constant could be accidentally reassigned.You will just have to be careful.
- <p>
- A peculiarity of installing constants as variables is that it is necessary to use the Tcl <tt>global</tt> statement to
- access constants in procedure bodies. For example:
- <blockquote>
- <pre>
- proc blah {} {
- global FOO
- bar $FOO
- }
- </pre>
- </blockquote>
- If a program relies on a lot of constants, this can be extremely annoying. To fix the problem, consider using the
- following typemap rule:
- <blockquote>
- <pre>
- %apply int CONSTANT { int x };
- #define FOO 42
- ...
- void bar(int x);
- </pre>
- </blockquote>
- When applied to an input argument, the <tt>CONSTANT</tt> rule allows a constant to be passed to a function using
- its actual value or a symbolic identifier name. For example:
- <blockquote>
- <pre>
- proc blah {} {
- bar FOO
- }
- </pre>
- </blockquote>
- When an identifier name is given, it is used to perform an implicit hash-table lookup of the value during argument
- conversion. This allows the <tt>global</tt> statement to be ommitted.
- <a name="n19"></a><H3>21.3.5 Pointers</H3>
- C/C++ pointers are fully supported by SWIG. Furthermore, SWIG has no problem working with
- incomplete type information. Here is a rather simple interface:
- <blockquote>
- <pre>
- %module example
- FILE *fopen(const char *filename, const char *mode);
- int fputs(const char *, FILE *);
- int fclose(FILE *);
- </pre>
- </blockquote>
- When wrapped, you will be able to use the functions in a natural way from Tcl.
- For example:
- <blockquote>
- <pre>
- % load ./example.so
- % set f [fopen junk w]
- % fputs "Hello World\n" $f
- % fclose $f
- </pre>
- </blockquote>
- If this makes you uneasy, rest assured that there is no
- deep magic involved. Underneath the covers, pointers to C/C++ objects are
- simply represented as opaque values--normally an encoded character
- string like this:
- <p>
- <blockquote><pre>
- % puts $f
- _c0671108_p_FILE
- %
- </pre></blockquote>
- This pointer value can be freely passed around to different C functions that
- expect to receive an object of type <tt>FILE *</tt>. The only thing you can't do is
- dereference the pointer from Tcl.
- <p>
- The NULL pointer is represented by the string <tt>NULL</tt>.
- <p>
- As much as you might be inclined to modify a pointer value directly
- from Tcl, don't. The hexadecimal encoding is not necessarily the
- same as the logical memory address of the underlying object. Instead
- it is the raw byte encoding of the pointer value. The encoding will
- vary depending on the native byte-ordering of the platform (i.e.,
- big-endian vs. little-endian). Similarly, don't try to manually cast
- a pointer to a new type by simply replacing the type-string. This
- may not work like you expect and it is particularly dangerous when
- casting C++ objects. If you need to cast a pointer or
- change its value, consider writing some helper functions instead. For
- example:
- <blockquote>
- <pre>
- %inline %{
- /* C-style cast */
- Bar *FooToBar(Foo *f) {
- return (Bar *) f;
- }
- /* C++-style cast */
- Foo *BarToFoo(Bar *b) {
- return dynamic_cast<Foo*>(b);
- }
- Foo *IncrFoo(Foo *f, int i) {
- return f+i;
- }
- %}
- </pre>
- </blockquote>
- Also, if working with C++, you should always try
- to use the new C++ style casts. For example, in the above code, the
- C-style cast may return a bogus result whereas as the C++-style cast will return
- <tt>None</tt> if the conversion can't be performed.
- <a name="n20"></a><H3>21.3.6 Structures</H3>
- If you wrap a C structure, it is wrapped by a Tcl interface that somewhat resembles a Tk widget.
- This provides a very natural interface. For example,
- <p>
- <blockquote><pre>struct Vector {
- double x,y,z;
- };
- </pre></blockquote>
- is used as follows:
- <p>
- <blockquote><pre>
- % Vector v
- % v configure -x 3.5 -y 7.2
- % puts "[v cget -x] [v cget -y] [v cget -z]"
- 3.5 7.2 0.0
- %
- </pre></blockquote>
- <p>
- Similar access is provided for unions and the data members of C++ classes.<p>
- <p>
- In the above example, <tt>v</tt> is a name that's used for the object. However,
- underneath the covers, there's a pointer to a raw C structure. This can be obtained
- by looking at the <tt>-this</tt> attribute. For example:
- <blockquote>
- <pre>
- % puts [v cget -this]
- _88e31408_p_Vector
- </pre>
- </blockquote>
- Further details about the relationship between the Tcl and the underlying C structure
- are covered a little later.
- <p>
- <tt>const</tt> members of a structure are read-only. Data members
- can also be forced to be read-only using the <tt>%immutable</tt> directive. For example:
- <blockquote>
- <pre>
- struct Foo {
- ...
- %immutable;
- int x; /* Read-only members */
- char *name;
- %mutable;
- ...
- };
- </pre>
- </blockquote>
- <p>
- When <tt>char *</tt> members of a structure are wrapped, the contents are assumed to be
- dynamically allocated using <tt>malloc</tt> or <tt>new</tt> (depending on whether or not
- SWIG is run with the -c++ option). When the structure member is set, the old contents will be
- released and a new value created. If this is not the behavior you want, you will have to use
- a typemap (described later).
- <p>
- If a structure contains arrays, access to those arrays is managed through pointers. For
- example, consider this:
- <blockquote>
- <pre>
- struct Bar {
- int x[16];
- };
- </pre>
- </blockquote>
- If accessed in Tcl, you will see behavior like this:
- <blockquote>
- <pre>
- % Bar b
- % puts [b cget -x]
- _801861a4_p_int
- %
- </pre>
- </blockquote>
- This pointer can be passed around to functions that expect to receive
- an <tt>int *</tt> (just like C). You can also set the value of an array member using
- another pointer. For example:
- <blockquote>
- <pre>
- % Bar c
- % c configure -x [b cget -x] # Copy contents of b.x to c.x
- </pre>
- </blockquote>
- For array assignment, SWIG copies the entire contents of the array starting with the data pointed
- to by <tt>b.x</tt>. In this example, 16 integers would be copied. Like C, SWIG makes
- no assumptions about bounds checking---if you pass a bad pointer, you may get a segmentation
- fault or access violation.
- <p>
- When a member of a structure is itself a structure, it is handled as a
- pointer. For example, suppose you have two structures like this:
- <blockquote>
- <pre>
- struct Foo {
- int a;
- };
- struct Bar {
- Foo f;
- };
- </pre>
- </blockquote>
- Now, suppose that you access the <tt>f</tt> attribute of <tt>Bar</tt> like this:
- <blockquote>
- <pre>
- % Bar b
- % set x [b cget -f]
- </pre>
- </blockquote>
- In this case, <tt>x</tt> is a pointer that points to the <tt>Foo</tt> that is inside <tt>b</tt>.
- This is the same value as generated by this C code:
- <blockquote>
- <pre>
- Bar b;
- Foo *x = &b->f; /* Points inside b */
- </pre>
- </blockquote>
- However, one peculiarity of accessing a substructure like this is that the returned
- value does work quite like you might expect. For example:
- <blockquote>
- <pre>
- % Bar b
- % set x [b cget -f]
- % x cget -a
- invalid command name "x"
- </pre>
- </blockquote>
- This is because the returned value was not created in a normal way from the interpreter (x is
- not a command object). To make it function normally, just
- evaluate the variable like this:
- <blockquote>
- <pre>
- % Bar b
- % set x [b cget -f]
- % $x cget -a
- 0
- %
- </pre>
- </blockquote>
- In this example, <tt>x</tt> points inside the original structure. This means that modifications
- work just like you would expect. For example:
- <blockquote>
- <pre>
- % Bar b
- % set x [b cget -f]
- % $x configure -a 3 # Modifies contents of f (inside b)
- % [b cget -f] -configure -a 3 # Same thing
- </pre>
- </blockquote>
- In many of these structure examples, a simple name like "v" or "b" has been given
- to wrapped structures. If necessary, this name can be passed to functions
- that expect to receive an object. For example, if you have a function like this,
- <blockquote>
- <pre>
- void blah(Foo *f);
- </pre>
- </blockquote>
- you can call the function in Tcl as follows:
- <blockquote>
- <pre>
- % Foo x # Create a Foo object
- % blah x # Pass the object to a function
- </pre>
- </blockquote>
- It is also possible to call the function using the raw pointer value. For
- instance:
- <blockquote>
- <pre>
- % blah [x cget -this] # Pass object to a function
- </pre>
- </blockquote>
- It is also possible to create and use objects using variables. For example:
- <blockquote>
- <pre>
- % set b [Bar] # Create a Bar
- % $b cget -f # Member access
- % puts $b
- _108fea88_p_Bar
- %
- </pre>
- </blockquote>
- Finally, to destroy objects created from Tcl, you can either let the object
- name go out of scope or you can explicitly delete the object. For example:
- <blockquote>
- <pre>
- % Foo f # Create object f
- % rename f ""
- </pre>
- </blockquote>
- or
- <blockquote>
- <pre>
- % Foo f # Create object f
- % f -delete
- </pre>
- </blockquote>
- Note: Tcl only destroys the underlying object if it has ownership. See the
- memory management section that appears shortly.
- <a name="n21"></a><H3>21.3.7 C++ classes</H3>
- C++ classes are wrapped as an extension of structure wrapping. For example, if you have this class,
- <p>
- <blockquote><pre>class List {
- public:
- List();
- ~List();
- int search(char *item);
- void insert(char *item);
- void remove(char *item);
- char *get(int n);
- int length;
- };
- </pre></blockquote>
- you can use it in Tcl like this:
- <blockquote><pre>
- % List x
- % x insert Ale
- % x insert Stout
- % x insert Lager
- % x get 1
- Stout
- % puts [l cget -length]
- 3
- %
- </pre></blockquote>
- Class data members are accessed in the same manner as C structures.
- <p>
- Static class members are accessed as global functions or variables.
- To illustrate, suppose you have a class like this:
- <blockquote>
- <pre>
- class Spam {
- public:
- static void foo();
- static int bar;
- };
- </pre>
- </blockquote>
- In Tcl, the static member is accessed as follows:
- <blockquote>
- <pre>
- % Spam_foo # Spam::foo()
- % puts $Spam_bar # Spam::bar
- </pre>
- </blockquote>
- <a name="n22"></a><H3>21.3.8 C++ inheritance</H3>
- SWIG is fully aware of issues related to C++ inheritance. Therefore, if you have
- classes like this
- <blockquote>
- <pre>
- class Foo {
- ...
- };
- class Bar : public Foo {
- ...
- };
- </pre>
- </blockquote>
- An object of type <tt>Bar</tt> can be used where a <tt>Foo</tt> is expected. For
- example, if you have this function:
- <blockquote>
- <pre>
- void spam(Foo *f);
- </pre>
- </blockquote>
- then the function <tt>spam()</tt> accepts a <tt>Foo *</tt> or a pointer to any class derived from <tt>Foo</tt>.
- For instance:
- <blockquote>
- <pre>
- % Foo f # Create a Foo
- % Bar b # Create a Bar
- % spam f # OK
- % spam b # OK
- </pre>
- </blockquote>
- <p>
- It is safe to use multiple inheritance with SWIG.
- <a name="n23"></a><H3>21.3.9 Pointers, references, values, and arrays</H3>
- In C++, there are many different ways a function might receive
- and manipulate objects. For example:
- <blockquote>
- <pre>
- void spam1(Foo *x); // Pass by pointer
- void spam2(Foo &x); // Pass by reference
- void spam3(Foo x); // Pass by value
- void spam4(Foo x[]); // Array of objects
- </pre>
- </blockquote>
- In Tcl, there is no detailed distinction like this.
- Because of this, SWIG unifies all of these types
- together in the wrapper code. For instance, if you actually had the
- above functions, it is perfectly legal to do this:
- <blockquote>
- <pre>
- % Foo f # Create a Foo
- % spam1 f # Ok. Pointer
- % spam2 f # Ok. Reference
- % spam3 f # Ok. Value.
- % spam4 f # Ok. Array (1 element)
- </pre>
- </blockquote>
- Similar behavior occurs for return values. For example, if you had
- functions like this,
- <blockquote>
- <pre>
- Foo *spam5();
- Foo &spam6();
- Foo spam7();
- </pre>
- </blockquote>
- then all three functions will return a pointer to some <tt>Foo</tt> object.
- Since the third function (spam7) returns a value, newly allocated memory is used
- to hold the result and a pointer is returned (Tcl will release this memory
- when the return value is garbage collected).
- <a name="n24"></a><H3>21.3.10 C++ overloaded functions</H3>
- C++ overloaded functions, methods, and constructors are mostly supported by SWIG. For example,
- if you have two functions like this:
- <blockquote>
- <pre>
- void foo(int);
- void foo(char *c);
- </pre>
- </blockquote>
- You can use them in Tcl in a straightforward manner:
- <blockquote>
- <pre>
- % foo 3 # foo(int)
- % foo Hello # foo(char *c)
- </pre>
- </blockquote>
- Similarly, if you have a class like this,
- <blockquote>
- <pre>
- class Foo {
- public:
- Foo();
- Foo(const Foo &);
- ...
- };
- </pre>
- </blockquote>
- you can write Tcl code like this:
- <blockquote>
- <pre>
- % Foo f # Create a Foo
- % Foo g f # Copy f
- </pre>
- </blockquote>
- Overloading support is not quite as flexible as in C++. Sometimes there are methods that SWIG
- can't disambiguate. For example:
- <blockquote>
- <pre>
- void spam(int);
- void spam(short);
- </pre>
- </blockquote>
- or
- <blockquote>
- <pre>
- void foo(Bar *b);
- void foo(Bar &b);
- </pre>
- </blockquote>
- If declarations such as these appear, you will get a warning message like this:
- <blockquote>
- <pre>
- example.i:12: Warning(509): Overloaded spam(short) is shadowed by spam(int) at example.i:11.
- </pre>
- </blockquote>
- To fix this, you either need to ignore or rename one of the methods. For example:
- <blockquote>
- <pre>
- %rename(spam_short) spam(short);
- ...
- void spam(int);
- void spam(short); // Accessed as spam_short
- </pre>
- </blockquote>
- or
- <blockquote>
- <pre>
- %ignore spam(short);
- ...
- void spam(int);
- void spam(short); // Ignored
- </pre>
- </blockquote>
- SWIG resolves overloaded functions and methods using a disambiguation scheme that ranks and sorts
- declarations according to a set of type-precedence rules. The order in which declarations appear
- in the input does not matter except in situations where ambiguity arises--in this case, the
- first declaration takes precedence.
- <P>
- Please refer to the "SWIG and C++" chapter for more information about overloading.
- <a name="n25"></a><H3>21.3.11 C++ operators</H3>
- Certain C++ overloaded operators can be handled automatically by SWIG. For example,
- consider a class like this:
- <blockquote>
- <pre>
- class Complex {
- private:
- double rpart, ipart;
- public:
- Complex(double r = 0, double i = 0) : rpart(r), ipart(i) { }
- Complex(const Complex &c) : rpart(c.rpart), ipart(c.ipart) { }
- Complex &operator=(const Complex &c);
- Complex operator+(const Complex &c) const;
- Complex operator-(const Complex &c) const;
- Complex operator*(const Complex &c) const;
- Complex operator-() const;
-
- double re() const { return rpart; }
- double im() const { return ipart; }
- };
- </pre>
- </blockquote>
- When wrapped, it works like this:
- <blockquote>
- <pre>
- % Complex c 3 4
- % Complex d 7 8
- % set e [c + d]
- % $e re
- 10.0
- % $e im
- 12.0
- </pre>
- </blockquote>
- It should be stressed that operators in SWIG have no relationship to operators
- in Tcl. In fact, the only thing that's happening here is that an operator like
- <tt>operator +</tt> has been renamed to a method <tt>+</tt>. Therefore, the
- statement <tt>[c + d]</tt> is really just invoking the <tt>+</tt> method on <tt>c</tt>.
- When more than operator is defined (with different arguments), the standard
- method overloading facilities are used. Here is a rather odd looking example:
- <blockquote>
- <pre>
- % Complex c 3 4
- % Complex d 7 8
- % set e [c - d] # operator-(const Complex &)
- % puts "[$e re] [$e im]"
- 10.0 12.0
- % set f [c -] # operator-()
- % puts "[$f re] [$f im]"
- -3.0 -4.0
- %
- </pre>
- </blockquote>
- One restriction with operator overloading support is that SWIG is not
- able to fully handle operators that aren't defined as part of the class.
- For example, if you had code like this
- <blockquote>
- <pre>
- class Complex {
- ...
- friend Complex operator+(double, const Complex &c);
- ...
- };
- </pre>
- </blockquote>
- then SWIG doesn't know what to do with the friend function--in fact,
- it simply ignores it and issues a warning. You can still wrap the operator,
- but you may have to encapsulate it in a special function. For example:
- <blockquote>
- <pre>
- %rename(Complex_add_dc) operator+(double, const Complex &);
- ...
- Complex operator+(double, const Complex &c);
- </pre>
- </blockquote>
- There are ways to make this operator appear as part of the class using the <tt>%extend</tt> directive.
- Keep reading.
- <a name="n26"></a><H3>21.3.12 C++ namespaces</H3>
- SWIG is aware of C++ namespaces, but namespace names do not appear in
- the module nor do namespaces result in a module that is broken up into
- submodules or packages. For example, if you have a file like this,
- <blockquote>
- <pre>
- %module example
- namespace foo {
- int fact(int n);
- struct Vector {
- double x,y,z;
- };
- };
- </pre>
- </blockquote>
- it works in Tcl as follows:
- <blockquote>
- <pre>
- % load ./example.so
- % fact 3
- 6
- % Vector v
- % v configure -x 3.4
- </pre>
- </blockquote>
- If your program has more than one namespace, name conflicts (if any) can be resolved using <tt>%rename</tt>
- For example:
- <blockquote>
- <pre>
- %rename(Bar_spam) Bar::spam;
- namespace Foo {
- int spam();
- }
- namespace Bar {
- int spam();
- }
- </pre>
- </blockquote>
- If you have more than one namespace and your want to keep their
- symbols separate, consider wrapping them as separate SWIG modules.
- For example, make the module name the same as the namespace and create
- extension modules for each namespace separately. If your program
- utilizes thousands of small deeply nested namespaces each with
- identical symbol names, well, then you get what you deserve.
- <a name="n27"></a><H3>21.3.13 C++ templates</H3>
- C++ templates don't present a huge problem for SWIG. However, in order
- to create wrappers, you have to tell SWIG to create wrappers for a particular
- template instantiation. To do this, you use the <tt>%template</tt> directive.
- For example:
- <blockquote>
- <pre>
- %module example
- %{
- #include "pair.h"
- %}
- template<class T1, class T2>
- struct pair {
- typedef T1 first_type;
- typedef T2 second_type;
- T1 first;
- T2 second;
- pair();
- pair(const T1&, const T2&);
- ~pair();
- };
- %template(pairii) pair<int,int>;
- </pre>
- </blockquote>
- In Tcl:
- <blockquote>
- <pre>
- % pairii p 3 4
- % p cget -first
- 3
- % p cget -second
- 4
- </pre>
- </blockquote>
- Obviously, there is more to template wrapping than shown in this example.
- More details can be found in the <a href="SWIGPlus.html">SWIG and C++</a> chapter. Some more complicated
- examples will appear later.
- <a name="n28"></a><H3>21.3.14 C++ Smart Pointers</H3>
- In certain C++ programs, it is common to use classes that have been wrapped by
- so-called "smart pointers." Generally, this involves the use of a template class
- that implements <tt>operator->()</tt> like this:
- <blockquote>
- <pre>
- template<class T> class SmartPtr {
- ...
- T *operator->();
- ...
- }
- </pre>
- </blockquote>
- Then, if you have a class like this,
- <blockquote>
- <pre>
- class Foo {
- public:
- int x;
- int bar();
- };
- </pre>
- </blockquote>
- A smart pointer would be used in C++ as follows:
- <blockquote>
- <pre>
- SmartPtr<Foo> p = CreateFoo(); // Created somehow (not shown)
- ...
- p->x = 3; // Foo::x
- int y = p->bar(); // Foo::bar
- </pre>
- </blockquote>
- To wrap this in Tcl, simply tell SWIG about the <tt>SmartPtr</tt> class and the low-level
- <tt>Foo</tt> object. Make sure you instantiate <tt>SmartPtr</tt> using <tt>%template</tt> if necessary.
- For example:
- <blockquote>
- <pre>
- %module example
- ...
- %template(SmartPtrFoo) SmartPtr<Foo>;
- ...
- </pre>
- </blockquote>
- Now, in Tcl, everything should just "work":
- <blockquote>
- <pre>
- % set p [CreateFoo] # Create a smart-pointer somehow
- % $p configure -x 3 # Foo::x
- % $p bar # Foo::bar
- </pre>
- </blockquote>
- If you ever need to access the underlying pointer returned by <tt>operator->()</tt> itself,
- simply use the <tt>__deref__()</tt> method. For example:
- <blockquote>
- <pre>
- % set f [$p __deref__] # Returns underlying Foo *
- </pre>
- </blockquote>
- <a name="n29"></a><H2>21.4 Further details on the Tcl class interface</H2>
- In the previous section, a high-level view of Tcl wrapping was
- presented. A key component of this wrapping is that structures and
- classes are wrapped by Tcl class-like objects. This provides a very
- natural Tcl interface and allows SWIG to support a number of
- advanced features such as operator overloading. However, a number
- of low-level details were omitted. This section provides a brief overview
- of how the proxy classes work.
- <a name="n30"></a><H3>21.4.1 Proxy classes</H3>
- In the <a href="SWIG.html">"SWIG basics"</a> and <a href="SWIGPlus.html">"SWIG and C++"</a> chapters,
- details of low-level structure and class wrapping are described. To summarize those chapters, if you
- have a class like this
- <blockquote>
- <pre>
- class Foo {
- public:
- int x;
- int spam(int);
- ...
- </pre>
- </blockquote>
- then SWIG transforms it into a set of low-level procedural wrappers. For example:
- <blockquote>
- <pre>
- Foo *new_Foo() {
- return new Foo();
- }
- void delete_Foo(Foo *f) {
- delete f;
- }
- int Foo_x_get(Foo *f) {
- return f->x;
- }
- void Foo_x_set(Foo *f, int value) {
- f->x = value;
- }
- int Foo_spam(Foo *f, int arg1) {
- return f->spam(arg1);
- }
- </pre>
- </blockquote>
- These wrappers are actually found in the Tcl extension module. For example, you can certainly do this:
- <blockquote>
- <pre>
- % load ./example.so
- % set f [new_Foo]
- % Foo_x_get $f
- 0
- % Foo_spam $f 3
- 1
- %
- </pre>
- </blockquote>
- However, in addition to this, the classname <tt>Foo</tt> is used as an object constructor
- function. This allows objects to be encapsulated objects that look a lot like Tk widgets
- as shown in the last section.
- <a name="n31"></a><H3>21.4.2 Memory management</H3>
- Associated with each wrapped object, is an ownership flag <tt>thisown</tt> The value of this
- flag determines who is responsible for deleting the underlying C++ object. If set to 1,
- the Tcl interpreter destroys the C++ object when the proxy class is
- garbage collected. If set to 0 (or if the attribute is missing), then the destruction
- of the proxy class has no effect on the C++ object.
- <P>
- When an object is created by a constructor or returned by value, Tcl automatically takes
- ownership of the result. For example:
- <blockquote>
- <pre>
- class Foo {
- public:
- Foo();
- Foo bar();
- };
- </pre>
- </blockquote>
- In Tcl:
- <blockquote>
- <pre>
- % Foo f
- % f cget -thisown
- 1
- % set g [f bar]
- % $g cget -thisown
- 1
- </pre>
- </blockquote>
- On the other hand, when pointers are returned to Tcl, there is often no way to know where
- they came from. Therefore, the ownership is set to zero. For example:
- <blockquote>
- <pre>
- class Foo {
- public:
- ...
- Foo *spam();
- ...
- };
- </pre>
- </blockquote>
- <blockquote>
- <pre>
- % Foo f
- % set s [f spam]
- % $s cget -thisown
- 0
- %
- </pre>
- </blockquote>
- This behavior is especially important for classes that act as
- containers. For example, if a method returns a pointer to an object
- that is contained inside another object, you definitely don't want
- Tcl to assume ownership and destroy it!
- <p>
- Related to containers, ownership issues can arise whenever an object is assigned to a member
- or global variable. For example, consider this interface:
- <blockquote>
- <pre>
- %module example
- struct Foo {
- int value;
- Foo *next;
- };
- Foo *head = 0;
- </pre>
- </blockquote>
- When wrapped in Tcl, careful observation will reveal that ownership changes whenever an object
- is assigned to a global variable. For example:
- <blockquote>
- <pre>
- % Foo f
- % f cget -thisown
- 1
- % set head f
- % f cget -thisown
- 0
- </pre>
- </blockquote>
- In this case, C is now holding a reference to the object---you probably don't want Tcl to destroy it.
- Similarly, this occurs for members. For example:
- <blockquote>
- <pre>
- % Foo f
- % Foo g
- % f cget -thisown
- 1
- % g cget -thisown
- 1
- % f configure -next g
- % g cget -thisown
- 0
- %
- </pre>
- </blockquote>
- <p>
- For the most part, memory management issues remain hidden. However,
- there are occasionally situations where you might have to manually
- change the ownership of an object. For instance, consider code like this:
- <blockquote>
- <pre>
- class Node {
- Object *value;
- public:
- void set_value(Object *v) { value = v; }
- ...
- };
- </pre>
- </blockquote>
- Now, consider the following Tcl code:
- <blockquote>
- <pre>
- % Object v # Create an object
- % Node n # Create a node
- % n setvalue v # Set value
- % v cget -thisown
- 1
- %
- </pre>
- </blockquote>
- In this case, the object <tt>n</tt> is holding a reference to
- <tt>v</tt> internally. However, SWIG has no way to know that this
- has occurred. Therefore, Tcl still thinks that it has ownership of the
- object. Should the proxy object be destroyed, then the C++ destructor
- will be invoked and <tt>n</tt> will be holding a stale-pointer. If
- you're lucky, you will only get a segmentation fault.
- <p>
- To work around this, it is always possible to flip the ownership flag. For example,
- <blockquote>
- <pre>
- % v -disown # Give ownership to C/C++
- % v -acquire # Acquire ownership
- </pre>
- </blockquote>
- It is also possible to deal with situations like this using
- typemaps--an advanced topic discussed later.
- <a name="n32"></a><H2>21.5 Input and output parameters</H2>
- A common problem in some C programs is handling parameters passed as simple pointers. For
- example:
- <blockquote>
- <pre>
- void add(int x, int y, int *result) {
- *result = x + y;
- }
- </pre>
- </blockquote>
- or perhaps
- <blockquote>
- <pre>
- int sub(int *x, int *y) {
- return *x+*y;
- }
- </pre>
- </blockquote>
- The easiest way to handle these situations is to use the <tt>typemaps.i</tt> file. For example:
- <blockquote>
- <pre>
- %module example
- %include "typemaps.i"
- void add(int, int, int *OUTPUT);
- int sub(int *INPUT, int *INPUT);
- </pre>
- </blockquote>
- In Tcl, this allows you to pass simple values instead of pointer. For example:
- <blockquote>
- <pre>
- set a [add 3 4]
- puts $a
- 7
- </pre>
- </blockquote>
- Notice how the <tt>INPUT</tt> parameters allow integer values to be passed instead of pointers
- and how the <tt>OUTPUT</tt> parameter creates a return result.
- <p>
- If you don't want to use the names <tt>INPUT</tt> or <tt>OUTPUT</tt>, use the <tt>%apply</tt>
- directive. For example:
- <blockquote>
- <pre>
- %module example
- %include "typemaps.i"
- %apply int *OUTPUT { int *result };
- %apply int *INPUT { int *x, int *y};
- void add(int x, int y, int *result);
- int sub(int *x, int *y);
- </pre>
- </blockquote>
- <p>
- If a function mutates one of its parameters like this,
- <blockquote>
- <pre>
- void negate(int *x) {
- *x = -(*x);
- }
- </pre>
- </blockquote>
- you can use <tt>INOUT</tt> like this:
- <blockquote>
- <pre>
- %include "typemaps.i"
- ...
- void negate(int *INOUT);
- </pre>
- </blockquote>
- In Tcl, a mutated parameter shows up as a return value. For example:
- <blockquote>
- <pre>
- set a [negate 3]
- puts $a
- -3
- </pre>
- </blockquote>
- <p>
- The most common use of these special typemap rules is to handle functions that
- return more than one value. For example, sometimes a function returns a result
- as well as a special error code:
- <blockquote>
- <pre>
- /* send message, return number of bytes sent, along with success code */
- int send_message(char *text, int len, int *success);
- </pre>
- </blockquote>
- To wrap such a function, simply use the <tt>OUTPUT</tt> rule above. For example:
- <blockquote>
- <pre>
- %module example
- %include "typemaps.i"
- %apply int *OUTPUT { int *success };
- ...
- int send_message(char *text, int *success);
- </pre>
- </blockquote>
- When used in Tcl, the function will return multiple values as a list.
- <blockquote>
- <pre>
- set r [send_message "Hello World"]
- set bytes [lindex $r 0]
- set success [lindex $r 1]
- </pre>
- </blockquote>
- Another common use of multiple return values are in query functions. For example:
- <blockquote>
- <pre>
- void get_dimensions(Matrix *m, int *rows, int *columns);
- </pre>
- </blockquote>
- To wrap this, you might use the following:
- <blockquote>
- <pre>
- %module example
- %include "typemaps.i"
- %apply int *OUTPUT { int *rows, int *columns };
- ...
- void get_dimensions(Matrix *m, int *rows, *columns);
- </pre>
- </blockquote>
- Now, in Perl:
- <blockquote>
- <pre>
- set dim [get_dimensions $m]
- set r [lindex $dim 0]
- set c [lindex $dim 1]
- </pre>
- </blockquote>
- <a name="n33"></a><H2>21.6 Exception handling </H2>
- The <tt>%exception</tt> directive can be used to create a user-definable
- exception handler in charge of converting exceptions in your C/C++
- program into Tcl exceptions. The chapter on customization features
- contains more details, but suppose you extended the array example into
- a C++ class like the following :<p>
- <blockquote><pre>
- class RangeError {}; // Used for an exception
- class DoubleArray {
- private:
- int n;
- double *ptr;
- public:
- // Create a new array of fixed size
- DoubleArray(int size) {
- ptr = new double[size];
- n = size;
- }
- // Destroy an array
- ~DoubleArray() {
- delete ptr;
- }
- // Return the length of the array
- int length() {
- return n;
- }
- // Get an item from the array and perform bounds checking.
- double getitem(int i) {
- if ((i >= 0) && (i < n))
- return ptr[i];
- else
- throw RangeError();
- }
- // Set an item in the array and perform bounds checking.
- void setitem(int i, double val) {
- if ((i >= 0) && (i < n))
- ptr[i] = val;
- else {
- throw RangeError();
- }
- }
- };
- </pre></blockquote>
- <p>
- The functions associated with this class can throw a C++ range
- exception for an out-of-bounds array access. We can catch this in our
- Tcl extension by specifying the following in an interface file :<p>
- <p>
- <blockquote><pre>%exception {
- try {
- $action // Gets substituted by actual function call
- }
- catch (RangeError) {
- Tcl_SetStringObj(tcl_result,"Array index out-of-bounds");
- return TCL_ERROR;
- }
- }
- </pre></blockquote>
- <p>
- As shown, the exception handling code will be added to every wrapper function.
- Since this is somewhat inefficient. You might consider refining the
- exception handler to only apply to specific methods like this:
- <blockquote>
- <pre>
- %exception getitem {
- try {
- $action
- }
- catch (RangeError) {
- Tcl_SetStringObj(tcl_result,"Array index out-of-bounds");
- return TCL_ERROR;
- }
- }
- %exception setitem {
- try {
- $action
- }
- catch (RangeError) {
- Tcl_SetStringObj(tcl_result,"Array index out-of-bounds");
- return TCL_ERROR;
- }
- }
- </pre>
- </blockquote>
- In this case, the exception handler is only attached to methods and functions
- named <tt>getitem</tt> and <tt>setitem</tt>.
- <p>
- If you had a lot of different methods, you can avoid extra typing by using a macro.
- For example:
- <blockquote>
- <pre>
- %define RANGE_ERROR
- {
- try {
- $action
- }
- catch (RangeError) {
- Tcl_SetStringObj(tcl_result,"Array index out-of-bounds");
- return TCL_ERROR;
- }
- }
- %enddef
- %exception getitem RANGE_ERROR;
- %exception setitem RANGE_ERROR;
- </pre>
- </blockquote>
- Since SWIG's exception handling is user-definable, you are not limited to C++ exception handling.
- See the chapter on "<a href="Customization.html">Customization Features</a>" for more examples.
- <a name="n34"></a><H2>21.7 Typemaps</H2>
- This section describes how you can modify SWIG's default wrapping behavior
- for various C/C++ datatypes using the <tt>%typemap</tt> directive. This
- is an advanced topic that assumes familiarity with the Tcl C API as well
- as the material in the "<a href="Typemaps.html">Typemaps</a>" chapter.
- <p>
- Before proceeding, it should be stressed that typemaps are not a required
- part of using SWIG---the default wrapping behavior is enough in most cases.
- Typemaps are only used if you want to change some aspect of the primitive
- C-Tcl interface.
- <a name="n35"></a><H3>21.7.1 What is a typemap?</H3>
- A typemap is nothing more than a code generation rule that is attached to
- a specific C datatype. For example, to convert integers from Tcl to C,
- you might define a typemap like this:
- <p>
- <blockquote><pre>%module example
- %typemap(in) int {
- if (Tcl_GetIntFromObj(interp,$input,&$1) == TCL_ERROR) return TCL_ERROR;
- printf("Received an integer : %d\n",$1);
- }
- extern int fact(int n);
- </pre></blockquote>
- <p>
- Typemaps are always associated with some specific aspect of code generation.
- In this case, the "in" method refers to the conversion of input arguments
- to C/C++. The datatype <tt>int</tt> is the datatype to which the typemap
- will be applied. The supplied C code is used to convert values. In this
- code a number of special variable prefaced by a <tt>$</tt> are used. The
- <tt>$1</tt> variable is placeholder for a local variable of type <tt>int</tt>.
- The <tt>$input</tt> variable is the input object of type <tt>Tcl_Obj *</tt>.
- <p>
- When this example is compiled into a Tcl module, it operates as follows:
- <p>
- <blockquote><pre>% load ./example.so
- % fact 6
- Received an integer : 6
- 720
- </pre></blockquote>
- <p>
- In this example, the typemap is applied to all occurrences of the <tt>int</tt> datatype.
- You can refine this by supplying an optional parameter name. For example:
- <blockquote><pre>%module example
- %typemap(in) int n {
- if (Tcl_GetIntFromObj(interp,$input,&$1) == TCL_ERROR) return TCL_ERROR;
- printf("n = %d\n",$1);
- }
- extern int fact(int n);
- </pre></blockquote>
- In this case, the typemap code is only attached to arguments that exactly match <tt>int n</tt>.
- <p>
- The application of a typemap to specific datatypes and argument names involves
- more than simple text-matching--typemaps are fully integrated into the
- SWIG type-system. When you define a typemap for <tt>int</tt>, that typemap
- applies to <tt>int</tt> and qualified variations such as <tt>const int</tt>. In addition,
- the typemap system follows <tt>typedef</tt> declarations. For example:
- <blockquote>
- <pre>
- %typemap(in) int n {
- if (Tcl_GetIntFromObj(interp,$input,&$1) == TCL_ERROR) return TCL_ERROR;
- printf("n = %d\n",$1);
- }
- typedef int Integer;
- extern int fact(Integer n); // Above typemap is applied
- </pre>
- </blockquote>
- However, the matching of <tt>typedef</tt> only occurs in one direction. If you
- defined a typemap for <tt>Integer</tt>, it is not applied to arguments of
- type <tt>int</tt>.
- <p>
- Typemaps can also be defined for groups of consecutive arguments. For example:
- <blockquote>
- <pre>
- %typemap(in) (char *str, int len) {
- $1 = Tcl_GetStringFromObj($input,&$2);
- };
- int count(char c, char *str, int len);
- </pre>
- </blockquote>
- When a multi-argument typemap is defined, the arguments are always handled as a single
- Tcl object. This allows the function to be used like this (notice how the length
- parameter is ommitted):
- <blockquote>
- <pre>
- % count e "Hello World"
- 1
- </pre>
- </blockquote>
- <a name="n36"></a><H3>21.7.2 Tcl typemaps</H3>
- The previous section illustrated an "in" typemap for converting Tcl objects to C.
- A variety of different typemap methods are defined by the Tcl module. For example,
- to convert a C integer back into a Tcl object, you might define an "out" typemap
- like this:
- <blockquote>
- <pre>
- %typemap(out) int {
- Tcl_SetObjResult(interp,Tcl_NewIntObj($1));
- }
- </pre>
- </blockquote>
- The following list details all of the typemap methods that can be used by the Tcl module:
- <p>
- <tt>%typemap(in) </tt>
- <blockquote>
- Converts Tcl objects to input function arguments<p>
- </blockquote>
- <tt>%typemap(out)</tt>
- <blockquote>
- Converts return value of a C function to a Tcl object<p>
- </blockquote>
- <tt>%typemap(varin)</tt>
- <blockquote>
- Assigns a C global variable from a Tcl object<p>
- </blockquote>
- <tt>%typemap(varout)</tt>
- <blockquote>
- Returns a C global variable as a Tcl object<p>
- </blockquote>
- <tt>%typemap(freearg)</tt>
- <blockquote>
- Cleans up a function argument (if necessary)<p>
- </blockquote>
- <tt>%typemap(argout)</tt>
- <blockquote>
- Output argument processing<p>
- </blockquote>
- <tt>%typemap(ret)</tt>
- <blockquote>
- Cleanup of function return values<p>
- </blockquote>
- <tt>%typemap(consttab)</tt>
- <blockquote>
- Creation of Tcl constants (constant table)<p>
- </blockquote>
- <tt>%typemap(constcode)</tt>
- <blockquote>
- Creation of Tcl constants (init function)
- </blockquote>
- <tt>%typemap(memberin)</tt>
- <blockquote>
- Setting of structure/class member data<p>
- </blockquote>
- <tt>%typemap(globalin)</tt>
- <blockquote>
- Setting of C global variables<p>
- </blockquote>
- <tt>%typemap(check)</tt>
- <blockquote>
- Checks function input values.<p>
- </blockquote>
- <tt>%typemap(default)</tt>
- <blockquote>
- Set a default value for an argument (making it optional).
- </blockquote>
- <tt>%typemap(arginit)</tt>
- <blockquote>
- Initialize an argument to a value before any conversions occur.
- </blockquote>
- Examples of these methods will appear shortly.
- <a name="n37"></a><H3>21.7.3 Typemap variables</H3>
- Within typemap code, a number of special variables prefaced with a <tt>$</tt> may appear.
- A full list of variables can be found in the "<a href="Typemaps.html">Typemaps</a>" chapter.
- This is a list of the most common variables:
- <p>
- <tt>$1</tt>
- <blockquote>
- A C local variable corresponding to the actual type specified in the
- <tt>%typemap</tt> directive. For input values, this is a C local variable
- that's supposed to hold an argument value. For output values, this is
- the raw result that's supposed to be returned to Tcl.
- </blockquote>
- <p>
- <tt>$input</tt>
- <blockquote>
- A <tt>Tcl_Obj *</tt> holding a raw Tcl object with an argument or variable value.
- </blockquote>
- <p>
- <tt>$result</tt>
- <blockquote>
- A <tt>Tcl_Obj *</tt> that holds the result to be returned to Tcl.
- </blockquote>
- <p>
- <tt>$1_name</tt>
- <blockquote>
- The parameter name that was matched.
- </blockquote>
- <p>
- <tt>$1_type</tt>
- <blockquote>
- The actual C datatype matched by the typemap.
- </blockquote>
- <p>
- <tt>$1_ltype</tt>
- <blockquote>
- An assignable version of the datatype matched by the typemap (a type that can appear on the left-hand-side of
- a C assignment operation). This type is stripped of qualifiers and may be an altered version of <tt>$1_type</tt>.
- All arguments and local variables in wrapper functions are declared using this type so that their values can be
- properly assigned.
- </blockquote>
- <tt>$symname</tt>
- <blockquote>
- The Tcl name of the wrapper function being created.
- </blockquote>
- <a name="n38"></a><H3>21.7.4 Converting a Tcl list to a char ** </H3>
- A common problem in many C programs is the processing of command line
- arguments, which are usually passed in an array of NULL terminated
- strings. The following SWIG interface file allows a Tcl list to be
- used as a <tt>char **</tt> object.<p>
- <p>
- <blockquote><pre>%module argv
- // This tells SWIG to treat char ** as a special case
- %typemap(in) char ** {
- Tcl_Obj **listobjv;
- int nitems;
- int i;
- if (Tcl_ListObjGetElements(interp, $input, &nitems, &listobjv) == TCL_ERROR) {
- return TCL_ERROR;
- }
- $1 = (char **) malloc((nitems+1)*sizeof(char *));
- for (i = 0; i < nitems; i++) {
- $1[i] = Tcl_GetStringFromObj(listobjv[i],0);
- }
- $1[i] = 0;
- }
- // This gives SWIG some cleanup code that will get called after the function call
- %typemap(freearg) char ** {
- if ($1) {
- free($1);
- }
- }
- // Now a test functions
- %inline %{
- int print_args(char **argv) {
- int i = 0;
- while (argv[i]) {
- printf("argv[%d] = %s\n", i,argv[i]);
- i++;
- }
- return i;
- }
- %}
- %include tclsh.i
- </pre></blockquote>
- In Tcl:
- <p>
- <blockquote><pre>% print_args {John Guido Larry}
- argv[0] = John
- argv[1] = Guido
- argv[2] = Larry
- 3
- </pre></blockquote>
- <a name="n39"></a><H3>21.7.5 Returning values in arguments</H3>
- The "argout" typemap can be used to return a value originating from a
- function argument. For example :<p>
- <p>
- <blockquote><pre>// A typemap defining how to return an argument by appending it to the result
- %typemap(argout) double *outvalue {
- Tcl_Obj *o = Tcl_NewDoubleObj($1);
- Tcl_ListObjAppendElement(interp,$result,o);
- }
- // A typemap telling SWIG to ignore an argument for input
- // However, we still need to pass a pointer to the C function
- %typemap(in,numinputs=0) double *outvalue (double temp) {
- $1 = &temp;
- }
- // Now a function returning two values
- int mypow(double a, double b, double *outvalue) {
- if ((a < 0) || (b < 0)) return -1;
- *outvalue = pow(a,b);
- return 0;
- };
- </pre></blockquote>
- When wrapped, SWIG matches the <tt>argout</tt> typemap to the
- "<tt>double *outvalue</tt>" argument. The numinputs=0 specification tells SWIG
- to simply ignore this argument when generating wrapper code. As a
- result, a Tcl function using these typemaps will work like this :<p>
- <p>
- <blockquote><pre>% mypow 2 3 # Returns two values, a status value and the result
- 0 8
- %
- </pre></blockquote>
- <a name="n40"></a><H3>21.7.6 Useful functions</H3>
- The following tables provide some functions that may be useful in
- writing Tcl typemaps.
- <p>
- <b>Integers</b>
- <blockquote>
- <pre>
- Tcl_Obj *Tcl_NewIntObj(int Value);
- void Tcl_SetIntObj(Tcl_Obj *obj, int Value);
- int Tcl_GetIntFromObj(Tcl_Interp *, Tcl_Obj *obj, int *ip);
- </pre>
- </blockquote>
- <b>Floating Point</b>
- <blockquote>
- <pre>
- Tcl_Obj *Tcl_NewDoubleObj(double Value);
- void Tcl_SetDoubleObj(Tcl_Obj *obj, double value);
- int Tcl_GetDoubleFromObj(Tcl_Interp *, Tcl_Obj *o, double *dp);
- </pre>
- </blockquote>
- <b>Strings</b>
- <blockquote>
- <pre>
- Tcl_Obj *Tcl_NewStringObj(char *str, int len);
- void Tcl_SetStringObj(Tcl_Obj *obj, char *str, int len);
- char *Tcl_GetStringFromObj(Tcl_Obj *obj, int *len);
- void Tcl_AppendToObj(Tcl_Obj *obj, char *str, int len);
- </pre>
- </blockquote>
- <b>Lists</b>
- <blockquote>
- <pre>
- Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *objv);
- int Tcl_ListObjAppendList(Tcl_Interp *, Tcl_Obj *listPtr, Tcl_Obj *elemListPtr);
- int Tcl_ListObjAppendElement(Tcl_Interp *, Tcl_Obj *listPtr, Tcl_Obj *element);
- int Tcl_ListObjGetElements(Tcl_Interp *, Tcl_Obj *listPtr, int *objcPtr, Tcl_Obj ***objvPtr);
- int Tcl_ListObjLength(Tcl_Interp *, Tcl_Obj *listPtr, int *intPtr);
- int Tcl_ListObjIndex(Tcl_Interp *, Tcl_Obj *listPtr, int index, Tcl_Obj_Obj **objptr);
- int