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.
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.
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.
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:
The name of the macro to define.
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.
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.
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.
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.
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.
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.
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.