32

SO上最近的一个问题让我思考。

在我尝试过的大多数 Linux 发行版上,一些 Perl 模块可以通过包管理器获得。其他人,当然不是。有一段时间,每当我需要安装一些 CPAN 模块时,我都会使用我的包管理器来确定一个包是否可用,并在它可用时安装它。

明显的优势是,只要有新版本的软件包可用,您就可以更新模块。

但是,当模块不以预打包形式提供并且该模块存在依赖项时,您就会遇到麻烦。每次 cpan shell 询问它是否应该遵循依赖项时都启动你的包管理器可能会很累人。

通常,另一个缺点是预打包模块的版本。如果您正在运行 Debian 或 Ubuntu,您很快就会发现您将无法生活在最前沿,就像许多 CPAN 模块作者似乎所做的那样。

Linux 上的其他 Perl 人员如何处理这个问题?你只是忽略了你的包管理器必须提供的东西吗?是否有任何工具可以使 apt(例如)和 cpan 成为更好的队友?还是您根本不通过 cpan shell 安装任何东西?

4

10 回答 10

35

为了开发,我安装了我自己的 Perl 并且不理会系统 Perl。如果我想升级系统 Perl,我使用系统包管理器。对于我的 Perl 开发,我使用 cpan 工具。

由于我将它们分开,我不应该弄乱系统维护任务等所需的 Perl,但我不必依赖系统的开发决策。

安装单独的 Perls 非常容易。当您从源代码分发版运行配置时,它会询问您要将所有内容安装在哪里。给它任何你喜欢的路径。例如,我在/usr/local/perls中安装了许多 Perls ,并且每个安装的所有内容都单独存在。然后我在/usr/local/bin中为它们创建符号链接(例如 perl5.8.9、perl.5.10.0、perl5.10.0 线程)。当我想要一个特定版本时,我只使用我想要的那个:

$ perl5.10.0 program.pl

特定的二进制文件确保程序选择正确的模块搜索路径等等(与该二进制文件的 Config.pm 模块中的内容相同)。

这是我用来创建符号链接的脚本。它在 bin 目录中查找,找出 Perl 版本,并制作类似的链接cpan5.10.1等等。每个程序都已经知道要调用的正确 perl:

#!perl

use 5.010;

use strict;
use warnings;

use File::Basename;
use File::Spec::Functions;

my $perls_directory = catfile(
    $ARGV[0] // '/usr/local/perls', 
    'perl*'
);
die "$perls_directory does not exist!\n" 
    unless -d dirname $perls_directory;

my $links_directory = $ARGV[1] // catfile( $ENV{HOME}, 'bin' ); #/
die "$links_directory does not exist!\n" unless -d $links_directory;

foreach my $directory ( glob( $perls_directory ) )
{
    say "Processing $directory...";

    unless( -e catfile( $directory, 'bin' ) )
    {
        say "\tNo bin/ directory. Skipping!";
        next;
    }

    my @perls = glob( catfile( $directory, qw( bin perl5* ) ) );    

    my( $perl_version ) = $perls[0] =~ m/(5\.\d+\.\d+)\z/;
    say "\tperl version is $perl_version";

    foreach my $bin ( glob( catfile( $directory, 'bin', '*' ) ) )
    {
        say "\tFound $bin";
        my $basename = basename( $bin );

        my $link_basename = do {
            if( $basename =~ m/5\.\d+\.\d+\z/) { $basename }
            else                               { "$basename$perl_version" }
        };

        my $link = catfile( $links_directory, $link_basename );
        next if -e $link;
        say "\t\tlinking $bin => $link";
        symlink $bin => $link or
            warn "\t\tCould not create symlink [$!]: $bin => $link!";
    }
}

对于特定的 Perl,一切都安装在正确的位置。

我也一直在考虑应该将那些 Perl 目录置于某种源代码控制之下。如果我添加了一个我不喜欢的模块,我会退回到较早的版本。不过,我才刚刚开始这样做,而且还没有玩太多。

我在 Effective Perler 博客中写了更多关于这类事情的文章:

于 2008-12-29T19:23:13.820 回答
12

我们通过 CPAN shell 安装所有东西。这确实忽略了包管理器必须提供的功能,但它避免了您在尝试使用它们时提到的令人头疼的问题(触发依赖关系,使用正确的版本)。

此外,这意味着我们的包可以在任何运行 CPAN 的平台上以编程方式(或通过 shell 手动)构建。依赖包管理器会影响您将软件分发到不使用/支持该包管理器的平台的能力。

于 2008-12-29T18:06:23.243 回答
9

自从最初提出这个问题以来,perlbrew已经发布。它使安装自定义的、独立的 perl 安装变得微不足道。在这些版本之间切换同样简单:

perlbrew switch $version
于 2012-03-13T14:32:48.227 回答
7

我使用Debian进行开发和生产,并依赖发行版提供的 debian Perl 软件包。

