conifgure.pl

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:

  1. Command-line argument handling

  2. Help output

  3. Build configuration

  4. 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.

Command-Line Argument Handling

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.

Help Output

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.

Build Configuration

Configuring a build tree involves several steps, and they are as follows:

  1. Load default configure script arguments (if any exist)

  2. Generate the reconfig helper script

  3. Run the appropriate configure scripts in the right order

  4. 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.

Load Default Arguments

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.

Generate reconfig

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.

Run the Configure Scripts

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.

Generate the Top-Level Makefile

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.

File Regeneration

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.