Following on from my previous post on CPAN terminology, this one focusses on the model and terminology related to dependencies: the modules that your dist uses, and the other CPAN distributions that use yours.

This post might seem a bit rough around the edges, because I've been writing it to clarify my understanding, and filling in gaps as I go. Let me know if I've got anything wrong or unclear, or missed anything you think fits here.

Module dependencies

Let's look at the module Web::Query, which gives you a jQuery-like interface for processing a web page. It uses List::MoreUtils, which in turn uses Exporter::Tiny:

This might seem obvious, but those are modules.

Distribution dependencies

You don't install modules though, you install the latest release of the distribution that contains the module. So when you type

# cpan Web::Query

you end up installing the Web-Query distribution. At the time I'm writing this, you'd install the 0.32 release of Web-Query, which is the tarball Web-Query-0.32.tar.gz

We started off talking about three modules, but now we're dealing with the distributions, all of which contain other modules:

Here the three modules we're talking about happen to be the main modules of their respective distributions. But this isn't always the case: if List::MoreUtils used Exporter::Shiny instead of Exporter::Tiny, then obviously that wouldn't be true (see, for example, Term::Vspark).

Upstream and downstream dependencies

Most of the time when people are talking about CPAN dependencies, they're talking about distribution dependencies. If we consider the three distributions above in the context of the river model, then here's roughly where they fit:

Exporter-Tiny and List-MoreUtils are both a long way up the river — they're used by a lot of other CPAN distributions. The usage count includes indirect usage: Web-Query uses Exporter-Tiny indirectly.

From the perspective of List-MoreUtils, Exporter-Tiny is upstream, and Web-Query is downstream. So for your distribution, upstream dependencies are the distributions that you use, and downstream dependencies are the ones using your dist.

Classifying the dependencies

So far we've been talking about runtime dependencies: every time your code uses List::MoreUtils , it uses Exporter::Tiny . This is called the runtime phase, and there are other phases that can have dependencies associated with them. The List-MoreUtils has a Makefile.PL , so if you were installing it manually, you'd run:

perl Makefile.PL make make test make install

With that in mind, these are the other phases:

configure dependencies are any modules that are needed to run Makefile.PL or Build.PL . List-MoreUtils has a Makefile.PL that uses ExtUtils::MakeMaker, so ExtUtils::MakeMaker is a configure dependency.

dependencies are any modules that are needed to run or . has a that uses ExtUtils::MakeMaker, so ExtUtils::MakeMaker is a configure dependency. build dependencies are those needed when you run make (or Build , if your distribution has a Build.PL ). This phase is blank for most distributions on CPAN, but if your distribution used the Template-Toolkit to build your .pm from templates, then you'd have Template listed as a build prereq.

dependencies are those needed when you run (or , if your distribution has a ). This phase is blank for most distributions on CPAN, but if your distribution used the Template-Toolkit to build your from templates, then you'd have Template listed as a build prereq. test dependencies are modules that are only used when running make test or Build test . This will often be Test::More and any other Test:: modules that your testsuite uses.

dependencies are modules that are only used when running or . This will often be Test::More and any other modules that your testsuite uses. develop dependencies are ones required by the author when working on, or releasing, the distribution, but that are not required when building, testing, or installing the dist. If your dist has author-only tests, and they rely on dists not used in your regular tests, then they'd be listed as develop dependencies rather than test dependencies.

In addition to phase, dependencies also have a relationship type, which in most cases specifies how hard the dependency is:

requires means the dist must be installed.

means the dist must be installed. recommends means that it's strongly encouraged, but not mandatory. For example, if your dist is doing HTTP, you might have IO::Socket::SSL as a recommended dependency, if most URLs are going to be https .

means that it's strongly encouraged, but not mandatory. For example, if your dist is doing HTTP, you might have IO::Socket::SSL as a recommended dependency, if most URLs are going to be . suggests are truly optional, but might enable additional functionality or performance. So if you're processing JSON, you might have JSON::PP as a required dependency (a core module since 5.14.0), and JSON::XS as a suggested dependency (in reality, these days you might just depend on JSON::MaybeXS, letting it worry about the upstream dependencies).

are truly optional, but might enable additional functionality or performance. So if you're processing JSON, you might have JSON::PP as a required dependency (a core module since 5.14.0), and JSON::XS as a suggested dependency (in reality, these days you might just depend on JSON::MaybeXS, letting it worry about the upstream dependencies). conflicts dependencies are anti-dependencies: they must not be installed when the particular phase is running. The spec says you should be very careful when specifying these. I've never seen a dist that does.

So now we can look at a more complete view of the upstream dependencies for List-MoreUtils, considering the modules used:

I didn't list all of the develop/requires dependencies. You can see that Test::More is required to run the test suite, but Test::LeakTrace is optional.

The official spec for dependency definitions is CPAN::Meta::Spec.

Core dependencies

One fuzzy area when specifying dependencies is core modules.

The main reason for specifying your dependencies is so that when a CPAN client is installing your distribution, it can check whether the dependencies are already installed, and if not, install them first.

But by definition, core modules will already have been installed.

As a result, some people list core module dependencies and some people don't. For example, List::MoreUtils uses strict and warnings, but they're not listed as formal prerequisites.

Personally I think you should list all prereqs:

Modules occasionally get dropped from the core, and while that's not likely to happen for strict or warnings, there's no harm in listing all modules you use.

Modules also get added to core, and given there are people using a lot of different versions of Perl out there, it's safest to just list everything.

If the module is dual-life, and you specify a minimum version, you might end up requiring a version which someone doesn't have with their version of Perl.

It is useful for CPAN analytics. For example I wanted to know how many CPAN distributions use Exporter, but it's hard to get an accurate figure because many of the dists using it don't list it as a runtime prereq (yes, you could use grep.cpan.me to come up with a rough figure).

Please enable JavaScript to view the comments powered by Disqus.

Disqus