www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - c++ interop in the library (just for fun)

reply "Adam D. Ruppe" <destructionator gmail.com> writes:
So now that there's a pragma(mangle), we can start hacking this 
up! I'm using Linux g++ 32 bit.

C++:

class Class {
public:
         Class() {}// printf("constructed\n"); }
         virtual void addNum(int a) { num += a; }
         virtual void addNum2(int a) { num2 += a; }

         void talk() { printf("%d %d\n", num, num2); }
         int num;
         int num2;
};


D:

         struct Class {
                 extern(C++) interface Vtable {
                         void addNum(int num);
                         void addNum2(int num2);
                 }
                 mixin CPlusPlusObject!(Vtable, typeof(this));

                 void cppCtor();

                 extern(C++) void talk();
                 int num;
                 int num2;
         }

magic D:


         string cppMangleCtor(alias Func)() {
                 import std.conv;
                 string m = "_ZN";
                 string cn = __traits(parent, Func).stringof;
                 m ~= to!string(cn.length) ~ cn;
                 m ~= "C2Ev"; // fixme: the actual argument list
                 return m;
         }

         string CppCtors(T)() {
                 string code;

                 foreach(member; __traits(allMembers, T)) {
                         static if(member == "cppCtor") {
                                 code ~= "pragma(mangle, 
`"~cppMangleCtor!(__traits(getMember, T, member))~"`) static 
extern(C++) void cppConstructor("~T.    stringof~"*);";
                                 code ~= "\n";
                                 code ~= "static " ~ T.stringof ~ 
" opCall() {
                                         auto c = 
"~T.stringof~".init;
                                         cppConstructor(&c);
                                         return c;
                                 }";
                         }
                 }
                 return code;
         }

         mixin template CPlusPlusObject(Virtuals, Main) {
                 void* virts;
                 Virtuals getVirtuals() { return cast(Virtuals) 
&this; }
                 alias getVirtuals this;

                  disable this();

                 mixin(CppCtors!Main());
                 pragma(msg, CppCtors!Main());
         }



Test functions, D:

extern(C++)  void doit(Class*);
extern(C++)  void whoa(Class* c) {
                 import core.stdc.stdio;
                 printf("whoa\n");
                 c.num += (30);
                 c.talk();

                 c.addNum(10);
         }


void main() {
         import std.stdio;
         writeln("MOVING ON");
         auto c = Class.opCall();
         doit(&c);
         writeln("All Done!");
}


C++:


extern void whoa(Class* c);

void doit(Class* ptr) {
         if(ptr == NULL)
                 ptr = new Class2();

         ptr->num = 10;
         ptr->num2 = 20;

         ptr->talk();
         whoa(ptr);
         ptr->talk();
}


Output:

$ ./testcpp
MOVING ON
constructed
10 20
whoa
40 20
50 20
All Done!



No crash! Now, normally, I'd say we should probably construct the 
objects in their native language, but I just had to try this and 
the fact that it worked I thought was pretty cool.

Here we see access to both virtual and non-virtual member 
functions of the C++ object from D, as well as direct access to 
the member variables! Liable to break? Oh yeah. Hacky? 
Definitely. But I thought this was kinda cool.

Inheritance can work too, but there's still a ways to go to make 
that right. (It works easily enough if you just access virtuals 
though, D's plain extern(C++) interface can do that.)



Maybe if we were to see this through it could be a good enough 
hack for some real world use too.
May 29 2013
next sibling parent Martin Nowak <code dawg.eu> writes:
On 05/30/2013 03:05 AM, Adam D. Ruppe wrote:
 Maybe if we were to see this through it could be a good enough hack for
 some real world use too.

That's really need. It could also allow you to access namespaces and operators.
May 30 2013
prev sibling next sibling parent Timothee Cour <thelastmammoth gmail.com> writes:
--047d7b471f6a455d2304ddf2d78d
Content-Type: text/plain; charset=ISO-8859-1

We need to support different C++ name mangling schemes. Maybe a template
argument that would indicate which scheme to choose from.

Also the next step would be:
mixin(importCPP("myheader.h"));

string importCPP(string file){
auto text = import(file);
return process_text(text);
}

doesn't have to work in 100% cases, but that would be an awesome feature.

On Thu, May 30, 2013 at 7:12 AM, Martin Nowak <code dawg.eu> wrote:

 On 05/30/2013 03:05 AM, Adam D. Ruppe wrote:

 Maybe if we were to see this through it could be a good enough hack for
 some real world use too.

That's really need. It could also allow you to access namespaces and operators.

--047d7b471f6a455d2304ddf2d78d Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable We need to support different C++ name mangling schemes. Maybe a template ar= gument that would indicate which scheme to choose from.<div><br></div><div>= Also the next step would be:</div><div>mixin(importCPP(&quot;myheader.h&quo= t;));</div> <div><br></div><div>string importCPP(string file){</div><div>auto text =3D = import(file);</div><div>return process_text(text);</div><div>}</div><div><b= r></div><div>doesn&#39;t have to work in 100% cases, but that would be an a= wesome feature.<br> <br><div class=3D"gmail_quote">On Thu, May 30, 2013 at 7:12 AM, Martin Nowa= k <span dir=3D"ltr">&lt;<a href=3D"mailto:code dawg.eu" target=3D"_blank">c= ode dawg.eu</a>&gt;</span> wrote:<br><blockquote class=3D"gmail_quote" styl= e=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> <div class=3D"im">On 05/30/2013 03:05 AM, Adam D. Ruppe wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> Maybe if we were to see this through it could be a good enough hack for<br> some real world use too.<br> </blockquote> <br></div> That&#39;s really need.<br> It could also allow you to access namespaces and operators.<br> <br> </blockquote></div><br></div> --047d7b471f6a455d2304ddf2d78d--
May 30 2013
prev sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thursday, 30 May 2013 at 17:29:42 UTC, Timothee Cour wrote:
 We need to support different C++ name mangling schemes.

Right, that's fairly straightforward to implement, we could probably use a UDA to change it ( VisualCpp void foo()) or choose the most sane default with version(Windows), version(GDC), etc.
 Also the next step would be:
 mixin(importCPP("myheader.h"));

You know I was actually thinking about that. Either using a dummy D class and going over it to build the C++ object: class Test_Cpp { int num; int num2; void talk(); final void sayHi(); // or whatever i dont have the file open right now } alias AccessCpp!Test_Cpp Test; // AccessCPP parses it into the equivalent c++ definitions then builds out the structs and mangle schemes Or reading the .h file like you said. Which would be pretty hard, even to do just partially, since the C++ definition might have inline definitions, #includes, macros and so on that just totally confuse the parser.
May 30 2013