www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Dll support: testers needed

reply Benjamin Thaut <code benjamin-thaut.de> writes:
I'm currently back on dll support and I'm applying finishing touches to 
my dll support PR. Now I want to know if I missed any corner cases and 
it would be great if a few more people gave the dll support a try.

-To try it out you will need to build dmd, druntime and phobos yourself. 
I'm not going to provide a binary distribution.
-You will need to target the microsoft linker. E.g. either use -m64 or 
-m32mscoff when compiling your programs.
-be warned, the state of the dll support is not final and subject to 
change. There is no garantuee that there won't be any breaking changes 
to dll support.

You can find a quick start guide here: 
http://stuff.benjamin-thaut.de/D/getting_started.html
If you need more information and examples take a look here: 
https://github.com/Ingrater/DIPs/blob/ReviveDIP45/DIPs/DIP45.md

Not all of phobos/druntime has correct export annotations yet as this is 
not the goal of my initial pull request. If you use a function from 
druntime/phobos that does not have a correct export annotation you will 
get a linker error. I'm not interrested in those. I'm interrested in 
cases where export is correctly used and you will still get linker 
errors / incorrect program behavior. So if you encounter a linker error 
first check if the declaration has a export annotation or not. Try 
adding it and see if the error goes away. If it does not go away, report 
it here or send me an e-mail to code at benjamin-thaut.de

If you find anything, small repro cases would be appreciated as it makes 
my life a lot easier.

-- 
Kind Regards
Benjamin Thaut
Jan 06 2018
next sibling parent reply Rubn <where is.this> writes:
Looks good. If you want testers though, providing binaries would 
be beneficial. Compiling dmd/druntime/phobos on Windows can be a 
pain.
Jan 06 2018
parent Benjamin Thaut <code benjamin-thaut.de> writes:
Am 07.01.2018 um 00:42 schrieb Rubn:
 Looks good. If you want testers though, providing binaries would be 
 beneficial. Compiling dmd/druntime/phobos on Windows can be a pain.
I made a binary distribution. I updated http://stuff.benjamin-thaut.de/D/getting_started.html with the details. -- Kind Regards Benjamin Thaut
Jan 07 2018
prev sibling next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
+infinity

Few things I would like answered:

- Why -useShared and not -fPIC?
   - If -useShared why not use it on *nix to turn on -fPIC?
- Why isn't DllIsUsedFromC.no automatically detected?

Regarding C-runtime, yes we need to distribute every version that we 
support on Windows. The compiler will pick the latest (or the installer 
I guess) to use, but we should be able to switch between them. Either 
that or we ship a static lib of Phobos to be linked into a dll upon 
first request of a specific C-runtime.
Jan 06 2018
parent Benjamin Thaut <code benjamin-thaut.de> writes:
Am 07.01.2018 um 03:57 schrieb rikki cattermole:
 +infinity

 Few things I would like answered:

 - Why -useShared and not -fPIC?
    - If -useShared why not use it on *nix to turn on -fPIC?
Because the DIP says that -useshared and -fPIC are loosley comparable. This does not mean that they are the same or interchangeable. In fact they are not. On linux when building a executable that uses a shared library -fPIC is not neccessary, unless your distribution requires position independend code everywhere. On windows on the other hand you will need to pass -useshared when building a executable that uses shared libraries.
 - Why isn't DllIsUsedFromC.no automatically detected?
Because its not possible. I don't know of any way to detect wether a dll is loaded by a c-executable or d-executable. As a result the user has to specify it. The main problem here is that currently D Dlls hijack all threads. This is neccessary because currently there is no shared version of phobos, so the information about the threads can't be shared between multiple D dlls. One possibility would also be to remove the thread hijacking alltogether and require the user to manually add threads that have been created from C. This is also the current state on linux if I'm not mistaken. But doing so would break backwards compatibility.
 Regarding C-runtime, yes we need to distribute every version that we 
support on Windows. The compiler will pick the latest (or the installer I guess) to use, but we should be able to switch between them. Either that or we ship a static lib of Phobos to be linked into a dll upon first request of a specific C-runtime. That really is a problem I'm not going to solve. It is more a problem of distributing dmd and building the installer which is beyond the scope of my current PR. -- Kind Regards Benjamin Thaut
Jan 07 2018
prev sibling next sibling parent reply MrSmith <mrsmith33 yandex.ru> writes:
On Saturday, 6 January 2018 at 19:32:51 UTC, Benjamin Thaut wrote:
 You can find a quick start guide here: 
 http://stuff.benjamin-thaut.de/D/getting_started.html
 If you need more information and examples take a look here: 
 https://github.com/Ingrater/DIPs/blob/ReviveDIP45/DIPs/DIP45.md
