How to upload a script to CPAN

If you’ve got a Perl script that does something useful, you might want to put it on CPAN. Becoming a CPAN author is a rite-of-passage for Perl programmers, you’ll learn about the CPAN infrastructure and sharing code is a nice thing to do. Within a few minutes of uploading a distribution to CPAN, it’s indexed and installable by anyone with a CPAN client, which is pretty incredible.

It usually prints “bar”, but on January 31, National Backward day, it prints “rab”. I’ll take you step-by-step through the process of putting it on CPAN.

Setup your distribution directory

An upload to CPAN is called a distribution, and each one contains several files, so I need to make a directory to contain all of the files I’m going to create. As most applications are uploaded under the namespace App, that’s what I’ll use too:

$ mkdir App-foo
$ cd App-foo

This is the root project directory. Now I’m going to make a few subdirectories:

$ mkdir script
$ mkdir -p lib/App

lib/App is a parent directory for the stub module that we’ll create shortly. The script directory is where I’ll place the foo script.

Prepare the script for CPAN

I’ll copy my script to script/foo. One change I like to make my CPAN scripts is the shebang line. For my personal scripts I typically use:

#!/usr/bin/env perl

The advantage of this is by calling env the Perl that is executed can be changed by updating my PATH. This is great when you’re running perlbrew or plenv. However not everyone manages multiple installations of Perl this way. Instead, I like to use:

#!perl

When the distribution is installed, the shebang line is automatically changed to the absolute path of the Perl executable used to install the distribution, like this:

#!/home/dfarrell/.plenv/versions/5.22.0/bin/perl5.22.0

You can also use #!/usr/bin/perl and it will be overwritten by the install process. One reason I like #!perl is that it won’t work without either installing the script or specifying the perl to run it with. This avoids mistakes like accidentally running the script with system Perl.

I should also add some documentation, so the final script looks like this:

Make a stub module

The CPAN toolchain requires at least one package in every distribution1, so I’m going to make a stub lib/App/foo.pm:

package App::foo;
our $VERSION = 0.01;
=head1 NAME
App::foo - an app that usually prints "bar"
=head1 DESCRIPTION
This is a stub module, see F<script/foo> for details of the app.
=head1 AUTHOR
David Farrell
=head1 LICENSE
FreeBSD
=cut
1;

This stub module does a couple of important things: having the package means CPAN can index the module and it will be searchable on metacpan and installable by CPAN clients like cpan and cpanm. It sets the distribution version number and it includes some basic documentation to point users towards the foo script, which is the meat and potatoes of this distribution.

1 You can trick CPAN by editing the META files and not providing a Perl module. Check out stasis for an example of this. The downside is it’s not clear what other tools in the Perl toolchain might break without a real package. Not recommended.

Create a Makefile.PL

The other file we need is Makefile.PL. This is a Perl script which will create the Makefile that builds, tests and installs the module. Later I’ll use some of the built-in routines in the Perl toolchain to use our Makefile.PL to do a bit more than that.

This Makefile.PL script uses ExtUtils::MakeMaker. Right at the top of the script the statement use 5.008004 ensures this script can only be run by Perl version 5.8.4 or higher. The MINIMUM_PERL_VERSION entry is there so CPAN clients and services like CPAN testers will know what minimum Perl version is required to use the distribution.

You can see I’ve set the version and abstract text to come from the stub module. I’ve set the license to be FreeBSD, but there are many others that are accepted. Both the license and minimum Perl version entries are newer options that may generate warnings in older versions of ExtUtils::MakeMaker - that’s fine, they’ll be ignored and the build can continue regardless.

The EXE_FILES line is important; it will make sure the script is copied to an executable directory on installation. PREREQ_PM is a hashref of the runtime modules used by the script. In this case the first version of DateTime that supported the mon() method used in the script was 0.37 (technically mon() is an alias that I could switch to month() but that would make for a less interesting example). For the strict and warnings pragmas, there is no minimum version so I can just use zero.

The final part of the script begins with the eval and it’s a little odd. Older versions of ExtUtils::MakeMaker didn’t support version 2 of the CPAN meta specification, so using META_MERGE this will only be included if being built with a modern version. This optional entry can be used if the distribution code is in a repository like GitHub, otherwise it’s not needed. Sites like MetaCPAN will include a link to the repo on GitHub if this is present.

Create a README

I like to cheat for this one:

$ perldoc -u script/foo > README.pod

This writes the raw POD out of the script into README.pod. One thing to remember is to include installation instructions in this file. This is why I included it in the script POD.

Add a LICENSE file

I’ve already specified this distribution’s software license as FreeBSD in the makefile, so I should include a copy of the license in the distribution. This is easy with App::Software::License:

Build the distribution tarball

This creates the Makefile but also META files which define the metadata of the distribution. These is used by the CPAN toolchain for things like indexing, version control and dependency management (CPAN::Meta::Spec describes the metadata specification).

Upload to CPAN

I already have a PAUSE account, so I can skip this step. Otherwise prospective CPAN authors need to register for a PAUSE account. Don’t skip on the “A short description of why you would like a PAUSE ID” entry - this is one way the PAUSE admins identify human versus bot requests, and you don’t want to be mistaken for a bot!

Once I login to PAUSE, I can upload the distribution from the uploads page. These days I like to do it from the command line with CPAN::Uploader. That would work like this:

$ cpan-upload -u DFARRELL App-foo-0.01.tar.gz

cpan-upload will then prompt for my PAUSE password, and confirm the upload was successful.

Within a few minutes, I’ll receive two emails from PAUSE: one confirms the uploaded distribution file, the other confirms it was indexed. Depending on how fast the CPAN mirrors update their index, users can now install the module at their command line with:

$ cpan App::foo

Wrap-up

It may seem like a lot of work at first, but I only had to create the stub module and the Makefile.PL, both of which can be copied from elsewhere, and edited. The other files were generated. All the files described in this article are available in the GitHub repo.

Chapter 12 of Intermediate Perl describes how to create a Perl distribution in greater detail. perlnewmod is a brief overview of how create a module and prepare it for CPAN.

Site Map

Contact Us

Legal

PerlTricks.com and the authors make no representations or warranties with respect to the accuracy or completeness of the contents of all work on this website and specifically disclaim all warranties, including without limitation warranties of fitness for a particular purpose. No warranty may be created or extended. The advice and strategies published on this website may not be suitable for every situation. All work on this website is provided with the understanding that PerlTricks.com and the authors are not engaged in rendering legal, accounting, or other professional services. Neither PerlTricks.com nor the authors shall be liable for damages arising herefrom.