Chapter 24. Using Autoconf

The autoconf system is often used to configure C programs to be able to compile them on any Unix system. This section explains how to use autoconf with Aap in a nice way. An alternative is to use the :conf command of Aap. It is much easier to use and also works on non-Unix systems. See Chapter 23, Automatic Configuration.

Running The Configure Script

A recipe that uses the configure script that autoconf generates can start like this:

        $BDIR/config.h $BDIR/config.aap :
                                configure config.arg config.h.in config.aap.in
            :sys ./configure `file2string("config.arg")`
            :move {force} config.h config.aap config.log
                                              config.cache config.status $BDIR
        config.arg:
            :touch {exist} config.arg

        :update $BDIR/config.aap
        :include $BDIR/config.aap

What happens here is that the "config.aap" target is updated before any of the building is done. This is required, because running the configure script will generate or update the "config.aap" file that influences how the building is done.

Remembering Configure Arguments

The arguments for configure are stored in the "config.arg" file. This makes it easy to run configure again with the same arguments. The file is read with the file2string() function. There should be a "config.txt" file that explains all the possible configure arguments, with examples that can be copied into "config.arg". Example:

        # Select the library to be used for terminal access.  When omitted a
        # series of libraries will be tried.  Useful values:
            --with-tlib=curses
            --with-tlib=termcap
            --with-tlib=termlib

The user can now copy one of the example lines to his "config.arg" file. Example:

        # select specific terminal library
            --with-tlib=termcap

Comment lines can be used, they must start with a "#". Note: a comment after an argument doesn't work, it will be seen as an argument.

When updating to a new version of the program, the same "config.arg" file can still be used. A "diff" between the old and the new "config.txt" will show what configure arguments have changed.

Variants And Configure

"config.aap" and "config.h" are put in $BDIR, because they depend on the current system. They might also depend on the variant to be built. In that case the :variant statement must be before the use of $BDIR. However, if the variant is selected by running configure, the variant must come later. "config.aap" and "config.h" are then updated when selecting another variant.

For the program to find "config.h" in $BDIR you must add an option to the C compiler. And you have to notify the compiler that the file exists, so that it will be included:

        INCLUDE += -I$BDIR
        DEFINE += -DHAVE_CONFIG_H

The "config.cache", "config.log" and "config.status" files are also moved to $BDIR. This means they are not available when running "./configure" again., This may be a bit slower, since the cache isn't used, but it is much more reliable. And you can view the log of each variant that was build.

Running Autoconf

For a developer there also needs to be a method to generate the configure script from configure.in. This needs to be done even before configure is run. Prepending this to the example above should work:

        configure {signfile = mysign} : configure.in
            :sys autoconf

Normally the "configure" script is distributed with the program, so that a user does not need to install and run autoconf. The "{signfile = mysign}" attribute on the target is used to avoid running autoconf when the user builds the program and the "configure" and "configure.in" files are still as they were distributed. The signatures in the "mysign" file, which you must include in the distribution, will match and Aap knows that "configure" is up-to-date. If using the "mysign" file was omitted, there would be no signature for the "configure" target and Aap would decide to run autoconf. When you change "configure.in" its signature will be different from what is stored in "mysign" and autoconf will be run.

Using A Distributed Configure Script

If you are porting an application that already has a configure script you can filter it to make it work with Aap. This means you can use the unmodified configure.in.

        configure_aap : configure
	:cat configure
		| :eval re.sub("Makefile", "config.aap", stdin)
		>! configure_aap
	:chmod 755 configure_aap

Now you need to execute "configure_aap" instead of "configure" in the first example above.

Skipping Configuration

Running configure can take quite a bit of time. And when you are not going to build anything that can be annoying. For example, "aap comment" doesn't require configure to run.

Also, configure doesn't work on a non-Unix system. When you have taken care in your code to handle this you can simply skip configure. This line above all the configure code should take care of this:

        @if osname() == "posix" and has_build_target():

The has_build_target() function checks for a target that will do some kind of building, which means configure must be run.

A Complete Example

Using all the parts mentioned above together we have a fairly complete method to handle running autoconf and configure. This code is used in the recipe that builds the Exuberant Ctags program.

    #
    # On Unix we run configure to generate config.h and config.aap.
    # This is skipped if there is no building to be done (e.g., for "clean").
    #
    @if osname() == "posix" and has_build_target():

        # "config.h" and "config.aap" are generated in $BDIR, because the are
        # different for each system.
        # Tell the compiler to find config.h in $BDIR.
        INCLUDE += -I$BDIR
        DEFINE += -DHAVE_CONFIG_H

        # Run autoconf when needed, but avoid doing this always, not everybody has
        # autoconf installed.  Include "mysign" in the distribution, it stores the
        # signature of the distributed configure script.
        configure {signfile = mysign} : configure.in
            @if not program_path("autoconf"):
                :print Can't find autoconf, using existing configure script.
            @else:
                :sys autoconf

        # Filter the configure script created by autoconf to generate config.aap
        # instead of Makefile.  This means we can use the unmodified configure.in
        # distributed with ctags.
        configure_aap : configure
            :cat configure
                    | :eval re.sub("Makefile", "config.aap", stdin)
                    >! configure_aap
            :chmod 755 configure_aap

        # Dependency to create config.aap by running the configure script.
        # The "config.arg" file is used for configure arguments.
        :attr config {virtual} {comment = Do configuration only}

        config $BDIR/config.h $BDIR/config.aap :
                    configure_aap config.arg config.h.in config.aap.in
            :sys ./configure_aap `file2string("config.arg")`
            # Move the results into $BDIR.  This also means the cache isn't used
            # the next time, it is unreliable.
            :move {force} config.h config.aap config.log config.cache
                                                               config.status $BDIR

        # Create an empty config.arg when it's missing.
        config.arg:
            :touch {exist} config.arg

        # Update config.aap before including it.  Forcefully when the "reconfig"
        # target is used.
        @if "reconfig" in var2list(_no.TARGETARG):
            :del {force} config.cache config.status
            :update {force} $BDIR/config.aap
        @else:
            :update $BDIR/config.aap

        :include $BDIR/config.aap