Last update March 7, 2012

Wrapping Cxx



Difference (last change) (no other diffs, normal page display)

Deleted: 399,509d398
jam tangan
jam tangan murah
jam tangan kw
hostgator coupon
kata mutiara
Jasa SEO
EZido
RDAnet
pioneer deh-1300mp
asus a53e-xa2
asus tf101-b1
asus tf101-a1
asus n53sv-eh72
asus republic of gamers g74sx
asus acer a5250
acer chromebook ac700
asus asus 53u
lg infinia 55lw5600
Sonicview 360 premier
asus 7 cu ft freezer
asus 30 single wall oven
brother cs6000i sewing machine
brother 1034d serger
brother sewing machines
Yokohama Geolandar H/T-S
crib tent tots in mind
kidco peapod plus
foscam fi8910w
samsung pl120 review
gopro helmet cam
Canon SX130IS
powershot s100
ContourHD 1080p
canon vixia hf r21
digital picture frame
canon ef 50mm f1.4
canon ef 70-300mm review
wide angle lenses
moving comfort sports bra
moving comfort bra
womens argyle sweater
bebe dresses
ViewSonic VX2250WM
Le Pan TC 970
Apple MacBook Air MC965LL
Sennheiser CX 880
plantronics cs540
ultrasonic jewelry cleaner
Sennheiser RS120
bose quietcomfort 15 acoustic noise cancelling headphones
logitech harmony one remote
logitech harmony 900
sony mhc-ec69i
sony mhcec909ip
bose wave music system
sony htss380
logitech squeezebox touch
sony dvp-fx970
onkyo tx-nr509
onkyo tx - nr609
onkyo ht-s3400
energy 5.1 take classic home theater system
polk audio psw505
onkyo ht-s5400
onkyo tx-nr709
belkin pf60
onkyo ht-rc360
denon avr-1912
Yamaha YHT-S400BL
fujitsu scansnap s1500
brother hl-2270dw
epson workforce 545
hp laserjet p2055dn
bushnell 8mp trophy cam
toshiba 32c110u
panasonic viera tc-p60s30
VIZIO E220VA
hauppauge wintv dcr-2650
Acer AM3970-U5022
Acer AspireRevo AR3700-U3002
Dell Inspiron i570
Dell GX620
Gateway FX6860-UR20P
Western Digital My Passport Essential SE 1 TB USB 3.0
Fujitsu ScanSnap S1300
Epson Perfection V300
Fujitsu SCANSNAP S1100
NeatDesk Desktop Scanner and Digital Filing System
Epson WorkForce Pro GT-S50
Kodak P811BK
Epson Perfection V330
Viewsonic VX2453MH
Asus VE228H
ViewSonic VA2431WM
Samsung B2230
HP 2711x
ASUS ML228H
Epson PowerLite Home Cinema 8350
Optoma PK301
Epson EX7210
Epson EX5210
ViewSonic PJD5133
Acer X1161P
FAVI RioHD-LED-2
Epson EX3210
ViewSonic PJD6531w
Trinity 360 Breville 800JEXL
Skil 3320-02
Delta 46-460
Grizzly G0555
Delta 18-900L

contributions needed!

This page discusses how to wrap C++ libraries so that they can be called from D.

The basic idea is to

  1. Create a C API that mirrors the C++ API, and then
  2. Port the resulting C headers to D, making a low-level C-like D API, and finally
  3. Wrap the low-level D API with a more object-oriented D API (optional).
The best example of this 3-step approach is perhaps the wxD project. The fltk4D wrappers appear to take this approach as well.

Wrapping C++ classes

coolstuff.h:
class Class
{
public:
    void *attribute;
    void *method(void *arg0, void *arg1, void *argN);
};

wrapper.cpp:

#include "coolstuff.h"

extern "C"
{
    void *_Class_this()
    {
        return new Class();
    }
    
    void _Class_destroy(Class *classptr)
    {
        delete classptr;
    }
    
    void *_Class_get_attribute(Class *classptr)
    {
        return classptr->attribute;
    }
    
    void _Class_set_attribute(Class *classptr, void *value)
    {
        classptr->attribute = value;
    }
    
    void *_Class_method(Class *classptr, void *arg0, void *arg1, void *argN)
    {
        return classptr->method(arg0, arg1, argN);
    }
}

coolstuff.d:

class Class
{
    void* classptr;
    bool newed;
    
    this()
    {
        this.classptr = _Class_this();
        this.newed = true;
    }
    
    ~this()
    {
        if(newed)
            _Class_destroy(classptr);
    }
    
    this(void* classptr)
    {
        this.classptr = classptr;
    }
    
    void* attribute()
    {
        return _Class_get_attribute(classptr);
    }
    
    void attribute(void* value)
    {
        _Class_set_attribute(classptr, value);
    }
	
    void* method(void* arg0, void* arg1, void* argN)
    {
        return _Class_method(classptr, arg0, arg1, argN);
    }
}

extern (C):
void* _Class_this();
void _Class_destroy(void* classptr);
void *_Class_get_attribute(void *classptr);
void _Class_set_attribute(void *classptr, void *value);
void* _Class_method(void* classptr, void* arg0, void* arg1, void* argN);

Wrapping structs

D's struct is compatible with C's struct, and can thereby be passed through the D and extern C part of the wrapper without change, but C++'s struct isn't compatible with C's struct (unless declared extern C).

So the only way a struct can go is: D->C C->D

Example

vector3f.h:

struct Vector3f
{
    float x, y, z;

    Vector3f(float x, float y, float z)
    {
        this->x = x;
        this->y = y;
        this->z = z;
    }
}

