www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to setup DLL and EXE projects in one VS solution

reply Igor <stojkovic.igor gmail.com> writes:
At the moment I have:

EXEProject:
   app.d - it does loadlibrary of dllproj and uses data structures 
defined in dllproj.d (it imports dllproj). On the file system 
this file is under <solutiondir>/platform/win32/ and is defined 
as module win32.app;

DLLProject
   dllproj.d - exports functions and contains data structures 
those function use. On file system this file is under 
<solutiondir>/source and is defined as module dllproj;

EXEProject depends on DLLProject. DLL project compiles and builds 
DLL fine but, of course EXE project breaks with an error:

module dllproj is in file dllproj.d which cannot be read.

I could just copy all the structs from dllproj.d to app.d and 
remove the import and I guess it would all work but there has to 
be a better way to structure code so structs are only written in 
one place?
May 17
next sibling parent reply solidstate1991 <laszloszeremi outlook.com> writes:
On Wednesday, 17 May 2017 at 16:56:13 UTC, Igor wrote:
 At the moment I have:

 EXEProject:
   app.d - it does loadlibrary of dllproj and uses data 
 structures defined in dllproj.d (it imports dllproj). On the 
 file system this file is under <solutiondir>/platform/win32/ 
 and is defined as module win32.app;

 DLLProject
   dllproj.d - exports functions and contains data structures 
 those function use. On file system this file is under 
 <solutiondir>/source and is defined as module dllproj;

 EXEProject depends on DLLProject. DLL project compiles and 
 builds DLL fine but, of course EXE project breaks with an error:

 module dllproj is in file dllproj.d which cannot be read.

 I could just copy all the structs from dllproj.d to app.d and 
 remove the import and I guess it would all work but there has 
 to be a better way to structure code so structs are only 
 written in one place?
I think you should make a binding for your DLL file. On the other hand I successfully set up a static library and an application in the same solution (now it has 2 apps, one is my map editor and file converter, the other is a window layout editor, going to add a third one for testing other functions later on) by adding the engine's sources and library files to the app.
May 17
parent reply Igor <stojkovic.igor gmail.com> writes:
On Wednesday, 17 May 2017 at 17:48:50 UTC, solidstate1991 wrote:
 I think you should make a binding for your DLL file. On the
 other hand I successfully set up a static library and an 
 application in the same solution (now it has 2 apps, one is my 
 map editor and file converter, the other is a window layout 
 editor, going to add a third one for testing other functions 
 later on) by adding the engine's sources and library files to 
 the app.
What exactly do mean by "binding"? If I understand the rest you are saying that I could just use "Add existing item" to add the dllproj.d file to EXEProject as well, but that would cause all of the code from it to be linked in the EXE and I only want that code in the DLL. I should also mention that I don't want to statically bind to DLL using a lib file because I want to be able to reload the DLL while the application is running.
May 17
parent reply Igor <stojkovic.igor gmail.com> writes:
On Wednesday, 17 May 2017 at 18:03:04 UTC, Igor wrote:
 What exactly do mean by "binding"?

 If I understand the rest you are saying that I could just use 
 "Add existing item" to add the dllproj.d file to EXEProject as 
 well, but that would cause all of the code from it to be linked 
 in the EXE and I only want that code in the DLL.

 I should also mention that I don't want to statically bind to 
 DLL using a lib file because I want to be able to reload the 
 DLL while the application is running.
I managed to get it to work by extracting all common structs to dllprojInterface.d module that sits at <solutionDir>/source/dllprojInterface.d on the file system but is added to both projects in the solution. I am still wondering if there is a better solution? Also I am wondering if using extern(C) as opposed to extern(D) only affects name mangling or am I losing some DLang possibilities since I am only calling DLang DLL from DLang EXE?
May 17
parent MGW <mgw yandex.ru> writes:
On Wednesday, 17 May 2017 at 19:48:42 UTC, Igor wrote:
 On Wednesday, 17 May 2017 at 18:03:04 UTC, Igor wrote:
 What exactly do mean by "binding"?
Also I am wondering if using extern(C) as opposed to extern(D) only affects name mangling or am I losing some DLang possibilities since I am only calling DLang DLL from DLang EXE?
Look at these materials, there can be they will are useful. https://vk.com/vk_dlang?z=photo-471951_456239025%2Fwall-471951_2095 https://www.youtube.com/watch?time_continue=2&v=HTgJaRRfLPk
May 18
prev sibling parent reply Rainer Schuetze <r.sagitario gmx.de> writes:
On 17.05.2017 18:56, Igor wrote:
 At the moment I have:

 EXEProject:
   app.d - it does loadlibrary of dllproj and uses data structures
 defined in dllproj.d (it imports dllproj). On the file system this file
 is under <solutiondir>/platform/win32/ and is defined as module win32.app;

 DLLProject
   dllproj.d - exports functions and contains data structures those
 function use. On file system this file is under <solutiondir>/source and
 is defined as module dllproj;

 EXEProject depends on DLLProject. DLL project compiles and builds DLL
 fine but, of course EXE project breaks with an error:

 module dllproj is in file dllproj.d which cannot be read.

 I could just copy all the structs from dllproj.d to app.d and remove the
 import and I guess it would all work but there has to be a better way to
 structure code so structs are only written in one place?
