5. Notes on Windows Support

While libtool has been written to bridge gaps in the support and implementation of shared libraries across operating systems, its design is centred around UNIX style libraries. Support for PE DLL (Portable Executable Dynamic Linking Library) is available when using the MinGW compiler suite, but requires some special considerations.

5.1. Explicit Symbol Tables

The first thing to know about PE DLLs is that, unlike UNIX shared objects, these require explicit tables for both imported and exported symbols. These can be declared in the code by using GCC's function attributes, by using symbol export options or by relying on linker options that makes it behave more like a UNIX system.

Different solutions have different advantages and problems, for instance relying on the linker hiding these quirks is convenient, but might have performance impact, while marking the imports and exports explicitly in the code is more convoluted, but has no performance impact. Discussing these solutions is outside the scope of this documentation.

5.2. Undefined Symbols

Because of the explicit nature of the table of imported symbols, it is not possible to leave a symbol in a PE DLL undefined at link time, to be satisfied at runtime, as it is instead possible with most UNIX shared objects.

It is possible to instruct libtool to not allow unbound undefined symbols when linking a shared library by using -no-undefined:

lib_LTLIBRARIES = libfoo.la
libfoo_la_LIBADD = -lws2_32
libfoo_la_LDFLAGS = -no-undefined

5.3. Opt-In Initialization

Modern MinGW toolchain makes it very easy to not have to explicitly design a shared library to work as a PE DLL, but libtool was developed at time when this was not possible, so it does, by default, refuse to build PE DLLs even when using newer versions of the toolchain.

To enable support for building PE DLLs, it is necessary to opt-in during the libtool initialization (LT_INIT):

dnl configure.ac
LT_INIT([win32-dll])

5.4. Library Version Support

In Section 4, “Library Versioning” the description assumes UNIX semantics for library version handling. PE and Windows do not support the same concept of versions or DT_SONAME, so only the actual filename of the library is used in determining which library to load.

Because of this reason, the final filename of the produced DLL file contains the calculated single-number version of the library (the same as the version number used for DT_SONAME.) If you want a filename that does not contain a version, you should use -avoid-version.

Example 3.8. Library versions for PE DLL

libfoo_la_LDFLAGS = -no-undefined -version-info 2:4:1

These parameters would produce a library named libfoo.so.1.1.4 (with libfoo.so.1 being the DT_SONAME) on Linux and libfoo-1.dll on Microsoft Windows.