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.
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.
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 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.
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.
This could be the end of the story were it not for CPAN. A package needs more than just a
Makefile.PL) file before it can be submitted to the CPAN. You need to add at least
META.yaml, or ...),
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
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
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.
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
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
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
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.