Thread overview
why do i need an extern(C): here?
Oct 15, 2020
WhatMeWorry
Oct 15, 2020
Ali Çehreli
Oct 16, 2020
Ali Çehreli
Oct 16, 2020
WhatMeWorry
Oct 16, 2020
Ali Çehreli
Oct 15, 2020
IGotD-
Oct 15, 2020
H. S. Teoh
October 15, 2020
I've go a small DLL and a test module both written in D. Why do I need to use the extern(C)?  Shouldn't both sides be using D name wrangling?

-------------------- mydll.d --------------------------------
module mydll;

extern(C):   // removing or changing to (D): results in error

export
{
    int addSeven(int a, int b) { return a+b+7; }
}


-------------------- user.d --------------------------------
module user;

import core.sys.windows.winbase;
import std.stdio;

void main()
{
    alias addSevenFuncSignature = int function(int, int);

    addSevenFuncSignature  addSeven;

    import core.runtime;
    auto mydll = Runtime.loadLibrary("mydll.dll");

    assert(mydll);

    addSeven = cast(addSevenFuncSignature)  GetProcAddress(mydll, "addSeven");

    int ret = addSeven(2,3);

    writeln("calling addSeven(2,3) = ", addSeven(2,3));

    Runtime.unloadLibrary(mydll);
}

------------------- execution results ------------------------------

c:\D\dmd2\samples\d\mydll>dmd -m64 mydll.d -L/DLL -L/NOENTRY
   Creating library mydll.lib and object mydll.exp

c:\D\dmd2\samples\d\mydll>dmd -m64 user.d

c:\D\dmd2\samples\d\mydll>user.exe
calling addSeven(2,3) = 12


October 15, 2020
On 10/15/20 2:29 PM, WhatMeWorry wrote:

> name wrangling?

Name mangling. :) I don't know the answer but I can hijack your thread.

>      import core.runtime;
>      auto mydll = Runtime.loadLibrary("mydll.dll");

Interesting. I've recently done the same by calling dlopen() and dlsym() directly. Runtime.loadLibrary documentation says "If the library contains a D runtime it will be integrated with the current runtime." That would explain why my program seg-faults for my first tester with the garbage collector signatures in the function call stack. Right? Thanks! :)

Ali

October 15, 2020
On Thursday, 15 October 2020 at 21:29:59 UTC, WhatMeWorry wrote:
>
> I've go a small DLL and a test module both written in D. Why do I need to use the extern(C)?  Shouldn't both sides be using D name wrangling?
>

You have answered your own question. If you're not using extern(C), D just like C++ adds a lot of name mangling which is not "addSeven" but extra characters as well. GetProcAddress which is a Windows call has no idea about D name mangling and therefore will not find the function.
October 15, 2020
On Thu, Oct 15, 2020 at 09:47:16PM +0000, IGotD- via Digitalmars-d-learn wrote:
> On Thursday, 15 October 2020 at 21:29:59 UTC, WhatMeWorry wrote:
> > 
> > I've go a small DLL and a test module both written in D. Why do I need to use the extern(C)?  Shouldn't both sides be using D name wrangling?
> > 
> 
> You have answered your own question. If you're not using extern(C), D just like C++ adds a lot of name mangling which is not "addSeven" but extra characters as well. GetProcAddress which is a Windows call has no idea about D name mangling and therefore will not find the function.

You can use .mangleof to get the mangled name of a D function that you can then lookup with GetProcAddress.


T

-- 
Notwithstanding the eloquent discontent that you have just respectfully expressed at length against my verbal capabilities, I am afraid that I must unfortunately bring it to your attention that I am, in fact, NOT verbose.
October 16, 2020
On 10/15/20 2:42 PM, Ali Çehreli wrote:

> I've recently done the same by calling dlopen() and dlsym()
> directly. Runtime.loadLibrary documentation says "If the library
> contains a D runtime it will be integrated with the current runtime."
> That would explain why my program seg-faults for my first tester with
> the garbage collector signatures in the function call stack.

Replacing dlopen() with Runtime.loadLibrary() did solve the segfault issue for me.

Ali


October 16, 2020
On Friday, 16 October 2020 at 15:14:03 UTC, Ali Çehreli wrote:
> On 10/15/20 2:42 PM, Ali Çehreli wrote:
>
> > I've recently done the same by calling dlopen() and dlsym()
> > directly. Runtime.loadLibrary documentation says "If the
> library
> > contains a D runtime it will be integrated with the current
> runtime."
> > That would explain why my program seg-faults for my first
> tester with
> > the garbage collector signatures in the function call stack.
>
> Replacing dlopen() with Runtime.loadLibrary() did solve the segfault issue for me.
>
> Ali

Isn't dlopen() for Linux and LoadLibrary() for Windows?  Or are you running Windows Subsystem for Linus (WSL) or mingw?


Just to add to the above discussions (for future searchers). I also found a demangle() in std.demangle that I used in the example below.

alias addSevenFuncSignature = int function(int, int);

addSevenFuncSignature  addSeven;
writeln(addSeven.mangleof);
writeln(demangle(addSeven.mangleof));

_D9onlineapp4mainFZ8addSevenPFiiZi
int function(int, int)* onlineapp.main().addSeven

October 16, 2020
On 10/16/20 4:12 PM, WhatMeWorry wrote:

> Isn't dlopen() for Linux

More like dlopen() is for Posix, which means it should be available on Windows as well.

However, as I've discovered, a D shared library cannot be loaded with dlopen() because the main program and the shared library would do their own garbage collection (presumably with separate GC states) without being aware of each other and this won't work. Runtime.loadLibrary() knows to do the right thing and both sides are aware of each other.

> and LoadLibrary() for Windows?

Yes, but I am talking about core.runtime.Runtime.loadLibrary, which should call appropriate functions depending on the operating system.

> Or are you
> running Windows

I run Windows with mild disgust :p only for work-related applications. Otherwise, it's all Linux.

Ali