Section 22.6. The SWIG Integration Code Generator


22.6. The SWIG Integration Code Generator

But don't do that. As you can probably tell, manual coding of C extensions can become fairly involved (this is almost inevitable in C language work). I've introduced the basics in this chapter thus far so that you understand the underlying structure. But today, C extensions are usually better and more easily implemented with a tool that generates all the required integration glue code automatically. There are a variety of such tools for use in the Python world, including SIP, SWIG, and Boost.Python; we'll explore alternatives at the end of this chapter. Of these, the SWIG system is likely still the most widely used.

The Simplified Wrapper and Interface Generator (SWIG) is an open source system created by Dave Beazley and now developed by its community, much like Python. It uses C and C++ type declarations to generate complete C extension modules that integrate existing libraries for use in Python scripts. The generated C (and C++) extension modules are complete: they automatically handle data conversion, error protocols, reference-count management, and more.

That is, SWIG is a program that automatically generates all the glue code needed to plug C and C++ components into Python programs; simply run SWIG, compile its output, and your extension work is done. You still have to manage compilation and linking details, but the rest of the C extension task is largely performed by SWIG.

22.6.1. A Simple SWIG Example

To use SIWG, instead of writing all that C code in the prior sections, write the C function you want to use from Python without any Python integration logic at all, as though it is to be used from C alone. For instance, Example 22-5 is a recoding of Example 22-1 as a straight C function.

Example 22-5. PP3E\Integrate\Extend\HelloLib\hellolib.c

 /*********************************************************************  * A simple C library file, with a single function, "message",  * which is to be made available for use in Python programs.  * There is nothing about Python here--this C function can be  * called from a C program, as well as Python (with glue code).  *********************************************************************/ #include <string.h> #include <hellolib.h> static char result[64];                  /* this isn't exported */ char * message(char *label)                     /* this is exported */ {     strcpy(result, "Hello, ");           /* build up C string */     strcat(result, label);               /* add passed-in label */     return result;                       /* return a temporary */ } 

While you're at it, define the usual C header file to declare the function externally, as shown in Example 22-6. This is probably overkill for such a small example, but it will prove a point.

Example 22-6. PP3E\Integrate\Extend\HelloLib\hellolib.h

 /********************************************************************  * Define hellolib.c exports to the C namespace, not to Python  * programs--the latter is defined by a method registration  * table in a Python extension module's code, not by this .h;  ********************************************************************/ extern char *message(char *label); 

Now, instead of all the Python extension glue code shown in the prior sections, simply write a SWIG type declarations input file, as in Example 22-7.

