www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - DLL's and D

reply "Chris Pons" <cmpons gmail.com> writes:
I haven't used DLL's much, especially one I've built on my own, 
so guidance would be appreciated.

I'm trying to figure out how to build a DLL which was written in 
D but i'm not sure i'm doing this right.

I'm using VS2010 and Visual D. Visual D has a template for Dll's 
in D, so I used that to create a new project.

The DLL compiles just fine, but i'm having trouble even getting 
import to work with it. I was following the How-To on this page, 
http://dlang.org/dll.html#Dcode , but I can't even get import to 
work.

With import, is that supposed to reference the name of the DLL? 
So if I had one named math.dll, I would write import math.dll?

Right now i'm getting an error, "Error: module test is in file 
test.d which cannot be read".

Also, what exactly is different between the dynamic load and 
static link in the link above?

Would I need to load the DLL for every module that imports it?

Do I need to use the export keyword for every class/function/etc 
that is meant to be used outside of the DLL?

Also, the DLL i'm trying to make, has several modules, can I 
import a specific module from the dll? Like, import math.calculus 
if calculus was a module in the math DLL?
Mar 14 2012
next sibling parent Mike Parker <aldacron gmail.com> writes:
On 3/15/2012 12:26 PM, Chris Pons wrote:
 I haven't used DLL's much, especially one I've built on my own, so
 guidance would be appreciated.

 I'm trying to figure out how to build a DLL which was written in D but
 i'm not sure i'm doing this right.

 I'm using VS2010 and Visual D. Visual D has a template for Dll's in D,
 so I used that to create a new project.

 The DLL compiles just fine, but i'm having trouble even getting import
 to work with it. I was following the How-To on this page,
 http://dlang.org/dll.html#Dcode , but I can't even get import to work.

 With import, is that supposed to reference the name of the DLL? So if I
 had one named math.dll, I would write import math.dll?

