/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
Possible License(s): LGPL-2.1, Cube, GPL-3.0, 0BSD, GPL-2.0
Large files files are truncated, but you can click here to view the full 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>
- </blockquo…
Large files files are truncated, but you can click here to view the full file