Does the implementation support dynamically loaded dlls?
Jan 07 2018
parent Benjamin Thaut <code benjamin-thaut.de> writes:
Am 07.01.2018 um 15:08 schrieb MrSmith:

 Does the implementation support dynamically loaded dlls?
Yes. There is even a test for it -- Kind Regards Benjamin Thaut
Jan 07 2018
prev sibling next sibling parent reply solidstate1991 <laszloszeremi outlook.com> writes:
On Saturday, 6 January 2018 at 19:32:51 UTC, Benjamin Thaut wrote:
 I'm currently back on dll support and I'm applying finishing 
 touches to my dll support PR. Now I want to know if I missed 
 any corner cases and it would be great if a few more people 
 gave the dll support a try.

 -To try it out you will need to build dmd, druntime and phobos 
 yourself. I'm not going to provide a binary distribution.
 -You will need to target the microsoft linker. E.g. either use 
 -m64 or -m32mscoff when compiling your programs.
 -be warned, the state of the dll support is not final and 
 subject to change. There is no garantuee that there won't be 
 any breaking changes to dll support.

 You can find a quick start guide here: 
 http://stuff.benjamin-thaut.de/D/getting_started.html
 If you need more information and examples take a look here: 
 https://github.com/Ingrater/DIPs/blob/ReviveDIP45/DIPs/DIP45.md

 Not all of phobos/druntime has correct export annotations yet 
 as this is not the goal of my initial pull request. If you use 
 a function from druntime/phobos that does not have a correct 
 export annotation you will get a linker error. I'm not 
 interrested in those. I'm interrested in cases where export is 
 correctly used and you will still get linker errors / incorrect 
 program behavior. So if you encounter a linker error first 
 check if the declaration has a export annotation or not. Try 
 adding it and see if the error goes away. If it does not go 
 away, report it here or send me an e-mail to code at 
 benjamin-thaut.de

 If you find anything, small repro cases would be appreciated as 
 it makes my life a lot easier.
I would volunteer, but I don't know how much I can do in my exam session. Maybe in February, until then not much.
Jan 07 2018
parent reply Benjamin Thaut <code benjamin-thaut.de> writes:
Am 08.01.2018 um 00:06 schrieb solidstate1991:
 On Saturday, 6 January 2018 at 19:32:51 UTC, Benjamin Thaut wrote:
 
 I would volunteer, but I don't know how much I can do in my exam 
 session. Maybe in February, until then not much.
Just do some testing whenever you find time, keep monitoring this thread foor upates. -- Kind Regards Benjamin Thaut
Jan 08 2018
parent reply Dylan Graham <dylan.graham2000 gmail.com> writes:
On Monday, 8 January 2018 at 09:01:29 UTC, Benjamin Thaut wrote:
 Am 08.01.2018 um 00:06 schrieb solidstate1991:
 On Saturday, 6 January 2018 at 19:32:51 UTC, Benjamin Thaut 
 wrote:
 
 I would volunteer, but I don't know how much I can do in my 
 exam session. Maybe in February, until then not much.
Just do some testing whenever you find time, keep monitoring this thread foor upates.
I'm waiting on VS2015 and Windows SDK to install. Once that's done, I'll begin testing. Also, thanks a tonne for doing this.
Jan 08 2018
parent reply Dylan Graham <dylan.graham2000 gmail.com> writes:
On Tuesday, 9 January 2018 at 03:50:25 UTC, Dylan Graham wrote:
 On Monday, 8 January 2018 at 09:01:29 UTC, Benjamin Thaut wrote:
 I'm waiting on VS2015 and Windows SDK to install. Once that's 
 done, I'll begin testing.

 Also, thanks a tonne for doing this.
I've done a test that mimics that the planned plugin system for my game. There is a core/engine which is built as a DLL. It exports a class called PluginBase. It also exports a function called getPlugins (to be run from an executable) that searches for plugin DLLs and calls a function from those plugin DLLs that returns their own override of PluginBase. It then runs a few functions on the object and prints the typeid(). The core is built with: dmd -m64 -shared -useshared -version=Shared -H pluginbase.d -L/IMPLIB:pluginbase.lib The resulting pluginbase.di and pluginbase.lib is copied into the directory of Plugin1 which builds against them. Command: dmd -m64 -shared -useshared plugin1.d pluginbase.lib I then made an executable that builds against pluginbase and calls getPlugins(). Command: dmd -m64 -useshared app.d pluginbase.lib pluginbase.dll and plugin1.dll are placed next to the executable. Running it prints this: PS C:\dmd-dll\test\execut> ./app.exe Plugin1 -- (name of plugin defined by overriden class) Hello world from Plugin1 -- (function of that class) plugin1.Plugin1 -- (typeid of that class) It's pretty basic but I'm glad it works. I'll try doing something more advanced.
Jan 08 2018
parent reply Benjamin Thaut <code benjamin-thaut.de> writes:
Am 09.01.2018 um 05:19 schrieb Dylan Graham:
 It's pretty basic but I'm glad it works. I'll try doing something more 
 advanced.
