【问题标题】:Why is cargo build not showing compilation errors with incompatible dependencies?为什么 cargo build 不显示具有不兼容依赖项的编译错误?
【发布时间】:2020-08-15 18:41:28
【问题描述】:

由于这个问题涉及到多个依赖关系,我不确定从哪个方向寻找重现它,我希望可以根据具体示例询问它。这个问题背后更普遍的模式是:有一个依赖链user => libExtension => libBaselibExtensionlibBase不兼容。

geo-booleanop 项目中,我们遇到了一个我们无法完全理解的有趣issue。它涉及以下软件包的相互作用:

  • geo-types (libBase):核心库,提供直线、矩形、多边形等基本类型。
  • geo-booleanop (libExtension):一个建立在地理类型之上的库,用一个新功能扩展它:一个新的特征BooleanOp,它具有交叉/联合/...等功能并针对地理类型中的多边形类型实现。
  • 任何将 geo-types 和 geo-booleanop 组合在一起的用户包,目的是为多边形使用 BooleanOp trait。

包地理类型最近从 0.4 版到 0.5 版发生了重大变化,例如,它将其 Rect 类型的一些字段从 pub 字段更改为 getter。

geo-booleanop 包尚未用于此更改,即,它仍显式使用这些 pub 字段。目前,geo-booleanop 的 Cargo.toml 指定了 geo-types = "0.4",并且尝试将其提高到 0.5 并在 geo-booleanop 中执行 cargo build 会导致在 pub 字段访问时出现编译器错误。

现在令人惊讶的是:在创建结合最新版本地理类型和地理布尔运算的用户包时,我们在用户包中看到来自 cargo build 的以下输出:

$ cargo build
[...]
   Compiling geo-booleanop v0.2.1
   Compiling geo-types v0.5.0
[...]

error[E0599]: no method named `union` found for type `geo_types::polygon::Polygon<{float}>` in the current scope
  --> src/main.rs:21:23
   |
21 |     let union = poly1.union(&poly2);
   |                       ^^^^^ method not found in `geo_types::polygon::Polygon<{float}>`

这很令人惊讶,因为:

  • 根本不可能同时编译 geo-booleanop v0.2.1 和 geo-types v0.5.0,因为它们不兼容。
  • 关于没有名为 union 的方法的错误令人困惑,因为用户代码做了所有正确的事情来将 BooleanOp 特征带入范围,这应该为多边形提供完全正确的方法。
  • 具有讽刺意味的是,编译器还会输出一个警告,指出 BooleanOp 特征导入未使用。

我的问题是:

  • 为什么cargo build 没有显示突出显示依赖项不兼容的编译错误?
  • 如果这是有意为之,我们可以在 geo-booleanop 网站上做些什么来让我们的用户更容易掌握这些问题吗?目前,他们在编写代码方面做的一切都是正确的,以将特征带入范围,但编译器的行为就像特征缺失一样——而实际上它是版本不匹配。我们可以在图书馆网站上强制执行更明确的错误吗?

详细信息以防万一:

  • BooleanOp 特征在其底层浮点类型 (see implementation) 中是通用的。这是否会导致问题,因为在客户端代码像在其他编程语言中一样使用泛型之前,不会实例化泛型?
  • 这是复制客户端代码:main.rsCargo.toml

【问题讨论】:

    标签: rust dependencies traits rust-cargo


    【解决方案1】:

    我将您的情况总结如下:

    • 您的 Cargo.toml 依赖于 geo-booleanop 0.2.1 和 geo-types 0.5.0
    • geo-booleanop 0.2.1 依赖于geo-types 0.4.x

    如果您查看 Cargo.lock 文件,您会注意到 geo-types 有两个 [[package]] 条目,一个用于 0.4.x,一个用于 0.5.0

    当同一个项目的两个(传递)依赖需求不兼容时, cargo 实际上试图编译它们中的both。 Cargo 不会向您的 crate 暴露间接依赖关系, 所以 Cargo 正在分别构建两个版本,就好像它们没有相同的 crate 名称一样。 只要您不尝试将geo-typesgeo-booleanop 一起使用, 他们实际上可以独立工作。

    为了清楚起见,我分别称这两个版本为geo_types_04geo_types_05。 geo-booleanop 适用于名为 geo_types_04 的依赖项, 其中geo_types_04 不会暴露在您的箱子中, 所以你根本不需要关心geo_types_04是否被使用。

    只有当geo-booleanop 公开一个接受/返回geo_types_04 中定义的某些类型的函数时,它才会成为问题。 然后你假设它是geo_types_05, 导致不兼容。

    这次你的错误实际上是更易读的错误之一。有时你会得到像Expected geo_types::Line, got geo_types::Line这样的错误,因为接受geo_types_04::Line的函数是用geo_types_05::Line调用的。

    【讨论】:

    • 嗯,geo-booleanop 的全部目的是扩展geo-types 中类型的功能。知道内部有两个版本geo-types 很有帮助,但这似乎违背了使用插件特征扩展核心类型的全部目的。真的没有办法让用户更清楚这个问题,特别是因为geo-types 未来的每一次重大变化都会出现令人困惑的“缺失特征”错误?例如,geo-booleanop 的 Cargo.toml 是否可以指定它想要稍后由用户确定的 geo-types 的相同版本?
    • geo-booleanop 仅支持特定版本的地理类型。不支持用户指定的任意版本。
    • 是否建议在此类插件库中使用geo-types = "*" 以确保插件特征可以任意遵循基础库?如果发布了仍兼容的geo-types 的新主要版本,用户可以立即继续使用新版本。如果新的主要版本不兼容,用户会看到实际的编译错误,最好将其报告为 GitHub 问题,而不是再次发生的“缺少特征”问题。通配符依赖是否适用于目标始终遵循基础库并让用户确定库版本的插件库?
    • 不,不推荐。根据定义,新的主要版本不兼容。没有编译错误,虽然通常是可靠的,但并不一定意味着兼容性。另外,如果你当前的 crate 是一个库,那么你就任意支持任何未来的版本,用户甚至不知道你的目标是哪个版本。
    • 肯定不是我希望的答案,因为我仍然不知道如何防止该问题在每个主要版本中再次发生。接受没有解决方案;)。
    猜你喜欢
    • 1970-01-01
    • 2022-09-13
    • 2022-11-24
    • 1970-01-01
    • 2012-01-22
    • 1970-01-01
    • 1970-01-01
    • 2019-09-10
    • 2014-11-19
    相关资源
    最近更新 更多