Autoconf, Automake, and Libtool: 24.4 Example: The Full Pull

| ## 24.4 Example: The Full Pull Suppose instead that I wanted to fully autoconfiscate `zip`. Let's ignore for now that `zip` can build on systems to which the GNU Autotools have not been ported, like TOPS-20---perhaps a big problem back in the real world. The first step should always be to run `autoscan`. `autoscan` is a program which examines your source code and then generates a file called ``configure.scan'` which can be used as a rough draft of a ``configure.in'`. `autoscan` isn't perfect, and in fact in some situations can generate a ``configure.scan'` which `autoconf` won't directly accept, so you should examine this file by hand before renaming it to ``configure.in'`. `autoscan` doesn't take into account macro names used by your program. For instance, if `autoscan` decides to generate a check for ``<fcntl.h>'`, it will just generate ordinary `autoconf` code which in turn might define ``HAVE_FCNTL_H'` at `configure` time. This just means that `autoscan` isn't a panacea -- you will probably have to modify your source to take advantage of the code that `autoscan` generates. Here is the ``configure.scan'` I get when I run `autoscan` on `zip`:
    dnl Process this file with autoconf to produce a configure script.
    AC_INIT(bits.c)

    dnl Checks for programs.
    AC_PROG_AWK
    AC_PROG_CC
    AC_PROG_CPP
    AC_PROG_INSTALL
    AC_PROG_LN_S
    AC_PROG_MAKE_SET

    dnl Checks for libraries.
    dnl Replace `main' with a function in -lx:
    AC_CHECK_LIB(x, main)

    dnl Checks for header files.
    AC_HEADER_DIRENT
    AC_HEADER_STDC
    AC_CHECK_HEADERS(fcntl.h malloc.h sgtty.h strings.h sys/ioctl.h \
    termio.h unistd.h)

    dnl Checks for typedefs, structures, and compiler characteristics.
    AC_C_CONST
    AC_TYPE_SIZE_T
    AC_STRUCT_ST_BLKSIZE
    AC_STRUCT_ST_BLOCKS
    AC_STRUCT_ST_RDEV
    AC_STRUCT_TM

    dnl Checks for library functions.
    AC_PROG_GCC_TRADITIONAL
    AC_FUNC_MEMCMP
    AC_FUNC_MMAP
    AC_FUNC_SETVBUF_REVERSED
    AC_TYPE_SIGNAL
    AC_FUNC_UTIME_NULL
    AC_CHECK_FUNCS(getcwd mktime regcomp rmdir strstr)

    AC_OUTPUT(acorn/makefile unix/Makefile Makefile atari/Makefile)
As you can see, this isn't suitable for immediate use as ``configure.in'`. For instance, it generates several ``Makefile'`s which we know we won't need. At this point there are two things to do in order to fix this file. First, we must fix outright flaws in ``configure.scan'`, add checks for libraries, and the like. For instance, we might also add code to see if we are building on Windows and set a variable appropriately:
    AC_CANONICAL_HOST
    case "$target" in
      *-cygwin* | *-mingw*)
        INCLUDES='-I$(srcdir)/win32'
        ;;
      *)
        # Assume Unix.
        INCLUDES='-I$(srcdir)/unix'
        ;;
    esac
    AC_SUBST(INCLUDES)
Second, we must make sure that the `zip` sources use the results we compute. So, for instance, we would check the `zip` source to see if we should use ``HAVE_MMAP'`, which is the result of calling `AC_FUNC_MMAP`. At this point you might also consider using a configuration header such as is generated by `AC_CONFIG_HEADER`. Typically this involves editing all your source files to include the header, but in the long run this is probably a cleaner way to go than using many `-D` options on the command line. If you are making major source changes in order to fully adapt your code to `autoconf`'s output, adding a ``#include'` to each file will not be difficult. This step can be quite difficult if done thoroughly, as it can involve radical changes to the source. After this you will have a minimal but functional ``configure.in'` and a knowledge of what portability information your program has already incorporated. Next, you want to write your ``Makefile.am'`s. This might involve restructuring your package so that it can more easily conform to what Automake expects. This work might also involve source code changes if the program makes assumptions about the layout of the install tree -- these assumptions might very well break if you follow the GNU rules about the install layout. At the same time as you are writing your ``Makefile.am'`s, you might consider libtoolizing your package. This makes sense if you want to export shared libraries, or if you have libraries which several executables in your package use. In our example, since there is no library involved, we won't use Libtool. The ``Makefile.am'` used in the minimal example is nearly sufficient for our use, but not quite. Here's how we change it to add dependency tracking and `dist` support:
    ## Process this file with automake to create Makefile.in.

    bin_PROGRAMS = zip

    if UNIX
    bin_SCRIPTS = unix/zipgrep
    os_sources = unix/unix.c
    else
    os_sources = win32/win32.c win32zip.c
    endif
    zip_SOURCES = zip.c zipfile.c zipup.c fileio.c util.c globals.c \
                  crypt.c ttyio.c crc32.c crctab.c deflate.c trees.c \
                  bits.c $(os_sources)

    ## It was easier to just list all the source files than to pick out the
    ## non-source files.
    EXTRA_DIST = algorith.doc README TODO Where crc_i386.S bits.c crc32.c \
    acorn/RunMe1st acorn/ReadMe acorn/acornzip.c acorn/makefile \
    acorn/match.s acorn/osdep.h acorn/riscos.c acorn/riscos.h \
    acorn/sendbits.s acorn/swiven.h acorn/swiven.s acorn/zipup.h crctab.c \
    crypt.c crypt.h deflate.c ebcdic.h fileio.c globals.c history \
    ...
    wizdll/wizdll.def wizdll/wizmain.c wizdll/wizzip.h wizdll/zipdll16.mak \
    wizdll/zipdll32.mak
The extremely long ``EXTRA_DIST'` macro above has be truncated for brevity, denoted by the ``...'` line. Note that we no longer define `INCLUDES` -- it is now automatically defined by `configure`. Note also that, due to a small technicality, this ``Makefile.am'` won't really work with Automake 1.4. Instead, we must modify things so that we don't try to compile ``unix/unix.c'` or other files from subdirectories.

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