Autoconf, Automake, and Libtool: A configure.in for DLLs

| ### 25.4.3 A configure.in for DLLs ``configure.in'` is used to generate the ``configure'` script:
    # Process this file with autoconf to create configure.

    AC_INIT(hello.h)
    AM_CONFIG_HEADER(config.h:config.hin)
    AM_INIT_AUTOMAKE(hello, 1.0)

    AC_PROG_CC
    AM_PROG_CC_STDC
    AC_C_CONST
    AM_PROG_LIBTOOL

    AC_OUTPUT(Makefile)
The ``AC_PROG_CC'` and ``AM_PROG_CC_STDC'` macros in the ``configure.in'` above will conspire to find a suitable compiler for the C code in this example, and to discover any extra switches required to put that compiler into an ANSI mode. I have used the `const` keyword in the sources, so I need to specify the ``AC_C_CONST'` macro, in case the compiler doesn't understand it, and finally I have specified the ``AM_PROG_LIBTOOL'` macro since I want the library to be built with Libtool. In order to set the build environment up we need to create the autogenerated files:
    $ ls
    Makefile.in    hello.c   main.c
    configure.in   hello.h
    $ aclocal
    $ autoheader
    $ libtoolize --force --copy
    $ automake --foreign --add-missing --copy
    automake: configure.in: installing ./install-sh
    automake: configure.in: installing ./mkinstalldirs
    automake: configure.in: installing ./missing
    $ autoconf
    $ ls
    Makefile.am    config.hin     hello.c       ltmain.sh      stamp-h.in
    Makefile.in    config.sub     hello.h       main.c
    aclocal.m4     configure      install-sh    missing
    config.guess   configure.in   ltconfig      mkinstalldirs
If you have already tried to build DLLs with Libtool, you have probably noticed that the first point of failure is during the configuration process. For example, running the new `configure` script you might see:
    ...
    checking if libtool supports shared libraries... yes
    checking if package supports dlls... no
    checking whether to build shared libraries... no
    ...
`libtool` provides a macro, ``AC_LIBTOOL_WIN32_DLL'`, which must be added to a package's ``configure.in'` to communicate to the `libtool` machinery that the package supports DLLs. Without this macro, `libtool` will never try to build a DLL on Windows. Add this macro to ``configure.in'` before the ``AM_PROG_LIBTOOL'` macro, and try again:
    $ make
    cd . && aclocal
    cd . && automake --foreign Makefile
    cd . && autoconf
    ...
    checking if libtool supports shared libraries... yes
    checking if package supports dlls... yes
    checking whether to build shared libraries... yes
    ...
    gcc -DHAVE_CONFIG_H -I. -I. -I. -g -O2 -Wp,-MD,.deps/hello.pp \
    -c  -DDLL_EXPORT -DPIC hello.c -o .libs/hello.lo
    gcc -DHAVE_CONFIG_H -I. -I. -I. -g -O2 -Wp,-MD,.deps/hello.pp \
    -c hello.c -o hello.o >/dev/null 2>&1
    mv -f .libs/hello.lo hello.lo
    ...
    gcc -g -O2 -o ./libs/hello main.o .libs/libimp-hello-0-0-0.a \
    -Wl,--rpath -Wl,/usr/local/lib
    creating hello
    ...
    $ ./hello
    Hello, World!
If you run this and watch the full output of the ``make'` command, Libtool uses a rather contorted method of building DLLs, with several invocations each of `dlltool` and `gcc`. I have omitted these from the example above, since they really are very ugly, and in any case are almost incomprehensible to most people. To see it all in its full horror you can always examine the output after running the commands yourself! In a future release of Cygwin, recent work on the binutils linker by DJ Delorie, will allow `gcc` to link DLLs in a single pass using the same syntax used on other systems to produce shared libraries. Libtool will adopt this method when it becomes available, deprecating the use of `dlltool`. I have extracted the interesting lines from amongst the many calls to `dlltool`(67) and `gcc` generated by `make` in the shell log. The main thing to notice is that we have a ``hello'` binary, which is executable, and which gives the right result when we run it! From the partial log above, it certainly appears that it has built ``libhello'` as a DLL and linked that into ``hello'`, but just to double check we can use `ldd`(68):
    $ libtool --mode=execute ldd ./hello
    lt-hello.exe    -> /tmp/.libs/lt-hello.exe
    libhello-0-0-0.dll      -> /tmp/.libs/libhello-0-0-0.dll
    cygwin1.dll     -> /usr/bin/cygwin1.dll
    kernel32.dll    -> /WINNT/system32/kernel32.dll
    ntdll.dll       -> /WINNT/system32/ntdll.dll
    advapi32.dll    -> /WINNT/system32/advapi32.dll
    user32.dll      -> /WINNT/system32/user32.dll
    gdi32.dll       -> /WINNT/system32/gdi32.dll
    rpcrt4.dll      -> /WINNT/system32/rpcrt4.dll
So now you know how to build and link a simple Windows DLL using GNU Autotools: You add ``-no-undefined'` to the Libtool library ``LDFLAGS'`, and include the ``AC_LIBTOOL_WIN32_DLL'` macro in your ``configure.in'`.

This document was generated by Gary V. Vaughan on February, 8 2006 using texi2html