Dynamically binding to D code using extern(D)
Hipreme
msnmancini at hotmail.com
Thu Sep 30 18:09:46 UTC 2021
I write this post as both a learning tool, a question and an
inquiry.
There are just a lot of drawbacks in trying to do function
exporting while using D.
That interface is absurdly confuse and that is probably why I've
never seen a project here which made an use of extern(D) while
using a DLL.
While I'm making my DLL's generation, there are a lot of pitfalls
that I can feel into.
**Simple Function**
```
module something;
extern(D) export int sum(int a, int b){return a + b;}
```
The correct way to bind to that function would be:
```
module app;
import core.demangle
int function(int a, int b) sum;
void main()
{
sum = cast(typeof(sum))GetProcAddress(someDll,
mangleFunc!(typeof(sum)("something.sum");
}
```
And that should be it for loading a simple function.
Now, lets make our case a bit more complicated:
**Overloaded function**
```
module something;
extern(D) export int add(int a, int b)
{
return a + b;
}
extern(D) export float add(float a, float b)
{
return a+b;
}
```
For loading those functions, the correct way would be
```
module app;
import core.demangle;
int function(int a, int b) sumInt;
float function(float a, float b) sumFloat;
int sum(int a, int b){return sumInt(a, b);}
float sum(float a, float b){return sumFloat(a,b);}
void main()
{
sumInt = cast(typeof(sumInt))GetProcAddress(dll,
mangleFunc!(typeof(sumInt))("something.sum"));
sumFloat = cast(typeof(sumFloat))GetProcAddress(dll,
mangleFunc!(typeof(sumFloat))("something.sum"));
}
```
Notice how much the overall complexity starts to increase as
there seems to be no way to put get the overloads and there
doesn't seem to be any advantage in using extern(D).
**Static Methods**
The only difference from the default functions is that we need to
pass the class name as a module name.
**Static Methods returning user data**
That is mainly the reason I'm writing that post. It made me
really wonder if I should really use extern(D).
This section will use 3 files because after all, there is really
a (consistency?) problem
```
module supertest;
import ultratest;
class SuperTest
{
extern(D) export static SuperTest getter(){return new
SuperTest();}
extern(D) export static UltraTest ultraGetter(){return new
UltraTest();}
import core.demangle;
pragma(msg,
mangleFunc!(typeof(&SuperTest.getter))("supertest.SuperTest.getter"));
//Prints _D9supertest9SuperTest6getterFZCQBeQx
pragma(msg,
mangleFunc!(typeof(&SuperTest.ultraGetter))("supertest.SuperTest.ultraGetter"));
//Prints
_D9supertest9SuperTest11ultraGetterFZC9ultratest9UltraTest
}
```
```
module ultratest;
class UltraTest{}
```
```
module app;
import core.demangle;
void main()
{
//???
}
```
As you can see at module supertest, the pattern seems to break
when returning user data
for another module. From my knowledge, I don't know how could I
get this function, specially because you will need to know: the
module that you're importing the function + the module that where
the userdata is defined for getting it.
It seems pretty insane to work with that.
extern(D) advantages:
-
extern(D) disadvantages:
- Code only callable in D(probably no other language as a
demangler)
- I don't remember seeing any other code before in that post
doing that, so, no documentation at all
- You will need to call the demangler for binding to a symbol,
which in my project, it could make each call to a unique type
from the demangler costs 15KB
- You will need to know the module which you imported your
function
- If your function returns userdata from another function, there
doesn't seem to be any workaround
- Doesn't provide any overloading binding support though the
language has support to overloading
extern(C) advantages:
- Code callable from any language as it is absolutely intuitive
- Well documented
extern(C) disadvantages:
- You will need to declare your function pointer as extern(C) or
it will swap the arguments order.
I have not even entered in the case where I tried overloading
static methods, which I think it would need to declarate aliases
to the static methods typings for actually generating a mangled
name.
I want to know if extern(D) is actually meant to not be touched.
adr said that his use for that was actually when doing
extern(C):
//Funcs defined here
extern(D): //Resets the linkage to the default one
So, there are just too many disadvantages for doing extern(D) for
binding it to any code, I would like to know where we can get
more documentation than what I posted here right now (really,
I've never saw any code binding to an extern(D) code). And I do
believe that is the main reason why people usually don't use
dynamic libs in D, it is just inviable as you would need to
regenerate all the API yourself
More information about the Digitalmars-d-learn
mailing list