Hi Dylan, I'm glad that it works for you. I'm curios though, why are you using an import library for your plugin? Normally plugins are build without and import library (the -L/IMPLIB parameter) and then loaded dynamically through LoadLibrary by your main executable. This way you can add/remove plugins without the need to recompile your main executable. Usually such plugin systems are done like this: You have some common library that defines shared functionality and the base interfaces such as a Plugin base class or Plugin interface. This common library is build into a dll with import library. You have one ore multiple plugins that link against the common library and implement the plugin interface / plugin base class. Each of these plugins provides a function "getPluginImpl" or something along the lines which can be used to get an instance of the Plugin implementation. You have the main executable, which links against the common library. It dynamically loads the plugin.dlls and calls the getPluginImpl method on them to retrieve the implementation. No import library involved here. What your doing is also a valid use case. It is usually done when link times get to long or if you want to have clean interface between the different subsystems in your application. Your codebase is usually split into multiple dlls each with a import library which are then all used by the main executable. -- Kind Regards Benjamin Thaut
Jan 09 2018
next sibling parent Dylan Graham <dylan.graham2000 gmail.com> writes:
On Tuesday, 9 January 2018 at 08:10:56 UTC, Benjamin Thaut wrote:
 Am 09.01.2018 um 05:19 schrieb Dylan Graham:
 It's pretty basic but I'm glad it works. I'll try doing 
 something more advanced.
Hi Dylan, I'm glad that it works for you. I'm curios though, why are you using an import library for your plugin? Normally plugins are build without and import library (the -L/IMPLIB parameter) and then loaded dynamically through LoadLibrary by your main executable.
In all honesty, I'm not sure. I saw the instructions on your website and just adapted it. Also, please excuse me, I'm fairly new to compiling native programs. I've been using DUB this entire time. With the common library (plugin base) DLL don't I need to generate a .lib for plugin implementations to compile/link against?
 This way you can add/remove plugins without the need to 
 recompile your main executable. Usually such plugin systems are 
 done like this:

 You have some common library that defines shared functionality 
 and the base interfaces such as a Plugin base class or Plugin 
 interface. This common library is build into a dll with import 
 library.

 You have one ore multiple plugins that link against the common 
 library and implement the plugin interface / plugin base class. 
 Each of these plugins provides a function "getPluginImpl" or 
 something along the lines which can be used to get an instance 
 of the Plugin implementation.
Check. I'm doing that.
 You have the main executable, which links against the common 
 library. It dynamically loads the plugin.dlls and calls the 
 getPluginImpl method on them to retrieve the implementation. No 
 import library involved here.
I'm doing that but the getPluginImpl call is done in the common library. The executable is only a bootstrap.
 What your doing is also a valid use case. It is usually done 
 when link times get to long or if you want to have clean 
 interface between the different subsystems in your application. 
 Your codebase is usually split into multiple dlls each with a 
 import library which are then all used by the main executable.
I am doing that. I don't need to recompile anything. I can add as many plugin implementations without recompiling the common library/executable.
Jan 09 2018
prev sibling parent reply MrSmith <mrsmith33 yandex.ru> writes:
Is it possible to put common code in exe, and use that code from 
dlls? Or anything can be exported only by dll?

Is it possible to have circular dependencies between dlls?

Tips for doing dlls with dub?
Jan 09 2018
parent reply Benjamin Thaut <code benjamin-thaut.de> writes:
Am 09.01.2018 um 12:02 schrieb MrSmith:
 Is it possible to put common code in exe, and use that code from dlls? 
 Or anything can be exported only by dll?
You can only export from dlls. I don't know of any use case where exporting from a executable would make sense. No, you can't put common code into a executable and use that code from dlls. Thats not how dlls are designed to work on windows. If you absoutely still want to export from an executable you can still use -L/EXPORT:"mangledSymbolName"
 
 Is it possible to have circular dependencies between dlls?
No. You will get linker errors. Same as in C/C++.
 
 Tips for doing dlls with dub?
