| Table of contents of this page | |
|
|
Wrap a C++ class
This example is adapted from the SWIG examples
Code to be wrapped
There are two files, the header file example.h and the function bodies example.cxx.
example.h
| /* File : example.h */
class Shape {
/* The member objects have been moved to private
* because of problems with the SWIG translation
* generating a wrapper code which will not compile
* without alteration */
private:
double x, y;
static int nshapes;
public:
Shape() {
nshapes++; x = 0; y = 0;
}
virtual ~Shape() {
nshapes--;
};
void move(double dx, double dy);
/* Added member functions to get the value back */
double x_get() { return x; }
double y_get() { return y; }
virtual double area(void) = 0;
virtual double perimeter(void) = 0;
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) { };
double radius_get() { return radius; }
virtual double area(void);
virtual double perimeter(void);
};
class Square : public Shape {
private:
double width;
public:
Square(double w) : width(w) { };
double width_get() { return width; }
virtual double area(void);
virtual double perimeter(void);
}; |
|
|
example.cxx
| /* File : example.cxx */
#include "example.h"
#define M_PI 3.14159265358979323846
/* Move the shape to a new location */
void Shape::move(double dx, double dy) {
x += dx;
y += dy;
}
int Shape::nshapes = 0;
double Circle::area(void) {
return M_PI*radius*radius;
}
double Circle::perimeter(void) {
return 2*M_PI*radius;
}
double Square::area(void) {
return width*width;
}
double Square::perimeter(void) {
return 4*width;
} |
|
|
Interface file
The interface file for this is quite simple, as it just uses the header file for the class. This is the real key to work with SWIG and C++ code.
example.i
| /* File : example.i */
%module example
/* Any section like this is transferred to the wrapper file,
so that the wrapper code will contain the header. */
%{
#include "example.h"
%}
/* Let's just grab the original header file here */
%include "example.h" |
|
|
Run SWIG
Note the added parameter c++.
This generates the following files:
- example.d
- classCircle.d
- classSquare.d
- classShape.d
- examplePINVOKE.d
- example_wrap.cxx
In this case
example.d is empty as there are no C++ functions to be wrapped which are not in a class. The interface to the D language is by calls to the D classes in the files with names starting
class. These call functions in
examplePINVOKE.d which uses C linkage to call
example_wrap.cxx, so making the interface possible.
Example Application
helloex.d
| /* Example for testing the D interface to a C++ class */
/* private import example; */
private import classCircle;
private import classSquare;
/* hello.d from the dmd distribution adapted as an example for D SWIG */
/* for C++ extensions it is necessary to link the C++ run time */
/* This can be done by compiling the D files first e.g. */
/* swig -dmd -c++ example.i */
/* dmd -c helloex.d */
/* dmd -c classCircle.d */
/* dmd -c classSquare.d */
/* dmd -c classShape.d */
/* g++ -c example_wrap.cxx */
/* g++ -c example.cxx */
/* g++ helloex.o -ohelloex classCircle.o classSquare.o classShape.o
* example_wrap.o example.o
* -lphobos -lpthread -lm */
int main(char[][] args)
{
printf("hello world\n");
printf("\nTesting interface to a C++ class\n\n");
/* Note how to declare new objects */
printf("Declare:\n");
printf("Circle circle = new Circle(10.);\n");
Circle circle = new Circle(10.);
printf("circle has radius %lf\n",circle.radius_get());
printf("circle has perimeter %lf\n",circle.perimeter());
printf("circle has area %lf\n",circle.area());
printf("\nDeclare:\n");
printf("Square square = new Square(10.);\n");
Square square = new Square(10.);
printf("square has width %lf\n",square.width_get());
printf("square has perimeter %lf\n",square.perimeter());
printf("square has area %lf\n",square.area());
printf("\nTesting inherited functions\n\n");
printf("square is at (%lf,%lf)\n",square.x_get(),square.y_get());
square.move(3.,4.);
printf("square.move(3.,4.);\n");
printf("square is at (%lf,%lf)\n",square.x_get(),square.y_get());
printf("\nEnd of testing\n");
return 0;
} |
|
|
Linux
| dmd -c helloex.d
dmd -c classCircle.d
dmd -c classSquare.d
dmd -c classShape.d
g++ -c example_wrap.cxx
g++ -c example.cxx
g++ helloex.o -ohelloex classCircle.o classSquare.o classShape.o example_wrap.o example.o -lphobos -lpthread -lm |
|
|
The compilation is quite complicated. Each C++ file has to be compiled with g++, and each D file with dmd, and then all linked together with both the C++ and D libraries. This is the reason that I suggested FeatureRequestList/LinuxLinkOption.
Windows The files have been copied unchanged from Linux.
| dmc -c example.cxx
dmc -c example_wrap.cxx
dmd helloex.d classCircle.d classSquare.d classShape.d example_wrap.obj example.obj |
|
|
Output
| hello world
Testing interface to a C++ class
Declare:
Circle circle = new Circle(10.);
circle has radius 10.000000
circle has perimeter 62.831853
circle has area 314.159265
Declare:
Square square = new Square(10.);
square has width 10.000000
square has perimeter 40.000000
square has area 100.000000
Testing inherited functions
square is at (0.000000,0.000000)
square.move(3.,4.);
square is at (3.000000,4.000000)
End of testing |
|
|
Note: this does not work with the original distribution by Andy Friesen. You will need my modifications to the files dmd.cxx and dmd.swg.
JohnFletcher