Thread overview
Calling D functions from C
May 27, 2008
Pontus Pihlgren
May 27, 2008
Robert Fraser
May 27, 2008
Matthias Walter
May 27, 2008
Pontus Pihlgren
May 27, 2008
BCS
May 27, 2008
downs
May 27, 2008
BCS
May 28, 2008
downs
May 28, 2008
BCS
May 27, 2008
Hi all.

Its a rather hypothetical I guess, but is it possible to call D functions from C? If so, are there limitations?

Kind Regards,
Pontus.
May 27, 2008
Pontus Pihlgren wrote:
> Hi all.
> 
> Its a rather hypothetical I guess, but is it possible to call D functions from C? If so, are there limitations?
> 
> Kind Regards,
> Pontus.

extern(C) your D functions & enjoy! If you're not running the D garbage collector, don't rely on garbage collection happening (obvious), and a bit less obvious is that many libraries require their static constructors to be called, so be sure to run those first. Also, don't throw exceptions over D-C lines. There's probably other limitations I'm not thinking of/don't know of.
May 27, 2008
Pontus Pihlgren Wrote:

> Hi all.
> 
> Its a rather hypothetical I guess, but is it possible to call D functions from C? If so, are there limitations?
> 
> Kind Regards,
> Pontus.

If you want to really call the D function from C code, compiling with a C compiler, this can get tricky, as the C compiler normally does not know the ABI of D. It therefore does not know in which registers / stack slots to put which argument, etc.

But you can write a Wrapper routine in D which simply calls your D routine but has an extern (C) calling convention:

# extern (C) int myFunctionWrapper (char a, int b, char* c)
# {
#    return myFunction (a,b,c); // myFunction is a normal D function.
# }

With this code you can call myFunctionWrapper from your C code like you do normally. Alternatively you can code all your C stuff in a .d file, putting extern (C) around everything. Then you can call it without a wrapper, too.

best regards
Matthias Walter
May 27, 2008
Matthias Walter skrev:
> Pontus Pihlgren Wrote:
> 
>> Hi all.
>>
>> Its a rather hypothetical I guess, but is it possible to call D functions from C? If so, are there limitations?
>>
>> Kind Regards,
>> Pontus.
> 
> If you want to really call the D function from C code, compiling with a C compiler, this can get tricky, as the C compiler normally does not know the ABI of D. It therefore does not know in which registers / stack slots to put which argument, etc.
> 
> But you can write a Wrapper routine in D which simply calls your D routine but has an extern (C) calling convention:
> 
> # extern (C) int myFunctionWrapper (char a, int b, char* c)
> # {
> #    return myFunction (a,b,c); // myFunction is a normal D function.
> # }
> 
> With this code you can call myFunctionWrapper from your C code like you do normally. Alternatively you can code all your C stuff in a .d file, putting extern (C) around everything. Then you can call it without a wrapper, too.
> 
> best regards
> Matthias Walter

That sound almost to easy, I thought that extern could only refer to, you know, external functions and not to declare new functions.

Looking more closely at the documentation at http://www.digitalmars.com/d/2.0/interfaceToC.html verifies it :) I guess I must have missed it the first time I read it.

Thanks,
Pontus.
May 27, 2008
Reply to Matthias,


> # extern (C) int myFunctionWrapper (char a, int b, char* c)
> # {
> #    return myFunction (a,b,c); // myFunction is a normal D function.
> # }

that deserves a template. 

I guess I known what to do at lunch today.


May 27, 2008
BCS wrote:
> Reply to Matthias,
> 
> 
>> # extern (C) int myFunctionWrapper (char a, int b, char* c)
>> # {
>> #    return myFunction (a,b,c); // myFunction is a normal D function.
>> # }
> 
> that deserves a template.
> I guess I known what to do at lunch today.
> 
> 

template Forward(string NAME) {
  mixin("extern(C) ReturnType!(&"~NAME~") c_"~NAME~"(ParameterTypeTuple!(&"~NAME~") p) {
    return "~NAME~"(p);
  }");
}

Untested, but should work.

 --downs
May 27, 2008
Reply to Downs,

