Perl 中的核心、供应商和站点位置之间有什么区别?

What is the difference between the core, vendor and site locations in Perl?

我最近 运行 在安装一些模块时遇到了一些麻烦,令我惊讶的是,许多已安装的模块都有重复的安装和版本。尝试使用 cpanm 跟踪标准(如果有这样的东西)安装的位置,我发现以下结果非常混乱。

报告显示了这些位置:

# cpan -V

/usr/bin/cpan script version 1.672, CPAN.pm version 2.22
--------------------------------------------------
Checking install dirs...
Checking core
        + /usr/share/perl5/5.26
        + /usr/lib/perl5/5.26/x86_64-cygwin-threads
Checking vendor
        + /usr/share/perl5/vendor_perl/5.26
        + /usr/lib/perl5/vendor_perl/5.26/x86_64-cygwin-threads
Checking site
        + /usr/local/share/perl5/site_perl/5.26
        + /usr/local/lib/perl5/site_perl/5.26/x86_64-cygwin-threads
Checking PERL5LIB
        no directories for PERL5LIB
Checking PERLLIB
        no directories for PERLLIB
# perl -V:.*site.* |column -t -s "=" |sort -d -i -k 1.22

d_sitearch           'define';
usesitecustomize     'undef';
siteprefix           '/usr/local';
siteprefixexp        '/usr/local';
installsitebin       '/usr/local/bin';
installsitescript    '/usr/local/bin';
sitebin              '/usr/local/bin';
sitebinexp           '/usr/local/bin';
sitescript           '/usr/local/bin';
sitescriptexp        '/usr/local/bin';
installsitearch      '/usr/local/lib/perl5/site_perl/5.26/x86_64-cygwin-threads';
sitearch             '/usr/local/lib/perl5/site_perl/5.26/x86_64-cygwin-threads';
sitearchexp          '/usr/local/lib/perl5/site_perl/5.26/x86_64-cygwin-threads';
installsitehtml1dir  '/usr/local/share/doc/perl/html/html1';
sitehtml1dir         '/usr/local/share/doc/perl/html/html1';
sitehtml1direxp      '/usr/local/share/doc/perl/html/html1';
installsitehtml3dir  '/usr/local/share/doc/perl/html/html3';
sitehtml3dir         '/usr/local/share/doc/perl/html/html3';
sitehtml3direxp      '/usr/local/share/doc/perl/html/html3';
installsiteman1dir   '/usr/local/share/man/man1';
siteman1dir          '/usr/local/share/man/man1';
siteman1direxp       '/usr/local/share/man/man1';
installsiteman3dir   '/usr/local/share/man/man3';
siteman3dir          '/usr/local/share/man/man3';
siteman3direxp       '/usr/local/share/man/man3';
installsitelib       '/usr/local/share/perl5/site_perl/5.26';
sitelib              '/usr/local/share/perl5/site_perl/5.26';
sitelib_stem         '/usr/local/share/perl5/site_perl/5.26';
sitelibexp           '/usr/local/share/perl5/site_perl/5.26';
# perl -e 'print join("\n",@INC,"")'

/usr/local/lib/perl5/site_perl/5.26/x86_64-cygwin-threads
/usr/local/share/perl5/site_perl/5.26
/usr/lib/perl5/vendor_perl/5.26/x86_64-cygwin-threads
/usr/share/perl5/vendor_perl/5.26
/usr/lib/perl5/5.26/x86_64-cygwin-threads
/usr/share/perl5/5.26

结果是 cpan-outdated -p --verbose 显示了与 cpan -lO 完全不同(并且更短)的过时模块列表。不用说,模块到处都安装了,我不知道如何理解是否有默认安装位置及其去向,或者应该去。


问题:

  1. 那么路径的corevendorsite类型有什么区别呢?
  2. 为什么每种类型都有 2 条路径?

这些安装位置的最佳参考可能是 ExtUtils::MakeMaker 安装位置的文档。本质上:

  • core(也称为 privlib)- 是随 Perl 安装的核心模块所在的位置。在早于 5.12 的 Perls 上,双生命模块的更新也需要安装在核心版本之上,而不是安装到站点或供应商库中,因为 privlib 在 5.12 之前的 @INC 中首先出现。这在系统 Perl 中尤其危险,因为 privlib 中的文件通常由包管理器管理。
  • vendor - 分发供应商可以将模块安装到的位置。这通常是系统包管理器安装非核心模块的地方。
  • site - 是 CPAN 客户端在直接调用时安装模块的位置,除非像上面提到的双生命模块这样的异常配置。

(双生模块是核心模块,在CPAN上也可以单独获取,也就是说可以安装更新版本。)

这些 lib 位置中的每一个都有一个 arch 变体,这是安装具有构建特定输出文件的发行版的地方。没有动态配置的纯 perl 发行版被安装到标准架构不可知目录中,并且通常可以 运行 在其他 Perl 和架构安装中保持不变,前提是它们的要求仍然得到满足(尽管这不是一个好主意,除非你真的知道你在做什么)。 带有任何已编译 XS 模块或在构建过程中动态生成模块的发行版被安装到 arch 目录中,从另一个 Perl 使用是不安全的。

所有这些位置都是在构建 Perl 时配置的,并且可以使用 perl -V 选项发现,如您所示。他们每个人都有附带的 scriptbin 目录(通常是相同的)和手册页目录。