对于需要在 debian 中不可用的 Perl 模块的情况,我通常会创建自己的 debian 包并安装它。

当然,这种方法也不是没有缺陷,因为很多 debian perl 模块已经过时(至少在当前的 debian 稳定版本 - etch 中),并且向后移植像Catalyst这样有很多依赖关系的东西是不切实际的。

但是,通过依赖 OS 包管理器,我保留了它的所有强大功能,这些功能带来了轻松的维护,特别是对于已部署的服务器,因为您确切知道安装了哪些包,以及一个简单的apt-get update;apt-get upgrade(来自 debian 或来自本地存储库) 将所有服务器升级到相同的状态,包括 Perl 模块。

于 2008-12-30T18:59:35.600 回答
6

我在所有盒子上执行以下操作:

  • 我自己编译 perl:我仍然使用 5.8.[89] 大多数情况下,股票 5.10.0 的性能回归让我很受打击,等待 5.10.1 再试一次;
  • 我使用(并强烈推荐) local::lib 模块来为每个项目保留一个模块目录。现在,该目录已同步到安装项目的所有服务器,但我正在使用 git 进行测试;
  • 我为每个项目创建一个 Task:: 模块,这样我就可以使用一个命令安装所有依赖项。
于 2008-12-30T01:42:36.817 回答
4

我还使用 cpan shell 和 local::lib。

您不应该为每个项目都需要一个 Task:: 。只需使用 Module::Install (我喜欢像这样使用 Module::Starter :

$ module-starter --mi --module=Module::Name --author="Me" --email=me@cpan.org

然后只需将您的依赖项弹出 requires 'module::dependency'; 在 Makefile.PL 中。最后,当它是安装时间时,您只需perl Makefile.PL(回答是)然后make installdeps

[从我最初给出这个答案的5年后编辑]

这些天 perlbrew 和 cpanm 是要使用的东西。local::lib 仍然有一个用例,但是 perlbrew 和 cpanm 的组合解决了这些情况的一个超集。当您不准备编译自己的 perl 时,请使用 local::lib。

于 2009-02-14T21:17:33.633 回答
0

我建议只使用 cpan。Linux 发行版中包含的模块仅用于覆盖包依赖性。当您在没有互联网访问的情况下仅使用 CD 安装 linux 时,它不能使用 cpan,因此某些模块作为包包含在内,但对于 Perl 开发人员来说,这很糟糕。

此外,我曾经配置了一个 cpan 来在我的家中安装模块(.perl),而无需 root 登录。

于 2008-12-29T18:41:51.830 回答
0

对于生产:

在开发中,选择一个似乎适合需求的 perl 模块版本;如果可能,请选择目标操作系统的出厂版本(这使得以下大部分内容变得多余),否则,请选择另一个。为它创建一个 RPM 规范文件。使用干净的构建 VM 以可重现的方式构建 RPM(从在适当的分支上签入的规范文件/源)。

当可以构建最终构建时(合并后),从发布分支执行相同的构建,将生成的 RPM 提交到部署存储库中。这将用于最终验证,然后通过复制到生产存储库来发布到生产。

生产中的所有服务器都使用经过全面测试的完全相同的二进制文件;他们使用与开发人员预期的相同的规范文件和源。

Perl 模块不会被任何不遵循此模型的进程升级。也没有任何其他生产软件。

于 2009-02-14T21:28:28.320 回答
0

我使用 FreeBSD 端口并将所有 CPAN 依赖项包装在“元端口”中,作为一种本地端口。FreeBSD 有相当多的 CPAN 模块,并且它们的构建系统足够平易近人,如果它不存在,您可以轻松编写自己的端口——只是不要忘记提交所述端口,以便将其包含在端口树中。如果 port 没有当前版本的库存,您可以随时编辑 port 的 Makefile 以便它使用新版本,同样不要忘记提交更改:-)。

最后,我使用Tinderbox将整个混乱构建为二进制包,然后将其安装在所有生产和开发机器上。

底线——一旦你克服了编辑 Makefile 的恐惧,FreeBSD 的移植是维护你的 perl 应用程序及其依赖项的好方法。

于 2009-03-02T21:54:43.480 回答
0

我最近开始使用 Gentoo,Gentoo 在这方面有一些非常重要的优势。第一个是g-cpan通常能够从 CPAN 安装许多(尽管不是全部)模块作为本地的 Gentoo 包,尽管更新成为一个问题。

通常在 Gentoo 上,我的方法是使用g-cpan创建一个 ebuild 文件,然后从中安装,必要时进行调整。优点是升级变得非常容易。然后我将文件从 g-cpan/perl 移动到 dev-perl 并将它放在一个覆盖中供其他人使用。这让我可以快速处理 g-cpan 无法处理的情况,而 gentoo 的包装无论如何都是轻而易举的事/

于 2017-09-28T08:06:15.420 回答