CPAN Dependencies, static and dynamic
Dependencies or prerequisites are an integral feature of the CPAN software repository. They define what other CPAN modules are required for a particular CPAN distribution to be built, tested, or ultimately to function, as well as optionally to improve or add functionality. To define them properly for a distribution, it is helpful to understand exactly how they will be used, and what all the different distribution files like Makefile.PL, Build.PL, META.json, and MYMETA.json are for.
sidebar: In this post, I will focus on the "requires" relationship for dependencies, which are hard dependencies that must be satisfied, but "recommends" and "suggests" relationships are also defined that indicate strongly and weakly optional dependencies respectively; CPAN installers may install these based on the options that are passed.
Most commonly and at a basic level, dependencies are defined in a (generated) file called META.json in the root of the CPAN distribution, but this may not be the complete picture. CPAN installers historically would determine what is needed at the time that the user requests to install the distribution ("install time"), and though there is now the formal concept of static prerequisites (the most common case where they are the same for every install environment), some distributions need to determine prerequisites at install time, using the original dynamic configuration process.
The Configure Phase
The very first step any CPAN installer takes is to check the primary metadata file META.json, or if that's not present, META.yml (which represents an older metadata specification). In this file, it finds the prereqs key, and within it the configure sub-key. This contains the prerequisites for the "configure" phase of CPAN installation, which largely consists of running the configure script (a file called Makefile.PL or Build.PL), so these dependencies must be installed before doing anything else. This, like the installation of other prerequisites later, is a recursive process, which starts again at the configure phase for each dependency installed in the chain, until it makes its way back up the tree to complete the installation of the originally requested CPAN distribution.
sidebar: The configure phase was not initially part of the specification, so ancient CPAN installers could only use core modules in the configure script; the introduction of configure phase dependencies enabled the configure script to use alternative installers like Module::Build::Tiny in place of the original ExtUtils::MakeMaker. This also meant that Module::Build could be removed from core, and Module::Install's overly clever bundling mechanism was no longer necessary.
The CPAN installer also can check two other metadata keys at this point: dynamic_config and x_static_install. dynamic_config, as the name implies, was initially meant to indicate whether the configure phase needs to be run to dynamically configure the distribution, but unfortunately in practice only indicates whether the prereqs specifically are dynamic. In other words, if this key is present and set to 0 (false), this indicates that the full list of prerequisites in META.json can be used as-is. It does not, however, allow the CPAN installer to skip the configure phase, as the configure script may do anything else a Perl script can do relevant to configuring the distribution, such as determining whether it can be installed at all in the current environment, or even dynamically generating other source files from .PL scripts.
The newer x_static_install is an unofficial metadata key that some installers are beginning to recognize as a second attempt to allow simple distributions to skip dynamic configuration; if this key is set to 1 (true) then the installer may choose to ignore the configure script and install the distribution with its own standard process. As of this writing, the cpm installer and development releases of the cpanm installer implement their own installation procedure by default if this metadata key is set: installing static prerequisites, running tests if requested, and finally copying the files to the install location. Otherwise, installation proceeds through the dynamic process below.
Once the configure prerequisites are installed, the configure script (Makefile.PL or Build.PL) is run. For historical reasons, Build.PL is run if both are present. This script is expected to do a couple specific things to inform the rest of the installation process: create a Makefile or Build script to handle the testing and installation functionality, and create a MYMETA.json (or MYMETA.yml) secondary metadata file. When dynamic_config has not been disabled, this new metadata file will be consulted for the remaining set of prerequisites, so it is the job of the configure script to dynamically determine this new list of prerequisites. Note that, because this happens during the configure phase itself, configure prerequsites cannot be dynamic.
Everything Else
Once prereqs are gathered either statically or from MYMETA, the CPAN installer will then install the prereqs from the other three installation phases: build, test, and runtime. Though it will only be subsequently building and testing the module, the runtime phase is considered a subset that is needed for both of these operations, so these prereqs are also required at this point. The CPAN installer can then build, test, and install the distribution, using the Makefile or Build script (or its own implementation in the case of x_static_install).
Technically, only the runtime phase dependencies are needed after installation, but configure and build prereqs are usually relatively light and may also be present in the runtime phase, so it's usually not worth the effort to exclude these from the runtime environment, but a CPAN installer could decide to only install them temporarily. Any test phase prereqs can be excluded by doing "notest" installations with most CPAN installers, which will avoid installing them at all.
So what does this all mean, as a CPAN author? It largely depends on your choice of authoring tool, but for static dependencies they will often be defined as a straightforward list in a configuration or metadata file, used by the authoring tool to generate the prereqs key of the shipped META.json file. For dynamic dependencies, instead of the authoring tool, the chosen installer used in the configure script (like ExtUtils::MakeMaker or Module::Build) must assemble the final dependency list when it runs at install time. This is often a gritty manual process, but some tools like Dist::Zilla::Plugin::DynamicPrereqs and Dist::Zilla::Plugin::DynamicPrereqs::Meta can help to structure the necessary logic.
sidebar: You may be familiar with the cpanfile format for declaring dependencies, but this is not directly relevant to CPAN dependency specification. A cpanfile may be used as an input file to an authoring tool to assemble a distribution's prerequisites into META.json for shipping, or as input directly to applications like cpanm or carton, but CPAN installers won't reference it while installing a standard CPAN distribution (unless specifically used by the configure script such as with ExtUtils::MakeMaker::CPANfile).
For further reading, I've written more about the structure and history of CPAN authoring in my Dist::Zilla::Starter tutorial.
I blog about Perl.
Leave a comment