digitalmars.D - c++ interop in the library (just for fun)
- Adam D. Ruppe (109/109) May 29 2013 So now that there's a pragma(mangle), we can start hacking this
- Martin Nowak (3/5) May 30 2013 That's really need.
- Timothee Cour (10/16) May 30 2013 We need to support different C++ name mangling schemes. Maybe a template
- Adam D. Ruppe (20/23) May 30 2013 Right, that's fairly straightforward to implement, we could
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
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
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.
May 30 2013
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