Structure of a configure.in File

We now move on to the basic structure of a configure.in file. As mentioned earlier, all configure scripts in the Juggler Project, save one, follow this basic structure. Each section is normally commented to distinguish its tasks from preceding and following sections.

Initialization

The first short block of configure.in performs some very basic initialization tasks. The RCS revision number of the script is maintained here so that the user can verify that s/he has the most recent version of the actual configure script. A check for one file in the source tree is also made to perform a very general, inexact verification that things are where they are supposed to be. For example, VR Juggler's configure script will do its sanity check based on the existence of vrj/vrjConfig.h. Next, the header file created when done with the configuration process is named. In VR Juggler, this file is called vrj/vrjDefines.h. Finally, Doozer++ initialization occurs using the DPP_INIT() macro.

Custom Arguments

In this block, the custom arguments for the configure script are defined. The first set defines the --with-package[=arg] and --without-package arguments. These are intended to be used for choosing some external software package to use at compile time. They are also used for providing a small level of customization to how the external software is found and/or used.

The second set defines the --enable-feature[=arg] and --disable-feature arguments that allow the user to choose which optional features can be built. From the Autoconf 2.12 documentation, “These options should never make a feature behave differently or cause one feature to replace another.

For both sets of options, the AC_ARG_WITH() and AC_ARG_ENABLE() macros behave the same way. The first argument is the package/feature. The second argument is the description printed when the user runs configure with the --help option. The third argument sets a user-defined variable in the script to the contents of $withval or $enableval respectively. If no argument is given (e.g., the user specified --enable-opengl), the variable will get either “yes” or “no” as its value depending upon whether the user used the positive or negative form of the argument.

After the custom arguments are defined, some of the values that may be read are processed. In particular, the application binary interface (ABI) under which the module will be compiled is defined. This is done prior to the system-dependent section to reduce duplicated code even though the ABI is highly dependent upon the operating system and underlying computer architecture.

System-Dependent Setup

Here, a common set of script variables are given values that are usually dependent upon the system on which the script is being run. Except in VPR's configure script, there is little system-dependent code. Most of it is hidden by the Doozer++ DPP_SYSTEM_SETUP() macro. In the case of VPR's configure.in, however, a large conditional block compares the value in $target_os (obtained from the AC_CANONICAL_TARGET() macro) with known systems and sets values for the variables appropriately.

Some existing variables may be modified here as well. These often include $CFLAGS, $CXXFLAGS and $INCLUDES. Each of these could have been set as part of the user's environment variables or previously in the script as part of executing a macro. Thus, they should be treated carefully so as not to destroy any existing values that may be stored in them.

Besides setting values in variables, custom pre-processor macros are often defined here using the AC_DEFINE() macro. This macro takes two parameters:

  1. The name of the macro to define.

  2. The value to which the macro will be set by the pre-processor.

To get something similar to:

#define VJ_DEF

use the following syntax:

AC_DEFINE([VJ_DEV],)

Defining macros that take parameters cannot be done with AC_DEFINE(). However, based on a check made for something (such as sginap(2)), such a macro can be defined at the bottom of acconfig.h or in the module's Config.h (vprConfig.h, tweekConfig.h, etc.) header after it includes the generated header.

External Program Checks

This block is for standard program checks that configure does to ensure that software needed for compiling the package works. Using the values in several preset variables (including $CC for the C compiler and $CXX for the C++ compiler), it runs tests on the software and reports any problems it finds.

External Library Checks

Checks for required external libraries are made here. In a configure script, a great deal of processing is often done in order to ensure that the source can be properly compiled and linked using certain external libraries. The basic process of checking for a library (say, the OpenGL library) involves first checking to see if the library can be linked. If the library can be linked, a check is then made for a standard header file associated with the library (in this case, GL/gl.h). In some cases, if a library cannot be found, a fallback check is provided. For example, in the case of the POSIX threads library, an attempt to link against libpthread is made. If that fails (as it will on HP-UX 10.20), a check is made to link against libcma.

Upon successfully finding a library and a needed header file, several variables are usually set that are used later in the makefile generation phase. If a library is not found, the script may simply issue a warning about the problem or it may exit altogether if the library's existence is crucial to the compiling process.

Adding new library checks can be complicated. The best method is to refer to the Autoconf documentation and the existing checks. All follow basically the same structure.

Header File Checks

Checks for standard header files and user-specified header files are made here. The user-specified list is a space-separated list of header files that may not exist on all systems. If a header file is found, HAVE_FILENAME_H is defined in the module's definition header (vprDefines.h, tweekDefines.h, etc.) when it is generated.

Library Function Checks

Here, checks are made for any library and system functions (e.g., gettimeofday(3), gethostbyname(2), usleep(2)) that may not exist on all systems. As with other sections, the user-specified list of functions to check is the space-separated parameter passed to the AC_CHECK_FUNCS() macro. If found, HAVE_FUNCNAME will be defined in the generated definition header.

Makefile Substitution

Within this block of configure.in, special symbols in the Makefile.in template files are slated for replacement with variable values. This is done through the AC_SUBST() macro, and it simply replaces a tag in a Makefile.in with the value stored in the corresponding configure script variable. The following example illustrates what happens during the file generation phase (discussed next). Say that some Makefile.in contains the following line:

CUSTOM_VAR = @CUSTOM_VAR@

The string enclosed by @'s is the tag that will be replaced when Makefile is generated. In configure.in, there following line must be present:

AC_SUBST(CUSTOM_VAR)

Note that the variable is not prepended by a `$' because variable interpolation should not be done here. Of course, $CUSTOM_VAR will generally have had some value set prior to this point. That is not required, however.

It is in this phase of configuration that most of the system-dependent build work is done. This is similar to what Imake template files do. Virtually everything preceding this point set variables to have values appropriate to the host machine, and now they are put into the makefiles to be used for compiling the code. There are several pre-defined variables that configure will substitute in the input template files. Refer to the section titled “Preset Output Variables” in the Autoconf 2.13 documentation for a list of these.

File Generation

In this last block, file generation is performed using the AC_OUTPUT() macro. It iterates through its space-separated list of files and finds the associated .in template file. In general, this step is only used for generating makefiles (the module's definition header is added automatically due to the AC_CONFIG_HEADER() call at the top of configure.in). When a new directory and corresponding Makefile.in are added to the source tree, an entry for it must be added to this list.