Thread overview
D2 __gshared and compatibility with D1
Jan 24, 2010
Stanislav Blinov
Jan 24, 2010
Mike Wey
Jan 25, 2010
Stanislav Blinov
January 24, 2010
Hello,

As some of you might know, there is a great package for D called Derelict (Derelict2 now actually). It provides bindings for several interesting C libraries like SDL, OpenGL and FreeType. The key point of Derelict is that it is designed to work exclusively with dynamic libraries. To achieve this, it provides a bunch of function pointers for  every library, and these pointers are bound to function addresses when dynamic library is actually loaded. Simple example:

extern(C) void function() someLibFunction;

//...
void main()
{
   DerelictSomeLib.load(); // this call will load dynamic library and initialize someLibFunction

   someLibFunction();

}

Another key point of Derelict is compatibility with both D1 and D2. But for current D2, someLibFunction will be initialized only for the thread that called DerelictSomeLib.load(), because the pointer itself is thread-local, thus all other threads will also need to call DerelictSomeLib.load(), which looks like a gap in compatibility. So basically it would require to enclose function pointers  in __gshared block, and here comes the problem: there is no __gshared in D1, so mixins should be used to keep compatibility.

I proposed a solution which is based on 'templating' function pointers, that is, putting them into a parameterless template, and then mixing this template in like this:

// for simplicity, no further version checking provided, but for
// dmd we would also need to check compiler version here
version (D_Version2)
{
    mixin("__gshared { mixin FunctionPointers; }");
}
else
{
    mixin FunctionPointers;
}

It works fine, but author and maintainer of Derelict is somewhat skeptical about templates (and thus he's against applying this solution), and actually I agree with him that this approach has a significant impact on compile times, especially for libraries with lots of functions like OpenGL.

Is there some other way of __gshared'ing a set of data without breaking compatibility with D1? Current D2 syntax allows __gshared import, but it  has no effect on imported module (and I don't think it should, seems more like an inconsistency to me).
January 24, 2010
On 01/24/2010 05:13 PM, Stanislav Blinov wrote:
> Hello,
>
> As some of you might know, there is a great package for D called
> Derelict (Derelict2 now actually). It provides bindings for several
> interesting C libraries like SDL, OpenGL and FreeType. The key point of
> Derelict is that it is designed to work exclusively with dynamic
> libraries. To achieve this, it provides a bunch of function pointers for
> every library, and these pointers are bound to function addresses when
> dynamic library is actually loaded. Simple example:
>
> extern(C) void function() someLibFunction;
>
> //...
> void main()
> {
> DerelictSomeLib.load(); // this call will load dynamic library and
> initialize someLibFunction
>
> someLibFunction();
>
> }
>
> Another key point of Derelict is compatibility with both D1 and D2. But
> for current D2, someLibFunction will be initialized only for the thread
> that called DerelictSomeLib.load(), because the pointer itself is
> thread-local, thus all other threads will also need to call
> DerelictSomeLib.load(), which looks like a gap in compatibility. So
> basically it would require to enclose function pointers in __gshared
> block, and here comes the problem: there is no __gshared in D1, so
> mixins should be used to keep compatibility.
>
> I proposed a solution which is based on 'templating' function pointers,
> that is, putting them into a parameterless template, and then mixing
> this template in like this:
>
> // for simplicity, no further version checking provided, but for
> // dmd we would also need to check compiler version here
> version (D_Version2)
> {
> mixin("__gshared { mixin FunctionPointers; }");
> }
> else
> {
> mixin FunctionPointers;
> }
>
> It works fine, but author and maintainer of Derelict is somewhat
> skeptical about templates (and thus he's against applying this
> solution), and actually I agree with him that this approach has a
> significant impact on compile times, especially for libraries with lots
> of functions like OpenGL.
>
> Is there some other way of __gshared'ing a set of data without breaking
> compatibility with D1? Current D2 syntax allows __gshared import, but it
> has no effect on imported module (and I don't think it should, seems
> more like an inconsistency to me).

With GtkD we define a function that returns an empty string or one containing __gshared depending on the dmd version, and then mixes that in with the function pointers, like so:

version(D_Version2)
{
	string gshared() { return "__gshared "; }
}
else
{
	char[] gshared() { return ""; }
}

mixin( gshared ~ "large string containing the function pointers" );

It does increase the compile time a little.

-- 
Mike Wey
January 25, 2010
Mike Wey wrote:
> With GtkD we define a function that returns an empty string or one containing __gshared depending on the dmd version, and then mixes that in with the function pointers

Thank you, that is an interesting option.