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 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 contains a list of functions and variables that the dll makes available to other programs. Think of this as the list of "global" symbols, the rest being hidden. Normally, you'd create this list by hand with a text editor, but it's possible to do it automatically from the list of functions in your code. The dlltool program creates the exports section of the dll from your text file of exported symbols.

The import library is a regular UNIX-like .a library, but it only contains the tiny bit of information needed to tell the OS how your program interacts with ("imports") the dll. This information is linked into your .exe. This is also generated by dlltool.

Building DLLs

OK, 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).

Now compile everything to objects:

gcc -c myprog.c
gcc -c mydll.c

Unfortunately, the process for building a dll is, well, convoluted. You have to run five commands, like this:

gcc -s -Wl,--base-file,mydll.base -o mydll.dll mydll.o -Wl,-e,_mydll_init@12 
dlltool --base-file mydll.base --def mydll.def --output-exp mydll.exp --dllname mydll.dll
gcc -s -Wl,--base-file,mydll.base,mydll.exp -o mydll.dll mydll.o -Wl,-e,_mydll_init@12
dlltool --base-file mydll.base --def mydll.def --output-exp mydll.exp --dllname mydll.dll
gcc -Wl,mydll.exp -o mydll.dll mydll.o -Wl,-e,_mydll_init@12

The extra steps give dlltool the opportunity to generate the extra sections (exports and relocation) that a dll needs. After this, you build the import library:

dlltool --def mydll.def --dllname mydll.dll --output-lib mydll.a

Now, when you build your program, you link against the import library:

gcc -o myprog myprog.o mydll.a

Note that we linked with -e _mydll_init@12. This tells the OS what the DLL's "entry point" is, and this is a special function that coordinates bringing the dll to life withing the OS. The minimum function looks like this:

#include <windows.h>

int WINAPI
mydll_init(HANDLE h, DWORD reason, void *foo)
{
  return 1;
}  

Linking Against DLLs

If you have an existing DLL already, you need to build a Cygwin-compatible import library (The supplied ones should work, but you might not have them) to link against. Unfortunately, there is not yet any tool to do this automatically. However, 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