Well, first my PR will have to get merged. Then you'll have to wait until a release exists that actually has my changes and then maybe there is support added in dub. Before that I think trying to use dub to create dlls is wasted effort. -- Kind Regards Benjamin Thaut
Jan 09 2018
parent reply Andre Pany <andre s-e-a-p.de> writes:
On Tuesday, 9 January 2018 at 14:43:43 UTC, Benjamin Thaut wrote:
 Am 09.01.2018 um 12:02 schrieb MrSmith:
 Is it possible to put common code in exe, and use that code 
 from dlls? Or anything can be exported only by dll?
You can only export from dlls. I don't know of any use case where exporting from a executable would make sense. No, you can't put common code into a executable and use that code from dlls. Thats not how dlls are designed to work on windows. If you absoutely still want to export from an executable you can still use -L/EXPORT:"mangledSymbolName"
 
 Is it possible to have circular dependencies between dlls?
No. You will get linker errors. Same as in C/C++.
 
 Tips for doing dlls with dub?
Well, first my PR will have to get merged. Then you'll have to wait until a release exists that actually has my changes and then maybe there is support added in dub. Before that I think trying to use dub to create dlls is wasted effort.
I am building a bridge between Delphi and D. At the moment the executable is written in D and the Dll (Firemonkey UI) is written in Delphi. But I think I want to enable also the other way around. The D coding which is then located in the Dll should be able to call Delphi methods located in the executable. The whole idea idea is that all logic is written in D and you only use the Framework (ui) and libraries Delphi provides. I think this might be a valid use case for a Dll calling functionality located in the exe. Kind regards Andre
Jan 09 2018
parent reply Benjamin Thaut <code benjamin-thaut.de> writes:
Am 09.01.2018 um 16:03 schrieb Andre Pany:
 
 I am building a bridge between Delphi and D. At the moment the 
 executable is written in D and the Dll (Firemonkey UI) is written in 
 Delphi. But I think I want to enable also the other way around. The D 
 coding which is then located in the Dll should be able to call Delphi 
 methods located in the executable. The whole idea idea is that all logic 
 is written in D and you only use the Framework (ui) and libraries Delphi 
 provides.
 
 I think this might be a valid use case for a Dll calling functionality 
 located in the exe.
 
 Kind regards
 Andre
First let me say that what you are describing is a very uncommon and ill-advised use case. As such there is not going to be any nice to use workflow to acieve what you are trying to do. Still this doesn't mean that it won't be possible. Why ill-advised? What you're describing is a cyclic dependency between your main executable and your dll written in delphi. If you google for "cyclic dependency dll" you will usually get the advice to break your cylic dependency by splitting your code into more dlls. My personal experience shows the same. Cyclic dependencies in dlls are usually not worth the additional effort and hassle. Also you want to export things from your executable, which is also very uncommon. What you should be doing is having 2 dlls and one executable. You have one common library written in D that is build into a dll. Then you have your delphi library which uses the common.dll. Finally you have your main executable written in D which uses both the common.dll and your delphi.dll. This should make it possibly to break the cycle and get you an easy setup. If you absolutley must do it the way you describe it, its still possible. You will have to compile all modules that export something from your executable with the "-c -shared" parameters. E.g. dmd -m64 -c -shared moduleThatExports1.d moduleThatExports2.d -ofexports.obj Now you link the resulting exports.obj file into your executable by calling dmd again dmd -m64 restOfModules.d exports.obj delphi.lib -ofmain.exe Finally you have to get the handle to your main executable by calling HMODULE handle; GetModuleHandleExA(0, null, &handle); in your delphi dll and then fetching the function pointer for each and every function you want to call from delphi via: GetProcAddress(handle, "mangeledFunctionSymbol") Now finally you can call these functions pointers from delphi and they will call into the D code within your executable. Instead of all that hassle you could instead just have a function in your delphi dll: void recieveFunctionPointer(const(char)* name, void* ptr); which you call for every function that you want to make available from D to delphi. Your delphi code then stores away these pointers depending on the name. That way you don't need to export anything from your executable and can build it normally. Instead of having a function call per function you could obviosuly also use a struct that is defined the same way in D and delphi and contains all relevant functions pointers. -- Kind Regards Benjamin Thaut
Jan 09 2018
parent reply Andre Pany <andre s-e-a-p.de> writes:
On Tuesday, 9 January 2018 at 18:32:24 UTC, Benjamin Thaut wrote:
 Am 09.01.2018 um 16:03 schrieb Andre Pany:
 [...]
