DLL's and D

Mike Parker aldacron at gmail.com
Wed Mar 14 22:06:18 PDT 2012


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?
>
>
Again, you don't import modules "from a DLL". Modules are 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.


More information about the Digitalmars-d-learn mailing list