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








"Adam D. Ruppe" <destructionator gmail.com>