【问题标题】:How does Perl6 decide which version of a module gets loaded?Perl6 如何决定加载哪个版本的模块?
【发布时间】:2019-09-04 09:39:56
【问题描述】:

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

【问题讨论】:

    标签: module package versioning raku api-versioning


    【解决方案1】:

    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。这是相关的,因为这样的 repo 可以包含多个发行版 - 包括同一发行版的多个版本 - 这对于用于 -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>永远不会选择。您可能会猜到这使得“最高版本”成为决定加载模块版本的第二个因素,但它实际上是第 4 个!但是我在这里提到了它,因为对于典型的用法,这已经足够了。


    决定加载哪个版本的模块的第二件事是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 -- 它以政策为重点,将成为大多数开发人员希望永远不必担心(ab)使用的电动工具/逃生舱。

    假设如下:

    • 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(*) 相同,因此即使其中一个 repo 假设包含一个没有 auth 的模块,这并不意味着它与 use Foo; 完全匹配。相反,:auth(*) 包含任何 auth 值作为匹配项(实际上意味着 auth 被完全忽略)。


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

    【讨论】:

    • 为这些漂亮的 SO Q/A 对竖起大拇指。您是否计划/希望在接下来的几周内发布另一对覆盖auth 的信息?如果不是,当我假设带有outauth 字段alwaysuse 语句忽略auth 元信息时,我是对的吗? (我假设这是因为对我来说是合乎逻辑的;以及对您所写内容的一种解释;以及测试文件中带有.candidates($cuspec-any-auth).elems.installed.grep(*.defined).elems 的行;以及您决定不解释这一点在这个 SO 中更进一步,因为它“超出了本文的范围”。)TIA 回复。
    • @raiph 是正确的,我为auth 添加了一个示例。我试图避免解释如何使用auth。它更加注重政策,并将成为大多数开发人员希望永远不必担心(ab)使用的电动工具/逃生舱。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-21
    • 1970-01-01
    • 2014-12-30
    • 2017-10-10
    • 2017-09-09
    相关资源
    最近更新 更多