Example 22-7. PP3E\Integrate\Extend\Swig\hellolib.i

 /******************************************************  * Swig module description file, for a C lib file.  * Generate by saying "swig -python hellolib.i".  ******************************************************/ %module hellowrap %{ #include <hellolib.h> %} extern char *message(char*);    /* or: %include "../HelloLib/hellolib.h"   */                                 /* or: %include hellolib.h, and use -I arg */ 

This file spells out the C function's type signature. In general, SWIG scans files containing ANSI C and C++ declarations. Its input file can take the form of an interface description file (usually with a .i suffix) or a C/C++ header or source file. Interface files like this one are the most common input form; they can contain comments in C or C++ format, type declarations just like standard header files, and SWIG directives that all start with %. For example:


%module

Sets the module's name as known to Python importers.


%{...%}

Encloses code added to generated wrapper file verbatim.


extern statements

Declare exports in normal ANSI C/C++ syntax.


%include

Makes SWIG scan another file (-I flags give search paths).

In this example, SWIG could also be made to read the hellolib.h header file of Example 22-6 directly. But one of the advantages of writing special SWIG input files like hellolib.i is that you can pick and choose which functions are wrapped and exported to Python, and you may use directives to gain more control over the generation process.

SWIG is a utility program that you run from your build scripts; it is not a programming language, so there is not much more to show here. Simply add a step to your makefile that runs SWIG and compile its output to be linked with Python. Example 22-8 shows one way to do it on Cygwin.

Example 22-8. PP3E\Integrate\Extend\Swig\makefile.hellolib-swig

 ################################################################## # Use SWIG to integrate hellolib.c for use in Python programs on # Cygwin.  The DLL must have a leading "_" in its name in current # SWIG (>1.3.13) because also makes a .py without "_" in its name. ################################################################## PYLIB = /usr/bin PYINC = /usr/include/python2.4 CLIB  = ../HelloLib # the library plus its wrapper _hellowrap.dll: hellolib_wrap.o $(CLIB)/hellolib.o         gcc -shared hellolib_wrap.o $(CLIB)/hellolib.o \                        -L$(PYLIB) -lpython2.4 -o $@ # generated wrapper module code hellolib_wrap.o: hellolib_wrap.c $(CLIB)/hellolib.h         gcc hellolib_wrap.c -g -I$(CLIB) -I$(PYINC) -c -o $@ hellolib_wrap.c: hellolib.i         swig -python -I$(CLIB) hellolib.i # C library code (in another directory) $(CLIB)/hellolib.o: $(CLIB)/hellolib.c $(CLIB)/hellolib.h         gcc $(CLIB)/hellolib.c -g -I$(CLIB) -c -o $(CLIB)/hellolib.o clean:         rm -f *.dll *.o *.pyc core force:         rm -f *.dll *.o *.pyc core hellolib_wrap.c hellowrap.py 

When run on the hellolib.i input file by this makefile, SWIG generates two files:


hellolib_wrap.c

The generated C extension module glue code file.[*]

[*] You can wade through this generated file in the book's examples distribution if you are so inclined, though they are highly prone to change over time (in fact, the .py module generated by SWIG for this example is also new since the second edition of this book). Also see the file PP3E\Integrate\Extend\HelloLib\hellolib_wrapper.c in the book's examples distribution for a handcoded equivalent; it's shorter because SWIG also generates extra support code.


hellowrap.py

A Python module that imports the generated C extension module.

The former is named for the input file, and the later per the %module directive. Really, SWIG generates two modules today: it uses a combination of Python and C code to achieve the integration. Scripts ultimately import the generated Python module file, which internally imports the generated and compiled C module.

To build the C module, the makefile runs a compile after running SWIG, and then combines the result with the original C library code:

 .../PP3E/Integrate/Extend/Swig$ make -f makefile.hellolib-swig force rm -f *.dll *.o *.pyc core hellolib_wrap.c hellowrap.py .../PP3E/Integrate/Extend/Swig$ ls Environ  Shadow  hellolib.i  makefile.hellolib-swig .../PP3E/Integrate/Extend/Swig$ make -f makefile.hellolib-swig swig -python -I../HelloLib hellolib.i gcc hellolib_wrap.c -g -I../HelloLib -I/usr/include/python2.4 -c     -o hellolib_wrap.o gcc -shared hellolib_wrap.o ../HelloLib/hellolib.o \                        -L/usr/bin -lpython2.4 -o _hellowrap.dll .../PP3E/Integrate/Extend/Swig$ ls Environ  _hellowrap.dll  hellolib_wrap.c  hellowrap.py Shadow   hellolib.i      hellolib_wrap.o  makefile.hellolib-swig 

More specifically, the makefile runs SWIG over the input file, compiles the generated C glue code file into a .o object file, and then links it with hellolib.c's compiled object file to produce _hellowrap.dll. The result is a dynamically loaded C extension module file ready to be imported by Python code. Like all modules, _hellowrap.dll must, along with hellowrap.py, be placed in a directory on your Python module search path (a period [.] will suffice if you're working in the directory where you compile).

Notice that the .dll file must be built with a leading underscore in its name; as of SWIG 1.3.14, this is required because SWIG also created the .py file of the same name without the underscore.

As usual in C development, you may have to barter with the makefile to get it to work on your system. Once you've run the makefile, though, you are finished. The generated C module is used exactly like the manually coded version shown before, except that SWIG has taken care of the complicated parts automatically:

 .../PP3E/Integrate/Extend/Swig$ python  >>> import hellowrap                       # import glue + library file >>> hellowrap.message('swig world')         # cwd always searched on imports 'Hello, swig world' >>> hellowrap._ _file_ _ 'hellowrap.py' >>> dir(hellowrap) ['_ _builtins_ _', '_ _doc_ _', '_ _file_ _', '_ _name_ _', '_hellowrap', ...] 

