Building and Using DLLs
DLLs are Dynamic Link Libraries, which means that they're linked
into your program at run time instead of build time. There are three
parts to a DLL:
the exports
the code and data
the import library
The code and data are the parts you write - functions,
variables, etc. All these are merged together, like if you were
building one big object files, and put into the dll. They are not
put into your .exe at all.
The exports is a list of functions and variables that the
dll makes available to other programs. Think of this as the list of
"public" symbols, the rest being hidden.
Note that ld's default behaviour is to export all
global symbols, if there otherwise wouldn't be any exported symbols
(i.e. because you haven't specified a def file or made any export
annotations). (See --export-all-symbols in the
ld man page for more details.)
This list can be in a module definition (.def) file, which you can write by hand
with a text editor, but it's also possible to have it generated automatically
from the functions and variables in your code, by annotating the declarations
with __attribute__ ((dllexport)).
If you're making these annotations on the declarations in a header which is
also installed to be included by users of your library, you probably want to
use macros to do the right thing and increase portability. See this example for details.
The import library is a regular UNIX-like .a library,
but it only contains the tiny bit of information ("a stub") needed to tell the
OS how your program interacts with ("imports") the dll. This information is
linked into your .exe.
Refer to the section of the ld
manual discussing Win32 PE specifics for more details.
Building DLLs
This page gives only a few simple examples of gcc's DLL-building
capabilities. To begin an exploration of the many additional options,
see the gcc documentation and website, currently at
http://gcc.gnu.org/
Let's go through a simple example of how to build a dll.
For this example, we'll use a single file
myprog.c for the program
(myprog.exe) and a single file
mydll.c for the contents of the dll
(mydll.dll).
Say you want to build this minimal function in
mydll.c:
#include <stdio.h>
int
hello()
{
printf ("Hello World!\n");
}
First compile mydll.c to the object
mydll.o:
gcc -c mydll.c
Then, tell gcc that it is building a shared library:
gcc -shared -o mydll.dll mydll.o -Wl,--out-implib libmydll.a
That's it! You now have the dll (mydll.dll) and the
import library (libmydll.a).
In fact, --out-implib is optional in this simple example,
because ld can automatically generate import stubs when
told to link directly to a .dll. (See --enable-auto-import in
the ld man page for more details.)
To finish up the example, you can now link to the dll with a simple program,
myprog.c:
int
main ()
{
hello ();
}
Then link to your dll with a command like:
gcc -o myprog myprog.c -L./ -lmydll
Try it out:
$ ./myprog
Hello World!
However, if you are building a dll for installation,
you will probably want to use a more complex syntax:
gcc -shared -o cyg${module}.dll \
-Wl,--out-implib=lib${module}.dll.a \
-Wl,--whole-archive ${objs_libs} -Wl,--no-whole-archive \
${dependency_libs}
The name of your library is ${module}, prefixed with
cyg for the DLL and lib for the
import library. Cygwin DLLs use the cyg prefix to
differentiate them from native-Windows MinGW DLLs.
${objs_libs} are all your object files, bundled together in
static libs or single object files
${dependency_libs} are static or import libs you need to link
against, e.g '-lpng -lz -L/usr/local/special -lmyspeciallib'
.
When the import library is installed into /usr/lib, it
can be linked to with just -l${module}. The dll itself is
installed into /usr/bin so it can be found on
PATH by the loader when a linked .exe is run.
dlltool
Historically, the process for building a dll with gcc and
binutils wasn't so simple, and the
dlltool tool was used:
To create the exports section of the dll, from the module definition file
or by scanning object files.
To generate the import library.
(See the dlltool man page for more details.)
Linking Against Foreign DLLs
If you have an existing DLL already, you need to build a
Cygwin-compatible import library. If you have the source to compile
the DLL, see for details on having
gcc build one for you. If you do not have the
source or a supplied working import library, you can get most of
the way by creating a .def file with these commands (you might need to
do this in bash for the quoting to work
correctly):
echo EXPORTS > foo.def
nm foo.dll | grep ' T _' | sed 's/.* T _//' >> foo.def
Note that this will only work if the DLL is not stripped.
Otherwise you will get an error message: "No symbols in
foo.dll".
Once you have the .def file, you can create
an import library from it like this:
dlltool --def foo.def --dllname foo.dll --output-lib foo.a