First let me say that what you are describing is a very uncommon and ill-advised use case. As such there is not going to be any nice to use workflow to acieve what you are trying to do. Still this doesn't mean that it won't be possible. Why ill-advised? What you're describing is a cyclic dependency between your main executable and your dll written in delphi. If you google for "cyclic dependency dll" you will usually get the advice to break your cylic dependency by splitting your code into more dlls. My personal experience shows the same. Cyclic dependencies in dlls are usually not worth the additional effort and hassle. Also you want to export things from your executable, which is also very uncommon. What you should be doing is having 2 dlls and one executable. You have one common library written in D that is build into a dll. Then you have your delphi library which uses the common.dll. Finally you have your main executable written in D which uses both the common.dll and your delphi.dll. This should make it possibly to break the cycle and get you an easy setup. If you absolutley must do it the way you describe it, its still possible. You will have to compile all modules that export something from your executable with the "-c -shared" parameters. E.g. dmd -m64 -c -shared moduleThatExports1.d moduleThatExports2.d -ofexports.obj Now you link the resulting exports.obj file into your executable by calling dmd again dmd -m64 restOfModules.d exports.obj delphi.lib -ofmain.exe Finally you have to get the handle to your main executable by calling HMODULE handle; GetModuleHandleExA(0, null, &handle); in your delphi dll and then fetching the function pointer for each and every function you want to call from delphi via: GetProcAddress(handle, "mangeledFunctionSymbol") Now finally you can call these functions pointers from delphi and they will call into the D code within your executable. Instead of all that hassle you could instead just have a function in your delphi dll: void recieveFunctionPointer(const(char)* name, void* ptr); which you call for every function that you want to make available from D to delphi. Your delphi code then stores away these pointers depending on the name. That way you don't need to export anything from your executable and can build it normally. Instead of having a function call per function you could obviosuly also use a struct that is defined the same way in D and delphi and contains all relevant functions pointers.
Thanks for your deep analysis. There are several reasons I want to have the exe as Delphi application: 1) I faced some minor (Delphi) IDE/Libraries bugs with having the Delphi gui within a dll. 2) The Delphi IDE provides you the possibility to e.g. easily change the exe icon/attach additional resources to the exe, ... 3) Delphi lets you also create android/iPhone applications. I assume there will be no other way than place the D coding within a shared object for this scenario. I completely agree with you, it is mad. My gut feeling is, you have the greatest benefit from the IDE and convenience if the executable is written in Delphi. I try to support both ways in my library, so the developer can decide. Kind regards Andre
Jan 09 2018
parent Bastiaan Veelo <Bastiaan Veelo.net> writes:
On Tuesday, 9 January 2018 at 20:07:03 UTC, Andre Pany wrote:
 On Tuesday, 9 January 2018 at 18:32:24 UTC, Benjamin Thaut 
 wrote:
 Thanks for your deep analysis. There are several reasons I want 
 to have the exe as Delphi application:
 1) I faced some minor (Delphi) IDE/Libraries bugs with having 
 the Delphi gui within a dll.
 2) The Delphi IDE provides you the possibility to e.g. easily 
 change the exe icon/attach additional resources to the exe, ...
 3) Delphi lets you also create android/iPhone applications. I 
 assume there will be no other way than place the D coding 
 within a shared object for this scenario.
I wrote a mixed language app with interdependent components (no D though). The exe is minimal and does not export anything, its main function is practically a one liner that calls into one of the DLLs; but it could contain a lot more. First only the export library is built for component 1. With it, component 2 is built completely, giving a DLL and export lib. Now the DLL for component 1 can be built and the exe. I don’t know if this is possible in your case, but you may be able to have a Delphi exe wth the things that must be there but no exports, then have a Delphi DLL and D DLL with exports to each other. Not sure if it would make a difference, but this construction works well for us.
Jan 09 2018
prev sibling parent reply Domain <dont_email empty.com> writes:
On Saturday, 6 January 2018 at 19:32:51 UTC, Benjamin Thaut wrote:
 I'm currently back on dll support and I'm applying finishing 
 touches to my dll support PR. Now I want to know if I missed 
 any corner cases and it would be great if a few more people 
 gave the dll support a try.

 [...]
I am glad to see this happen. But my use case is not working: http://forum.dlang.org/post/giywzmvfeuddvmvkrpal forum.dlang.org
Jan 09 2018
parent reply Benjamin Thaut <code benjamin-thaut.de> writes:
Am 10.01.2018 um 05:18 schrieb Domain:
 On Saturday, 6 January 2018 at 19:32:51 UTC, Benjamin Thaut wrote:
 I'm currently back on dll support and I'm applying finishing touches 
 to my dll support PR. Now I want to know if I missed any corner cases 
 and it would be great if a few more people gave the dll support a try.

 [...]
