Perl6 如何决定加载哪个版本的模块?

How does Perl6 decide which version of a module gets loaded?

当我执行 use Foo:ver<1.0>; 时,它会加载模块 Foo 的 1.0 版。但是当我做 use Foo; 时会发生什么?

TL;DR: 当没有给定特定版本时,默认的 Perl6 安装将从它遇到的第一个 CompUnit::Repository 加载最新版本,该版本与该模块的任何版本匹配(不一定是所有版本中的最高版本) CompUnit::Repository).


可以创建和加载非核心 CompUnit::Repository 除非另有说明,否则它本身只会加载模块的随机版本。此答案不适用于这些,并将重点放在各种核心 CompUnit::Repository 的行为和规范上。

决定加载哪个模块的第一件事是 CompUnit::Repository 首先匹配请求的身份。默认的存储库链看起来像这样:

# EXAMPLE 1

$ perl6 -e '.say for $*REPO.repo-chain'
inst#/home/ugexe/.perl6
inst#/home/ugexe/perl6/install/share/perl6/site
inst#/home/ugexe/perl6/install/share/perl6/vendor
inst#/home/ugexe/perl6/install/share/perl6

inst# 前缀告诉我们这是一个 CompUnit::Repository::Installation。这是相关的,因为这样的回购可以包含多个发行版——包括同一发行版的多个版本——这对于用于 -I.-Ilib 的单一发行版 CompUnit::Repository::FileSystem 是不正确的( 真的 -Ifile#/home/ugexe/repos/Foo-Ifile#/home/ugexe/repos/Foo/lib).

# EXAMPLE 2

$ perl6 -I. -e '.say for $*REPO.repo-chain'
file#/home/ugexe/repos/Foo
inst#/home/ugexe/.perl6
inst#/home/ugexe/perl6/install/share/perl6/site
inst#/home/ugexe/perl6/install/share/perl6/vendor
inst#/home/ugexe/perl6/install/share/perl6

假设如下:

  • file#/home/ugexe/repos/Foo 包含 Foo:ver<0.5>

  • inst#/home/ugexe/.perl6 包含 Foo:ver<0.1>Foo:ver<1.0>

  • inst#/home/ugexe/.perl6 包含 Foo:ver<2.0>Foo:ver<0.1>

use Foo; 将加载:

  • 示例 1 - Foo:ver<1.0> 来自 inst#/home/ugexe/.perl6

  • 示例 2 - Foo:ver<0.5> 来自 file#/home/ugexe/repos/Foo

即使所有存储库中的最高版本是 Foo:ver<2.0> 链中与 Foo 的 任何 版本匹配的第一个存储库(即 use Foo ) 获胜,因此永远不会选择 Foo:ver<2.0>。您可能猜到这使得 "highest version" 成为决定加载模块版本的第二个因素,但它实际上是第四个因素!但是我在这里提到它是因为对于典型的使用来说这已经足够了。


决定加载模块版本的第二件事是 api 字段。这本质上是另一个版本字段,当与版本本身结合时,提供了一种固定主要版本的基本方法。

假设如下:

  • file#/home/ugexe/repos/Foo 包含 Foo:api<0>:ver<0.5>

  • inst#/home/ugexe/.perl6 包含 Foo:api<1>:ver<0.1>Foo:api<0>:ver<1.0>

use Foo; 将加载:

  • 示例 1 - Foo:api<1>:ver<0.1> 来自 inst#/home/ugexe/.perl6

  • 示例 2 - Foo:api<0>:ver<0.5> 来自 file#/home/ugexe/repos/Foo

尽管在示例 1 中最高版本是 Foo:api<0>:ver<1.0>,但最高 api 版本是 Foo:api<1>:ver<0.1>,因此被选中。


决定加载模块版本的第三件事是 auth 字段。与 apiver 不同,它并不意味着任何排序。而且与 apiver 字段不同,您可能不应该在您的示例中使用它。 use Foo -- 它以政策为重点,将成为 power-tool/escape 孵化器,希望大多数开发人员永远不必担心(滥用)使用。

假设如下:

  • file#/home/ugexe/repos/Foo 包含 Foo:auth<github:ugexe>:ver<0.5>

  • inst#/home/ugexe/.perl6 包含 Foo:ver<0.1>Foo:auth<github:ugexe>:ver<1.0>

use Foo; 将加载:

  • 示例 1 - Foo:auth<github:ugexe>:ver<1.0> 来自 inst#/home/ugexe/.perl6

  • 示例 2 - Foo:auth<github:ugexe>:ver<0.5> 来自 file#/home/ugexe/repos/Foo

在这两个示例中,use Foo;use Foo:auth(*):ver(*) 相同,因此即使其中一个回购假设包含一个没有 auth 的模块,但这并不意味着它是完全匹配的对于 use Foo;。相反,:auth(*) 包含任何 auth 值作为匹配项(实际上意味着 auth 被完全忽略)。


有关更多示例,spec tests 是一个很好的来源