I l@ve RuBoard |
19.4 The SWIG Integration Code GeneratorBut don't do that. I'm introducing C extension basics so you understand the underlying structure, but today, C extensions are usually better and more easily implemented with the SWIG integration code generator. SWIG -- the Simplified Wrapper and Interface Generator -- is an open source system created by Dave Beazley. 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 extension modules are complete: they automatically handle data conversion, error protocols, reference-count management, and more. That is, SWIG automatically generates all the "glue" code needed to plug C and C++ components into Python programs; simply 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 done by SWIG. 19.4.1 A Simple SWIG ExampleFor instance, instead of writing all that C code in the prior section, 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. This is illustrated in Example 19-4. Example 19-4. PP2E\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 19-5. This is probably overkill, but will prove a point. Example 19-5. PP2E\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 section, simply write a SWIG type declarations input file, as in Example 19-6. Example 19-6. PP2E\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 an .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:
In this example, SWIG could also be made to read the hellolib.h header file 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; scanning a library's entire header file wraps everything it defines. SWIG is really a utility that you run from your build scripts, 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 19-7 shows one way to do it on Linux. Example 19-7. PP2E\Integrate\Extend\Swig\makefile.hellolib-swig############################################################### # Use SWIG to integrate hellolib.c for use in Python programs. ############################################################### # unless you've run make install SWIG = ./myswig PY = $(MYPY) LIB = ../HelloLib # the library plus its wrapper hellowrap.so: hellolib_wrap.o $(LIB)/hellolib.o ld -shared hellolib_wrap.o $(LIB)/hellolib.o -o hellowrap.so # generated wrapper module code hellolib_wrap.o: hellolib_wrap.c $(LIB)/hellolib.h gcc hellolib_wrap.c -c -g -I$(LIB) -I$(PY)/Include -I$(PY) hellolib_wrap.c: hellolib.i $(SWIG) -python -I$(LIB) hellolib.i # C library code (in another directory) $(LIB)/hellolib.o: $(LIB)/hellolib.c $(LIB)/hellolib.h gcc $(LIB)/hellolib.c -c -g -I$(LIB) -o $(LIB)/hellolib.o clean: rm -f *.o *.so core force: rm -f *.o *.so core hellolib_wrap.c hellolib_wrap.doc When run on the hellolob.i input file by this makefile, SWIG generates two files:
This makefile simply runs SWIG, compiles the generated C glue code file into an .o object file, and then combines it with hellolib.c 's compiled object file to produce hellowrap.so. The latter is the dynamically loaded C extension module file, and the one to place in a directory on your Python module search path (or "." if you're working in the directory where you compile). Assuming you've got SWIG set to go, run the makefile to generate and compile wrappers for the C function. Here is the build process running on Linux: [mark@toy ~/.../PP2E/Integrate/Extend/Swig]$ make -f makefile.hellolib-swig ./myswig -python -I../HelloLib hellolib.i Generating wrappers for Python gcc hellolib_wrap.c -c -g -I../HelloLib ...more text deleted here... ld -shared hellolib_wrap.o ../HelloLib/hellolib.o -o hellowrap.so And once you've run this makefile, 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: [mark@toy ~/.../PP2E/Integrate/Extend/Swig]$ python >>> import hellowrap # import the glue+library file >>> hellowrap.__file__ # cwd always searched on imports './hellowrap.so' >>> hellowrap.message('swig world') 'Hello, swig world' 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. 19.4.2 SWIG DetailsOf 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 (or find it at http://examples.oreilly.com/python2) and build it from its source code. You'll need a C++ compiler (e.g., g++), but the install is very simple; see SWIG's README file for more details. SWIG is a command-line program, and generally can be run just by saying this: swig -python hellolib.i In my build environment, things are a bit more complex because I have a custom SWIG build. I run SWIG from this csh script called myswig: #!/bin/csh # run custom swig install source $PP2EHOME/Integrate/Extend/Swig/setup-swig.csh swig $* This file in turn sets up pointers to the SWIG install directory by loading the following csh file, called setup-swig.csh : # source me in csh to run SWIG with an unofficial install setenv SWIG_LIB /home/mark/PP2ndEd/dev/examples/SWIG/SWIG1.1p5/swig_lib alias swig "/home/mark/PP2ndEd/dev/examples/SWIG/SWIG1.1p5/swig" But you won't need either of these files if you run a make install command in the SWIG source directory to copy it to standard places. Along the way in this chapter, I'll show you a few more SWIG-based alternatives to the remaining examples. You should consult the SWIG Python user manual for the full scoop, but here is a quick look at a few more SWIG highlights:
Although the SWIG examples in this book are simple, you should know that SWIG handles industrial-strength libraries just as easily. For instance, Python developers have successfully used SWIG to integrated libraries as complex as Windows extensions and commonly used graphics APIs. 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 choices -- C/C++ libraries can be plugged in to whatever scripting language you prefer to use (I prefer to use Python, but I might be biased). SWIG's support for things like 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 like COM and CORBA (described in Chapter 20), but provides a code-generation-based alternative instead of an object model. You can find SWIG on this book's CD (see http://examples.oreilly.com/python2) or at its home page on the Web, http://www.swig.org. Along with full source code, SWIG comes with outstanding documentation (including a manual specifically for Python), so I won't cover all of its features in this book. The documentation also describes how to build SWIG extensions on Windows. A SWIG book is reportedly in the works as I write this, so be sure to check the books list at http://www.python.org for additional resources. |
I l@ve RuBoard |