I am glad to see this happen. But my use case is not working: http://forum.dlang.org/post/giywzmvfeuddvmvkrpal forum.dlang.org
Hi Domain, what your describing is a very simple use case and should definitly work. Did you try it using my binary distribution? Please post a repro-case. I don't have the time to rebuild everyones use case and saying "My use case is not working" does not help at all. -- Kind Regards Benjamin Thaut
Jan 10 2018
parent reply Domain <dont_email empty.com> writes:
On Wednesday, 10 January 2018 at 11:30:47 UTC, Benjamin Thaut 
wrote:
 Am 10.01.2018 um 05:18 schrieb Domain:
 On Saturday, 6 January 2018 at 19:32:51 UTC, Benjamin Thaut 
 wrote:
 I'm currently back on dll support and I'm applying finishing 
 touches to my dll support PR. Now I want to know if I missed 
 any corner cases and it would be great if a few more people 
 gave the dll support a try.

 [...]
I am glad to see this happen. But my use case is not working: http://forum.dlang.org/post/giywzmvfeuddvmvkrpal forum.dlang.org
Hi Domain, what your describing is a very simple use case and should definitly work. Did you try it using my binary distribution? Please post a repro-case. I don't have the time to rebuild everyones use case and saying "My use case is not working" does not help at all.
Sorry, my mistake. But I cannot use your binary: D:\>dmd -m64 -shared dll.d -ofdll.dll Error: unrecognized file extension dll
Jan 10 2018
parent reply Benjamin Thaut <code benjamin-thaut.de> writes:
Am 10.01.2018 um 13:39 schrieb Domain:
 
 Sorry, my mistake. But I cannot use your binary:
 
 D:\>dmd -m64 -shared dll.d -ofdll.dll
 Error: unrecognized file extension dll
 
 
This works just fine for me. What is the output when you execute "dmd --version"? -- Kind Regards Benjamin Thaut
Jan 10 2018
next sibling parent reply Domain <dont_email empty.com> writes:
On Wednesday, 10 January 2018 at 13:14:10 UTC, Benjamin Thaut 
wrote:
 Am 10.01.2018 um 13:39 schrieb Domain:
 
 Sorry, my mistake. But I cannot use your binary:
 
 D:\>dmd -m64 -shared dll.d -ofdll.dll
 Error: unrecognized file extension dll
 
 
