To achieve complete independance from the language and tools used for a project, the build stage of the autobuild cycle is considered a black box. To perform the build, autobuild merely invokes an opaque control file provided by the developer. This shell script will typically perform four tasks - configure, build, install and package. The autobuild will capture the standard output and error streams, saving to the modules build log files. In common with standard UNIX behaviour, an exit status of zero indicates a successful build, while non-zero indicates failure.
Environment variables
When the control file is invoked, a number of environment variables will be set in its shell. In versions 1.0.x, there are two environment variables.
- AUTO_BUILD_ROOT
- The path to a virtual root directory where software should be installed. When a module is built, it is guarenteed that the installed files from any dependant modules will be present in this directory. This enables a module to depend on the output of another module. The contents of this directory, however, are not preserved across runs of the build.
- AUTO_BUILD_COUNTER
- A counter identifying the current run of the build. Typically this will be the number of seconds since the UNIX at the time the current build cycle began, but may alternatively be a version control changelist.
In the 1.1.x series, these two are deprecated (but still available) in favour of an expanded set
- AUTOBUILD_MODULE
- The name of the module which is being built
- AUTOBUILD_INSTALL_ROOT
- The path to a virtual root directory where software should be installed. When a module is built, it is guarenteed that the installed files from any dependant modules will be present in this directory. This enables a module to depend on the output of another module. The contents of this directory, however, are not preserved across runs of the build.
- AUTOBUILD_PACKAGE_ROOT
- The path to a directory in which a module's build process will create any
binary packages it generates, for example RPMs, or Debian packages.
The packages are typically placed into a package type specific
sub-directory.Consider, for example, a module which generates an RPM, of itself.
The $AUTOBUILD_PACKAGE_ROOT directory would be used to set the
'_topdir' macro for the RPM build process
rpmbuild --define '_topdir $AUTOBUILD_PACKAGE_ROOT/rpm' -ta foo.tar.gz
- AUTOBUILD_SOURCE_ROOT
- The path to the directory in which modules are checked out. This can be used in conjunction with $AUTOBUILD_MODULE to identify the root directory for the module
- AUTOBUILD_COUNTER
- A counter identifying the current run of the build. Typically this will be the number of seconds since the UNIX at the time the current build cycle began, but may alternatively be a version control changelist.
- AUTOBUILD_TIMESTAMP
- A counter identifying the timestamp taken at the start of the build cycle. When checking out code, all version control systems are synchronized to no later than this timestamp. For a given value of $AUTOBUILD_TIMESTAMP the source code being built will always be identical, thus this is suitable for use as a unique identifier for a build.
Integrating with Perl (ExtUtils::MakeMaker)
All Perl modules which use ExtUtils::MakeMaker for their build and
install process can use the same pattern for their control file.
The key to this pattern is to set the value for the PREFIX
variable to $AUTO_BUILD_PREFIX when running the
Makefile.PL script:
perl Makefile.PL PREFIX=$AUTOBUILD_INSTALL_ROOT
Any non-trivial Perl module will likely have dependancies on
other modules built and installed earlier in the cycle. To
enable MakeMaker's pre-requisite checking to pick these up, it
is neccessary to set the PERL5LIB environment variable
to point to the virtual install root containing the site specific
modules:
PERL5LIB=$AUTOBUILD_INSTALL_ROOT/lib/perl5/site_perl/5.8.0
Hard coding the site_perl in this way is not
very good practice, however, since the same code (and thus control
file) may be used across many autobuild instances with differing
versions of Perl installed. The solution is to make use of the
standard Config module to extract the location.
PERL5LIB=`perl -e 'use Config; my $dir = $Config{sitelib}; \
$dir =~ s|/usr|$ENV{AUTOBUILD_INSTALL_ROOT}|; print $dir'`
To a complete script to configure, build, install the module and create a source code distribution would look like:
#!/bin/sh
set -e
# Pull in prerequisite modules
PERL5LIB=`perl -e 'use Config; my $dir = $Config{sitelib}; \
$dir =~ s|/usr|$ENV{AUTOBUILD_INSTALL_ROOT}|; print $dir'`
export PERL5LIB
# Clean up build area
[ -f Makefile ] && make -k realclean ||:
rm -rf MANIFEST blib
# Configure the build
perl Makefile.PL PREFIX=$AUTOBUILD_INSTALL_ROOT
# Make & install
make
make install
# Create source code dist
make dist
Integrating with C & C++ (AutoConf / AutoMake)
With a few notable exceptions (Perl & Apache), C and C++ programmers have been increasingly converging on GNU Auto Tools for configuring and building their software. As with MakeMaker, the key task is to set the installation prefix when running the configure script:
./configure --prefix=$AUTOBUILD_INSTALL_ROOT
The task of resolving inter-module build dependancies is somewhat less well defined. There are a number of approaches that may work - some programs may even need a combination of all of them!
Configuration helper program
Some libraries install a small shell script to the bin
directory that programs can use to determine the correct
compiler and linker flags. For example, the gtk-config
script can print out the compiler flags required when building
against GTK. These scripts are typically generated at build time
based on the values to the configure script. Thus
it is sufficient to add the bin directory containing
this script to the PATH environment variable:
PATH=$AUTOBUILD_INSTALL_ROOT/bin:$PATH
Configure script options
Another common approach to locating pre-requisite libraries is for the program's configure script to have command line options for specifying include and library search paths. For example, when building the Resin Java servlet container, the configure script has --with-openssl-lib and --with-openssl-include options. Thus when configuring Resin, as well as setting the prefix, we'd set these two options:
./configure --prefix=$AUTOBUILD_INSTALL_ROOT \ --with-openssl-lib=$AUTOBUILD_INSTALL_ROOT/lib --with-openssl-include=$AUTOBUILD_INSTALL_ROOT/include
An alternative to specifying both library and include search paths is to just tell the configure script the installation prefix of the library:
./configure --prefix=$AUTOBUILD_INSTALL_ROOT \ --with-openssl=$AUTOBUILD_INSTALL_ROOT
Compiler environment variables
If there is no explicit support for specifying the location
of pre-requisite libraries then the final approach is to try
setting compiler environment variables. The two important
ones being CFLAGS and LDFLAGS:
CFLAGS=-I$AUTOBUILD_INSTALL_ROOT/include LDFLAGS=-L$AUTOBUILD_INSTALL_ROOT/lib
Now a complete example control file might look like
#!/bin/sh set -e # Pull in config scripts PATH=$AUTOBUILD_INSTALL_ROOT/bin:$PATH export PATH # Clean up build area [ -f Makefile ] && make -k maintainer-clean ||: # Re-generate autotools scripts autoconf automake -a # Configure the build ./configure --prefix=$AUTOBUILD_INSTALL_ROOT \ --with-openssl=$AUTOBUILD_INSTALL_ROOT # Make & install make make install # Create source code dist make dist
Integrating with Java (ANT)
When it comes to writing build.xml files for Java programs
with ANT, pretty much anything goes. Fortunately, most of
the time there are only two things to worry about, firstly
where/how any pre-requisite JARs are located/found, and
secondly where to put any generated JARs. For Linux systems,
JPackage has been pushing
standardization efforts towards a central repository in /usr/share/java,
with the alternatives program being used to manage
concurrent, differing versions. Thus the first step when creating
a Java program is to get the pre-requisite libraries into the
ClassPath. The simplest way is to have a bunch of lines such as:
CLASSPATH=$CLASSPATH:$AUTOBUILD_INSTALL_ROOT/share/java/[somepackage].jar
Some ANT build.xml files may have a property for specifying the location of libraries which can be set for compilation
ant -Dlibrary.dir=$AUTOBUILD_INSTALL_ROOT/share/java build
Very few ANT build.xml files concern themselves with installation
of JARs, however, it is pretty simple to use the standard UNIX
install program from the control file:
install -D mylib.jar $AUTOBUILD_INSTALL_ROOT/share/java/mylib.jar
So a complete control file for a Java program might look like
#!/bin/sh ant -Dlibrary.dir=$AUTOBUILD_INSTALL_ROOT/share/java build install -D mylib.jar $AUTOBUILD_INSTALL_ROOT/share/java/mylib.jar