Module::Build
by Dave RolskyFebruary 12, 2003
Dave Rolsky is a co-author of the recently released Embedding Perl in HTML with Mason.
This article was originally published in February of 2003, and was updated by Dave Rolsky and Michael Schwern in January, 2008.
If you've ever created a Perl module for distribution on CPAN, you've
used the ExtUtils::MakeMaker module. This venerable module goes
back to the dawn of modern Perl, which began with the release of Perl
5.000.
Recently, Ken Williams has created a potential replacement for
ExtUtils::MakeMaker called Module::Build, which was first
released in August of 2002. Hugo van der Sanden, the pumpking for the
current development version of Perl, has expressed interest in
replacing ExtUtils::MakeMaker with Module::Build for the 5.10
release of Perl, and Michael Schwern, the current
ExtUtils::MakeMaker maintainer, agrees with him.
ExtUtils::MakeMaker won't go away any time soon, but we can hope
for a gradual transition to a new and improved build system.
Why ExtUtils::MakeMaker is Important
The ExtUtils::MakeMaker module, along with the h2xs script, has
been a huge boon to the Perl community, as it makes it possible to
have a standard way to distribute and install Perl modules. It
automates many tasks that module authors would otherwise have to to
implement by hand, such as turning XS into C, compiling that C code,
generating man pages from POD, running a module's test suite, and of
course, installing the module.
ExtUtils::MakeMaker is a huge part of what makes PAUSE and CPAN
possible, and it is quite a programming feat. Python did not have a
similar utility until the September, 1999 release of distutils, PHP's
PEAR didn't begin until mid-2000, and Ruby is just beginning to work
on a standard library distribution mechanism.
The Scary Guts of ExtUtils::MakeMaker
ExtUtils::MakeMaker works by generating a makefile that contains
targets for the various tasks needed when maintaining or installing a
module. Here's an example target:
install :: all pure_install doc_install
If you're familiar with makefile syntax, you'll realize that all this target does is call three other targets, which are named "all", "pure_install", and "doc_install". These targets in turn may call other targets, or use system commands to do whatever action is needed, in this case installing the module and its associated documentation.
The makefiles generated by ExtUtils::MakeMaker are fairly complex.
For example, using version 6.05 of ExtUtils::MakeMaker to install
my Exception::Class module, a pure Perl distribution containing
just one module, creates a makefile with about 390 lines of makefile
code. Figuring out what this makefile actually does is no simple
feat, because it consists of a maze of twisty macros, all alike, many
of which simply call Perl one-liners from the command line to perform
some task.
The ExtUtils::MakeMaker code itself is extremely complicated, as it
works on many operating systems (almost as many as Perl itself), and
needs to accommodate their file systems, command line shells,
different versions of make, and so on. And this is all done with an
extra layer of indirection in place, because it is generating a
makefile which does all the work.
If you want to customize the module build or installation process,
good luck. To do this, you must subclass ExtUtils::MakeMaker,
override methods that generate specific makefile targets, and then
tweak the generated text to include your custom behavior, all the
while preserving the basic behavior of the target. Considering that
there is no documentation describing what to expect from these
targets, and that the actual target text may change between releases
of ExtUtils::MakeMaker or between different OS's, this can be quite
painful to implement and maintain.
And by the way, you can't really subclass ExtUtils::MakeMaker,
instead you are subclassing the MY package. This is a deeply
strange hack, but the end result is that you can only override certain
pre-defined methods in ExtUtils::MakeMaker.
For example, the HTML::Mason module includes this snippet:
package MY;
sub test {
my $self = shift;
my $test = $self->SUPER::test(@_);
# %MY::APACHE is set in makeconfig.pl.
# If we are not going to test with Apache there is no harm in
# setting this anyway.
# The PORT env var is used by Apache::test. Don't delete it!
my $port = $MY::APACHE{port} || 8228;
$MY::APACHE{apache_dir} ||= ";
my $is_maintainer = main::is_maintainer();
# This works for older MakeMakers
$test =~ s/(runtests \@ARGV;)/\$\$ENV{MASON_VERBOSE} ==
\$(TEST_VERBOSE) ? \$(TEST_VERBOSE) : \$\$ENV{MASON_VERBOSE};
\$\$ENV{PORT}=$port;
\$\$ENV{APACHE_DIR}=q^$MY::APACHE{apache_dir}^;
\$\$ENV{MASON_MAINTAINER}=$is_maintainer; $1/;
my $bs = $^O =~ /Win32/i ? " : '\\';
# This works for newer MakeMakers (5.48_01 +)
$test =~ s/("-MExtUtils::Command::MM" "-e" ")
(test_harness\(\$\(TEST_VERBOSE\).*?\)"
\$\(TEST_FILES\))/$1 $bs\$\$ENV{MASON_VERBOSE} == \$(TEST_VERBOSE) ?
\$(TEST_VERBOSE) : $bs\$\$ENV{MASON_VERBOSE}; $bs\$\$ENV{PORT}=$port;
$bs\$\$ENV{APACHE_DIR}=q^$MY::APACHE{apache_dir}^;
$bs\$\$ENV{MASON_MAINTAINER}=$is_maintainer; $2/;
return $test;
}
The goal of all this code is to pass some additional environment
information to the test scripts when they are run, so we can do tests
with a live Apache server. It accommodates several versions of
ExtUtils::MakeMaker, and attempts to work properly on multiple
operating systems (at least Win32 and *nix), and it has to be careful
about escaping things properly so that it executes properly from the
shell.
Why not Perl?
All of this prompts the question of "why not just use Perl itself for
all of this?" That's exactly the question that Ken Williams answered
with Module::Build. The goal of Module::Build is to do
everything useful that ExtUtils::MakeMaker does, but to do this all
with pure Perl wherever possible.
This greatly simplifies the build system code, and Module::Build
works on systems which don't normally include make, like Win32 and Mac
OS. Of course, if a module installation requires the compilation of C
code, you'll still need an external C compiler.
Additionally, customizing Module::Build's behavior is often quite
trivial, and only requires that you know Perl, as opposed to knowing
make syntax and possibly having to learn about multiple command line
environments.
Module::Build also aims to improve on some of the features provided
by ExtUtils::MakeMaker. One example is its prerequisite-checking
system, which provides much more flexibility than what
ExtUtils::MakeMaker allows. While these features could be added to
ExtUtils::MakeMaker, it's risky to make major changes to such an
important module, especially one with such complex internals.
Using Module::Build
From an end-user perspective, a module that uses Module::Build
looks quite a bit like one using ExtUtils::MakeMaker, and
intentionally so. So to install a module using Module::Build you'd
type the following lines from the command line:
perl Build.PL ./Build ./Build test ./Build install
The Build.PL script tells Module::Build to create a Build
script. During this process, Module::Build also writes some files
to a _build/ directory. These files are used to store the build
system's state between invocations of the Build script. This
script, when invoked, simply loads up Module::Build again, and
tells it to perform the specified action. An action is the
Module::Build version of a makefile target, and actions are
implemented in pure Perl whenever possible.
A bare bones Build.PL script might look like this:
use Module::Build;
Module::Build->new
( module_name => 'My::Module',
license => 'perl',
)->create_build_script;
The "module_name" parameter is like the ExtUtils::MakeMaker "NAME"
parameter.
The "license" parameter is new with Module::Build, and its intended
use it allow automated tools to determine under which license your
module is distributed.
To determine your module's version, Module::Build looks in the
module specified by the "module_name" parameter, though this can be
overridden either by specifying a different module to look in, or by
providing the version number directly.
Of course, there are more options than those. For example,
Module::Build implements a prerequisite feature similar to that
implemented by ExtUtils::MakeMaker, so we can write:
Module::Build->new
( module_name => 'My::Module',
license => 'perl',
requires => { 'CGI' => 0,
'DBD::mysql' => 2.1013,
},
)->create_build_script;
If you have any experience with ExtUtils::MakeMaker, you can
probably figure out that this says that our module requires any
version of CGI, and version 2.1013 or greater of DBD::mysql. So
far, this looks just like what ExtUtils::MakeMaker provides, but
Module::Build goes further.

