This script pulls everything together. After calling
JugglerConfigure::parseConfigFile(), the returned
hash (see the section called “JugglerConfigure”) is used to
perform all the relevant operations including, but not limited to,
invoking each Autoconf-based configure script in the correct order. As
a whole, the work done by configure.pl is fairly
straightforward, regardless of the arguments passed on the command
line. In this section, we will examine the four main aspects of this
script's functionality:
Command-line argument handling
Help output
Build configuration
File regeneration
We will present each in turn with the goal that understanding these pieces of functionality, extensions to configure.pl will be easier to perform. Of these points, #3 will require the most discussion since that is the main reason for configure.pl's existence.
The handling of command-line arguments in configure.pl is rather unique. To function correctly as a wrapper around multiple Autoconf-based build systems, this script must be capable of passing the correct arguments to the individual configure scripts. In other words, when the user executes the following:
configure.pl --module=VPR --enable-subsystem=NSPR --with-nspr=$HOME/nspr-4.2
the argument --module must be handled by
configure.pl while the other two are passed
through to VPR's configure script. Luckily, the Perl module
Getopt::Long provides a mechanism for doing just
that. The module is configured to allow unrecognized arguments to be
passed through so that, after the execution of
GetOptions(), @ARGV will
contain what GetOptions() did not handle. When
the time comes to execute a module's configure script,
@ARGV is passed to the script as normal
arguments.
This usage of Getopt::Long is not without a
drawback or two. Allowing the pass through of unrecognized arguments
means that GetOptions() is not performing
robust error checking on user input. What if
--module were spelled as --mdoule
accidentally? GetOptions() would not recognize
it, and the execution of configure.pl would not
proceed the way the user had intended. Because of this, it is
important for users to be especially careful with the options they
give when running configure.pl.
Two types of output can be printed by
configure.pl: usage for
configure.pl and usage for all the known
configure scripts. The first is done quite simply. The
Pod::Usage module is used to render the internal
POD as usage
output[6]. This output is printed when the user passes
--help on the command line.
Usage information for the known configure scripts can be
printed using the --all-help argument. This is
provided so that users have a way to get a complete listing of all
the command-line arguments that may be passed when running
configure.pl. (The exact details of how this
works were described in the previous subsection.) Only the relevant
output is actually printed when this argument is passed. The meaning
of “relevant” is tied to the module the user is
configuring. For example, with an unmodified
juggler.cfg, the default module is “VRJuggler”
(sic). If the --module option is not specified in
conjunction with --all-help, then the usage
information for the VR Juggler configure script and the use
information for the configure scripts of all of its dependencies are
printed. If a different module is specified, the output will change
based on the alternate module and its dependencies.
To print this information, each configure script is run by
configure.pl with the --help
command-line option. The output is collected and processed so that
the arguments are printed to the screen in an orderly fashion.
Duplicated output is discarded. The process of presenting the output
to the user is very important because there exists the potential for
a large amount of information.
Configuring a build tree involves several steps, and they are as follows:
Load default configure script arguments (if any exist)
Generate the reconfig helper script
Run the appropriate configure scripts in the right order
Generate the top-level makefile that invokes targets in each module's glue makefile
Each of these steps will be discussed in turn in the following sub-subsections.
To simplify the execution of configure.pl, users may write a default arguments file or a Perl plug-in that provides default arguments. In either case, the idea is that arguments for Autoconf-generated configure scripts can be collected into reusable platform- and site-specified pieces so that they do not have to be passed every time configure.pl is run. The preferred method for specifying default arguments is the Perl plug-in, but for users who do not know Perl, a simple configuration file can be used instead. Here, we will only describe the process of loading these files, not how to use them.
To load the Perl plug-in, the arguments file is treated as
loadable Perl code. (Indeed, the requirements of using the Perl
plug-in state that it must be valid Perl code with a subroutine
that can be called by another package.) Once the plug-in is loaded
into memory, its subroutine is executed. The subroutine must
return an array of command-line arguments that can be merged with
@ARGV. It is the responsibility of the plug-in
to inform configure.pl of its executable
subroutine by assigning a subroutine reference to a global
variable in configure.pl's scope. In
configure.pl, this whole process involves
roughly four lines of code, thus making it very attractive from
the standpoint of maintaining
configure.pl.
Loading the simple configuration file requires more effort
because the file format must be parsed. In
configure.pl, the parsing code for this file
format is found in loadDefaultArgs(). To
summarize the file format, platform-specific blocks are defined,
and within a block, each line gives a configure script argument.
The platform-specific blocks are named according to platform,
though they can be named with user-defined identifiers when used
in conjunction with the --os command-line option.
Parsing the file simply means reading the right block(s) and
adding each line to @ARGV.
Generating the reconfig helper script is
quite simple. The arguments passed on the command line are simply
saved to the reconfig file. In addition,
commands to remove any Autoconf cache files (named
config.cache) are added. Finally, the
reconfig file is made executable.
This step is where configure.pl works the hardest. Ultimately, what must happen is that a given module's configure script is executed, and if it exits without failing, the execution environment of configure.pl is extended to reflect new information. This new information comes from the environment variable settings in the original configuration file. The details of how this works are a little bit more complicated, however.
The real goal of configure.pl is to run
the configure script of the module the user wants to configure and
build. Along the way, it may have to run configure scripts for one
or more dependencies. Dependency information has already been
covered in great detail, and we will not repeat it here. To ensure
that the dependencies are configured in the correct order, the
array of dependencies within the
JugglerModule object is requested. Each
dependency's configure script is run, and the execution
environment is extended accordingly. The last dependency of a
module is the actual module the user wants to configure and build.
Once its configure script completes successfully, the top-level
makefile can at last be generated.
The environment variables that are set reflect the delicate
balance between configure.pl,
configure.pl's configuration file, the
*-config scripts, and the
*.m4 files (see the section called “The *-config Scripts and the
*.m4 Macro Files”). Based on the rules set forth
by the *-config scripts and the
*.m4 files, the execution environment must be
set up so that each subsequent configure script can get
information about any dependencies it has.
Generating the top-level makefile is relatively easy (it is
mostly search-and-replace operations), but interestingly, this is
one of the places where configure.pl falls
short of acting like an Autoconf-based configure script. A
template makefile (juggler/Makefile.in) is
always the only file generated by configure.pl
(aside from the reconfig script). There is no
way to specify other files. Even if there were,
configure.pl does not have easy access to the
results of all the tests performed by the various configure
scripts.
As a result of these limitations, there are only a few
strings that can be expanded in the generated makefile. At this
time, only two variables can be expanded:
@JUGGLER_PROJECTS@ and
@topdir@. The expansion of the first depends on
the configured module and its dependencies; the expansion of the
second is simply the directory where
configure.pl was run.
When an Autoconf-generated configure script is run
successfully, a shell script called
config.status is created. This script contains all the state
information generated as a result of running
configure. If there is a need to regenerate the
files created by configure,
config.status can do the job quickly because it
reuses the static information from when it was created without
re-running all the tests. There is no global
config.status created by
configure.pl, but an alternate method is provided
through the --regen argument.
When --regen is passed on the command line,
configure.pl iteratively executes the individual
config.status scripts instead of the configure
scripts. This allows users to regenerate files more quickly than by
running all the configure scripts again. Deciding which
config.status scripts to run is a somewhat
difficult process, however.
In a normal situation when only one
config.status exists, it is easy for a user to
decide when (and how) to run it. In the context of the VR Juggler
build system, there are many configure scripts, each having its own
config.status script. Furthermore, some
config.status scripts may not exist based on
which module (in juggler.cfg) was configured. As with all other cases where
configure.pl must decide what to execute, the
requested module dictates the execution behavior. Thus, if the user
did not configure the default module, the --module
argument must be passed with --regen to ensure
proper execution of the various config.status
scripts.
[6] Use of this very handy Perl module has actually been a source of problems. In particular, IRIX 6.5 ships with a version of Perl that does not contain this module. For that reason, Perl 5.005 or newer is required to run configure.pl and some other Perl scripts used by the build system.