In other words, once you learn how to use SWIG, you can largely forget all the integration coding details introduced in this chapter. In fact, SWIG is so adept at generating Python glue code that it's usually much easier and less error prone to code C extensions for Python as purely C- or C++-based libraries first, and later add them to Python by running their header files through SWIG, as demonstrated here.

22.6.2. SWIG Details

Of course, you must have SWIG before you can run SWIG; it's not part of Python itself. Unless it is already on your system, fetch SWIG off the Web and run its installer or build it from its source code. To do the latter, you'll need a C++ compiler; see SWIG's README file and web site for more details. SWIG is a command-line program and generally can be run just by saying the following:

 swig -python hellolib.i 

Along the way in this chapter, we'll meet a few more SWIG-based alternatives to the remaining examples. By way of introduction, here is a quick look at a few more SWIG highlights:


C++ "shadow" classes

We'll learn how to use SWIG to integrate C++ classes for use in your Python scripts. When given C++ class declarations, SWIG generates glue code that makes C++ classes look just like Python classes in Python scripts. In fact, C++ classes are Python classes under SWIG; you get what SWIG calls a C++ shadow (or proxy) class that interfaces with a C++-coded extension module, which in turn talks to C++ classes using a function-based interface. Because the integration's outer layer is Python classes, those classes may be subclassed in Python and their instances processed with normal Python object syntax.


Variables

Besides functions and C++ classes, SWIG can also wrap C global variables and constants for use in Python: they become attributes of an object named cvar inserted in generated modules (e.g., module.cvar.name fetches the value of C's variable name from a SWIG-generated wrapper module).


structs

C structs are converted into a set of get and set accessor functions that are called to fetch and assign fields with a struct object pointer (e.g., module.Vector_fieldx_get(v) fetches C's Vector.fieldx from a Vector pointer v, like C's v->fieldx). Similar accessor functions are generated for data members and methods of C++ classes (the C++ class is roughly a struct with extra syntax), but the SWIG shadow class feature allows you to treat wrapped classes just like Python classes, instead of calling the lower-level accessor functions.


Other

For C++, besides wrapping up classes and functions for use from Python, SWIG also generates code to support overloaded operators, routing of virtual method calls from C++ back to Python, templates, and much more.

Consult the SWIG Python user manual for the full scoop on its features. SWIG's feature set and implementation are both prone to change over time (e.g., its pointers are no longer strings, and Python new-style classes are employed in dual-mode proxy classes), so we'll defer to its documentation for more internals information.

Later in this chapter, we'll see SWIG in action two more times, wrapping up C environment calls and a C++ class. Although the SWIG examples in this book are simple, you should also know that SWIG handles industrial-strength libraries just as easily. For instance, Python developers have successfully used SWIG to integrate libraries as complex as Windows extensions and commonly used graphics APIs such as OpenGL.

SWIG can also generate integration code for other scripting languages such as Tcl and Perl. In fact, one of its underlying goals is to make components independent of scripting language choicesC/C++ libraries can be plugged into whatever scripting language you prefer to use (I prefer to use Python, but I might be biased). SWIG's support for things such as classes seems strongest for Python, though, probably because Python is considered to be strong in the classes department. As a language-neutral integration tool, SWIG addresses some of the same goals as systems such as COM and CORBA (described in Chapter 23), but it provides a code generation-based alternative rather than an object model.

You can find SWIG by a web search or by visiting its current home page on the Web at http://www.swig.org. Along with full source code, SWIG comes with outstanding documentation (including documentation specifically for Python). The documentation also describes how to build SWIG extensions with other platforms and compilers, including standard Windows without Cygwin.




Programming Python
Programming Python
ISBN: 0596009259
EAN: 2147483647
Year: 2004
Pages: 270
Authors: Mark Lutz

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net