> BCS wrote:
> 
>> Reply to Matthias,
>> 
>>> # extern (C) int myFunctionWrapper (char a, int b, char* c)
>>> # {
>>> #    return myFunction (a,b,c); // myFunction is a normal D
>>> function.
>>> # }
>> that deserves a template.
>> I guess I known what to do at lunch today.
> template Forward(string NAME) {
> mixin("extern(C) ReturnType!(&"~NAME~")
> c_"~NAME~"(ParameterTypeTuple!(&"~NAME~") p) {
> return "~NAME~"(p);
> }");
> }
> Untested, but should work.
> 
> --downs
> 

maybe, I'd kind rather not use a mixin for that. (I avoid them wherever I can) I'll take real a pass at it later.

On second look it seem the mixin is needed to make the name work but it seem to be over kill for the rest

// untested
template Forward(alias NAME)
{
 mixin(
  "extern(C) ReturnType!(&NAME) c_"~NAME.stringof~"(ParameterTypeTuple!(&NAME) p) { return NAME(p);}"
 );
}


May 28, 2008
BCS wrote:
> Reply to Downs,
> 
>> BCS wrote:
>>
>>> Reply to Matthias,
>>>
>>>> # extern (C) int myFunctionWrapper (char a, int b, char* c)
>>>> # {
>>>> #    return myFunction (a,b,c); // myFunction is a normal D
>>>> function.
>>>> # }
>>> that deserves a template.
>>> I guess I known what to do at lunch today.
>> template Forward(string NAME) {
>> mixin("extern(C) ReturnType!(&"~NAME~")
>> c_"~NAME~"(ParameterTypeTuple!(&"~NAME~") p) {
>> return "~NAME~"(p);
>> }");
>> }
>> Untested, but should work.
>>
>> --downs
>>
> 
> maybe, I'd kind rather not use a mixin for that. (I avoid them wherever I can) I'll take real a pass at it later.
> 
> On second look it seem the mixin is needed to make the name work but it seem to be over kill for the rest
> 
> // untested
> template Forward(alias NAME)
> {
>  mixin(
>   "extern(C) ReturnType!(&NAME)
> c_"~NAME.stringof~"(ParameterTypeTuple!(&NAME) p) { return NAME(p);}"
>  );
> }
> 
> 
Remember. stringof is not guaranteed to be in any sort of sane format.
For example, the above code would fail if it for some obscure reason contains spaces (or other invalid characters).
If you let the user pass a string, at least you know where the blame lies.

 --downs
May 28, 2008
Reply to Downs,

> BCS wrote:
> 
>> Reply to Downs,
>> 
>>> BCS wrote:
>>> 
>>>> Reply to Matthias,
>>>> 
>>>>> # extern (C) int myFunctionWrapper (char a, int b, char* c)
>>>>> # {
>>>>> #    return myFunction (a,b,c); // myFunction is a normal D
>>>>> function.
>>>>> # }
>>>> that deserves a template.
>>>> I guess I known what to do at lunch today.
>>> template Forward(string NAME) {
>>> mixin("extern(C) ReturnType!(&"~NAME~")
>>> c_"~NAME~"(ParameterTypeTuple!(&"~NAME~") p) {
>>> return "~NAME~"(p);
>>> }");
>>> }
>>> Untested, but should work.
>>> --downs
>>> 
>> maybe, I'd kind rather not use a mixin for that. (I avoid them
>> wherever I can) I'll take real a pass at it later.
>> 
>> On second look it seem the mixin is needed to make the name work but
>> it seem to be over kill for the rest
>> 
>> // untested
>> template Forward(alias NAME)
>> {
>> mixin(
>> "extern(C) ReturnType!(&NAME)
>> c_"~NAME.stringof~"(ParameterTypeTuple!(&NAME) p) { return NAME(p);}"
>> );
>> }
> Remember. stringof is not guaranteed to be in any sort of sane format.
> 
> For example, the above code would fail if it for some obscure reason
> contains spaces (or other invalid characters).
> 
> If you let the user pass a string, at least you know where the blame
> lies.
> 
> --downs
> 

// untested
template Forward(alias fn, char[] name)
{
mixin(
"extern(C)ReturnType!(&NAME)"~name~"(ParameterTypeTuple!(&fn) p){return fn(p);}"
);
}