You have to add an import path to the folder with dllproj inside to the project configuration of the exeproject. If you want to limit the imported code to the declarations, you can enable "generate interface headers" and add an import path to these instead. Sharing data or resources between executable and DLL is currently limited to separate ownership as each binary contains its own copy of the runtime. (There is currently work being done to have a shared runtime, though). You might also run into other cross module dependencies...
May 18
parent reply Igor <stojkovic.igor gmail.com> writes:
On Thursday, 18 May 2017 at 07:10:54 UTC, Rainer Schuetze wrote:
 You have to add an import path to the folder with dllproj 
 inside to the project configuration of the exeproject.

 If you want to limit the imported code to the declarations, you 
 can enable "generate interface headers" and add an import path 
 to these instead.

 Sharing data or resources between executable and DLL is 
 currently limited to separate ownership as each binary contains 
 its own copy of the runtime. (There is currently work being 
 done to have a shared runtime, though). You might also run into 
 other cross module dependencies...
I tried just adding import paths to project and to di files and although compilation passes I still get link errors like: error LNK2019: unresolved external symbol _D10handmade_h10game_input6__initZ (handmade_h.game_input.__init) referenced in function _D8platform5win324main9myWinMainFPvPvPaiZi (int platform.win32.main.myWinMain(void*, void*, char*, int)) where game_input is a struct in interface file. I also tried adding the di file to the exeproject but it still doesn't work. It seems VisualD doesn't add di files to compiler invocation arguments like it does with *.d and *.def files.
May 18
next sibling parent Mike Parker <aldacron gmail.com> writes:
On Thursday, 18 May 2017 at 07:53:02 UTC, Igor wrote:

 I tried just adding import paths to project and to di files and 
 although compilation passes I still get link errors like:

 error LNK2019: unresolved external symbol 
 _D10handmade_h10game_input6__initZ 
 (handmade_h.game_input.__init) referenced in function 
 _D8platform5win324main9myWinMainFPvPvPaiZi (int 
 platform.win32.main.myWinMain(void*, void*, char*, int))

 where game_input is a struct in interface file. I also tried 
 adding the di file to the exeproject but it still doesn't work. 
 It seems VisualD doesn't add di files to compiler invocation 
 arguments like it does with *.d and *.def files.
.di files don't need to be passed to the compiler. They are neither compiled nor linked. The whole point of them is that they only provide the declarations, not the implementations. You still need to link to a compiled implementation, either in the form of an object or library file. I've never used Visual D (or DMD for that matter) to create a DLL, but I assume an import library should have been produced along with the DLL. Are you linking to it in your executable project?
May 18
prev sibling parent reply Rainer Schuetze <r.sagitario gmx.de> writes:
On 18.05.2017 09:53, Igor wrote:
 On Thursday, 18 May 2017 at 07:10:54 UTC, Rainer Schuetze wrote:
 You have to add an import path to the folder with dllproj inside to
 the project configuration of the exeproject.

 If you want to limit the imported code to the declarations, you can
 enable "generate interface headers" and add an import path to these
 instead.

 Sharing data or resources between executable and DLL is currently
 limited to separate ownership as each binary contains its own copy of
 the runtime. (There is currently work being done to have a shared
 runtime, though). You might also run into other cross module
 dependencies...
I tried just adding import paths to project and to di files and although compilation passes I still get link errors like: error LNK2019: unresolved external symbol _D10handmade_h10game_input6__initZ (handmade_h.game_input.__init) referenced in function _D8platform5win324main9myWinMainFPvPvPaiZi (int platform.win32.main.myWinMain(void*, void*, char*, int))
That's what I meant with "other cross module dependencies". In this case it might work if you export _D10handmade_h10game_input6__initZ from your DLL with the help of a def-file, but that's not something that scales well. This talk will give you some details on the complications involved: https://www.youtube.com/watch?v=MQRHxI2SrYM
May 18
parent Igor <stojkovic.igor gmail.com> writes:
On Thursday, 18 May 2017 at 18:00:02 UTC, Rainer Schuetze wrote:
 That's what I meant with "other cross module dependencies". In 
 this case it might work if you export 
 _D10handmade_h10game_input6__initZ from your DLL with the help 
 of a def-file, but that's not something that scales well.

 This talk will give you some details on the complications 
 involved: https://www.youtube.com/watch?v=MQRHxI2SrYM
Thanks for the link Rainer. I actually watched that a few days ago but it didn't help me understand what I just figured out. It slipped my mind that structs in D are not just structs like the ones in C. In D they have default initializer which is actually a function and as you said I am not exporting that function and it doesn't scale well to hunt all hidden functions that you need to export for all common datatypes. Even if I did, since I am loading DLL and its functions dynamically using GetProcAddress, how could I even tell D to use loaded function pointer as initialization function for a type... Anyway I will stick with the solution of using a separate file where all common datatypes are defined in both projects and see how far I get with it.
May 18