This works just fine for me. What is the output when you execute "dmd --version"?
I restart my computer, and it can produce dll now. But when I compile exe: dmd -m64 -useshared app.d -ofapp.exe app.obj : error LNK2019: 无法解析的外部符号 _D3std12experimental6logger4core17stdThreadLocalLogFNdNfZCQCeQCdQBsQBo6Logger 该符号在函数 _D3std12experimental6logger4core__T18defaultLogFunctionVEQCdQCcQBrQBn8LogLeveli64Z__TQByVii9VAyaa5_6170702e64VQra8_6170702e6d61696eVQBna15_766f6964206170702e6d61696e2829VQCza3_617 70TQDmZQFwFNfLQDxZv 中被引用 app.obj : error LNK2019: 无法解析的外部符号 _D6object__T8__equalsTxaTxaZQqFNaNbNiNfAxaQdZb,该符号在函数 _D3std5array__T8AppenderTAyaZQo4Data11__xopEqualsFKxSQBzQBy__TQ vTQBpZQCdQBqKxQBaZb 中被引用 app.obj : error LNK2019: 无法解析的外部符号 _D3std12experimental6logger4core14globalLogLevelFNdNiNfZEQCdQCcQBrQBn8LogLevel 该符号在函数 _D3std12experimental6logger4core6Logger__T15memLogFunctionsVEQChQCgQBvQBr8LogLeveli64Z__T7logImplVii9VAyaa5_6170702e64VQra8_6170702e6d61696eVQBna15_766f6964206170702e6d61696e2829VQCza3_6170 0TQDmZQEdMFNfLQDyZv 中被引用 app.obj : error LNK2019: 无法解析的外部符号 _D3std11concurrency7thisTidFNdNfZSQBgQBf3Tid,该符号在函数 _D3std12experimental6logger4core6Logger__T15memLogFunctionsVEQChQCgQBvQBr8LogLeveli64Z__T7logImplVii9VAyaa5_6170702e64VQra8_6170702e6d61696eVQBna15_766f6964206170702e6d61696e2829VQCza3_6170 0TQDmZQEdMFNfLQDyZv 中被引用 app.obj : error LNK2019: 无法解析的外部符号 _D3std8datetime8timezone9LocalTime6opCallFNaNbNeZyCQBxQBwQBqQ k,该符号在函 数 _D3std12experimental6logger4core6Logger__T15memLogFunctionsVEQChQCgQBvQBr8LogLeveli64Z__T7logImplVii9VAyaa5_6170702e64VQra8_6170702e6d61696eVQBna15_766f6964206170702e6d61696e2829VQCza3_6170 0TQDmZQEdMFNfLQDyZv 中被引用 app.obj : error LNK2019: 无法解析的外部符号 _D3std12experimental6logger4core8MsgRange6__ctorMFNcNfCQCbQCaQBpQBl6LoggerZSQCwQCvQCkQCgQCe 该符号在函数 _D3std12experimental6logger4core6Logger__T15memLogFunctionsVEQChQCgQBvQBr8LogLeveli64Z__T7logImplVii9VAyaa5_6170702e64VQra8_6170702e6d61696eVQBna15_766f6964206170702e6d61696e2829VQCza3_6170 0TQDmZQEdMFNfLQDyZv 中被引用 app.obj : error LNK2019: 无法解析的外部符号 _D3std8datetime7systime7SysTime6__ctorMFNaNbNcNflyCQBxQBw8timezone8TimeZoneZSQCxQCwQCqQCl 该符号在函数 _D3std8datetime7systime5Clock__T8currTimeVE4core4time9ClockTypei0ZQBiFNfyCQCuQCt8timezone8TimeZon ZSQDuQDtQDn7SysTime 中被引用 app.obj : error LNK2019: 无法解析的外部符号 _D3std8datetime7systime17FILETIMEToStdTimeFNfMxPS4core3sys7windows7winbase8FILETIMEZl 该符号在函数 _D3std8datetime7systime5Clock__T11currStdTimeVE4core4time9Cl ckTypei0ZQBmFNdNeZl 中被引用 app.obj : error LNK2019: 无法解析的外部符号 _D3std12experimental6logger4core8MsgRange3putMFNfwZv,该符号在函数 _D3std5range10primitives__T5doPutTSQBh12experimental6logger4core8MsgRa geTaZQBxFNfKQBxKaZv 中被引用 app.obj : error LNK2001: 无法解析的外部符号 _D3std8datetime7systime7SysTime6toHashMxFNaNbNiNfZm app.obj : error LNK2001: 无法解析的外部符号 _D3std8datetime7systime7SysTime8opEqualsMxFNaNbNfKxSQByQBxQBrQBmZb app.obj : error LNK2001: 无法解析的外部符号 _D3std8datetime7systime7SysTime8__xopCmpFKxSQBqQBpQBjQBeKxQpZi app.obj : error LNK2001: 无法解析的外部符号 _D3std8datetime7systime7SysTime8toStringMxFNbNfZAya app.exe : fatal error LNK1120: 13 个无法解析的外部命令 Error: linker exited with status 1120 Sources: ///////app.d: import std.experimental.logger; import core.sys.windows.windows; import core.runtime; extern(C) alias void function() startFn; void main() { info("Loading dll1.dll"); auto handle1 = cast(HMODULE)Runtime.loadLibrary("dll1.dll"); auto fp1 = GetProcAddress(handle1, "start"); (cast(startFn)fp1)(); info("Loading dll2.dll"); auto handle2 = cast(HMODULE)Runtime.loadLibrary("dll2.dll"); auto fp2 = GetProcAddress(handle2, "start"); (cast(startFn)fp2)(); } ///////dll1.d import std.stdio; import std.experimental.logger; import core.sys.windows.dll; mixin SimpleDllMain!(DllIsUsedFromC.no); class MyLogger : Logger { this(LogLevel lv) safe { super(lv); } override protected void writeLogMsg(ref LogEntry entry) trusted { writefln("MyLogger: %s", entry.msg); } } export extern(C) void start() { info("dll1 starting"); sharedLog = new MyLogger(LogLevel.info); info("dll1 started"); } ///////dll2.d import std.stdio; import std.experimental.logger; import core.sys.windows.dll; mixin SimpleDllMain!(DllIsUsedFromC.no); export extern(C) void start() { info("dll2 started"); } dmd -m64 app.d -ofapp.exe dmd -m64 -shared dll1.d -ofdll1.dll dmd -m64 -shared dll2.d -ofdll2.dll output: 2018-01-11T12:04:51.635:app.d:main:9 Loading dll1.dll 2018-01-11T12:04:51.894:dll1.d:start:22 dll1 starting MyLogger: dll1 started 2018-01-11T12:04:51.897:app.d:main:14 Loading dll2.dll 2018-01-11T12:04:52.164:dll2.d:start:9 dll2 started I expected: 2018-01-11T12:04:51.635:app.d:main:9 Loading dll1.dll 2018-01-11T12:04:51.894:dll1.d:start:22 dll1 starting MyLogger: dll1 started MyLogger: Loading dll2.dll MyLogger: dll2 started
Jan 10 2018
parent reply Benjamin Thaut <code benjamin-thaut.de> writes:
Am 11.01.2018 um 05:10 schrieb Domain:
 I restart my computer, and it can produce dll now. But when I compile exe:
 dmd -m64 -useshared app.d -ofapp.exe
 
 app.obj : error LNK2019: 无法解析的外部符号 
 _D3std12experimental6logger4core17stdThreadLocalLogFNdNfZCQC
