Last update July 7, 2004

Dwith Swig / Examples /
Class



Table of contents of this page
Wrap a C++ class   
Code to be wrapped   
Interface file   
Run SWIG   
Example Application   
Compile and Link   
Output   

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    

swig -dmd -c++ example.i

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;
}

Compile and Link    

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


FrontPage | News | TestPage | MessageBoard | Search | Contributors | Folders | Index | Help | Preferences | Edit

Edit text of this page (date of last change: July 7, 2004 0:18 (diff))