Perl 包指南
32 位 – CLR – CMake – 交叉编译 – DKMS – Eclipse – Electron – 字体 – Free Pascal – GNOME – Go – Haskell – Java – KDE – 内核模块 – Lisp – Meson – MinGW – Node.js – 非自由软件 – OCaml – Perl – PHP – Python – R – Ruby – Rust - 安全 – Shell – VCS – Web – Wine
本文档涵盖了为通过 CPAN(Comprehensive Perl Authors Network,综合 Perl 作者网络)分发的 perl 模块创建 PKGBUILD 的内容。本文档的目标读者是 perl 模块的打包者。有关 Perl 策略,请参阅 Perl 策略。
Arch Linux 打包约定
应使用以下约定来保持 perl 模块软件包的一致性。本节从 Arch Linux 的角度介绍 perl 打包的概念;即软件包管理和系统管理。为了让只想快速了解的读者满意,最简单和/或最流行的材料放在最前面。
软件包名称
对于模块,软件包名称应以 perl-
开头,名称的其余部分应通过将模块名称转换为小写,然后将冒号替换为连字符来构建。例如,与 HTML::Parser
对应的软件包名称将是 perl-html-parser
。Perl 应用程序应具有与应用程序相同的名称,但应为小写。
软件包文件位置
Perl 软件包应将模块文件安装到 /usr/lib/perl5/$version/vendor_perl/
(在脚本中使用 perl -V:vendorarch
),或 /usr/share/perl5/vendor_perl/
。这通过将 INSTALLDIRS
命令行参数设置为 vendor
来完成,如下所示。不应将任何文件存储在 /usr/lib/perl5/$version/site_perl/
中,因为该目录保留供系统管理员在软件包管理系统之外安装 Perl 软件包使用。当用户使用 cpan shell 全系统安装模块时,模块最终会出现在 site-perl 子目录中。
文件 perllocal.pod
和 .packlist
也不应存在;这由下面描述的 PKGBUILD 示例处理。
架构
在大多数情况下,arch
数组应包含 'any'
,因为大多数 Perl 软件包与架构无关。XS 模块被编译成动态加载库(.so 文件),应将其架构明确设置为 ('x86_64')
,以表明它们在构建时与架构相关。XS 模块通常包含一个或多个 .xs 文件,这些文件动态生成 .c 文件。
自动化
第二代 CPAN shell CPANPLUS 的插件在 perl-cpanplus-dist-arch 软件包中提供。此插件会在 CPANPLUS 安装发行版时动态打包发行版。在线文档可在 https://metacpan.org/release/CPANPLUS-Dist-Arch 获取
PKGBUILD 示例
PKGBUILD 示例可以在 [1] 找到。
以下两个 PKGBUILD 示例使用了本页介绍的技术,旨在使 PKGBUILD 更能应对更复杂的问题。由于构建脚本有两种样式,因此有两个 PKGBUILD 示例。第一个 PKGBUILD 示例说明了如何打包使用 Makefile.PL
的发行版。第二个 PKGBUILD 可以用作使用 Build.PL
的发行版的起点。
PKGBUILD
# Contributor: Your Name <youremail@domain.example> pkgname=perl-foo-bar pkgver=1.0 pkgrel=1 pkgdesc='This packages the Foo-Bar distribution, containing the Foo::Bar module!' _dist=Foo-Bar arch=('any') url="https://metacpan.org/release/$_dist" license=( 'GPL-1.0-or-later' 'Artistic-1.0-Perl' ) depends=('perl') options=('!emptydirs' 'purge') source=("https://cpan.metacpan.org/authors/id/BAZ/$_dist-$pkgver.tar.gz") md5sums=(...) build() { cd $_dist-$pkgver unset PERL5LIB PERL_MM_OPT PERL_LOCAL_LIB_ROOT export PERL_MM_USE_DEFAULT=1 PERL_AUTOINSTALL=--skipdeps /usr/bin/perl Makefile.PL make } check() { cd $_dist-$pkgver unset PERL5LIB PERL_MM_OPT PERL_LOCAL_LIB_ROOT export PERL_MM_USE_DEFAULT=1 make test } package() { cd $_dist-$pkgver unset PERL5LIB PERL_MM_OPT PERL_LOCAL_LIB_ROOT make install INSTALLDIRS=vendor DESTDIR="$pkgdir" }
PKGBUILD
# Contributor: Your Name <youremail@domain.example> pkgname=perl-foo-bar pkgver=1.0 pkgrel=1 pkgdesc='This packages the Foo-Bar distribution, containing the Foo::Bar module!' _dist=Foo-Bar arch=('any') url="https://metacpan.org/release/$_dist" license=( 'GPL-1.0-or-later' 'Artistic-1.0-Perl' ) depends=('perl') makedepends=('perl-module-build') options=('!emptydirs' 'purge') source=("https://cpan.metacpan.org/authors/id/BAZ/$_dist-$pkgver.tar.gz") md5sums=(...) build() { cd $_dist-$pkgver unset PERL5LIB PERL_MM_OPT PERL_MB_OPT PERL_LOCAL_LIB_ROOT export PERL_MM_USE_DEFAULT=1 MODULEBUILDRC=/dev/null /usr/bin/perl Build.PL ./Build } check() { cd $_dist-$pkgver unset PERL5LIB PERL_MM_OPT PERL_MB_OPT PERL_LOCAL_LIB_ROOT export PERL_MM_USE_DEFAULT=1 ./Build test } package() { cd $_dist-$pkgver unset PERL5LIB PERL_MM_OPT PERL_MB_OPT PERL_LOCAL_LIB_ROOT ./Build install --installdirs=vendor --destdir="$pkgdir" }
在后面的章节中尝试解释了这些 PKGBUILD 增加复杂性的理由。
CPAN 模块机制
有许多精心设计和不太精心设计的机制协同工作以创建模块系统。当使用 CPAN 时,必须遵循程序来获取模块的源代码,构建获取的模块,并将其插入到系统软件中以供以后执行。为了理解应该如何打包模块,如果理解模块在没有任何来自 pacman 和 Arch Linux 软件包的参与下是如何工作的,将非常有帮助。我们最终的目标是尽量做到不引人注目,同时提高最终产品的组织性和一致性。
模块
模块在 perl 中使用 package
关键字声明。模块包含在 .pm
(“dot-pee-em”)文件中。尽管一个文件中可能包含多个模块 (package
)。模块具有用 ::
(双冒号)分隔的命名空间,例如:Archlinux::Module
。加载模块时,::
被替换为目录分隔符。例如:将为模块 Archlinux::Module
加载 Archlinux/Module.pm
。
核心模块包含在 perl 安装中。某些核心模块仅与 perl 捆绑提供。其他模块仍然可以从 CPAN 单独下载和安装。
发行版
(又名 dist,package)这相当于 CPAN 术语中的 Arch Linux 软件包。发行版是充满文件的 .tar.gz
存档。这些存档主要包含 .pm 模块文件、包含模块的测试、模块的文档以及任何其他认为必要的内容。
通常,发行版包含一个具有相同名称的主模块。有时情况并非如此,例如 Template-Toolkit 发行版。最新的软件包 Template-Toolkit-2.22.tar.gz
,对于 Template-Toolkit
发行版,不包含 Template::Toolkit
模块!
有时因为发行版以主模块命名,所以它们的名称可以互换使用,并且它们会混淆在一起。但是,有时将它们视为单独的实体很有用(例如在 Template-Toolkit 的情况下)。
CPAN
每个 CPAN 镜像都包含索引,其中列出了 CPAN 上的发行版、发行版中的模块以及上传发行版的作者姓名。这些只是文本文件。最有用的索引在每个 CPAN 镜像提供的 /modules/02packages.details.txt.gz
文件中。“软件包”一词在这里指的是 perl 语言本身的 package
关键字,而不是类似于 pacman 软件包的东西。CPAN shell,通常小写并斜体化为 cpan,只是一个古老的 perl 脚本,它导航索引以找到您想要安装的模块。
模块在 02packages.details.txt.gz
列表中找到。与模块/软件包名称在同一行的是包含该模块的发行版 tarball 的路径。当您要求 cpan 安装模块时,它将查找该模块并安装相关的发行版。在安装发行版时,它将生成模块依赖项列表。Cpan 将尝试将每个模块依赖项加载到 perl 解释器中。如果无法加载给定版本的模块,则重复该过程。
cpan shell 不必担心它正在安装的所需模块的版本。cpan 可以依赖于这样一个事实,即最新版本的模块必须满足它最初开始安装的原始模块的要求。软件包详细信息文件中仅列出了模块的最新版本。不幸的是,对于 perl 软件包作者来说,我们不能总是依赖于我们的软件包提供 perl 发行版的最新版本以及其中包含的模块。Pacman 依赖项检查更加静态且强制性更强。
模块依赖
与 python eggs 和 ruby gems 等类似系统相比,Perl 有一种独特的定义依赖项的方式。Eggs 定义对其他 eggs 的依赖项。Gems 依赖于 gems。Perl dists 依赖于模块。模块仅可从 CPAN 发行版获得,因此在某种程度上,perl 发行版仅间接依赖于发行版。模块可以在模块源代码中定义独立于发行版版本的版本。这是通过定义一个名为 $VERSION
的package 变量来完成的。当使用 strict 和 warnings 时,这是用 our 关键字定义的。例如
package Foo::Module; use warnings; use strict; our $VERSION = '1.00';
模块可以随意更改其版本,甚至可以具有与发行版版本不同的版本。这的实用性值得怀疑,但重要的是要记住这一点。模块版本更难从 perl 解释器外部确定,并且需要解析 perl 代码本身,甚至可能需要将模块加载到 perl 中。优点是从 perl 解释器内部很容易确定模块版本。例如
use Foo::Module; print $Foo::Module::VERSION, "\n";
依赖定义
依赖项在 perl 发行版中的什么位置定义?它们在 Makefile.PL
或 Build.PL
脚本中“定义”。例如,在 Makefile.PL
脚本中,调用 WriteMakeFile
函数来生成 Makefile
,如下所示
use ExtUtils::MakeMaker; WriteMakeFile( 'NAME' => 'ArchLinux::Module', 'VERSION' => '0.01', 'PREREQ_PM' => { 'POSIX' => '0.01' }, );
这是一个人为的例子,但重要的是要理解依赖项在运行 Makefile.PL
或 Build.PL
脚本之后才最终确定。依赖项在运行时指定,这意味着可以使用 perl 的全部功能来更改或修改它们。这意味着模块作者可以在安装发行版之前添加、删除或更改依赖项的版本。一些模块作者使用它来做过于聪明的事情,例如仅在安装模块时才依赖模块。一些多平台发行版在不同的操作系统上安装时也依赖于特定于系统的模块。
例如,CPANPLUS 发行版会查找当前安装的 CPANPLUS::Dist 插件。如果为当前安装的 CPANPLUS 版本安装了任何插件,它会将它们添加到新 CPANPLUS 的先决条件中。我不太确定为什么。幸运的是,对于 perl 打包者来说,大多数依赖项都是静态的,就像上面的例子中那样,它需要 POSIX 模块,最低版本为 0.01。
元信息
元文件包含在最新的发行版中,其中包含有关发行版的元信息,例如名称、作者、摘要描述和模块要求。以前有 YAML 格式的 META.yml
文件,但最近已切换到 JSON 格式的 META.json
文件。这些文件可以手动编辑,但更常见的是,它们在打包发行版以发布时由 Makefile.PL
或 Build.PL
脚本自动生成。最新的规范在 CPAN::Meta::Spec 的在线文档中描述。
请记住,依赖项可以在运行时更改!因此,在运行构建脚本后会生成另一个元文件。第二个元文件称为 MYMETA.json
,它反映了脚本在运行时所做的更改,并且可能与在为 CPAN 打包发行版时生成的元文件不同。
CPAN 上的旧发行版根本没有元文件。这些旧版本早于 META.yml 文件的概念,仅在其 Makefile.PL
中描述了它们的先决条件。
安装模块
perl 最伟大的优势之一是 CPAN 上提供的模块数量之多。毫不奇怪,也有几个不同的模块用于安装……嗯……模块!TMTOWTDI!我不知道这些类型的模块的标准名称,所以我只是将它们称为“安装模块”。
这些模块关注构建发行版并将模块文件安装到用户喜欢的任何位置。这看起来很简单,但考虑到 perl 运行的各种不同系统,这可能会变得很复杂。安装模块都将 perl 代码文件放在 dist tarball 中。运行此 perl 脚本将启动构建和安装过程。该脚本始终以 .PL
后缀结尾,并在下面的列表中称为“构建脚本”。
ExtUtils::MakeMaker
- 构建脚本
Makefile.PL
- CPAN 链接
- https://search.cpan.org/dist/ExtUtils-MakeMaker
用于安装模块的原始、最古老的模块是 ExtUtils::MakeMaker
。此模块的主要缺点是它需要 make
程序来构建和安装所有内容。对于 linux 用户来说,这似乎没什么大不了的,但对于 Windows 用户来说,这确实很麻烦!
Module::Build
- 构建脚本
Build.PL
- CPAN 链接
- https://search.cpan.org/dist/Module-Build
Module::Build 的主要优点是它是纯 perl 的。这意味着它不需要安装 make
程序即可构建/安装模块。它的采用过程很坎坷,因为如果尚未安装 Module::Build
,您将无法运行捆绑的 Build.PL
脚本!对于最新版本的 perl 来说,这不是问题,因为 Module::Build
是一个核心模块。(注意:从 perl 5.22 开始,Module::Build 将不再是核心模块)
Module::Build::Tiny
- 构建脚本
Build.PL
- CPAN 链接
- https://search.cpan.org/dist/Module-Build-Tiny
这是另一个纯 perl 构建工具。作为接口,它实现了 Module::Build 接口的子集,特别是它要求参数前带有破折号(Module::Build 接受带或不带破折号的参数),并且不支持 .modulebuildrc
。
Module::Install
- 构建脚本
Makefile.PL
- CPAN 链接
- https://search.cpan.org/dist/Module-Install
另一个现代构建/安装模块 Module::Install
仍然需要安装 make
程序才能运行。MI
被设计为 MakeMaker
的直接替代品,以解决 MakeMaker
的一些缺点。具有讽刺意味的是,它依赖于 MakeMaker
才能运行。MI
生成的 Makefile.PL
文件看起来非常不同,并且是使用简单的领域特定语言实现的。
一个非常有趣的功能是 Module::Install
将完整副本的自身捆绑到发行版文件中。因此,与 MakeMaker
或 M::B
不同,您不需要在系统上安装 Module::Install
。
另一个非常独特的功能是自动安装。尽管 Module::Install
的作者不推荐此功能,但此功能的使用非常频繁。当模块作者为其发行版启用自动安装时,Module::Install
将搜索并安装在执行 Makefile.PL
时未安装的任何先决条件模块。当 Module::Install
检测到它正在由 CPAN
或 CPANPLUS
运行时,将跳过此功能。但是,当在……哦,我不知道……PKGBUILD 中运行时,不会跳过此功能!我希望您能看到一个流氓 perl 程序在 PKGBUILD 内部随意下载和安装模块会成为什么问题。请参阅 #PERL_AUTOINSTALL 环境变量,以了解如何解决此问题。
环境变量
许多环境变量会影响模块的构建或安装方式。有些具有非常显着的效果,如果被误解,可能会导致问题。高级用户可能正在使用这些环境变量。其中一些变量会破坏毫无戒心的 PKGBUILD 或导致意外行为。
PERL_MM_USE_DEFAULT
当此变量设置为真值时,安装模块将假装对它通常会提出的任何问题给出了默认答案。这并不总是有效,但所有安装模块都遵守它。但这并不意味着模块作者会遵守!
PERL_AUTOINSTALL
您可以使用此变量将其他命令行参数传递给 Module::Install
的 Makefile.PL
。为了关闭自动安装(强烈建议),请为此变量赋值 --skipdeps
。
export PERL_AUTOINSTALL='--skipdeps'
PERL_MM_OPT
您可以使用此变量将其他命令行参数传递给 Makefile.PL
和/或 Build.PL
。例如,您可以使用以下命令将模块安装到您的主目录中
export PERL_MM_OPT=INSTALLBASE=~/perl5
PERL_MB_OPT
这与 PERL_MM_OPT
相同,只是它仅适用于 Module::Build
。例如,您可以使用以下命令将模块安装到您的主目录中
export PERL_MB_OPT=--install_base=~/perl5
MODULEBUILDRC
Module::Build
允许您使用 rc 文件覆盖其命令行参数。默认情况下为 ~/.modulebuildrc
。这在 perl 工具链中被认为是已弃用的。您可以通过在 MODULEBUILDRC
中设置 rc 文件的路径来覆盖它使用的文件。偏执狂可能会将 MODULEBUILDRC
设置为 /dev/null
……以防万一。
PERL5LIB
用户可以通过设置 PERL5LIB
来设置库的搜索目录(特别是如果他们正在使用 Local::Lib
)。应在构建之前清除它。
PERL_LOCAL_LIB_ROOT
如果用户正在使用 Local::Lib
,它将设置 PERL_LOCAL_LIB_ROOT
。应在构建之前清除它。
用户安装 perl 的问题
一个微妙的问题是,高级 perl 程序员可能喜欢安装多个版本的 perl。这对于测试已创建程序的向后兼容性很有用。编译您自己的自定义 perl 解释器(即不带线程)也有速度优势。自定义 perl 的另一个原因仅仅是因为官方 perl Arch Linux 软件包有时落后于 perl 版本。用户可能正在尝试最新的 perl……谁知道呢?
如果用户在其 $PATH
中有自定义 perl 可执行文件,则当用户在 shell 上键入 perl 命令时,将运行自定义 perl。事实上,自定义 perl 也将在 PKGBUILD
内部运行!这可能会导致难以理解的隐蔽问题。
问题在于编译后的 XS 模块。这些模块桥接 perl 和 C。因此,它们必须使用 perl 的内部 C API 来完成此桥接。Perl 的 C API 随不同版本的 perl 略有变化。如果用户的 perl 版本与系统 perl (/usr/bin/perl
) 不同,则使用用户的 perl 编译的任何 XS 模块都将与系统范围的 perl 不兼容。当尝试将编译后的 XS 模块与系统 perl 一起使用时,该模块将无法加载并出现链接错误。
一个简单的解决方案是在 PKGBUILD
中运行 perl 时始终使用系统范围的 perl 解释器的绝对路径 (/usr/bin/perl
)。