Managing Perl Code¶
TL;DR: we recommend using Dist::Zilla
for managing Perl packages. It is worth to invest time in learning this tool. The other tools mentioned on this page set the context and are important if you want to form a well reasoned opinion.
Motivation¶
If you maintain Perl code you probably want to manage your software as packages. You can use autoconf as described in Managing a Software Package with the GNU Autotools. However, there is a whole ecosystem for managing packages within the Perl community that started with the CPAN. It is recommended that you use those tools for Perl code.
True to their motto There is more than one way to do it (TIMTOWTDI) the Perl community has over the years developed several tools for the task. As you browse the available literature you may get confused as to when to use one or the other tool. Depending on when an article was written it may even be that some of the issues mentioned do not apply anymore.
The goal of this writeup is to show how the most frequently used Perl packaging tools relate to each other. This may help you decide how you want to package your own code.
ExtUtils::MakeMaker¶
With the invention of CPAN there needed to be a well defined way to install a package. At the time very often there were parts of the package written in C that needed to be built along the Perl code. Using make
was a given but the Makefile
needed to conform to certain conventions. To ensure these conventions a script Makefile.PL
was written using the ExtUtils::MakeMaker module. With this the sequence to install a Perl package became:
perl Makefile.PL
make
make test
make install
If you need to maintain a package written using ExtUtils::MakeMaker
you may want to read the ExtUtils::MakeMaker::Tutorial and then the extensive manual. However, if you start a new project you should use one of the newer tools mentioned below.
Module::Build¶
Module::Build was written to replace ExtUtils::MakeMaker
with the goal of getting rid of the dependency on make
. This allows Module::Build
to be based purely on Perl. Once Perl itself is installed it already provides a certain standard across the platform that it supports. Module::Build
profits from this standard and is therefore much more reliable. Instead of a Makefile
it uses a Perl script called Build
which is generated by a script Build.PL
. The latter is written using the Module::Build
module. Installing a package becomes:
perl Build.PL
./Build
./Build test
./Build install
The similarity to the use of ExtUtils::MakeMaker
above is intentional. For most simple projects both approaches require about the same effort and both are as easy to understand as the other.
Ever since Module::Build
became available there has been controversy as to which approach is better. As it turns out, having to rely on make
is often not a curse but a blessing. make
allows dry runs with make -n
which Module::Build
does not support. For all relevant platforms make
is fundamental enough that there is at least one version of make
available that supports all important modern features.
As the situation presents itself as of this writing there are plans to remove Module::Build
from Perl core (sometime after version 5.020). ExtUtils::MakeMaker
is now the preferred tool and is still used and maintained actively.
To quote from the ExtUtils::MakeMaker::FAQ:
Module::Build was long the official heir apparent to MakeMaker. The rate of both its development and adoption has slowed in recent years, though, and it is unclear what the future holds for it. That said, Module::Build set the stage for something to become the heir to MakeMaker. MakeMaker's maintainers have long said that it is a dead end and should be kept functioning, but not extended with new features. It's complicated enough as it is!
For all practical purposes there is a way out. Read on.
Module::Starter¶
This could be the end of the story were it not for CPAN. A package needs more than just a Build.PL
(or Makefile.PL
) file before it can be submitted to the CPAN. You need to add at least MANIFEST
, META.yml
(or META.json
, or META.yaml
, or ...), LICENSE
, and README
or some variations thereof. This can be a bit daunting so Module::Starter was written with the module-starter command line tool.
module-starter
will create a skeleton of a Perl package. You can choose between Module::Build
and ExtUtils::MakeMaker
and set a few other options. Once created you can change the files the way you want them to be and do the actual work of writing the code and documentation that makes up your package.
Module::Starter
does in now way obsolete either ExtUtils::MakeMaker
or Module::Build
but rather gives you a head start to use it properly for CPAN conforming Perl packages. Plus, it allows you to choose which one to use when you start the project.
Dist::Zilla¶
While module-starter
gives you a nice skeleton for your package you still need to maintain consistency and update all the boilerplate over the lifetime of your package. This is where Dist::Zilla shines. It collects all the relevant information in a file called dist.ini
and puts the documentation close to where it belongs (e.g., as POD text inside Perl code or in designated .pod files). The goal is to avoid redundancies whenever possible and it is impressive how far that can go. If you need to update a piece of information (e.g., a version number) you edit it in exactly one place and the rest is generated by Dist::Zilla
.
The typical workflow for, say, an internally used module Foo::Bar
at version 1.4 becomes like this:
dzil build
cd Foo-Bar-1.4
perl Build.PL
./Build
./Build test
./Build install
Or if you want to submit to CPAN you will use the .tar.gz
file generated by dzil build
directly or even use dzil
to upload to CPAN automatically.
All of the files dzil
generates are put in a target directory and none of your source files are changed by dzil
. This allows you to keep generated files strictly separate from the files you edit. It also enables consistent builds. dzil build
will allways generate all boilerplate and keep the distribution of your package consistent.
Dist::Zilla
supports both Module::Build
and ExtUtils::MakeMaker
as backends. So you continue to profit from the work that went into them and avoid the burden of updating all the boilerplate. It also allows you switch between ExtUtils::MakeMaker
and Module::Build
by substituting one plugin for the other. See, you can have it both ways
For most typical projects Dist::Zilla
is the ideal package maintenance tool. Once your project becomes more complex you may encounter some limitations. You can then either dig into the internals of ExtUtils::MakeMaker
or write your own Dist::Zilla::Plugin::
. Writing your own plugin may well turn out to be the better choice.