Perl package guidelines
This document covers the creation of PKGBUILDs for Perl modules distributed over CPAN, the Comprehensive Perl Authors Network. For Perl policies, see Perl Policy.
Arch Linux packaging conventions
The following conventions ensure consistency in Perl module packaging for Arch Linux. Material is organized from simplest to most complex.
Package names
Module package names should begin with perl-, followed by the module name converted to lowercase with colons replaced by hyphens (e.g. HTML::Parser becomes perl-html-parser).
Package file placement
Perl packages should install module files to vendor directories by setting INSTALLDIRS=vendor. This installs to /usr/lib/perl5/version/vendor_perl/ for architecture-specific modules or /usr/share/perl5/vendor_perl/ for architecture-independent modules. Files should not be installed to site_perl directories (/usr/lib/perl5/version/site_perl/ and /usr/share/perl5/site_perl), which are reserved for installations outside the package management system (e.g. via the cpan shell).
The perllocal.pod and .packlist files should not be present; this is handled by the example PKGBUILDs below.
Architecture
Most Perl packages are architecture-independent and should use arch=('any'). XS modules are compiled into dynamically loaded libraries (.so files) and should set their architecture to arch=('x86_64') to indicate they are architecture-dependent when built. XS modules typically contain .xs files that dynamically generate .c files.
Automation
As Perl is centered around CPAN, there are tools that use it to generate PKGBUILDs and save you writing them by hand.
- App::cpan2arch — Generate PKGBUILD from CPAN metadata.
- CPANPLUS::Dist::Arch — A plugin for the second-generation CPAN shell. This plugin packages distributions on the fly as they are installed by CPANPLUS.
PKGBUILD examples
The following PKGBUILD examples use techniques to address Perl packaging issues. Because there are two types of build scripts, two examples are provided: the first for distributions using Makefile.PL, and the second for distributions using Build.PL. Their complexity is explained in the sections below.
PKGBUILD
# Maintainer: Your Name <youremail@domain.example>
_dist=Foo-Bar
pkgname=perl-foo-bar
pkgver=1.0
pkgrel=1
pkgdesc='This packages the Foo-Bar distribution, containing the Foo::Bar module!'
arch=('any')
url="https://metacpan.org/dist/$_dist"
license=('Artistic-1.0-Perl OR GPL-1.0-or-later')
depends=('perl')
options=('!emptydirs')
source=("https://cpan.metacpan.org/authors/id/BAZ/$_dist-$pkgver.tar.gz")
sha256sums=('deadbeef')
build() {
cd "$_dist-$pkgver"
unset PERL_MM_OPT PERL5LIB PERL_LOCAL_LIB_ROOT
export PERL_MM_USE_DEFAULT=1 PERL_AUTOINSTALL=--skipdeps
/usr/bin/perl Makefile.PL NO_PACKLIST=1 NO_PERLLOCAL=1
make
}
check() {
cd "$_dist-$pkgver"
unset PERL5LIB PERL_LOCAL_LIB_ROOT
make test
}
package() {
cd "$_dist-$pkgver"
unset PERL5LIB PERL_LOCAL_LIB_ROOT
make install INSTALLDIRS=vendor DESTDIR="$pkgdir"
}
PKGBUILD
# Maintainer: Your Name <youremail@domain.example>
_dist=Foo-Bar
pkgname=perl-foo-bar
pkgver=1.0
pkgrel=1
pkgdesc='This packages the Foo-Bar distribution, containing the Foo::Bar module!'
arch=('any')
url="https://metacpan.org/dist/$_dist"
license=('Artistic-1.0-Perl OR GPL-1.0-or-later')
depends=('perl')
makedepends=('perl-module-build')
options=('!emptydirs')
source=("https://cpan.metacpan.org/authors/id/BAZ/$_dist-$pkgver.tar.gz")
sha256sums=('deadbeef')
build() {
cd "$_dist-$pkgver"
unset PERL_MB_OPT PERL5LIB PERL_LOCAL_LIB_ROOT
export PERL_MM_USE_DEFAULT=1 MODULEBUILDRC=/dev/null
/usr/bin/perl Build.PL --create_packlist=0
./Build
}
check() {
cd "$_dist-$pkgver"
unset PERL5LIB PERL_LOCAL_LIB_ROOT
./Build test
}
package() {
cd "$_dist-$pkgver"
unset PERL5LIB PERL_LOCAL_LIB_ROOT
./Build install --installdirs=vendor --destdir="$pkgdir"
}
CPAN module mechanics
The CPAN module system involves fetching the module distribution, configuring and building it, running tests, and installing it into the system. Understanding how modules work independently of pacman and Arch Linux packages helps clarify how they should be packaged.
Modules
Modules are declared with the package keyword in Perl and contained in .pm files. Multiple modules can exist in a single file. Module namespaces use ::, e.g. Archlinux::Module. When loading a module, :: is replaced with directory separators, so Archlinux::Module loads from Archlinux/Module.pm.
Core modules are included with a Perl installation. Some core modules are only available bundled with Perl, while others can be downloaded and installed separately from CPAN.
Distributions
Distributions (also called dists or packages) are the CPAN equivalent of Arch Linux packages. They are .tar.gz archives containing .pm module files, tests, documentation, and other necessary files.
Usually a distribution contains a main module with the same name, but not always (e.g. Template-Toolkit-2.22.tar.gz from Template-Toolkit dist contains no Template::Toolkit module).
Because distributions are often named after their main module, the terms are sometimes used interchangeably, which can cause confusion. However, it is useful to consider them separate entities.
CPAN
CPAN mirrors provide plain-text indices listing modules, distributions, and authors; the primary index is /modules/02packages.details.txt.gz. Here "packages" refers to Perl's package keyword, not pacman packages. The CPAN shell (cpan) is a Perl script that uses these indices to locate and install modules.
Modules are listed in 02packages.details.txt.gz; each entry shows the module name, version, and the path to the distribution tarball that contains the module. When you ask cpan to install a module, it looks up the module, downloads and installs the relevant distribution. During the build, dependency information from metadata is used and cpan will try to ensure required dependencies are installed. If a required dependency is missing or a version requirement is not met, cpan will attempt to fetch and install a distribution that satisfies the requirement.
Only the latest version per module is listed in 02packages.details.txt.gz. Perl package authors should not assume consumers will always receive their most recent release, since pacman dependency checking is more static and strictly enforced.
Module dependencies
Perl distributions depend on modules (unlike Python eggs or Ruby gems, which depend on other eggs or gems). Modules are obtained from CPAN distributions and define their own versions independently using a $VERSION package variable:
package Foo::Module; use warnings; use strict; our $VERSION = '1.00';
Module versions can differ from their distribution version, which can be problematic. Determining module versions externally requires parsing Perl code or loading the module; however, they are easily accessible from within Perl:
use Foo::Module; print $Foo::Module::VERSION, "\n";
Dependency definition
Dependencies are defined in the Makefile.PL or Build.PL script. For example, in Makefile.PL, WriteMakefile is called to generate the Makefile:
use ExtUtils::MakeMaker;
WriteMakefile(
NAME => 'ArchLinux::Module',
VERSION => '0.01',
PREREQ_PM => { POSIX => '0.01' },
);
Dependencies are not final until after the Makefile.PL or Build.PL script is run. Since dependencies are specified at runtime using Perl, authors can add, remove, or modify dependencies before the distribution is installed. Some module authors use this to do clever things like depend on modules only if they are installed. Also, some multi-platform dists depend on system-specific modules when installed on different operating systems.
For example, the CPANPLUS distribution checks for installed CPANPLUS::Dist plugins and adds them to the new CPANPLUS's prerequisites if any plugins are installed for the current installed CPANPLUS. However, most dependencies are static as shown in the above example where POSIX requires a minimum version of 0.01.
Metadata
Meta files in modern Perl distributions contain information such as the distribution name, author, abstract, and module requirements. Older distributions used META.yml but newer ones use META.json. These files are typically generated when packaging the distribution for release, e.g. by Makefile.PL or Build.PL. See CPAN::Meta::Spec for the latest specification.
Since the build script can modify dependencies at runtime, a secondary meta file, MYMETA.json, is generated to reflect these runtime changes and may differ from the META.json packaged for CPAN.
Ancient distributions on CPAN have no meta file at all and instead only describe their prerequisites in their Makefile.PL, because these releases predate the idea of the META.yml.
Installation modules
CPAN contains a vast number of modules. Consequently, following Perl's philosophy of "There's More Than One Way to Do It" (TMTOWTDI), several installation modules are available.
Installation modules work by placing a build script (a Perl file with a .PL suffix) in the distribution tarball. Running this script configures the distribution before building it, running tests, and installing module files to the user's preferred location. Handling this across different systems can be complex, which is why multiple installation tools exist.
ExtUtils::MakeMaker
- Build script
Makefile.PL- CPAN link
- https://metacpan.org/pod/ExtUtils::MakeMaker
ExtUtils::MakeMaker is the oldest module for installing Perl distributions. Its major downside is requiring the make program, which is not available by default on Windows systems.
Module::Build
- Build script
Build.PL- CPAN link
- https://metacpan.org/pod/Module::Build
Module::Build is pure-perl, eliminating the need for make. Initially, adoption was hindered because Build.PL required Module::Build to already be installed. This was resolved when Module::Build became a Perl core module.
Module::Build was removed from core in Perl 5.22. [1]Module::Build::Tiny
- Build script
Build.PL- CPAN link
- https://metacpan.org/pod/Module::Build::Tiny
Module::Build::Tiny is a lightweight pure-perl build tool that implements a minimal subset of Module::Build. Arguments must be prefixed with dashes (unlike Module::Build, which accepts both), and it does not support .modulebuildrc.
Module::Install
- Build script
Makefile.PL- CPAN link
- https://metacpan.org/pod/Module::Install
Module::Install was designed as a drop-in replacement for ExtUtils::MakeMaker to address some of MakeMaker's shortcomings. Despite this, Module::Install depends on MakeMaker to operate. Makefile.PL files generated by Module::Install use a simple domain-specific language.
Module::Install bundles a complete copy of itself into the distribution, eliminating the need to have it installed on your system, unlike MakeMaker or Module::Build.
Auto-install is a feature discouraged by Module::Install's authors but widely used. When enabled, Module::Install searches for and installs missing prerequisites when Makefile.PL is executed. This feature is skipped when run by CPAN or CPANPLUS, but not when run inside a PKGBUILD, potentially allowing arbitrary module installation. See #PERL_AUTOINSTALL to disable this.
Module::Install is discouraged by the maintainers [2] since it has become largely unmaintained and is considered obsolete in the modern CPAN toolchain. [3]Environment variables
Environment variables can affect how modules are built or installed. Some can cause problems if misunderstood, potentially breaking a PKGBUILD or causing unexpected behavior.
PERL_MM_USE_DEFAULT
When set to a true value, causes the installation module to skip interactive prompts and use default answers. All installation modules respect this variable, though module authors may not.
PERL_AUTOINSTALL
Set this variable to pass command-line arguments to Module::Install's Makefile.PL. Disable auto-install (recommended) with:
export PERL_AUTOINSTALL='--skipdeps'
PERL_MM_OPT
Set this variable to pass command-line arguments to Makefile.PL. For example, to install modules into your home directory:
export PERL_MM_OPT=INSTALLBASE=~/perl5
PERL_MB_OPT
Set this variable to pass command-line arguments to Module::Build. For example, to install modules into your home directory:
export PERL_MB_OPT=--install_base=~/perl5
MODULEBUILDRC
Module::Build uses an rcfile to override command-line arguments, which defaults to ~/.modulebuildrc. Set MODULEBUILDRC to specify an alternative rcfile path, or set it to /dev/null to disable this.
.modulebuildrc is considered deprecated within the Perl toolchain. [4]PERL5LIB
The directories searched for libraries can be set by the user (particularly if they are using local::lib) with this variable. That should be cleared before building.
PERL_LOCAL_LIB_ROOT
This variable will be set if the user is using local::lib. That should be cleared before building.
Problems with user-installed perl
Users may install multiple perl versions for testing or custom builds. If a custom perl is in $PATH, it will be executed during PKGBUILD runs instead of the system perl.
This causes problems with compiled XS modules. XS modules use Perl's internal C API, which changes between versions. If compiled against a custom perl version, they will fail to load with link errors when run by system perl.
To avoid this, always use the absolute path /usr/bin/perl in PKGBUILDs.