This will produce 3 files. The first file, example_wrap.c contains all of the C code needed to build a Perl5 module. The second file, example.pm contains supporting Perl code needed to properly load the module into Perl. The third file will be a documentation file (the exact filename depends on the documentation style). To finish building a module, you will need to compile the file example_wrap.c and link it with the rest of your program (and possibly Perl itself). There are several methods for doing this.swig -perl5 example.i
#include "Extern.h" #include "perl.h" #include "XSUB.h"
These are usually located in a directory like this
/usr/local/lib/perl5/arch-osname/5.003/CORE
The SWIG configuration script will try to find this directory, but it's not entirely foolproof. You may have to dig around yourself.
% gcc example.c % gcc example_wrap.c -I/usr/local/lib/perl5/arch-osname/5.003/CORE -Dbool=char -c % ld -shared example.o example_wrap.o -o example.so # Irix
The name of the shared object file must match the module name used in the SWIG interface file. If you used `%module example', then the target should be named `example.so', `example.sl', or the appropriate name on your system (check the man pages for the linker).
Unfortunately, the process of building dynamic modules varies on every single machine. Both the C compiler and linker may need special command line options. SWIG tries to guess how to build dynamic modules on your machine in order to run its example programs. Again, the configure script isn't foolproof .
Now, to build a module, simply follow these steps :# File : Makefile.PL use ExtUtils::MakeMaker; WriteMakefile( `NAME' => `example', # Name of package `LIBS' => [`-lm'], # Name of custom libraries `OBJECT' => `example.o example_wrap.o' # Object files );
% perl Makefile.PL % make % make install
This is the preferred approach if you building general purpose Perl5 modules for distribution. More information about MakeMaker can be found in "Programming Perl, 2nd ed." by Larry Wall, Tom Christiansen, and Randal Schwartz.
% swig -perl5 -static example.i
By default SWIG includes code for dynamic loading, but the -static option takes it out.
Next, you will need to supply a main() function that initializes your extension and starts the Perl interpreter. While, this may sound daunting, SWIG can do this for you automatically as follows :
%module example extern double My_variable; extern int fact(int); // Include code for rebuilding Perl %include perlmain.i
The same thing can be accomplished by running SWIG as follows :
The permain.i file inserts Perl's main() function into the wrapper code and automatically initializes the SWIG generated module. If you just want to make a quick a dirty module, this may be the easiest way. By default, the perlmain.i code does not initialize any other Perl extensions. If you need to use other packages, you will need to modify it appropriately. You can do this by just copying perlmain.i out of the SWIG library, placing it in your own directory, and modifying it to suit your purposes.% swig -perl5 -static -lperlmain.i example.i
To build your new Perl executable, follow the exact same procedure as for a dynamic module, but change the link line as follows :
% ld example.o example_wrap.o -L/usr/local/lib/perl5/arch/5.003/CORE \ -lperl -lsocket -lnsl -lm -o myperl
This will produce a new version of Perl called myperl. It should be functionality identical to Perl with your C/C++ extension added to it. Depending on your machine, you may need to link with additional libraries such as -lsocket, -lnsl, -ldl, etc...
Compiling dynamic modules for C++ is also a tricky business. When compiling C++ modules, you may need to link using the C++ compiler such as :
unix > c++ -shared example_wrap.o example.o -o example.so
It may also be necessary to link against the libgcc.a, libg++.a, and libstdc++.a libraries (assuming g++). C++ may also complain about one line in the Perl header file "perl.h" and the invalid use of the "explicit" keyword. To work around this problem, put the option -Dexplicit= in your compiler flags.
If all else fails, put on your wizard cap and start looking around in the header files. Once you've figured out how to get one module to compile, you can compile just about all other modules.
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 Perl extension, simply run Perl and use the use command as normal. For example :
It appears that DLL's will work if they are placed in the current working directory. To make a generally DLL available, it should be place (along with its support files) in the Lib\Auto\[module] sub-directory of the Perl directory where [module] is the name of your module.DOS > perl use example; $a = example::fact(4); print "$a\n";
# Makefile for building an ActiveWare Perl for Win32 extension # Note : Extensions must be compiled with the C++ compiler! SRCS = example.cxx IFILE = example INTERFACE = $(IFILE).i WRAPFILE = $(IFILE)_wrap.cxx # 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 /W3 /nologo # Perl 5.004 PERL_INCLUDE = -Id:\perl5\lib\CORE PERLLIB = d:\perl5\lib\CORE\perl.lib PERLFLAGS = /DWIN32 /DMSWIN32 /DWIN32IO_IS_STDIO # ActiveWare PERL_INCLUDE = -Id:\perl -Id:\perl\inc PERL_LIB = d:\perl\Release\perl300.lib PERLFLAGS = /DWIN32 /DMSWIN32 /DPERL_OBJECT perl:: ..\..\swig -perl5 -o $(WRAPFILE) $(INTERFACE) $(CC) $(CFLAGS) $(PERLFLAGS) $(PERL_INCLUDE) $(SRCS) $(WRAPFILE) set LIB=$(TOOLS)\lib $(LINK) $(LOPT) -out:example.dll $(LIBS) $(PERLLIB) example.obj example_wrap.obj
To build the extension, run NMAKE (note that you may be to run vcvars32 before doing this to set the correct environment variables). This is a simplistic Makefile, but hopefully its enough to get you started.
% perl5 use example; # load the example module print example::fact(4),"\n" # Call a function in it 24
Usually, a module consists of a collection of code that is contained within a single file. A package, on the other hand, is the Perl equivalent of a namespace. A package is alot like a module, except that it is independent of files. Any number of files may be part of the same package--or a package may be broken up into a collection of modules if you prefer to think about it in this way.
By default, SWIG installs its functions into a package with the same name as the module. This can be changed by giving SWIG the -package option :
% swig -perl5 -package FooBar example.i
In this case, we still create a module called `example', but all of the functions in that module will be installed into the package `FooBar.' For example :
use example; # Load the module like before print FooBar::fact(4),"\n"; # Call a function in package FooBar
Perl supports object oriented programming using packages. A package can be thought of as a namespace for a class containing methods and data. The reader is well advised to consult "Programming Perl, 2nd Ed." by Wall, Christiansen, and Schwartz for most of the gory details.
Will be used in Perl like this :%module example int foo(int a); double bar (double, double b = 3.0); ...
Okay, this is pretty straightforward...enough said.use example; $a = &example::foo(2); $b = &example::bar(3.5,-1.5); $c = &example::bar(3.5); # Use default argument for 2nd parameter
is accessed as follows :%module example; ... double Spam; ...
SWIG supports global variables of all C datatypes including pointers and complex objects.use example; print $example::Spam,"\n"; $example::Spam = $example::Spam + 4 # ... etc ...
Matrix *new_Matrix(int n, int m);
SWIG will return a value as if you had done this :
$ptr = new_Matrix(int n, int m); # Save pointer return result bless $ptr, "MatrixPtr"; # Bless it as a MatrixPtr
SWIG uses the "blessing" to check the datatype of various pointers. In the event of a mismatch, an error or warning message will be generated.
To check to see if a value is the NULL pointer, use the defined() command :
To create a NULL pointer, you should pass the undef value to a function.if (defined($ptr)) { print "Not a NULL pointer."; } else { print "Is a NULL pointer."; }
The "value" of a Perl reference is not the same as the underlying C pointer that SWIG wrapper functions return. Suppose that $a and $b are two references that point to the same C object. In general, $a and $b will be different--since they are different references. Thus, it is a mistake to check the equality of $a and $b to check the equality of two C pointers. The correct method to check equality of C pointers is to dereference them as follows :
It is easy to get burned by references in more subtle ways. For example, if you are storing a hash table of objects, it may be best to use the actual C pointer value rather than the Perl reference as a key. Since each Perl reference to the same C object may be different, it would be impossible to find anything in the hash without this. As a general rule, the best way to avoid problems with references is to make sure hash tables, comparisons, and other pointer operations use the value of the reference (ie. $$a), not the reference itself.if ($$a == $$b) { print "a and b point to the same thing in C"; } else { print "a and b point to different objects."; }
This gets turned into the following collection of Perl functions :%module vector class Vector { public: double x,y,z; Vector(); ~Vector(); double magnitude(); };
To use the class, simply use these functions. As it turns out, SWIG has a mechanism for creating shadow classes that hides these functions and uses an object oriented interface instead--keep reading.vector::Vector_x_get($obj); vector::Vector_x_set($obj,$x); vector::Vector_y_get($obj); vector::Vector_y_set($obj,$y); vector::Vector_z_get($obj); vector::Vector_z_set($obj,$z); vector::new_Vector(); vector::delete_Vector($obj); vector::Vector_magnitude($obj);
class RangeError {}; // Used for an exception class DoubleArray { private: int n; double *ptr; public: // Create a new array of fixed size DoubleArray(int size) { ptr = new double[size]; n = size; } // Destroy an array ~DoubleArray() { delete ptr; } // Return the length of the array int length() { return n; } // Get an item from the array and perform bounds checking. double getitem(int i) { if ((i >= 0) && (i < n)) return ptr[i]; else throw RangeError(); } // Set an item in the array and perform bounds checking. void setitem(int i, double val) { if ((i >= 0) && (i < n)) ptr[i] = val; else { throw RangeError(); } } };
The functions associated with this class can throw a range exception for an out-of-bounds array access. We can catch this in our Perl extension by specifying the following in an interface file :
Now, when the C++ class throws a RangeError exception, our wrapper functions will catch it, turn it into a Perl exception, and allow a graceful death as opposed to just having some sort of mysterious program crash. Since SWIG's exception handling is user-definable, we are not limited to C++ exception handling. It is also possible to write a language-independent exception handler that works with other scripting languages. Please see the chapter on exception handling for more details.%except(perl5) { try { $function // Gets substituted by actual function call } catch (RangeError) { croak("Array index out-of-bounds"); } }
Typemap specifications require a language name, method name, datatype, and conversion code. For Perl5, "perl5" should be used as the language name. The "in" method refers to the input arguments of a function. The `int' datatype tells SWIG that we are remapping integers. The conversion code is used to convert from a Perl scalar value to the corresponding datatype. Within the support code, the variable $source contains the source data (a Perl object) and $target contains the destination of the conversion (a C local variable).%module example %typemap(perl5,in) int { $target = (int) SvIV($source); printf("Received an integer : %d\n", $target); } ... extern int fact(int n);
When this example is used in Perl5, it will operate as follows :
use example; $n = example::fact(6); print "$n\n"; ... Output : Received an integer : 6 720
General discussion of typemaps can be found in the main SWIG users reference.
%typemap(perl5,in) Converts Perl5 object to input function arguments.
%typemap(perl5,out) Converts function return value to a Perl5 value.
%typemap(perl5,varin) Converts a Perl5 object to a global variable.
%typemap(perl5,varout) Converts a global variable to a Perl5 object.
%typemap(perl5,freearg) Cleans up a function argument after a function call
%typemap(perl5,argout) Output argument handling
%typemap(perl5,ret) Clean up return value from a function.
%typemap(memberin) Setting of C++ member data (all languages).
%typemap(memberout) Return of C++ member data (all languages).
%typemap(perl5,check) Check value of input parameter.
$source Source value of a conversion
$target Target of conversion (where result should be stored)
$type C datatype being remapped
$mangle Mangled version of datatype (for blessing objects)
$arg Function argument (when applicable).
In this example, two typemaps are applied to the char ** datatype. However, the second typemap will only be applied to arguments named `argv'. A named typemap will always override an unnamed typemap.%module foo // This typemap will be applied to all char ** function arguments %typemap(perl5,in) char ** { ... } // This typemap is applied only to char ** arguments named `argv' %typemap(perl5,in) char **argv { ... }
Due to the name matching scheme, typemaps do not follow typedef declarations. For example :
Is is odd behavior to be sure, but you can work around the problem using the %apply directive as follows :%typemap(perl5,in) double { ... get a double ... } double foo(double); // Uses the double typemap above typedef double Real; Real bar(Real); // Does not use the typemap above (double != Real)
%typemap(perl5,in) double { ... get a double ... } double foo(double); // Uses the double typemap above typedef double Real; %apply double { Real }; // Apply the double typemap to Reals. Real bar(Real); // Uses the double typemap already defined.
Named typemaps are extremely useful for managing special cases. It is also possible to use named typemaps to process output arguments (ie. function arguments that have values returned in them).
When this module is compiled, our wrapped C functions can be used in a Perl script as follows :%module argv // This tells SWIG to treat char ** as a special case %typemap(perl5,in) char ** { AV *tempav; I32 len; int i; SV **tv; if (!SvROK($source)) croak("$source is not a reference."); if (SvTYPE(SvRV($source)) != SVt_PVAV) croak("$source is not an array."); tempav = (AV*)SvRV($source); len = av_len(tempav); $target = (char **) malloc((len+2)*sizeof(char *)); for (i = 0; i <= len; i++) { tv = av_fetch(tempav, i, 0); $target[i] = (char *) SvPV(*tv,na); } $target[i] = 0; }; // This cleans up our char ** array after the function call %typemap(perl5,freearg) char ** { free($source); } // Creates a new Perl array and places a char ** into it %typemap(perl5,out) char ** { AV *myav; SV **svs; int i = 0,len = 0; /* Figure out how many elements we have */ while ($source[len]) len++; svs = (SV **) malloc(len*sizeof(SV *)); for (i = 0; i < len ; i++) { svs[i] = sv_newmortal(); sv_setpv((SV*)svs[i],$source[i]); }; myav = av_make(len,svs); free(svs); $target = newRV((SV*)myav); sv_2mortal($target); } // Now a few test functions %inline %{ int print_args(char **argv) { int i = 0; while (argv[i]) { printf("argv[%d] = %s\n", i,argv[i]); i++; } return i; } // Returns a char ** list char **get_args() { static char *values[] = { "Dave", "Mike", "Susan", "John", "Michelle", 0}; return &values[0]; } %}
use argv; @a = ("Dave", "Mike", "John", "Mary"); # Create an array of strings argv::print_args(\@a); # Pass it to our C function $b = argv::get_args(); # Get array of strings from C print @$b,"\n"; # Print it out
Of course, there are many other possibilities. As an alternative to array references, we could pass in strings separated by some delimeter and perform a splitting operation in C.
%module return // This tells SWIG to treat an double * argument with name 'OutDouble' as // an output value. %typemap(perl5,argout) double *OutDouble { $target = sv_newmortal(); sv_setnv($target, *$source); argvi++; /* Increment return count -- important! */ } // If we don't care what the input value is, we can make the typemap ignore it. %typemap(perl5,ignore) double *OutDouble(double junk) { $target = &junk; /* junk is a local variable that has been declared */ } // Now a function to test it %{ /* Returns the first two input arguments */ int multout(double a, double b, double *out1, double *out2) { *out1 = a; *out2 = b; return 0; }; %} // If we name both parameters OutDouble both will be output int multout(double a, double b, double *OutDouble, double *OutDouble); ...
When output arguments are encountered, they are simply appended to the stack used to return results. This will show up as an array when used in Perl. For example :
@r = multout(7,13); print "multout(7,13) = @r\n";
By default, SWIG doesn't know how to the handle the name structure since it's an array, not a pointer. In this case, SWIG will make the array member readonly. However, member typemaps can be used to make this member writable from Perl as follows :#define NAMELEN 32 typedef struct { char name[NAMELEN]; ... } Person;
Whenever a char[NAMELEN] type is encountered in a structure or class, this typemap provides a safe mechanism for setting its value. An alternative implementation might choose to print an error message if the name was too long to fit into the field.%typemap(memberin) char[NAMELEN] { /* Copy at most NAMELEN characters into $target */ strncpy($target,$source,NAMELEN); }
It should be noted that the [NAMELEN] array size is attached to the typemap. A datatype involving some other kind of array would be affected. However, we can write a typemap that will work for any array dimension as follows :
When code is generated, $dim0 gets filled in with the real array dimension.%typemap(memberin) char [ANY] { strncpy($target,$source,$dim0); }
A common misinterpretation of this function is the following Perl script :void add(double a, double b, double *c) { *c = a + b; }
# Perl script $a = 3.5; $b = 7.5; $c = 0.0; # Output value add($a,$b,\$c); # Place result in c (Except that it doesn't work)
Unfortunately, this does NOT work. There are many reasons for this, but the main one is that SWIG has no idea what a double * really is. It could be an input value, an output value, or an array of 2 million elements. As a result, SWIG leaves it alone and looks exclusively for a C pointer value (which is not the same as a Perl reference--well, at least note of the type used in the above script).
However, you can use a typemap to get the desired effect. For example :
%typemap(perl5,in) double * (double dvalue) { SV* tempsv; if (!SvROK($source)) { croak("expected a reference\n"); } tempsv = SvRV($source); if ((!SvNOK(tempsv)) && (!SvIOK(tempsv))) { croak("expected a double reference\n"); } dvalue = SvNV(tempsv); $target = &dvalue; } %typemap(perl5,argout) double * { SV *tempsv; tempsv = SvRV($arg); sv_setnv(tempsv, *$source); }
Now, if you place this before our add function, we can do this :
You'll get the output value of "11.0" which is exactly what we wanted. While this is pretty cool, it should be stressed that you can easily shoot yourself in the foot with typemaps--of course SWIG is has never been too concerned about legislating morality....$a = 3.5; $b = 7.5; $c = 0.0; add($a,$b,\$c); # Now it works! print "$c\n";
Perl Integer Functions
Perl Floating Point Functionsint SvIV(SV *); void sv_setiv(SV *sv, IV value); SV *newSViv(IV value); int SvIOK(SV *);
Perl String Functionsdouble SvNV(SV *); void sv_setnv(SV *, double value); SV *newSVnv(double value); int SvNOK(SV *);
Perl Referenceschar *SvPV(SV *, int len); void sv_setpv(SV *, char *val); void sv_setpvn(SV *, char *val, int len); SV *newSVpv(char *value, int len); int SvPOK(SV *); void sv_catpv(SV *, char *); void sv_catpvn(SV *, char *, int);
void sv_setref_pv(SV *, char *, void *ptr); int sv_isobject(SV *); SV *SvRV(SV *); int sv_isa(SV *, char *0;
(rewrite)
(rewrite)
The total number of return values should not exceed the number of input values unless you explicitly extend the argument stack. This can be done using the EXTEND() macro as in :
%typemap(perl5,argout) int *OUTPUT { if (argvi >= items) { EXTEND(sp,1); /* Extend the stack by 1 object */ } $target = sv_newmortal(); sv_setiv($target,(IV) *($source)); argvi++; }
Shadow classes are new in SWIG 1.1 and still somewhat experimental. The current implementation is a combination of contributions provided by Gary Holt and David Fletcher--many thanks!
Using the low-level interface, SWIG creates Perl wrappers around classes, structs, and functions. This collection of wrappers becomes the Perl module that you will use in your Perl code, not the low-level package (the original package is hidden, but working behind the scenes).
When wrapped, SWIG creates the following set of low-level accessor functions.%module vector struct Vector { Vector(double x, double y, double z); ~Vector(); double x,y,z; };
These functions can now be used to create a Perl shadow class that looks like this :Vector *new_Vector(double x, double y, double z); void delete_Vector(Vector *v); double Vector_x_get(Vector *v); double Vector_x_set(Vector *v, double value); double Vector_y_get(Vector *v); double Vector_y_set(Vector *v, double value); double Vector_z_get(Vector *v); double Vector_z_set(Vector *v, double value);
package Vector; @ISA = qw( vector ); %OWNER = (); %BLESSEDMEMBERS = (); sub new () { my $self = shift; my @args = @_; $self = vectorc::new_Vector(@args); return undef if (!defined($self)); bless $self, "Vector"; $OWNER{$self} = 1; my %retval; tie %retval, "Vector", $self; return bless \%retval,"Vector"; } sub DESTROY { my $self = shift; if (exists $OWNER{$self}) { delete_Vector($self)); delete $OWNER{$self}; } sub FETCH { my ($self,$field) = @_; my $member_func = "vectorc::Vector_${field}_get"; my $val = &$member_func($self); if (exists $BLESSEDMEMBERS{$field}) { return undef if (!defined($val)); my %retval; tie %retval,$BLESSEDMEMBERS{$field},$val; return bless \%retval, $BLESSEDMEMBERS{$field}; } return $val; } sub STORE { my ($self,$field,$newval) = @_; my $member_func = "vectorc::Vector_${field}_set"; if (exists $BLESSEDMEMBERS{$field}) { &$member_func($self,tied(%{$newval})); } else { &$member_func($self,$newval); } }
Each structure or class is mapped into a Perl package of the same name. The C++ constructors and destructors are mapped into constructors and destructors for the package and are always named "new" and "DESTROY". The constructor always returns a tied hash table. This hash table is used to access the member variables of a structure in addition to being able to invoke member functions. The %OWNER and %BLESSEDMEMBERS hash tables are used internally and described shortly.
To use our new shadow class we can simply do the following:
# Perl code using Vector class $v = new Vector(2,3,4); $w = Vector->new(-1,-2,-3); # Assignment of a single member $v->{x} = 7.5; # Assignment of all members %$v = ( x=>3, y=>9, z=>-2); # Reading members $x = $v->{x}; # Destruction $v->DESTROY();
This function takes a Vector pointer and returns a pointer to another Vector. Such a function might be used to manage arrays or lists of vectors (in C). Now contrast this function with the constructor for a Vector object :Vector *Vector_get(Vector *v, int index) { return &v[i]; }
Both functions return a Vector, but the constructor is returning a brand-new Vector while the other function is returning a Vector that was already created (hopefully). In Perl, both vectors will be indistinguishable---clearly a problem considering that we would probably like the newly created Vector to be destroyed when we are done with it.Vector *new_Vector(double x, double y, double z) { Vector *v; v = new Vector(x,y,z); // Call C++ constructor return v; }
To manage these problems, each class contains two methods that access an internal hash table called %OWNER. This hash keeps a list of all of the objects that Perl knows that it has created. This happens in two cases: (1) when the constructor has been called, and (2) when a function implicitly creates a new object (as is done when SWIG needs to return a complex datatype by value). When the destructor is invoked, the Perl shadow class module checks the %OWNER hash to see if Perl created the object. If so, the C/C++ destructor is invoked. If not, we simply destroy the Perl object and leave the underlying C object alone (under the assumption that someone else must have created it).
This scheme works remarkably well in practice but it isn't foolproof. In fact, it will fail if you create a new C object in Perl, pass it on to a C function that remembers the object, and then destroy the corresponding Perl object (this situation turns out to come up frequently when constructing objects like linked lists and trees). When C takes possession of an object, you can change Perl's owership by simply deleting the object from the %OWNER hash. This is done using the DISOWN method.
# Perl code to change ownership of an object $v = new Vector(x,y,z); $v->DISOWN();
To acquire ownership of an object, the ACQUIRE method can be used.
As always, a little care is in order. SWIG does not provide reference counting, garbage collection, or advanced features one might find in sophisticated languages.# Given Perl ownership of a file $u = Vector_get($v); $u->ACQUIRE();
In this case, the members of the structure are complex objects that have already been encapsulated in a Perl shadow class. To handle these correctly, we use the %BLESSEDMEMBERS hash which would look like this (along with some supporting code) :struct Particle { Vector r; Vector v; Vector f; int type; }
When fetching members from the structure, %BLESSEDMEMBERS is checked. If the requested field is present, we create a tied-hash table and return it. If not, we just return the corresponding member unmodified.package Particle; ... %BLESSEDMEMBERS = ( r => `Vector', v => `Vector', f => `Vector', );
This implementation allows us to operate on nested structures as follows :
# Perl access of nested structure $p = new Particle(); $p->{f}->{x} = 0.0; %${$p->{v}} = ( x=>0, y=>0, z=>0);
Since Vector is an object already wrapped into a shadow class, we need to modify this function to accept arguments that are given in the form of tied hash tables. This is done by creating a Perl function like this :double dot_product(Vector *v1, Vector *v2);
sub dot_product { my @args = @_; $args[0] = tied(%{$args[0]}); # Get the real pointer values $args[1] = tied(%{$args[1]}); my $result = vectorc::dot_product(@args); return $result; }
This function replaces the original function, but operates in an identical manner.
The resulting, Perl wrapper class will create the following code :// shapes.i // SWIG interface file for shapes class %module shapes %{ #include "shapes.h" %} class Shape { public: virtual double area() = 0; virtual double perimeter() = 0; void set_location(double x, double y); }; class Circle : public Shape { public: Circle(double radius); ~Circle(); double area(); double perimeter(); }; class Square : public Shape { public: Square(double size); ~Square(); double area(); double perimeter(); }
The @ISA array determines where to look for methods of a particular class. In this case, both the Circle and Square classes inherit functions from Shape so we'll want to look in the Shape base class for them. All classes also inherit from the top-level module shapes. This is because certain common operations needed to implement shadow classes are implemented only once and reused in the wrapper code for various classes and structures.Package Shape; @ISA = (shapes); ... Package Circle; @ISA = (shapes Shape); ... Package Square; @ISA = (shapes Shape);
Since SWIG shadow classes are implemented in Perl, it is easy to subclass from any SWIG generated class. To do this, simply put the name of a SWIG class in the @ISA array for your new class. However, be forewarned that this is not a trivial problem. In particular, inheritance of data members is extremely tricky (and I'm not even sure if it really works).
The %ITERATORS hash table maintains the state of each object for which the keys or each function has been applied to. The state is maintained by keeping a list of the member names.sub FIRSTKEY { my $self = shift; @ITERATORS{$self} = [`x','y','z', ]; my $first = shift @{$ITERATORS{$self}}; return $first; } sub NEXTKEY { my $self = shift; $nelem = scalar @{$ITERATORS{$self}}; if ($nelem > 0) { my $member = shift @{$ITERATORS{$self}}; return $member; } else { @ITERATORS{$self} = [`x','y','z', ]; return (); } }
While iterators may be of limited use when working with C/C++ code, it turns out they can be used to perform an element by element copy of an object.
However, this is not a deep copy so they probably works better with C than with C++.$v = new Vector(1,2,3); $w = new Vector(0,0,0); %$w = %$v; # Copy contents of v into w