QCdQBsQBo6Logger, 
 该符号在函数 
 _D3std12experimental6logger4core__T18defaultLogFunctionVEQCdQCcQBrQBn8LogLeveli64Z__TQByVii9VAyaa5_6170702e64VQra8_6170702e6d61696eVQBna15_766f6964206170702e6d61696e2829VQCza3_617
70TQDmZQFwFNfLQDxZv 
 中被引用
As I said in the first post, I'm not interrested in linker errors due to missing 'export' annotation. std.experimental.logger does not have an export annotations and therefor will cause linker errors. If you absolutely must use std.experimental.logger you will have to annotate it with 'export' and recompile phobos. The idea behind my initial PR is to build in basic support for dlls, not to fully annotate all of phobos with 'export'.
 
 dmd -m64 app.d -ofapp.exe
 dmd -m64 -shared dll1.d -ofdll1.dll
 dmd -m64 -shared dll2.d -ofdll2.dll
Your command line is wrong. You are missing the -useshared option and therefore your dlls / executable don't share the same version of druntime.
 
 output:
 
 2018-01-11T12:04:51.635:app.d:main:9 Loading dll1.dll
 2018-01-11T12:04:51.894:dll1.d:start:22 dll1 starting
 MyLogger: dll1 started
 2018-01-11T12:04:51.897:app.d:main:14 Loading dll2.dll
 2018-01-11T12:04:52.164:dll2.d:start:9 dll2 started
How can you get the output of your program if it fails to link? -- Kind Regards Benjamin Thaut
Jan 11 2018
next sibling parent Domain <dont_email empty.com> writes:
On Thursday, 11 January 2018 at 18:56:23 UTC, Benjamin Thaut 
wrote:
 Am 11.01.2018 um 05:10 schrieb Domain:
 [...]
As I said in the first post, I'm not interrested in linker errors due to missing 'export' annotation. std.experimental.logger does not have an export annotations and therefor will cause linker errors. If you absolutely must use std.experimental.logger you will have to annotate it with 'export' and recompile phobos. The idea behind my initial PR is to build in basic support for dlls, not to fully annotate all of phobos with 'export'.
 [...]
Your command line is wrong. You are missing the -useshared option and therefore your dlls / executable don't share the same version of druntime.
 [...]
How can you get the output of your program if it fails to link?
I misunderstand what you mean. I thought -useshared is used when I want to use phobos as a dll.
Jan 11 2018
prev sibling parent reply Domain <dont_email empty.com> writes:
On Thursday, 11 January 2018 at 18:56:23 UTC, Benjamin Thaut 
wrote:
 Am 11.01.2018 um 05:10 schrieb Domain:
 [...]
As I said in the first post, I'm not interrested in linker errors due to missing 'export' annotation. std.experimental.logger does not have an export annotations and therefor will cause linker errors. If you absolutely must use std.experimental.logger you will have to annotate it with 'export' and recompile phobos. The idea behind my initial PR is to build in basic support for dlls, not to fully annotate all of phobos with 'export'.
So I cannot use phobos as a static library when I use dll?
Jan 11 2018
parent Benjamin Thaut <code benjamin-thaut.de> writes:
Am 12.01.2018 um 04:02 schrieb Domain:
 On Thursday, 11 January 2018 at 18:56:23 UTC, Benjamin Thaut wrote:
 Am 11.01.2018 um 05:10 schrieb Domain:
 [...]
So I cannot use phobos as a static library when I use dll?
If you have a single D-dll that is used from a C program then you can use phobos as a static library. In all other cases you must use the dll version of phobos otherwise the sharing of objects between dlls/exe doesn't work correctly. -- Kind Regards Benjamin Thaut
Jan 11 2018
prev sibling parent Domain <dont_email empty.com> writes:
On Wednesday, 10 January 2018 at 13:14:10 UTC, Benjamin Thaut 
wrote:
 Am 10.01.2018 um 13:39 schrieb Domain:
 
 Sorry, my mistake. But I cannot use your binary:
 
 D:\>dmd -m64 -shared dll.d -ofdll.dll
 Error: unrecognized file extension dll
 
 
This works just fine for me. What is the output when you execute "dmd --version"?
D:\git\testdll\source>dmd --version DMD64 D Compiler v2.078.0 Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved written by Walter Bright
Jan 10 2018