14

我一直在使用 local::lib 来处理服务器上 Perl 模块的安装,因此我可以为某些开发工作获得正确的版本,而不会污染系统安装。

但是,系统管理员最近将 Perl 从 5.16 升级到 5.18,我现在遇到了与二进制模块相关的错误,例如

perl -e 'use Scalar::Util'
Perl API version v5.16.0 of List::Util does not match v5.18.0 at /usr/lib64/perl5/5.18.2/XSLoader.pm line 92.
Compilation failed in require at /home/paul/perl5/lib/perl5/x86_64-linux/Scalar/Util.pm line 11.
Compilation failed in require at -e line 1.
BEGIN failed--compilation aborted at -e line 1.

我的理解是,我可以通过强制 local::lib 重建其所有模块来解决问题,但我在文档中找不到任何告诉我如何执行此操作,甚至如何获取所有模块的列表已使用 local::lib 安装的模块(如果我在“每行一个模块”文本文件中有它,我可以轻松编写一个 Bash 脚本来处理它)。

这可能吗,还是我必须删除 ~/perl5 目录并从头开始重新安装所有模块(可能缺少一些,因为我不记得它们全部)?

4

2 回答 2

7

更新:一段时间以来,INSTALL_BASE一直在生产一个更好的目录结构,以避免新安装的这个问题。

这就是为什么 install::lib 使用的perl Makefile.PL INSTALL_BASE=...约定(以及对应的约定Build.PL)很糟糕的原因。

删除(或重命名目录以便备份)是最简单的解决方案。您可以通过查找文件找出您安装的.pm内容。

cd ~
mv perl5{,16}
cd perl516/lib/perl5
find -name '*.pm' | xargs perl -MConfig -E'
   for (@ARGV) {
      s!^\./!!;
      s!^5\.\d+\.\d+/!!;
      s!^x86_64-linux/!!;
      s!^auto/!!;
      s!\.pm\z!!;
      s!/!::!g;
      say;
   }
' | xargs cpan

(先做一次空跑——一个没有尾随的跑| xargs cpan。)

请注意,如果您不想受管理员升级的摆布,您可以使用perlbrew在您的主目录中轻松安装 Perl 的整个构建。

于 2014-09-02T13:47:19.103 回答
3

如果您正在使用,您可以使用和开关cpanm强制它在您的位置重建模块:local::lib-L--reinstall

list_modules | cpanm -L ~/perl5 --reinstall

wherelist_modules是一个提供模块名称的脚本cpanm(还有一个-f选项cpanm)。这个脚本可能像上面的@ikegami 或类似的东西cpan-outdated(但是它只列出了过时的模块)。这是一个最近对我有用的hackish尝试(注意:ikegami的可能更好)-当它失败或脚本给出cpanm它无法识别的模块名称时,cpanm继续运行并且似乎没有破坏任何东西(但进行备份):

cd $PERL_LOCAL_LIB_ROOT  
perl -MFile::Find -MConfig -E'
      find { 
        wanted => sub { 
                       $mod = $_ if /\.pm\z/; 
                       $mod =~ s/lib\/perl5\/auto\/.*//g;
                       $mod =~ s/lib\/perl5\/\Q$Config{archname}\E\/.*//g;
                       $mod =~ s/lib\/perl5\///g;
                       push @mods, $mod unless $mod =~ /^$/;
                      },no_chdir=>1 
           },"lib/perl5"; @modhash{@mods}=(); say for sort keys %modhash '

通过更改File::Find查找的位置和内容,wanted()您可以将不同的模块列表提供给cpanm. 如果cpancpanm有一个内部_method-switch允许您强制重建local::lib使用 XS 的已安装模块,那就太好了。有这样的事吗?

正是cpanmcarton(并且看到了该node.js工具npm的实际应用)启发了我进行更多local::lib基于安装的安装。现在,与 perl ( ) 一起提供的 CORE 捆绑的“CPAN 客户端”cpan似乎变得更加自动化并且更易于使用。我真的很喜欢local::lib,因为它允许您使用系统perl,但无需系统级权限即可管理您自己的模块堆栈。但是,如果您用于perlbrew运行“非系统”(“本地”) ,则总体上可以更轻松地管理更改和升级perl。当然你可以这样做并且仍然有local::libcarton 等等。管理目录或应用程序特定的模块堆栈。

1)。进行升级的另一种方法是使用perllocal生成当前安装的模块的列表(注意我不完全确定是否perllocal.pod保持在可靠/有用的状态)。[编辑:实际上perllocal保留了已安装模块的历史记录,而不是当前已安装模块的列表。您需要对此进行过滤,否则您最终将一个接一个地重新安装整个模块版本系列!)。这个 perlmonks 节点展示了如何清理你的perllocal.podhttp ://www.perlmonks.org/?node_id=483020 。我更喜欢保留历史。]

要解析perllocal.pod的输入cpanm,搜索文件并将匹配项保存在一个数组中,然后将它们除以两个以从数组元素 ( key,value,key,value) 中创建一个散列。文件中较新的安装和版本号较低,因此您可以创建一个以模块名称作为键的哈希,并通过以后的条目更新值:

 perl -ne 'push @arr, grep {defined}
 (/\A=head2.*:\s+C<Module>\s+L<(.*)\||.*C<VERSION:\s(.*)>\Z/msx); }{
 %h = map{ split/,/,$_,2 } @arr; print "$_\@$h{$_}\n" for keys %h' perllocal.pod

(注意:这不是错误检查 - 条目perllocal.pod偶尔会缺少VERSION数据和其他奇怪的东西,所以要小心。)

2)。这种方法与 ilmari 在 IRC 上的#perl-help 中提到的 shell 脚本相比显得相形见绌。它使用 - 一个你真正需要jq的命令行实用程序(在此之后你会更想要它)。如果您曾经安装过模块,它将创建文件。您可以利用它来制作列表以重新安装当前的模块集:cpanminstall.jsoncpanm

 find ~/perl5/ -name install.json -exec jq '.name + "@" + .version' {} +

非常快速,非常简单,您可以将其与使用自行安装的cpanm方法相结合,以重建您的模块。curl

3)。如果您使用perlbrew管理 perl 安装,您可以轻松地将所有模块从一个版本复制并重新安装perl到另一个版本。

于 2014-09-02T19:28:13.230 回答