You are misunderstanding what the import statement does. It has absolutely nothing to do with linked libraries or DLLs. It works at the source level. In the example, the source module that is used to compile the DLL is called mydll.d (so is the DLL, but that's irrelevant). Then, in the program that uses it, you use 'import mydll;' to make the declarations in that source module visible to the compiler. For this to work, mydll.d has to be the import path, either relative to test.d in the example, or somewhere you specify with the -I switch. The actual DLL file has no part in this process. It becomes involved later, in the link step. So if your math DLL has source modules named, for example, math/vector.d and math/matrix.d, *those* are what you import in your code. ======== import math.vector; import math.matrix; ======== As long as those modules are somewhere on the import path, that's all you need. The compiler doesn't know or care about the DLL itself at this point.
 Also, what exactly is different between the dynamic load and static link
 in the link above?

I assume you already understand how to link static libraries to a program -- you pass it to the linker. When using DMD, we typically pass it to the compiler and it hands it off to the linker for us: dmd mymodule.d someLibrary.lib That's the only way to make the symbols in a static library available to the executable at runtime -- those symbols must be compiled into the executable. A DLL is not compiled into the executable. It is loaded at runtime. This can be done in two ways: by the operating system (static load), or manually by the executable (dynamic load). In the example, you compile mydll.d and mydll.def with the following command: dmd -ofmydll.dll -L/IMPLIB mydll.d dll.d mydll.def This results in mydll.dll and mydll.lib. Now, assuming mydll.lib is in the same directory as test.d, you can use this command to create an executable that will use static loading: dmd test.d mydll.lib The actual symbols of mydll are in mydll.dll. mydll.lib, in this case, does not contain those symbols. Instead, it contains the necessary information for the OS to load the DLL into memory. So when the executable is launched, the OS sees that information, then looks for mydll.dll automatically. For dynamic loading, you don't link with mydll.lib. Instead, you have to implement some extra code in your program to load the DLL and any symbols you need via the Win32 API. The last example on that page does just that. It uses Runtime.loadLibrary (which, under the hood, uses the Win32 function LoadLibrary) to load the DLL. It then loads the getMyClass function using the Win32 function GetProcAddress. Note that it uses the fully mangled name of the function to do so. So, to dynamically load the mydll example, you would add code to test.d to load mydll.dll and to load the pointer for the print function. To compile, you would do this: dmd test.d You no longer need to link with mydll.lib, since you are loading the library manually (dynamically).
 Would I need to load the DLL for every module that imports it?

No. Once the executable is compiled, the concept of modules essentially disappears. Everything is loaded into memory. The DLL is loaded into the executable's address space exactly one time. This makes the symbols available to everything in the same process. Even if you were to manually load the DLL multiple times with Runtime.loadLibrary, the OS would only actually load it once. I believe you've used Derelict, yes? When you call something like DerelictSDL2.load(), Derelict dynamically loads the SDL2 DLL into memory. You only need to call it at one point in your program. After that, it's available to everything in your program. But you still need to import the derelict.sdl2.sdl module into every module uses it so that the compiler knows which declarations are available for you to use. Source modules are used at compile time and must be imported into every module that uses them. DLLs are used at runtime and are only loaded into memory once. I suggest you read up on the difference between compilation, linkage, and execution of a program for the reasons behind all of this to become more clear.
 Do I need to use the export keyword for every class/function/etc that is
 meant to be used outside of the DLL?

Unfortunately, it's not possible to export D classes from DLLs. So you don't need the export keyword on classes. But you do need it on all of the functions and variables that should be visible outside of the DLL. This is exactly what is demonstrated in the section, 'D Code calling D code in DLLs' of that page you linked above.
 Also, the DLL i'm trying to make, has several modules, can I import a
 specific module from the dll? Like, import math.calculus if calculus was
 a module in the math DLL?

used by the compiler at compile time. If you have class Foo in bar.d, you have to import bar into any module where you want to use the Foo class. Otherwise, the compiler doesn't even know that the Foo class exists. So, by importing math.calculus any given module, you are telling the compiler which source declarations exist and are available for that module to use. The compiler uses all of that information to compile all of the symbols into object files. At runtime, we are no longer concerned with source declarations, but with binary symbols that are loaded in memory. Some of those symbols will be part of the executable file (either compiled in one step or statically linked). Some will be part of a DLL that is loaded into memory separately from the executable. But none of them have anything to do with the import statement. I hope that helps.
Mar 14 2012
prev sibling next sibling parent "Chris Pons" <cmpons gmail.com> writes:
Yes, this is a lot more clear, thanks.

On Thursday, 15 March 2012 at 05:06:16 UTC, Mike Parker wrote:
 On 3/15/2012 12:26 PM, Chris Pons wrote:
 I haven't used DLL's much, especially one I've built on my 
 own, so
 guidance would be appreciated.

 I'm trying to figure out how to build a DLL which was written 
 in D but
 i'm not sure i'm doing this right.

 I'm using VS2010 and Visual D. Visual D has a template for 
 Dll's in D,
 so I used that to create a new project.

 The DLL compiles just fine, but i'm having trouble even 
 getting import
 to work with it. I was following the How-To on this page,
 http://dlang.org/dll.html#Dcode , but I can't even get import 
 to work.

 With import, is that supposed to reference the name of the 
 DLL? So if I
 had one named math.dll, I would write import math.dll?

You are misunderstanding what the import statement does. It has absolutely nothing to do with linked libraries or DLLs. It works at the source level. In the example, the source module that is used to compile the DLL is called mydll.d (so is the DLL, but that's irrelevant). Then, in the program that uses it, you use 'import mydll;' to make the declarations in that source module visible to the compiler. For this to work, mydll.d has to be the import path, either relative to test.d in the example, or somewhere you specify with the -I switch. The actual DLL file has no part in this process. It becomes involved later, in the link step. So if your math DLL has source modules named, for example, math/vector.d and math/matrix.d, *those* are what you import in your code. ======== import math.vector; import math.matrix; ======== As long as those modules are somewhere on the import path, that's all you need. The compiler doesn't know or care about the DLL itself at this point.
 Also, what exactly is different between the dynamic load and 
 static link
 in the link above?

I assume you already understand how to link static libraries to a program -- you pass it to the linker. When using DMD, we typically pass it to the compiler and it hands it off to the linker for us: dmd mymodule.d someLibrary.lib That's the only way to make the symbols in a static library available to the executable at runtime -- those symbols must be compiled into the executable. A DLL is not compiled into the executable. It is loaded at runtime. This can be done in two ways: by the operating system (static load), or manually by the executable (dynamic load). In the example, you compile mydll.d and mydll.def with the following command: dmd -ofmydll.dll -L/IMPLIB mydll.d dll.d mydll.def This results in mydll.dll and mydll.lib. Now, assuming mydll.lib is in the same directory as test.d, you can use this command to create an executable that will use static loading: dmd test.d mydll.lib The actual symbols of mydll are in mydll.dll. mydll.lib, in this case, does not contain those symbols. Instead, it contains the necessary information for the OS to load the DLL into memory. So when the executable is launched, the OS sees that information, then looks for mydll.dll automatically. For dynamic loading, you don't link with mydll.lib. Instead, you have to implement some extra code in your program to load the DLL and any symbols you need via the Win32 API. The last example on that page does just that. It uses Runtime.loadLibrary (which, under the hood, uses the Win32 function LoadLibrary) to load the DLL. It then loads the getMyClass function using the Win32 function GetProcAddress. Note that it uses the fully mangled name of the function to do so. So, to dynamically load the mydll example, you would add code to test.d to load mydll.dll and to load the pointer for the print function. To compile, you would do this: dmd test.d You no longer need to link with mydll.lib, since you are loading the library manually (dynamically).
 Would I need to load the DLL for every module that imports it?

No. Once the executable is compiled, the concept of modules essentially disappears. Everything is loaded into memory. The DLL is loaded into the executable's address space exactly one time. This makes the symbols available to everything in the same process. Even if you were to manually load the DLL multiple times with Runtime.loadLibrary, the OS would only actually load it once. I believe you've used Derelict, yes? When you call something like DerelictSDL2.load(), Derelict dynamically loads the SDL2 DLL into memory. You only need to call it at one point in your program. After that, it's available to everything in your program. But you still need to import the derelict.sdl2.sdl module into every module uses it so that the compiler knows which declarations are available for you to use. Source modules are used at compile time and must be imported into every module that uses them. DLLs are used at runtime and are only loaded into memory once. I suggest you read up on the difference between compilation, linkage, and execution of a program for the reasons behind all of this to become more clear.
 Do I need to use the export keyword for every 
 class/function/etc that is
 meant to be used outside of the DLL?

Unfortunately, it's not possible to export D classes from DLLs. So you don't need the export keyword on classes. But you do need it on all of the functions and variables that should be visible outside of the DLL. This is exactly what is demonstrated in the section, 'D Code calling D code in DLLs' of that page you linked above.
 Also, the DLL i'm trying to make, has several modules, can I 
 import a
 specific module from the dll? Like, import math.calculus if 
 calculus was
 a module in the math DLL?

source files used by the compiler at compile time. If you have class Foo in bar.d, you have to import bar into any module where you want to use the Foo class. Otherwise, the compiler doesn't even know that the Foo class exists. So, by importing math.calculus any given module, you are telling the compiler which source declarations exist and are available for that module to use. The compiler uses all of that information to compile all of the symbols into object files. At runtime, we are no longer concerned with source declarations, but with binary symbols that are loaded in memory. Some of those symbols will be part of the executable file (either compiled in one step or statically linked). Some will be part of a DLL that is loaded into memory separately from the executable. But none of them have anything to do with the import statement. I hope that helps.

Mar 15 2012
prev sibling next sibling parent "Chris Pons" <cmpons gmail.com> writes:
Ok, I've actually run into another problem. I've decided to use a 
static library, since my project is small. I have added the path 
to the static library's .lib file in my project properties, just 
like with derelict2. However, I'm not sure how to use import 
properly.

The library in question is in location (relative to my project) 
Libraries/Math/math.lib.

If a module in math.lib is matrix, i've tried import declarations 
like:

import Libraries.Math.math.matrix; //probably very wrong
import math.matrix;
import matrix;

I tried to look at derelict2 for an example, and the VisualD 
project file there, since it created .lib files. The VS 2010 
solution file was in project/visuald/DerelictSDL(etc), and each 
project refernces modules in Derelict2\DerelictSDL\derelict\sdl\ 
(for example). So it makes sense that the import would be import 
derelict.sdl.sdl to import sdl.d.

This just lead me to believe that import matrix or import 
math.matrix should work.

Am I wrong in assuming that the library contains the D code I 
need to use? So I would not be trying to import the .d file I 
used to construct the static library?
Mar 15 2012
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Mar 15, 2012 at 09:16:45PM +0100, Chris Pons wrote:
 Ok, I've actually run into another problem. I've decided to use a
 static library, since my project is small. I have added the path to
 the static library's .lib file in my project properties, just like
 with derelict2. However, I'm not sure how to use import properly.

The import statement *always* works with D files. Well, technically, you can use a .di file generated by the compiler for your library, but it's basically a reduced form of the library D code. But in either case, you need to import the library D (or Di) file, not the .lib file. The compiler itself doesn't even care about .lib files until it has finished compilation and moved on to the linking stage.
 The library in question is in location (relative to my project)
 Libraries/Math/math.lib.
 
 If a module in math.lib is matrix, i've tried import declarations
 like:
 
 import Libraries.Math.math.matrix; //probably very wrong

It's correct, albeit a bit ugly. To alleviate the ugliness, you can tell the compiler where the "root" directory for the library is supposed to be. For example, if you invoked dmd with -ILibraries/Math, then you'll be able to say: import math.matrix; and the compiler will know to look for Libraries/Math/math/matrix.d. [...]
 This just lead me to believe that import matrix or import math.matrix
 should work.

Correct. Provided you specify the right -I option to the compiler.
 Am I wrong in assuming that the library contains the D code I need to
 use? So I would not be trying to import the .d file I used to
 construct the static library?

The .lib file contains the *compiled* form of the library, which is no longer D code but machine code. So it can't be used with import. The import statement needs either the original library .d file, or the reduced .di generated by the compiler's -H option. Hope this helps. T -- ASCII stupid question, getty stupid ANSI.
Mar 15 2012
prev sibling next sibling parent "Chris Pons" <cmpons gmail.com> writes:
Yes thank you. That cleared this up.

On Thursday, 15 March 2012 at 22:08:18 UTC, H. S. Teoh wrote:
 On Thu, Mar 15, 2012 at 09:16:45PM +0100, Chris Pons wrote:
 Ok, I've actually run into another problem. I've decided to 
 use a
 static library, since my project is small. I have added the 
 path to
 the static library's .lib file in my project properties, just 
 like
 with derelict2. However, I'm not sure how to use import 
 properly.

The import statement *always* works with D files. Well, technically, you can use a .di file generated by the compiler for your library, but it's basically a reduced form of the library D code. But in either case, you need to import the library D (or Di) file, not the .lib file. The compiler itself doesn't even care about .lib files until it has finished compilation and moved on to the linking stage.
 The library in question is in location (relative to my project)
 Libraries/Math/math.lib.
 
 If a module in math.lib is matrix, i've tried import 
 declarations
 like:
 
 import Libraries.Math.math.matrix; //probably very wrong

It's correct, albeit a bit ugly. To alleviate the ugliness, you can tell the compiler where the "root" directory for the library is supposed to be. For example, if you invoked dmd with -ILibraries/Math, then you'll be able to say: import math.matrix; and the compiler will know to look for Libraries/Math/math/matrix.d. [...]
 This just lead me to believe that import matrix or import 
 math.matrix
 should work.

Correct. Provided you specify the right -I option to the compiler.
 Am I wrong in assuming that the library contains the D code I 
 need to
 use? So I would not be trying to import the .d file I used to
 construct the static library?

The .lib file contains the *compiled* form of the library, which is no longer D code but machine code. So it can't be used with import. The import statement needs either the original library .d file, or the reduced .di generated by the compiler's -H option. Hope this helps. T

Mar 15 2012
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 3/15/12, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:
 It's correct, albeit a bit ugly. To alleviate the ugliness, you can tell
 the compiler where the "root" directory for the library is supposed to
 be. For example, if you invoked dmd with -ILibraries/Math, then you'll
 be able to say:

 	import math.matrix;

What import path you need to pass depends on the *module declaration* and not the relative location of some module from a directory (this isn't C/C++). If the module declaration is "module Math.math.matrix;" you'll never be able to do "import math.matrix;", you will always have to import it with "import Math.math.matrix;" regardless of any -I switch. And then when you know the module declaration, figuring out the import switch is easy. It's always one directory UP of the base package.
Mar 15 2012