perl 升级local::lib安装的所有模块

0yg35tkg  于 2023-02-05  发布在  Perl
关注(0)|答案(2)|浏览(186)

我一直在使用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脚本来处理它)。
这是可能的吗?或者我必须删除~/perl 5目录并从头重新安装所有模块(可能丢失了一些模块,因为我记不清它们)?

ezykj2lf

ezykj2lf1#

更新*:一段时间以来,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

(Do空运行-没有拖尾| xargs cpan的空运行-第一个。)
请注意,如果您不想受制于管理员的升级,可以使用perlbrew在您的主目录中轻松地安装整个Perl版本。

jvidinwx

jvidinwx2#

如果您使用的是cpanm,则可以使用-L--reinstall开关强制它在您的local::lib位置重新构建模块:
list_modules | cpanm -L ~/perl5 --reinstall
其中list_modules是一个脚本,它将模块的名称提供给cpanmcpanm也有一个-f选项)。这个脚本可能类似于上面的@ikegami,也可能类似于cpan-outdated(只列出过时的模块)。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::Findwanted()中找到的位置和内容,您可以向cpanm提供不同的模块列表。如果cpancpanm有一个内部_method-switch,允许您强制重建local::lib安装的使用XS的模块,那就太好了。有这样的事情吗?
它是cpanm``carton(并看到node.js工具npm的运行),这激励了我进行更多基于local::lib的安装。(cpan)似乎越来越自动化,也越来越容易使用。我真的很喜欢local::lib,因为它允许您使用系统perl,但不需要系统级权限就可以管理自己的模块堆栈。如果使用perlbrew运行“非系统”,则总体上管理更改和升级会更容易(“本地”)perl。当然,您可以这样做并且仍然有local::libcarton * 等 *。管理目录或应用程序特定的模块堆栈。
1).另一种升级的方法是使用perllocal生成当前安装模块的列表(NB我不完全确定perllocal.pod是否保持在可靠/有用的状态).[编辑:事实上perllocal保存的是已安装模块的 * 历史记录 * 而不是那些 * 当前 * 已安装模块的列表。您需要过滤这个列表,否则您将一个接一个地重新安装整个系列的模块版本!).这个perlmonks节点展示了如何清理您的perllocal.pod:http://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

(NB:这不会进行错误检查-perllocal.pod中的条目偶尔会缺少VERSION数据和其他奇怪的东西,所以要小心。
2).* 但是 * 这个方法与ilmari在IRC上的#perl-help中提到的shell脚本相比就相形见绌了。它使用jq--一个命令行实用程序,你 * 真的需要 *(在此之后你会更需要它).如果你使用cpanm来安装你的模块,它将创建install.json文件.您可以利用它来制作列表,以馈送到cpanm,以便重新安装当前的模块集:

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

非常快,非常简单,您可以将其与使用curlcpanm方法相结合来自行安装,以便重建您的模块。
3).如果你使用perlbrew来管理你的perl安装,你可以将你的所有模块从一个perl版本easily copy and reinstall到另一个版本。
啊!

相关问题