Thread overview
boilerplate generation
Dec 29, 2013
Carl Sturtivant
Dec 29, 2013
Dicebot
Dec 29, 2013
Carl Sturtivant
Dec 30, 2013
Dicebot
Dec 30, 2013
Carl Sturtivant
Dec 30, 2013
John Colvin
Dec 30, 2013
Carl Sturtivant
Dec 30, 2013
Dicebot
December 29, 2013
I want to be able to define a number of extern(C) functions that will define a C API in a DLL, varying only in their names, each as follows.

export extern(C) int f( uint argc, A* argv) { return Wrapper!f( argc, argv); }

Here Wrapper!f is a wrapper around a D function named f that does the work, called from C via the f defined here.

I'd like a piece of D machinery that provides a short clean way to embed one of these in a program, where the name f is specified once, and the code is invisible. I've had no success at solving this problem with templates or mixin templates. I can use CTFE so I can write

mixin( Export("f"));

to introduce the definition for f. Is this the best way to proceed? What are other options?


December 29, 2013
Does this look clean enough? (Not sure I have completely understood the question)

/* export extern(C) int f( uint argc, A* argv) { return Wrapper!f(
argc, argv); } */

struct A {}

int Wrapper(alias func, T...)(T args) { return 42; }

template ExternC(alias existingFunc)
{
	import std.string : format;
	import std.traits : ReturnType;
	
	static assert(is(typeof(&existingFunc) : int function(uint, A*)));
	
	mixin(format(
		"export extern(C) int %s(uint argc, A* argv) { return Wrapper!(%s)(argc, argv); }",
		__traits(identifier, existingFunc),
		__traits(identifier, existingFunc)
	));
}

// to avoid name clash, assuming you have different module in real code
struct X
{	
	static int fff(uint, A*)
	{
		return 42;
	}
}

mixin ExternC!(X.fff);

pragma(msg, typeof(fff));
// extern (C) int(uint argc, A* argv)

void main()
{
}
December 29, 2013
On Sunday, 29 December 2013 at 22:01:19 UTC, Dicebot wrote:
> Does this look clean enough? (Not sure I have completely understood the question)
>
> /* export extern(C) int f( uint argc, A* argv) { return Wrapper!f(
> argc, argv); } */
>
> struct A {}
>
> int Wrapper(alias func, T...)(T args) { return 42; }
>
> template ExternC(alias existingFunc)
> {
> 	import std.string : format;
> 	import std.traits : ReturnType;
> 	
> 	static assert(is(typeof(&existingFunc) : int function(uint, A*)));
> 	
> 	mixin(format(
> 		"export extern(C) int %s(uint argc, A* argv) { return Wrapper!(%s)(argc, argv); }",
> 		__traits(identifier, existingFunc),
> 		__traits(identifier, existingFunc)
> 	));
> }
>
> // to avoid name clash, assuming you have different module in real code
> struct X
> {	
> 	static int fff(uint, A*)
> 	{
> 		return 42;
> 	}
> }
>
> mixin ExternC!(X.fff);
>
> pragma(msg, typeof(fff));
> // extern (C) int(uint argc, A* argv)
>
> void main()
> {
> }

Very nice. Only one problem: when I use dmd/win32 to build the
DLL, and analyze the resulting export, it's
_D5mixin43__T7ExternCS28_D5mixin1X3fffFkPS5mixin1AZiZ3fffUkPS5mixin1AZi
and not _fff or similar. So somehow the extern(C) hasn't led to a C symbol.


December 30, 2013
On Sunday, 29 December 2013 at 22:28:00 UTC, Carl Sturtivant wrote:
> Very nice. Only one problem: when I use dmd/win32 to build the
> DLL, and analyze the resulting export, it's
> _D5mixin43__T7ExternCS28_D5mixin1X3fffFkPS5mixin1AZiZ3fffUkPS5mixin1AZi
> and not _fff or similar. So somehow the extern(C) hasn't led to a C symbol.

Ah, yeah, have missed that. Such thing is expected if symbol is nested and can't have clear C mangling (then extern(C) only impacts ABI). It is kind of weird that this is also the case for mixin templates as those are injected into target scope but makes sense once you remember that even mixin templates conform symbol hygiene.

It can be forced by pragma(mangle) though. Updated code:

struct A {}

int Wrapper(alias func, T...)(T args) { return 42; }

template ExternC(alias existingFunc)
{
	import std.string : format;
	import std.traits : ReturnType;
	
	static assert(is(typeof(&existingFunc) : int function(uint,
A*)));
	
	private enum name = __traits(identifier, existingFunc);
	
	mixin(format(
		q{pragma(mangle, "%s") export extern(C) int %s(uint argc, A* argv) { return Wrapper!(%s)(argc, argv); }},
		name,
		name,
		name
	));
}

// to avoid name clash, assuming you have different module in
// real code
struct X
{	
	static int fff(uint, A*)
	{
		return 42;
	}
}

mixin ExternC!(X.fff);

pragma(msg, typeof(fff));
// extern (C) int(uint argc, A* argv)

pragma(msg, fff.mangleof);
// fff

void main()
{}
December 30, 2013
On Monday, 30 December 2013 at 04:35:34 UTC, Dicebot wrote:
> It can be forced by pragma(mangle) though. Updated code: [...]

Never heard of pragma(mangle)! Very useful. What role does it play in D? Is it guaranteed implemented on x86 or amd64?

Thanks for the answer, very nice.
December 30, 2013
On Monday, 30 December 2013 at 17:33:13 UTC, Carl Sturtivant wrote:
>
> On Monday, 30 December 2013 at 04:35:34 UTC, Dicebot wrote:
>> It can be forced by pragma(mangle) though. Updated code: [...]
>
> Never heard of pragma(mangle)! Very useful. What role does it play in D? Is it guaranteed implemented on x86 or amd64?
>
> Thanks for the answer, very nice.

It's unrelated to the target architecture, it's just for naming. See dlang.org/abi.html
December 30, 2013
On Monday, 30 December 2013 at 17:46:57 UTC, John Colvin wrote:
> It's unrelated to the target architecture, it's just for naming. See dlang.org/abi.html


Apologies, I was perhaps unclear. I'm just wondering if pragma(mangle) is guaranteed to be implemented, so I can safely put it in portable D. It's not mentioned in http://dlang.org/pragma.html

December 30, 2013
On Monday, 30 December 2013 at 20:04:00 UTC, Carl Sturtivant wrote:
> Apologies, I was perhaps unclear. I'm just wondering if pragma(mangle) is guaranteed to be implemented, so I can safely put it in portable D. It's not mentioned in http://dlang.org/pragma.html

Nature of reference compiler is that anything implemented there is approved as part of spec. I guess one implementing it just forgot to add matching documentation entry as it is relatively new addition.

https://d.puremagic.com/issues/show_bug.cgi?id=11846