void setPosition(Vector3f newPos);

wrapper.cpp:

#include "vector3f.h"

extern "C"
{
    struct CVector3f
    {
        float x, y, z;
    
        CVector3f(float x, float y, float z)
        {
            this->x = x;
            this->y = y;
            this->z = z;
        }
    }
    
    void _setPosition(CVector3f newPos)
    {
        setPosition(Vector3f(newPos.x, newPos.y, newPos.z));
    }
}

vector3f.d:

struct Vector3f
{
    float x, y, z;
}

void setPosition(Vector3f newPos)
{
    _setPosition(newPos);
}

extern(C):
_setPosition(Vector3f newPos);

Note: As a struct and class in C++ is almost the same thing, the struct in vector3f.h could be changed to a class, without any changes to the wrapper.

Wrapping templated classes and structs

You have to create a D class/struct for each instanced template.

Example

dimension2d.h:

template <class T>
class Dimension2D
{
public:
    T w, h;
};

wrapper.cpp:

#include "dimension2d.h"

extern "C"
{
    //int
    void *_Dimension2D_this()
    {
        return new Dimension2D<int>();
    }
	
    void _Dimension2D_destroy(Dimension2D<int> *classptr)
    {
        delete classptr;
    }
    
    int _Dimension2D_get_w(Dimension2D<int> *classptr)
    {
        return classptr->w;
    }
    
    void _Dimension2D_set_w(Dimension2D<int> *classptr, int value)
    {
        classptr->w = value;
    }
    
    int _Dimension2D_get_h(Dimension2D<int> *classptr)
    {
        return classptr->h;
    }
	
    void _Dimension2D_set_h(Dimension2D<int> *classptr, int value)
    {
        classptr->h = value;
    }
    
    //float
    void *_Dimension2Df_this()
    {
        return new Dimension2D<float>();
    }
	
    void _Dimension2Df_destroy(Dimension2D<float> *classptr)
    {
        delete classptr;
    }
	
    float _Dimension2Df_get_w(Dimension2D<float> *classptr)
    {
        return classptr->w;
    }
    
    void _Dimension2Df_set_w(Dimension2D<float> *classptr, float value)
    {
        classptr->w = value;
    }
    
    float _Dimension2Df_get_h(Dimension2D<float> *classptr)
    {
        return classptr->h;
    }
    
    void _Dimension2Df_set_h(Dimension2D<float> *classptr, float value)
    {
        classptr->h = value;
    }
}

dimension2d.d:

class Dimension2D
{
    void* classptr;
    bool newed;
    
    this()
    {
        this.classptr = _Dimension2D_this();
        this.newed = true;
    }
    
    ~this()
    {
        if(newed)
            _Dimension2D_destroy(classptr);
    }
    
    this(void* classptr)
    {
        this.classptr = classptr;
    }
    
    int w()
    {
        return _Dimension2D_get_w(classptr);
    }
    
    void w(int value)
    {
        _Dimension2D_set_w(classptr, value);
    }
    
    int h()
    {
        return _Dimension2D_get_h(classptr);
    }
    
    void h(int value)
    {
        _Dimension2D_set_h(classptr, value);
    }
}

class Dimension2Df
{
    void* classptr;
    bool newed;
    
    this()
    {
        this.classptr = _Dimension2Df_this();
        this.newed = true;
    }
    
    ~this()
    {
        if(newed)
            _Dimension2Df_destroy(classptr);
    }
	
    this(void* classptr)
    {
        this.classptr = classptr;
    }
    
    float w()
    {
        return _Dimension2Df_get_w(classptr);
    }
    
    void w(float value)
    {
        _Dimension2Df_set_w(classptr, value);
    }
    
    float h()
    {
        return _Dimension2Df_get_h(classptr);
    }
    
    void h(float value)
    {
        _Dimension2Df_set_h(classptr, value);
    }
}

extern(C):
//int
void* _Dimension2D_this();
void _Dimension2D_destroy(void* classptr);
int _Dimension2D_get_w(void* classptr);
void _Dimension2D_set_w(void* classptr, int value);
int _Dimension2D_get_h(void* classptr);
void _Dimension2D_set_h(void* classptr, int value);

//float
void* _Dimension2Df_this();
void _Dimension2Df_destroy(void* classptr);
float _Dimension2Df_get_w(void* classptr);
void _Dimension2Df_set_w(void* classptr, float value);
float _Dimension2Df_get_h(void* classptr);
void _Dimension2Df_set_h(void* classptr, float value);

Argument overloading

You can't use argument overloading in extern C code. An alternative is to use method1, method2, methodN instead.

Example

void draw(int x, int y, Image image);
void draw(int x, int y, Color color);

//becomes
void draw1(int x, int y, Image image);
void draw2(int x, int y, Color color);

Wrapping with tango

You will want to import tango.stdc.stringz for easy C-string handling with toStringz and fromUtf8z.

Compiling and linking

Using rebuild on x86_64

g++ wrapper.cpp -c
rebuild test.d wrapper.o -L-lstdc++ -L-L/usr/lib/gcc/x86_64-pc-linux-gnu/4.2.2/ -full -oq.build

Automation

The described wrapping process could probably be automated by a smallish program.

Collaborations

Many languages are able to make calls directly into C libraries. So there is potential for collaboration when creating the C-wrappers of a large C++ API. For instance the D and C# wrappers for wxWidgets share the same low-level C wrapper of the wxWidgets API.

Tools

bcd.gen http://www.dsource.org/projects/bcd/ - generates C or C++ bindings from .h files


Back to the Porting Overview


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

Edit text of this page (date of last change: March 7, 2012 20:33 (diff))