关于 cpan-outdated 的差异 - 这个工具(像许多使用 ExtUtils::Installed 的工具一样)仅限于查找具有 packlists 的模块,它们是使用 CPAN 客户端安装模块时包含,但不包含核心模块,它们通常从供应商包中删除。所以很可能 cpan-outdated 只会发现 sitelib 中的模块,但这通常是您需要找到的全部内容。我不确定 cpan 命令使用什么机制。

更新

感谢 ikegami 的 SO link,我已经浏览了一些源代码,在那里我们可以找到很多关于这个的信息。要获取更具体的位置:

# perl -V:'install(privlib|archlib|vendorlib|vendorarch|sitelib|sitearch)' |column -t -s "="

installarchlib     '/usr/lib/perl5/5.26/x86_64-cygwin-threads';
installprivlib     '/usr/share/perl5/5.26';
installsitearch    '/usr/local/lib/perl5/site_perl/5.26/x86_64-cygwin-threads';
installsitelib     '/usr/local/share/perl5/site_perl/5.26';
installvendorarch  '/usr/lib/perl5/vendor_perl/5.26/x86_64-cygwin-threads';
installvendorlib   '/usr/share/perl5/vendor_perl/5.26';

那么对于那些的含义,我们可以在文件中查看(在 perl 源代码中):./Porting/Glossary:

installarchlib    '- is the same for modules with arch- or build-dependent components.'
installprivlib    '- contains the "pure Perl" modules that came with Perl.'
installsitearch   '- is the same for modules with arch- or build-dependent components.'
installsitelib    '- contains the "pure Perl" modules installed by you.'
installvendorarch '- is the same for modules with arch- or build-dependent components.'
installvendorlib  '- contains the "pure Perl" modules installed by your distro.'

关于 installstyle 选项的额外有趣注释:

installstyle (installstyle.U):

This variable describes the style of the perl installation. This is intended to be useful for tools that need to manipulate entire perl distributions. Perl itself doesn't use this to find its libraries -- the library directories are stored directly in Config.pm. Currently, there are only two styles: lib and lib/perl5. The default library locations (e.g. privlib, sitelib) are either $prefix/lib or $prefix/lib/perl5. The former is useful if $prefix is a directory dedicated to perl (e.g. /opt/perl), while the latter is useful if $prefix is shared by many packages, e.g. if $prefix=/usr/local.

Unfortunately, while this "style" variable is used to set defaults for all three directory hierarchies (core, vendor, and site), there is no guarantee that the same style is actually appropriate for all those directories. For example, $prefix might be /opt/perl, but $siteprefix might be /usr/local. (Perhaps, in retrospect, the "lib" style should never have been supported, but it did seem like a nice idea at the time.)

The situation is even less clear for tools such as MakeMaker that can be used to install additional modules into non-standard places. For example, if a user intends to install a module into a private directory (perhaps by setting PREFIX on the Makefile.PL command line), then there is no reason to assume that the Configure-time $installstyle setting will be relevant for that PREFIX.

This may later be extended to include other information, so be careful with pattern-matching on the results.

For compatibility with perl5.005 and earlier, the default setting is based on whether or not $prefix contains the string "perl".

所有详细信息都可以在 INSTALLATION 文件的 Installation Directories 标题下找到。

  • Directories for the perl distribution:
    默认情况下,Configure 将使用以下目录 (5.28.1):

        Configure variable  Default value
        $prefixexp          /usr/local
        $binexp             $prefixexp/bin
        $scriptdirexp       $prefixexp/bin
        $privlibexp         $prefixexp/lib/perl5/$version
        $archlibexp         $prefixexp/lib/perl5/$version/$archname
    
  • Directories for site-specific add-on files:

       Configure        Default
       variable          value
     $siteprefixexp    $prefixexp
     $sitebinexp       $siteprefixexp/bin
     $sitescriptexp    $siteprefixexp/bin
     $sitelibexp       $siteprefixexp/lib/perl5/site_perl/$version
     $sitearchexp      $siteprefixexp/lib/perl5/site_perl/$version/$archname
    
  • Directories for vendor-supplied add-on files:

    如果正在构建用于分发的 perl 二进制分发,请配置 可以选择设置以下目录供您使用 分发 add-on 个模块。

       Configure          Default
       variable            value
     $vendorprefixexp    (none)
    
     (The next ones are set only if vendorprefix is set.)
    
     $vendorbinexp       $vendorprefixexp/bin
     $vendorscriptexp    $vendorprefixexp/bin
     $vendorlibexp       $vendorprefixexp/lib/perl5/vendor_perl/$version
     $vendorarchexp      $vendorprefixexp/lib/perl5/vendor_perl/$version/$archname
    
  • otherlibdirs:
    作为最后一个 catch-all,Configure 还提供了一个 $otherlibdirs 变量。 此变量包含一个 colon-separated 附加目录列表 添加到 @INC。默认情况下,它将为空。

  • APPLLIB_EXP:
    还有另一种在 perl build 中添加路径到 @INC 的方法 时间,那就是通过设置 APPLLIB_EXP C pre-processor 令牌。 APPLLIB_EXP 定义的目录被添加到 @INC 第一,领先于其他人。
    sh Configure -Accflags='-DAPPLLIB_EXP=\"/usr/libperl\"'