www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Library Interop

reply Deja Augustine <deja scratch-ware.net> writes:
I've reached the point in D.NET where I'm playing around with calling 
native D code from .NET.  I'm running into an interesting dilema, as I 
cannot figure out what D is expecting.  This is best demonstrated by a 
couple examples:

If I have a function in a native D DLL:
extern (D) void foo(int i) { printf("%i in foo", i); }

and I push a 32-bit integer onto the stack prior to the call to that 
function, it invariably is either printed as some address or as 0. 
However, if I do the same thing with a function that takes a float and I 
pass it a 4-byte floating point number, then it Just Works.

What does work, with ints, however, is if I do:
extern (D) void foo(int i, int j) { printf("%i in foo", i); }

and then pass two 32-bit integers.  Except that i works and j is that 
same address regardless of how many integers I push onto the stack.

Strings are a similar problem.  If foo takes a char[] and I pass it a 
32-bit integer representing the length of the string and then I pass a 
valid pointer to the string, the D end sees the char[] as being empty.

I have none of these problems if I use extern (C) so it has to be 
something with the way that D expects its arguments, and I, for one, am 
dumbfounded.

Does anyone have any insight into this problem?

-Deja
Aug 06 2004
next sibling parent Nick <Nick_member pathlink.com> writes:
In article <cf095i$inp$1 digitaldaemon.com>, Deja Augustine says...
If I have a function in a native D DLL:
extern (D) void foo(int i) { printf("%i in foo", i); }

and I push a 32-bit integer onto the stack prior to the call to that 
function, it invariably is either printed as some address or as 0. 
However, if I do the same thing with a function that takes a float and I 
pass it a 4-byte floating point number, then it Just Works.

I really have no idea, but maybe DMD passes single ints as registers rather than on the stack? Have you tried playing around with disassembled D code? Nick
Aug 06 2004
prev sibling parent reply "Walter" <newshound digitalmars.com> writes:
For D functions, the last argument will be passed in EAX if it fits in EAX.
Aug 06 2004
next sibling parent reply Deja Augustine <deja scratch-ware.net> writes:
Walter wrote:

 For D functions, the last argument will be passed in EAX if it fits in EAX.
 
 

Well, that prevents .NET from directly interacting with D. People will have to rely on extern (C) wrappers (which are already supported) since there's no way to work directly with registers using .NET Maybe by D.NET 2.0 it'll be able to automatically generate the machine code wrapper, but for now there are too many things more important. But that at least solves the mystery. Thanks! Deja
Aug 06 2004
next sibling parent reply Sean Kelly <sean f4.ca> writes:
In article <cf0qdu$th6$1 digitaldaemon.com>, Deja Augustine says...
Walter wrote:

 For D functions, the last argument will be passed in EAX if it fits in EAX.

Well, that prevents .NET from directly interacting with D. People will have to rely on extern (C) wrappers (which are already supported) since there's no way to work directly with registers using .NET

Are you sure? How does C++/CLI do the marshalling between managed and unmanaged code? Sean
Aug 06 2004
parent Andy Friesen <andy ikagames.com> writes:
Sean Kelly wrote:
 In article <cf0qdu$th6$1 digitaldaemon.com>, Deja Augustine says...
 
Walter wrote:


For D functions, the last argument will be passed in EAX if it fits in EAX.

Well, that prevents .NET from directly interacting with D. People will have to rely on extern (C) wrappers (which are already supported) since there's no way to work directly with registers using .NET

Are you sure? How does C++/CLI do the marshalling between managed and unmanaged code?

The Managed C++ compiler cheats. :) It has both a native and a managed code generator, so it can flip between one and the other at will, depending on the function it's compiling. Making a D compiler that can do the same is certainly possible (we already have an x86 code generator in the form of DLI, after all) but a project in and of itself. -- andy
Aug 06 2004
prev sibling parent "Walter" <newshound digitalmars.com> writes:
"Deja Augustine" <deja scratch-ware.net> wrote in message
news:cf0qdu$th6$1 digitaldaemon.com...
 Walter wrote:

 For D functions, the last argument will be passed in EAX if it fits in



Well, that prevents .NET from directly interacting with D. People will have to rely on extern (C) wrappers (which are already supported) since there's no way to work directly with registers using .NET Maybe by D.NET 2.0 it'll be able to automatically generate the machine code wrapper, but for now there are too many things more important. But that at least solves the mystery. Thanks!

No problem, just use the extern (C) calling convention in your D code that you want to interface with .NET. No need for wrappers.
Aug 06 2004
prev sibling parent reply Derek <derek psyc.ward> writes:
On Fri, 6 Aug 2004 12:24:19 -0700, Walter wrote:

 For D functions, the last argument will be passed in EAX if it fits in EAX.

I guess this only applies to the DMD compiler and 'D' - the language. Another D compiler might do it differently. -- Derek Melbourne, Australia
Aug 06 2004
parent reply J C Calvarese <jcc7 cox.net> writes:
Derek wrote:
 On Fri, 6 Aug 2004 12:24:19 -0700, Walter wrote:
 
 
For D functions, the last argument will be passed in EAX if it fits in EAX.

I guess this only applies to the DMD compiler and 'D' - the language. Another D compiler might do it differently.

