/tags/ttn-post-libtool-1-4-3-upgrade/SWIG/Doc/Manual/Advanced.html
HTML | 350 lines | 293 code | 53 blank | 4 comment | 0 complexity | b02f2caa0c57eb30a07009175faca205 MD5 | raw file
Possible License(s): LGPL-2.1, Cube, GPL-3.0, 0BSD, GPL-2.0
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <!-- Published by Quadralay WebWorks HTML Lite 1.5.1 -->
- <!-- And munged by Dave's special Python script -->
- <html>
- <head>
- <title>Advanced Topics</title>
- </head>
- <body bgcolor="#ffffff">
- <a name="n1"></a><H1>13 Advanced Topics</H1>
- <!-- INDEX -->
- <ul>
- <li><a href="#n2">Creating multi-module packages</a>
- <ul>
- <li><a href="#n3">Runtime support (and potential problems)</a>
- <li><a href="#n4">Why doesn't C++ inheritance work between modules?</a>
- <li><a href="#n5">The SWIG runtime library</a>
- <li><a href="#n6">A few dynamic loading gotchas</a>
- </ul>
- <li><a href="#n7">Dynamic Loading of C++ modules</a>
- <li><a href="#n8">Inside the SWIG type-checker</a>
- <ul>
- <li><a href="#n9">Type equivalence</a>
- <li><a href="#n10">Type casting</a>
- <li><a href="#n11">Why a name based approach?</a>
- <li><a href="#n12">Performance of the type-checker</a>
- </ul>
- </ul>
- <!-- INDEX -->
- <b>Caution: This chapter is under repair!</b>
- <a name="n2"></a><H2>13.1 Creating multi-module packages</H2>
- SWIG can be used to create packages consisting of many different modules. However, there are some technical aspects of doing this and techniques for managing the problem.<p>
- <a name="n3"></a><H3>13.1.1 Runtime support (and potential problems)</H3>
- All SWIG generated modules rely upon a small collection of functions that are used during run-time. These functions are primarily used for pointer type-checking, exception handling, and so on. When you run SWIG, these functions are included in the wrapper file (and declared as static). If you create a system consisting of many modules, each one will have an identical copy of these runtime libraries :<p>
- <center><img src="ch11.1.png"></center><p>
- <p>
- This duplication of runtime libraries is usually harmless since there are no namespace conflicts and memory overhead is minimal. However, there is serious problem related to the fact that modules do not share type-information. This is particularly a problem when working with C++ (as described next).<p>
- <a name="n4"></a><H3>13.1.2 Why doesn't C++ inheritance work between modules?</H3>
- Consider for a moment the following two interface files :<p>
- <p>
- <blockquote><pre>// File : a.i
- %module a
- // Here is a base class
- class a {
- public:
- a();
- ~a();
- void foo(double);
- };
- // File : b.i
- %module b
- // Here is a derived class
- %import a.i // Gets definition of base class
- class b : public a {
- public:
- bar();
- };
- </pre></blockquote>
- When compiled into two separate modules, the code does not work properly. In fact, you get a type error such as the following:<p>
- <p>
- <blockquote><pre>
- [beazley@guinness shadow]$ <b>python</b>
- Python 1.4 (Jan 16 1997) [GCC 2.7.2]
- Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
- >>> <b>from a import *</b>
- >>> <b>from b import *</b>
- >>> <b># Create a new "b"</b>
- >>> <b>b = new_b()</b>
- >>> <b># Call a function in the base class</b>
- ...
- >>> <b>a_foo(b,3)</b>
- Traceback (innermost last):
- File "<stdin>", line 1, in ?
- TypeError: Type error in argument 1 of a_foo. Expected _a_p.
- >>>
- </pre></blockquote>
- <p>
- However, from our class definitions we know that "b" is an "a" by inheritance and there should be no type-error. This problem is directly due to the lack of type-sharing between modules. If we look closely at the module modules created here, they look like this :<p>
- <center><img src="ch11.2.png"></center><p>
- <p>
- The type information listed shows the acceptable values for various C datatypes. In the "a" module, we see that "a" can only accept instances of itself. In the "b" module, we see that "a" can accept both "a" and "b" instances--which is correct given that a "b" is an "a" by inheritance.<p>
- <p>
- Unfortunately, this problem is inherent in the method by which SWIG makes modules. When we made the "a" module, we had no idea what derived classes might be used at a later time. However, it's impossible to produce the proper type information until after we know all of the derived classes. A nice problem to be sure, but one that can be fixed by making all modules share a single copy of the SWIG run-time library.<p>
- <a name="n5"></a><H3>13.1.3 The SWIG runtime library</H3>
- To reduce overhead and to fix type-handling problems, it is possible to share the SWIG run-time functions between multiple modules. This requires the use of the SWIG runtime library which is optionally built during SWIG installation. To use the runtime libraries, follow these steps:<p>
- <p>
- 1. Build the SWIG run-time libraries. The <tt>SWIG/Runtime</tt> directory contains a makefile for doing this. If successfully built, you will end up with 8 files that are usually installed in <tt>/usr/local/lib</tt>.<p>
- <p>
- <blockquote><pre>
- libswigpl.a # Perl library (static)
- libswigpl.so # Perl library (shared)
- libswigpy.a # Python library (static)
- libswigpy.so # Python library (shared)
- libswigtcl8.a # Tcl 8.x library (static)
- libswigtcl8.so # Tcl 8.x library (shared)
- libswigrb.a # Ruby library (static)
- libswigrb.so # Ruby library (shared)
- </pre></blockquote>
- <p>
- Note that certain libraries may be missing due to missing packages or unsupported features (like dynamic loading) on your machine.<p>
- <p>
- 2. Compile all SWIG modules using the <tt>-c</tt> option. For example :<p>
- <p>
- <blockquote><pre>
- % <b>swig -c -python a.i</b>
- % <b>swig -c -python b.i</b>
- </pre></blockquote>
- The <tt>-c</tt> option tells SWIG to omit runtime support. It's now up to you to provide it separately--which we will do using our libraries.<p>
- <p>
- 3. Build SWIG modules by linking against the appropriate runtime libraries.<p>
- <p>
- <blockquote><pre>
- % <b>swig -c -python a.i</b>
- % <b>swig -c -python b.i</b>
- % <b>gcc -c a_wrap.c b_wrap.c -I/usr/local/include</b>
- % <b>ld -shared a_wrap.o b_wrap.o -lswigpy -o a.so</b>
- </pre></blockquote>
- or if building a new executable (static linking)<p>
- <p>
- <blockquote><pre>
- % <b>swig -c -tcl -ltclsh.i a.i</b>
- % <b>gcc a_wrap.c -I/usr/local/include -L/usr/local/lib -ltcl -lswigtcl -lm -o mytclsh</b>
- </pre></blockquote>
- <p>
- When completed you should now end up with a collection of modules like this:<p>
- <center><img src="ch11.3.png"></center><p>
- <p>
- <p>
- In this configuration, the runtime library manages all datatypes and other information between modules. This management process is dynamic in nature--when new modules are loaded, they contribute information to the run-time system. In the C++ world, one could incrementally load classes as needed. As this process occurs, type information is updated and base-classes learn about derived classes as needed.<p>
- <a name="n6"></a><H3>13.1.4 A few dynamic loading gotchas</H3>
- When working with dynamic loading, it is critical to check that only one copy of the run-time library is being loaded into the system. When working with <tt>.a</tt> library files, problems can sometimes occur so there are a few approaches to the problem.<p>
- <p>
- 1. Rebuild the scripting language executable with the SWIG runtime library attached to it. This is actually, fairly easy to do using SWIG. For example :<p>
- <p>
- <blockquote><pre>%module mytclsh
- %{
- static void *__embedfunc(void *a) { return a};
- %}
- void *__embedfunc(void *);
- %include tclsh.i
- </pre></blockquote>
- <p>
- Now, run SWIG and compile as follows:<p>
- <p>
- <blockquote><pre>
- % <b>swig -c -tcl mytclsh.i</b>
- % <b>gcc mytclsh_wrap.c -I/usr/local/include -L/usr/local/lib -ltcl -lswigtcl -ldl -lm \
- -o tclsh</b>
- </pre></blockquote>
- This produces a new executable "<tt>tclsh</tt>" that contains a copy of the SWIG runtime library. The weird <tt>__embedfunc()</tt> function is needed to force the functions in the runtime library to be included in the final executable.<p>
- <p>
- To make new dynamically loadable SWIG modules, simply compile as follows :<p>
- <p>
- <blockquote><pre>
- % <b>swig -c -tcl example.i</b>
- % <b>gcc -c example_wrap.c -I/usr/local/include</b>
- % <b>ld -shared example_wrap.o -o example.so</b>
- </pre></blockquote>
- Linking against the <tt>swigtcl</tt> library is no longer necessary as all of the functions are now included in the <tt>tclsh</tt> executable and will be resolved when your module is loaded.<p>
- <p>
- 2. Using shared library versions of the runtime library<p>
- <p>
- If supported on your machine, the runtime libraries will be built as shared libraries (indicated by a <tt>.so</tt>, <tt>.sl</tt>, or .<tt>dll</tt> suffix). To compile using the runtime libraries, you link process should look something like this:<p>
- <blockquote><pre>
- % <b>ld -shared swigtcl_wrap.o -o libswigtcl.so</b> # Irix
- % <b>gcc -shared swigtcl_wrap.o -o libswigtcl.so</b> # Linux
- % <b>ld -G swigtcl_wrap.o -o libswigtcl.so</b> # Solaris
- </pre></blockquote>
- In order for the <tt>libswigtcl.so</tt> library to work, it needs to be placed in a location where the dynamic loader can find it. Typically this is a system library directory (ie. <tt>/usr/local/lib</tt> or <tt>/usr/lib</tt>).<p>
- <p>
- When running with the shared libary version, you may get error messages such as the following:<p>
- <p>
- <blockquote><pre>Unable to locate libswigtcl.so</pre></blockquote>
- This indicates that the loader was unable to find the shared libary at run-time. To find shared libaries, the loader looks through a collection of predetermined paths. If the <tt>libswigtcl.so</tt> file is not in any of these directories, it results in an error. On most machines, you can change the loader search path by changing the Unix environment variable <tt>LD_LIBRARY_PATH</tt>, e.g.<p>
- <p>
- <blockquote><pre>% <b>setenv LD_LIBRARY_PATH .:/home/beazley/packages/lib</b></pre></blockquote>
- A somewhat better approach is to link your module with the proper path encoded. This is typically done using the `<tt>-rpath</tt>' or `<tt>-R</tt>' option to your linker (see the man page). For example:<p>
- <p>
- <blockquote><pre>% <b>ld -shared example_wrap.o example.o -rpath /home/beazley/packages/lib \
- -L/home/beazley/packages/lib -lswigtcl.so -o example.so</b>
- </pre></blockquote>
- The <tt>-rpath</tt> option encodes the location of shared libraries into your modules and gets around having to set the <tt>LD_LIBRARY_PATH</tt> variable.<p>
- <p>
- If all else fails, pull up the man pages for your linker and start playing around.<p>
- <a name="n7"></a><H2>13.2 Dynamic Loading of C++ modules</H2>
- Dynamic loading of C++ modules presents a special problem for many systems. This is because C++ modules often need additional supporting code for proper initialization and operation. Static constructors are also a bit of a problem.<p>
- <p>
- While the process of building C++ modules is, by no means, and exact science, here are a few rules of thumb to follow :<p>
- <p>
- <ul>
- <li>Don't use static constructors if at all possible (not always avoidable).
- <li>Try linking your module with the C++ compiler using a command like `c++ -shared'. This often solves alot of problems.
- <li>Sometimes it is necessary to link against special libraries. For example, modules compiled with g++ often need to be linked against the <tt>libgcc.a</tt>, <tt>libg++.a</tt>, and <tt>libstdc++.a</tt> libraries.
- <li>Read the compiler and linker man pages over and over until you have them memorized (this may not help in some cases however).
- <li>Search articles on Usenet, particularly in <tt>comp.lang.tcl</tt>, <tt>comp.lang.perl</tt>, <tt>comp.lang.python</tt> and <tt>comp.lang.ruby</tt>. Building C++ modules is a common problem.
- </ul>
- <p>
- The SWIG distribution contains some additional documentation about C++ modules in the Doc directory as well.<p>
- <a name="n8"></a><H2>13.3 Inside the SWIG type-checker</H2>
- The SWIG runtime type-checker plays a critical role in the correct operation of SWIG modules. It not only checks the validity of pointer types, but also manages C++ inheritance, and performs proper type-casting of pointers when necessary. This section provides some insight into what it does, how it works, and why it is the way it is.<p>
- <a name="n9"></a><H3>13.3.1 Type equivalence</H3>
- SWIG uses a name-based approach to managing pointer datatypes. For example, if you are using a pointer like "<tt>double *</tt>", the type-checker will look for a particular string representation of that datatype such as "<tt>_double_p</tt>". If no match is found, a type-error is reported.<p>
- <p>
- However, the matching process is complicated by the fact that datatypes may use a variety of different names. For example, the following declarations<p>
- <p>
- <blockquote><pre>typedef double Real;
- typedef Real * RealPtr;
- typedef double Float;
- </pre></blockquote>
- define two sets of equivalent types :<p>
- <p>
- <blockquote><pre>{double, Real, Float}
- {RealPtr, Real *}