gd::fclose($out);
# Clean up
gd::gdImageDestroy($im);
3.2 Input Files
In the gd example, SWIG was given a special interface
file containing a list of the C declarations to be included
in the Perl module. When working with a large C library,
interface files can often be constructed by copying an
existing header file and modifying it slightly. However,
in some cases, it is possible to include a header file as
follows:
%module
%{
#include "gd.h"
%}
// Grab the declarations from gd.h
%include "gd.h"
// Some file I/O functions
FILE *fopen(char *name, char *mode);
void fclose(FILE *);
The %include directive tells SWIG to include a file
and parse all of the declarations it contains. In this case,
the interface would now wrap every function in the gd
library as opposed to the half-dozen functions listed in
the first example.
SWIG also includes a C preprocessor that can be used
for macro expansion and conditional compilation. If a
new application is being written with SWIG in mind,
header files can be written as follows:
#ifdef SWIG
%module gd
%{
#include "gd.h"
%}
#endif
/* C declarations */
...
With this approach, the file can serve as both a valid C
header file and as an interface specification. The SWIG
symbol is only defined when SWIG is parsing so special
directives can be easily hidden from the C compiler as
needed.
Finally, for the truly lazy, SWIG can sometimes be
run directly on C header and source files. For example,
% swig -perl5 -module gd gd.h
% swig -perl5 -module example example.c
Most users, however, use a mix of dedicated interface
files and header files.
3.3 Data Model
The most critical part of interfacing Perl to C pro-
grams is the management of data. Since Perl and C uti-
lize a different set of internal datatypes, wrapper gener-
ators are responsible for producing code that marshals
data and objects between languages. For fundamental
types such as int and double the conversion pro-
cess is straightforward. However, pointers, arrays, struc-
tures, and objects complicate the process. Furthermore,
since most C/C++ programs make extensive use of these
datatypes, it is important for wrapper generators to sup-
port as many of these datatypes as possible.
3.3.1 Pointers
SWIG maps C pointers and C++ references into Perl
blessed references. These references contain both the
value of the pointer itself, plus a type-signature. In the
gd example, pointers were used to manage both images
and files. If one were to print out the value a pointer, it
would appear as follows:
gdImagePtr=SCALAR(0x80b9914)
SWIG uses the type-signature to perform run-time
checking of all pointer values. These checks emulate
many of the checks that would have been performed by
a C compiler. When an invalid Perl datatype or pointer
of invalid type is used, a run-time error is generated. For
example,
% perl
use gd;
$f = gd::fopen("test.gif","w");
gd::gdImageLine($f,20,50,180,140,0);
Type error in argument 1 of gdImageLine.
Expected gdImagePtr. at - line 3.
Type-checking is based on the name of each datatype.
However, the type-checker also keeps track of C++ in-
heritance hierarchies and typedef definitions. Thus,
an acceptable pointer type includes any alternate names
that might have been created with a typedef declara-
tion as well as any derived datatypes in C++.
When pointers are manipulated in Perl, they are
opaque values. That is, pointers can be created and
passed around to other C functions, but they can not
be dereferenced directly. Thus, in the example, it is
difficult (or impractical) for a user to directly manip-
ulate the internal representation of an image from the
Perl interpreter. Furthermore, SWIG, by default, han-
dles all pointers in a uniform manner. Thus, datatypes
such as FILE * are represented as blessed references
even though such types may appear remarkably similar
to other Perl datatypes such as file handles.