I think that something like that should be compatible from compiler to compiler as much as possible (unless it's platform-dependent). I'm hoping that information will become part of the D standard, e.g. http://www.digitalmars.com/d/abi.html At the minimum, it should be documented. -- Justin (a/k/a jcc7) http://jcc_7.tripod.com/d/
Aug 06 2004
parent reply Ilya Minkov <minkov cs.tum.edu> writes:
J C Calvarese schrieb:

 I think that something like that should be compatible from compiler to 
 compiler as much as possible (unless it's platform-dependent). I'm 
 hoping that information will become part of the D standard, e.g. 
 http://www.digitalmars.com/d/abi.html

It is platform-dependent. :)
 At the minimum, it should be documented.

I guess the docs say something about leaving the calling conventions, memory layouts, etc. unspecified, so that these can be tuned to performance in future. Instead, all communication with other language runtimes should happen via extern(...) interfaces. However, one could think of disigning another extern interface to standardize a link-compatible interface to D features, where performance is not essential. -eye
Aug 07 2004
parent reply "Walter" <newshound digitalmars.com> writes:
"Ilya Minkov" <minkov cs.tum.edu> wrote in message
news:cf26tn$1n01$1 digitaldaemon.com...
 Instead, all communication with other language runtimes should happen
 via extern(...) interfaces. However, one could think of disigning
 another extern interface to standardize a link-compatible interface to D
 features, where performance is not essential.

I think the extern(C) fills that role adequately. The C calling convention is the lingua franca on most platforms, another one is not needed.
Aug 07 2004
next sibling parent Nick <Nick_member pathlink.com> writes:
In article <cf3275$22h3$1 digitaldaemon.com>, Walter says...
"Ilya Minkov" <minkov cs.tum.edu> wrote in message
news:cf26tn$1n01$1 digitaldaemon.com...
 Instead, all communication with other language runtimes should happen
 via extern(...) interfaces. However, one could think of disigning
 another extern interface to standardize a link-compatible interface to D
 features, where performance is not essential.

I think the extern(C) fills that role adequately. The C calling convention is the lingua franca on most platforms, another one is not needed.

So I guess this means you will always have to use extern(C) when making shared libraries? Nick
Aug 08 2004
prev sibling parent reply Lars Ivar Igesund <larsivar igesund.net> writes:
Walter wrote:
 "Ilya Minkov" <minkov cs.tum.edu> wrote in message
 news:cf26tn$1n01$1 digitaldaemon.com...
 
Instead, all communication with other language runtimes should happen
via extern(...) interfaces. However, one could think of disigning
another extern interface to standardize a link-compatible interface to D
features, where performance is not essential.

I think the extern(C) fills that role adequately. The C calling convention is the lingua franca on most platforms, another one is not needed.

So why did you invent extern(D)? If you should use extern(C) to create interoperable libraries, it is kinda stupid to have extern(D) as default. Lars Ivar Igesund
Aug 08 2004
next sibling parent J C Calvarese <jcc7 cox.net> writes:
Lars Ivar Igesund wrote:
 Walter wrote:
 
 "Ilya Minkov" <minkov cs.tum.edu> wrote in message
 news:cf26tn$1n01$1 digitaldaemon.com...

 Instead, all communication with other language runtimes should happen
 via extern(...) interfaces. However, one could think of disigning
 another extern interface to standardize a link-compatible interface to D
 features, where performance is not essential.

I think the extern(C) fills that role adequately. The C calling convention is the lingua franca on most platforms, another one is not needed.

So why did you invent extern(D)? If you should use extern(C) to create interoperable libraries, it is kinda stupid to have extern(D) as default. Lars Ivar Igesund

I'm trying to understand that, too. I guess it's supposed to be more efficient. Maybe the name extern(D) should be renamed to extern(DMD) if it's going to be proprietary and undocumented. I don't know whether studying the public front end code would be enough to explain what makes extern(D) special. Perhaps Walter is saying: Use extern(C) for now [but later when extern(D) is documented and standarized, you could probably use it, too]. (I don't know that he's stated the important bracketed part yet, but this topic is pretty much over my head.) So there's no problem right now (we can use the C way) and the situation will even improve in the future when the D way becomes an option. We can hope anyway. :) -- Justin (a/k/a jcc7) http://jcc_7.tripod.com/d/
Aug 08 2004
prev sibling parent reply Deja Augustine <deja scratch-ware.net> writes:
Lars Ivar Igesund wrote:
 Walter wrote:
 
 "Ilya Minkov" <minkov cs.tum.edu> wrote in message
 news:cf26tn$1n01$1 digitaldaemon.com...

 Instead, all communication with other language runtimes should happen
 via extern(...) interfaces. However, one could think of disigning
 another extern interface to standardize a link-compatible interface to D
 features, where performance is not essential.

I think the extern(C) fills that role adequately. The C calling convention is the lingua franca on most platforms, another one is not needed.

So why did you invent extern(D)? If you should use extern(C) to create interoperable libraries, it is kinda stupid to have extern(D) as default. Lars Ivar Igesund

Well, because the D calling convention, as Walter stated, uses the EAX register for the last parameter. Since the majority of functions will have 0-1 arguments, this is a pretty decent speed increase since most of the time, the argument will already be there from a previous operation. Since D's default behavior is interacting with other D applications, it makes sense that extern(D) should be the default so as to default to the increased speed. If you're interoping with something that can't take advantage of that, then you use the extern(C) to use the standard C calling convention. As a point of note, creating a DLL that actually exports extern(D) code is a major pain in the rear since you have to figure out the mangled name of your method and put THAT into your .def file. So having to use extern(C) to interop with .NET makes life easier in other ways as well. -Deja
Aug 08 2004
parent Lars Ivar Igesund <larsivar igesund.net> writes:
Deja Augustine wrote:

 As a point of note, creating a DLL that actually exports extern(D) code 
 is a major pain in the rear since you have to figure out the mangled 
 name of your method and put THAT into your .def file.  So having to use 
 extern(C) to interop with .NET makes life easier in other ways as well.

This is not a problem. Prefix all exported symbols with 'export' in code and you can omit the symbols from the .def file altogether. Lars Ivar Igesund
Aug 08 2004