digitalmars.D.learn - How to call a function from a dll created with d ?
- Vinod KC (36/36) Jul 01 2022 Hi all,
- ryuukk_ (1/1) Jul 01 2022 I think it is `extern(D) void testFunc();`?
- Vinod K Chandran (2/3) Jul 01 2022 Thanks for the reply. But the result is same linker error.
- mw (3/22) Jul 01 2022 I think the problem is the linker looking for dime.testFunc,
- Vinod K Chandran (3/5) Jul 01 2022 Thanks for the reply. What about this `mixin SimpleDllMain;` I
- mw (3/9) Jul 01 2022 Try follow instructions here:
- Vinod K Chandran (3/5) Jul 01 2022 Thanks. So using a `def` file is a must I think. At first, I
- Adam D Ruppe (3/4) Jul 01 2022 no it is not. you just need to mark things export and make sure
- Vinod K Chandran (10/14) Jul 01 2022 Thanks for the reply. These are my questions.
- Ruby The Roobster (4/4) Jul 01 2022 The solution is to remove the extern declaration. That does it
- Vinod KC (2/6) Jul 01 2022 Thank you for the reply. Let me try that.
- =?UTF-8?Q?Ali_=c3=87ehreli?= (19/27) Jul 01 2022 // ...
- Vinod K Chandran (40/43) Jul 02 2022 Hi, Thanks for the reply. I have tried your suggestion. First, I
- apz28 (34/34) Jul 02 2022 Below is working on Windows
- Vinod KC (31/33) Jul 02 2022 Thanks for the reply. Well, I am sorry to say that your
- mw (3/12) Jul 02 2022 Actually, can you create a github repo, I'm sure people will send
- Vinod K Chandran (2/4) Jul 02 2022 Yes I can. I will inform here once I did it.
- frame (39/44) Jul 03 2022 I tried the -H switch. You can't rely on that. I comment the
- cc (6/24) Jul 07 2022 Does importing dimedll into app.d properly NOT link in the
- frame (11/16) Jul 08 2022 IMHO this is the expected behaviour since the compiler comes
- Ruby The Roobster (27/61) Jul 07 2022 First issue - you're using dmd on windows. Dmd gives me errors
- kinke (40/40) Jul 02 2022 With LDC, this is sufficient for this trivial example:
- frame (13/54) Jul 03 2022 Are you sure? You import `testFunc` as normal import, the
Hi all, I have created a dll file with this code. ```d module dimedll; import core.sys.windows.windows; import core.sys.windows.dll; // I don't what is this for. import std.stdio; mixin SimpleDllMain; export void testFunc() { writeln("This is from dll"); } ``` So now I have a dll fie named `dimedll.dll` and a lib file named `dimedll.lib`. Now, I have created a d source file called `dime.d` and wrote this code. ```d import std.stdio; import core.sys.windows.windows; import std.stdio : log = writeln; pragma(lib, "dimedll.lib"); extern void testFunc(); void main() { log("Lets build our own ime"); testFunc(); } ``` Everything seems to be okay. So I called dmd with this command. `dmd -i -run dime.d` But I got this error message. ``` dime.obj : error LNK2019: unresolved external symbol __D4dime8testFuncFZv referenced in function __Dmain dime.exe : fatal error LNK1120: 1 unresolved externals Error: linker exited with status 1120``` How to fix this ?
Jul 01 2022
On Friday, 1 July 2022 at 20:08:45 UTC, ryuukk_ wrote:I think it is `extern(D) void testFunc();`?Thanks for the reply. But the result is same linker error.
Jul 01 2022
On Friday, 1 July 2022 at 19:11:16 UTC, Vinod KC wrote:Hi all, I have created a dll file with this code. ```d module dimedll; export void testFunc() { writeln("This is from dll"); } ``` void main() { log("Lets build our own ime"); testFunc(); } ``` ``` dime.obj : error LNK2019: unresolved external symbol __D4dime8testFuncFZv referenced inI think the problem is the linker looking for dime.testFunc, while your lib function is dimedll.testFunc
Jul 01 2022
On Friday, 1 July 2022 at 21:02:20 UTC, mw wrote:I think the problem is the linker looking for dime.testFunc, while your lib function is dimedll.testFuncThanks for the reply. What about this `mixin SimpleDllMain;` I suspect this.
Jul 01 2022
On Friday, 1 July 2022 at 21:15:50 UTC, Vinod K Chandran wrote:On Friday, 1 July 2022 at 21:02:20 UTC, mw wrote:Try follow instructions here: https://wiki.dlang.org/Win32_DLLs_in_DI think the problem is the linker looking for dime.testFunc, while your lib function is dimedll.testFuncThanks for the reply. What about this `mixin SimpleDllMain;` I suspect this.
Jul 01 2022
On Friday, 1 July 2022 at 22:22:42 UTC, mw wrote:Try follow instructions here: https://wiki.dlang.org/Win32_DLLs_in_DThanks. So using a `def` file is a must I think. At first, I thought I can skip that.
Jul 01 2022
On Friday, 1 July 2022 at 22:32:24 UTC, Vinod K Chandran wrote:So using a `def` file is a must I think.no it is not. you just need to mark things export and make sure names match (including module name)
Jul 01 2022
On Friday, 1 July 2022 at 22:38:17 UTC, Adam D Ruppe wrote:On Friday, 1 July 2022 at 22:32:24 UTC, Vinod K Chandran wrote:Thanks for the reply. These are my questions. 1. `mixin` statement in dll file - Do I need to export it ? 2. There is only one function and that is marked with `export`. 3. Name of the module which I wrote the dll code is `dimedll`. So my dll file's name is `dimedll.dll`. And my lib file's name is `dimedll.lib`. No change in names. 4. Name of my exported function is `testFunc`. And the same name is used in `extern` keyword and the calling site. So where do I check again ?So using a `def` file is a must I think.no it is not. you just need to mark things export and make sure names match (including module name)
Jul 01 2022
The solution is to remove the extern declaration. That does it for me, and it prints the expected output. No need for a .def file, unless you are using optlink as your linker (which, as a matter of principle, you should use lld or ld instead.)
Jul 01 2022
On Saturday, 2 July 2022 at 00:23:20 UTC, Ruby The Roobster wrote:The solution is to remove the extern declaration. That does it for me, and it prints the expected output. No need for a .def file, unless you are using optlink as your linker (which, as a matter of principle, you should use lld or ld instead.)Thank you for the reply. Let me try that.
Jul 01 2022
On 7/1/22 12:11, Vinod KC wrote: The following function is dimedll.testFunc:```d module dimedll;// ...export void testFunc() { writeln("This is from dll"); } ```We suspect the name of the file that defines main() is dime.d.extern void testFunc();That symbol belongs to this module, which is implied to be 'module dime'.testFunc();That's a call to dime.testFunc, which does not exist. With the provided information alone, the following is what I would do: 1) This dll must have a .di file, which should contain the following: // dimedll.di void testFunc(); (.di files can be generated by dmd with its -H command line switch.) 2) Provide dimedll.di as your library's interface file (a la "header file"). 3) The users of this dll should import that .di file (declaring the functions themselves won't work): import dimedll; void main() { // ... } Ali
Jul 01 2022
On Saturday, 2 July 2022 at 01:05:25 UTC, Ali Çehreli wrote:3) The users of this dll should import that .di file (declaring the functions themselves won't work): AliHi, Thanks for the reply. I have tried your suggestion. First, I compiled my dll's source code with `-H` switch as you said. Then I got the header file with this content. ```d // D import file generated from dimedll.d module dimedll; import core.sys.windows.windows; import core.sys.windows.dll; import std.stdio; mixin SimpleDllMain!(); export void testFunc(); ``` So far so good. Then I change my `dime.d` source file like this. ```d import dimedll; void main() { log("Lets build our own ime"); testFunc(); } ``` Unfortunately, I got this error message. dime.obj : error LNK2019: unresolved external symbol __imp___D7dimedll8testFuncFZv referenced in function __Dmain dime.obj : error LNK2001: unresolved external symbol __D7dimedll12__ModuleInfoZ dime.exe : fatal error LNK1120: 2 unresolved externals Error: linker exited with status 1120 Then I have tested with `dimedll.testFunc()` instead of `testFunc()` at the calling site. Then also I got an error message like this. dime.obj : error LNK2019: unresolved external symbol __imp___D7dimedll8testFuncFZv referenced in function __Dmain dime.obj : error LNK2001: unresolved external symbol __D7dimedll12__ModuleInfoZ dime.exe : fatal error LNK1120: 2 unresolved externals Error: linker exited with status 1120 I want to test this with ddemangle.exe, but there is no proper documentation for that tool. So I don't know how to use that tool. So Actually I am stuck.
Jul 02 2022
Below is working on Windows --file dimedll.d: module dimedll; import core.sys.windows.windows; import core.sys.windows.dll; import std.stdio; mixin SimpleDllMain; export void testFunc() { writeln("This is from dll"); } --file dime.d: import core.sys.windows.windows; import std.stdio; import dimedll; pragma(lib, "dimedll.lib"); void main() { writeln("Lets call testFunc()"); testFunc(); } --file dimedll.di: module dimedll; extern void testFunc(); --file dimedll.def LIBRARY "dimedll.dll" EXETYPE NT SUBSYSTEM WINDOWS CODE SHARED EXECUTE DATA WRITE -- command lines in sequence: -- there should be files as first dmd: dimedll.exp, dimedll.lib, dimedll.obj dmd -of=dimedll.dll dimedll.d dimedll.def dmd dime.d dimedll.di
Jul 02 2022
On Saturday, 2 July 2022 at 14:32:11 UTC, apz28 wrote:dmd -of=dimedll.dll dimedll.d dimedll.def dmd dime.d dimedll.diThanks for the reply. Well, I am sorry to say that your suggestions resulted in failure. First of all, when I used this command -- ` dmd -of=dimedll.dll dimedll.d dimedll.def` I got this error message- `Error: unrecognized file extension dll`. So I avoided the `-of=dimedll.dll` part. Then I compiled it with this command - `dmd -H dimedll.d dimedll.def` And I got some warnings. Here are they. ```d dimedll.def(2) : warning LNK4017: EXETYPE statement not supported for the target platform; ignored dimedll.def(3) : warning LNK4017: SUBSYSTEM statement not supported for the target platform; ignored dimedll.def(4) : warning LNK4017: CODE statement not supported for the target platform; ignored dimedll.def(4) : warning LNK4017: DATA statement not supported for the target platform; ignored Creating library dimedll.lib and object dimedll.exp ``` I know all of them are from my `def` file. Anyways, I stepped forward and tried to run the main file with this dll & lib. So I ran this command. - `dmd dime.d dimedll.di`. But I got this error message. ```d dime.obj : error LNK2001: unresolved external symbol __D7dimedll12__ModuleInfoZ dime.exe : fatal error LNK1120: 1 unresolved externals Error: linker exited with status 1120 ```
Jul 02 2022
On Saturday, 2 July 2022 at 20:43:41 UTC, Vinod KC wrote:On Saturday, 2 July 2022 at 14:32:11 UTC, apz28 wrote:Actually, can you create a github repo, I'm sure people will send you a working PR.dmd -of=dimedll.dll dimedll.d dimedll.def dmd dime.d dimedll.diThanks for the reply. Well, I am sorry to say that your suggestions resulted in failure. First of all, when I used this command -- ` dmd -of=dimedll.dll dimedll.d dimedll.def` I got this error message- `Error: unrecognized file extension dll`.
Jul 02 2022
On Saturday, 2 July 2022 at 21:36:50 UTC, mw wrote:Actually, can you create a github repo, I'm sure people will send you a working PR.Yes I can. I will inform here once I did it.
Jul 02 2022
On Saturday, 2 July 2022 at 20:43:41 UTC, Vinod KC wrote:But I got this error message. dime.obj : error LNK2001: unresolved external symbol __D7dimedll12__ModuleInfoZ dime.exe : fatal error LNK1120: 1 unresolved externals Error: linker exited with status 1120I tried the -H switch. You can't rely on that. I comment the lines that shouldn't be there - then it should work: dimedll.di ```d // D import file generated from 'dimedll.d' module dimedll; // import core.sys.windows.dll; // import std.stdio; // mixin SimpleDllMain!(); export void testFunc(); ``` dimedll.d: ```d module dimedll; import core.sys.windows.dll; import std.stdio; mixin SimpleDllMain; export void testFunc() { writeln("This is from dll"); } ``` app.d: ```d module app; import dimedll; import std.stdio; import std.stdio : log = writeln; pragma(lib, "dimedll.lib"); void main() { log("Lets build our own ime"); testFunc(); } ``` You should be able to change contents in the DLL and run the executable wihtout re-compiling (the library file should be round ~2kB). PS: ddemangle just waits for your input. You copy in the mangled symbol like `__D7dimedll12__ModuleInfoZ` and press enter ;-)
Jul 03 2022
On Sunday, 3 July 2022 at 09:43:20 UTC, frame wrote:app.d: ```d module app; import dimedll; import std.stdio; import std.stdio : log = writeln; pragma(lib, "dimedll.lib"); void main() { log("Lets build our own ime"); testFunc(); } ``` You should be able to change contents in the DLL and run the executable wihtout re-compiling (the library file should be round ~2kB). PS: ddemangle just waits for your input. You copy in the mangled symbol like `__D7dimedll12__ModuleInfoZ` and press enter ;-)Does importing dimedll into app.d properly NOT link in the functions that are exported to the DLL? When I tried something similar with dmd, I had to create a .di file containing just stubs, otherwise it looked like it was ignoring the DLL and compiling in an additional copy of each fuction.
Jul 07 2022
On Thursday, 7 July 2022 at 17:29:42 UTC, cc wrote:Does importing dimedll into app.d properly NOT link in the functions that are exported to the DLL? When I tried something similar with dmd, I had to create a .di file containing just stubs, otherwise it looked like it was ignoring the DLL and compiling in an additional copy of each fuction.IMHO this is the expected behaviour since the compiler comes before the linker and `pragma(lib)` is a linker directive, so if dimedll.di is not present it looks for dimedll.d instead and just compiles the code. The link to DLL is only present in the actual lib-file and only used by the linker. The pitfall with DMD is that the automatic generated di-file is not usable as it contains a mixin that is meant for the DLL but not the application that links it, resulting in _ModuleInfoZ error while trying.
Jul 08 2022
On Saturday, 2 July 2022 at 20:43:41 UTC, Vinod KC wrote:On Saturday, 2 July 2022 at 14:32:11 UTC, apz28 wrote:First issue - you're using dmd on windows. Dmd gives me errors about the ModuleInfo, while LDC doesn't. [This is the LDC download link.](https://github.com/ldc-developers/ldc/releases/download/v1.29.0/ldc2-1.29.0-w ndows-multilib.exe) Next, change dimedll.d to the following: ```d module dimedll; export void testFunc() { import std.stdio; writeln("Lets build our own ime."); } ``` and dime.d to the following: ```d import dimedll; //In case you ever write more functions for dimedll.d; pragma(lib, "dimedll.lib"); void main() { testFunc(); } ``` Then run ```ldc2 -shared dimedll.d``` and right after that ```ldc2 dime.d```. If I didn't make a mistake in writing this (I tested it on my own system), it should output a working program that prints the expected output when ran.dmd -of=dimedll.dll dimedll.d dimedll.def dmd dime.d dimedll.diThanks for the reply. Well, I am sorry to say that your suggestions resulted in failure. First of all, when I used this command -- ` dmd -of=dimedll.dll dimedll.d dimedll.def` I got this error message- `Error: unrecognized file extension dll`. So I avoided the `-of=dimedll.dll` part. Then I compiled it with this command - `dmd -H dimedll.d dimedll.def` And I got some warnings. Here are they. ```d dimedll.def(2) : warning LNK4017: EXETYPE statement not supported for the target platform; ignored dimedll.def(3) : warning LNK4017: SUBSYSTEM statement not supported for the target platform; ignored dimedll.def(4) : warning LNK4017: CODE statement not supported for the target platform; ignored dimedll.def(4) : warning LNK4017: DATA statement not supported for the target platform; ignored Creating library dimedll.lib and object dimedll.exp ``` I know all of them are from my `def` file. Anyways, I stepped forward and tried to run the main file with this dll & lib. So I ran this command. - `dmd dime.d dimedll.di`. But I got this error message. ```d dime.obj : error LNK2001: unresolved external symbol __D7dimedll12__ModuleInfoZ dime.exe : fatal error LNK1120: 1 unresolved externals Error: linker exited with status 1120 ```
Jul 07 2022
With LDC, this is sufficient for this trivial example: ```d module dimedll; export void testFunc() { // export only needed when compiling with `-fvisibility=hidden` import std.stdio; writeln("This is from dll"); } ``` `ldc2 -shared dimedll.d` generates import lib + DLL. ```d import dimedll : testFunc; pragma(lib, "dimedll"); void main() { import std.stdio; writeln("Lets build our own ime"); testFunc(); } ``` `ldc2 -link-defaultlib-shared dime.d` generates the .exe and makes it share the druntime/Phobos DLLs with `dimedll.dll`. (More complex cases might need `-dllimport=all`). ``` C:\temp\dllTest>dime Lets build our own ime This is from dll C:\temp\dllTest>dir … 07/02/2022 03:54 PM 155 dime.d 07/02/2022 03:57 PM 18,432 dime.exe 07/02/2022 03:57 PM 19,679 dime.obj 07/02/2022 03:56 PM 162 dimedll.d 07/02/2022 03:57 PM 20,480 dimedll.dll 07/02/2022 03:57 PM 7,534 dimedll.exp 07/02/2022 03:56 PM 13,036 dimedll.lib 07/02/2022 03:57 PM 21,233 dimedll.obj ``` On Posix, the only difference is that one would have to link `libdimedll.{so,dylib}` explicitly via `-L-ldimedll` instead of the `pragma(lib)`.
Jul 02 2022
On Saturday, 2 July 2022 at 14:06:03 UTC, kinke wrote:With LDC, this is sufficient for this trivial example: ```d module dimedll; export void testFunc() { // export only needed when compiling with `-fvisibility=hidden` import std.stdio; writeln("This is from dll"); } ``` `ldc2 -shared dimedll.d` generates import lib + DLL. ```d import dimedll : testFunc; pragma(lib, "dimedll"); void main() { import std.stdio; writeln("Lets build our own ime"); testFunc(); } ``` `ldc2 -link-defaultlib-shared dime.d` generates the .exe and makes it share the druntime/Phobos DLLs with `dimedll.dll`. (More complex cases might need `-dllimport=all`). ``` C:\temp\dllTest>dime Lets build our own ime This is from dll C:\temp\dllTest>dir … 07/02/2022 03:54 PM 155 dime.d 07/02/2022 03:57 PM 18,432 dime.exe 07/02/2022 03:57 PM 19,679 dime.obj 07/02/2022 03:56 PM 162 dimedll.d 07/02/2022 03:57 PM 20,480 dimedll.dll 07/02/2022 03:57 PM 7,534 dimedll.exp 07/02/2022 03:56 PM 13,036 dimedll.lib 07/02/2022 03:57 PM 21,233 dimedll.obj ``` On Posix, the only difference is that one would have to link `libdimedll.{so,dylib}` explicitly via `-L-ldimedll` instead of the `pragma(lib)`.This is from dllAre you sure? You import `testFunc` as normal import, the compiler ignores `pragma(lib)` - that's only for the linker which will ignore it too since the symbol is already in your executable. If you can run your exectuable without dimedll.dll present, then the function is **not** statically linked in. A static linked function should generate a very small lib-file and yours look too big to me. I don't know about LDC but with DMD I struggle with static linked DLLs because the library generated does not link to the DLL. To get right results, I need to pass the linker flag -`-L=/IMPLIB` (or `-L=/DLL` for 64bit) to generate a lib-file that is really linked to the DLL later.
Jul 03 2022
On Sunday, 3 July 2022 at 08:15:38 UTC, frame wrote:Are you sure?100%, just try yourself.You import `testFunc` as normal import, the compiler ignores `pragma(lib)` - that's only for the linker which will ignore it too since the symbol is already in your executable.Why would the symbol be defined in the executable? `dimedll.d` isn't compiled into the executable.A static linked function should generate a very small lib-file and yours look too big to me.The code is using Phobos std.stdio.writeln templates, so the ~20 KB for both exe and DLL are to be expected and IMO absolutely acceptable.I don't know about LDC but with DMD I struggle with static linked DLLs because the library generated does not link to the DLL. To get right results, I need to pass the linker flag -`-L=/IMPLIB` (or `-L=/DLL` for 64bit) to generate a lib-file that is really linked to the DLL later.DMD's DLL support is waaay behind LDC's, especially once stuff gets more interesting than trivial examples.
Jul 03 2022
On Sunday, 3 July 2022 at 12:54:45 UTC, kinke wrote:On Sunday, 3 July 2022 at 08:15:38 UTC, frame wrote:Yeah, I tried LDC and there are differences: The library file generated by LDC contains the link to the DLL. The library file generated by DMD is missing that link. So linking the DMD library would embed the symbol from the library - that was my confusion with your example. Only the -H switch or manual linker command generates a valid link to the DLL with DMD but then it's missing all the other library contents (also it needs `SimpleDllMain` or bails out linking errors to `_calloc` and Windows symbols) :\ Also the -H switch doesn't work correctly. Without supplying -L/DLL flag too, I get link error: ``` 1561: entry point must be defined ```Are you sure?100%, just try yourself. Why would the symbol be defined in the executable? `dimedll.d` isn't compiled into the executable. The code is using Phobos std.stdio.writeln templates, so the ~20 KB for both exe and DLL are to be expected and IMO absolutely acceptable. DMD's DLL support is waaay behind LDC's, especially once stuff gets more interesting than trivial examples.
Jul 03 2022
On Sunday, 3 July 2022 at 16:48:52 UTC, frame wrote:Only the -H switch or manual linker command generates a valid link to the DLL with DMD but then it's missing all the other library contents (also it needs `SimpleDllMain` or bails out linking errors to `_calloc` and Windows symbols) :\`dmd -shared` / `dmd -H -shared` seems to work too (library contains link to DLL). Don't know why I had in mind that it would fail - maybe it did in the past. However both DMD and LDC produces questionable header files for this task.
Jul 04 2022