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.
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.
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
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])
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.