www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - why do i need an extern(C): here?

reply WhatMeWorry <kheaser gmail.com> writes:
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
Oct 15 2020
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Oct 15 2020
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 10/15/20 2:42 PM, Ali =C3=87ehreli 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=20 issue for me. Ali
Oct 16 2020
parent reply WhatMeWorry <kheaser gmail.com> writes:
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
Oct 16 2020
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Oct 16 2020
prev sibling parent reply IGotD- <nise nise.com> writes:
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.
Oct 15 2020
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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.
Oct 15 2020