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?
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.