常见问题解答
计划使用 GitHub 作为包存储库吗?
不。Cargo 的计划是使用 crates.io,就像 npm 或 Rubygems 使用 npmjs.com 和 rubygems.org 一样。
我们计划永远支持 git 仓库作为软件包的来源,因为它们可以用于早期开发和临时补丁,即使人们将注册表作为软件包的主要来源。
为什么构建 crates.io 而不是使用 GitHub 作为注册表?
我们认为支持多种下载软件包的方式非常重要,包括从 GitHub 下载并将软件包复制到您自己的软件包中。
也就是说,我们认为 crates.io 提供了许多重要的好处,并且很可能成为人们在 Cargo 中下载软件包的主要方式。
作为先例,Node.js 的 npm 和 Ruby 的 bundler 都支持中心注册表模型和基于 Git 的模型,并且大多数软件包都是通过这些生态系统中的注册表下载的,其中一小部分软件包使用基于 git 的软件包。
使中心注册表在其他语言中流行的优点包括
- 可发现性。中心注册表提供了一个轻松查找现有软件包的地方。结合标签,这还使得注册表可以提供生态系统范围的信息,例如最受欢迎或最依赖的软件包列表。
- 速度。中心注册表使得可以轻松快速有效地获取软件包的元数据,然后有效地下载已发布的软件包,而不是存储库中可能存在的其他臃肿内容。这大大提高了依赖项解析和获取的速度。随着依赖图的扩展,下载所有 git 存储库会迅速陷入困境。还要记住,并非所有人都有高速、低延迟的互联网连接。
Cargo 可以与 C 代码(或其他语言)一起使用吗?
可以!
Cargo 处理编译 Rust 代码,但我们知道许多 Rust 包会链接到 C 代码。我们也知道围绕编译 Rust 以外的语言已经构建了数十年的工具。
我们的解决方案:Cargo 允许软件包指定一个脚本(用 Rust 编写),在调用 rustc
之前运行。Rust 用于实现特定于平台的配置并重构软件包之间的常见构建功能。
可以在 make
(或 ninja
,或 ...) 中使用 Cargo 吗?
确实可以。虽然我们打算将 Cargo 作为一种在顶层编译 Rust 软件包的独立方式使用,但我们知道有些人希望从其他构建工具调用 Cargo。
我们已经将 Cargo 设计为在这些上下文中良好运行,注意诸如错误代码和机器可读输出模式之类的事情。我们仍然需要在这些方面做一些工作,但是从一开始就设计了在传统脚本的上下文中使用 Cargo,并且我们将继续优先考虑。
Cargo 是否处理多平台软件包或交叉编译?
Rust 本身提供了用于基于平台配置代码部分的功能。Cargo 还支持特定于平台的依赖项,并且我们计划在将来在 Cargo.toml
中支持更多每平台配置。
从长远来看,我们正在研究使用 Cargo 方便地交叉编译软件包的方法。
Cargo 是否支持诸如 production
或 test
之类的环境?
我们通过使用配置文件来支持环境:
- 特定于环境的标志(例如,开发环境使用
-g --opt-level=0
,生产环境使用--opt-level=3
)。 - 特定于环境的依赖项(例如,测试断言使用
hamcrest
)。 - 特定于环境的
#[cfg]
cargo test
命令
Cargo 在 Windows 上可以使用吗?
可以!
需要对 Cargo 的所有提交在 Windows 上通过本地测试套件。如果在 Windows 上运行时遇到问题,我们将其视为错误,因此请提交问题。
为什么要在版本控制中包含 Cargo.lock
?
虽然cargo new
默认在版本控制中跟踪 Cargo.lock
,但是否这样做取决于您的软件包的需求。
Cargo.lock
锁定文件的目的是描述成功构建时的世界状态。Cargo 使用锁定文件通过确保使用与最初生成 Cargo.lock
文件时完全相同的依赖项和版本,从而在不同时间和不同系统上提供确定性构建。
确定性构建有助于:
- 运行
git bisect
以查找错误的根本原因 - 确保 CI 仅因新的提交而失败,而不是外部因素
- 当贡献者看到与其他人或 CI 相比不同的行为时,减少困惑
当需要针对一致版本的依赖项验证项目时,此依赖项快照也很有帮助,例如当:
- 验证低于依赖项最新版本支持的最低支持 Rust 版本 (MSRV)
- 验证不具有兼容性保证的人类可读输出(例如,快照测试错误消息以确保它们是“可理解的”,这是一个太模糊而无法自动化的指标)
但是,这种确定性可能会给人一种虚假的安全感,因为 Cargo.lock
不会影响您的软件包的消费者,只有 Cargo.toml
会影响。例如:
cargo install
将选择最新的依赖项,除非传入--locked
。- 新的依赖项,例如通过
cargo add
添加的依赖项,将锁定到最新版本
锁定文件也可能成为合并冲突的来源。
有关通过 CI 验证较新版本依赖项的策略,请参阅验证最新依赖项。
库可以使用 *
作为其依赖项的版本吗?
从 2016 年 1 月 22 日起,crates.io 拒绝所有带有通配符依赖项约束的软件包(不仅仅是库)。
严格来说,库可以这样做,但不应该这样做。版本要求为 *
表示“这将适用于所有版本”,这永远不会是真的。库应始终指定它们适用的范围,即使它像“每个 1.x.y 版本”那样笼统。
为什么是 Cargo.toml
?
作为与 Cargo 最频繁的交互之一,为什么配置文件命名为 Cargo.toml
的问题时不时会出现。选择首字母大写的 C
是为了确保清单与目录列表中其他类似的配置文件分组在一起。文件排序通常将大写字母放在小写字母之前,从而确保将 Makefile
和 Cargo.toml
等文件放在一起。选择后缀 .toml
是为了强调该文件采用 TOML 配置格式这一事实。
Cargo 不允许其他名称(例如 cargo.toml
或 Cargofile
)出现,以强调如何轻松识别 Cargo 存储库。历史上,多种可能的名称选择导致了混淆,其中一种情况得到了处理,但其他情况被意外遗忘了。
Cargo 如何离线工作?
--offline
或 --frozen
标志告诉 Cargo 不要访问网络。如果它要访问网络,则会返回错误。您可以在一个项目中使用 cargo fetch
在离线之前下载依赖项,然后在另一个项目中使用相同的依赖项。请参阅配置值) 通过 Cargo 配置进行设置。
供应商化也相关,有关更多信息,请参阅有关源替换的文档。
为什么 Cargo 要重建我的代码?
Cargo 负责增量编译项目中的 crate。这意味着如果您两次键入 cargo build
,则第二次不应重建您的 crates.io 依赖项。尽管如此,还是会出现错误,并且 Cargo 有时会在您不期望的时候重建代码!
我们早就希望提供更好的诊断信息,但不幸的是,很长一段时间以来我们一直无法在该问题上取得进展。但是,同时,您可以通过设置 CARGO_LOG
环境变量来至少稍微调试一下重建过程。
$ CARGO_LOG=cargo::core::compiler::fingerprint=info cargo build
这将导致 Cargo 打印出大量有关诊断和重建的信息。这通常包含有关为什么您的项目正在被重建的线索,尽管您通常需要自己连接一些点,因为此输出尚不十分易于阅读。请注意,CARGO_LOG
需要设置为您认为不应重建时执行重建的命令。不幸的是,Cargo 目前无法进行事后调试“为什么要重建?”
我们历史上看到的一些可能导致 crate 被重建的问题是:
-
构建脚本打印
cargo::rerun-if-changed=foo
,其中foo
是一个不存在的文件,并且没有任何东西生成它。在这种情况下,Cargo 将继续运行构建脚本,认为它会生成该文件,但实际上什么也没有。解决方法是避免在这种情况下打印rerun-if-changed
。 -
两个连续的 Cargo 构建可能在某些依赖项启用的功能集上有所不同。例如,如果第一个构建命令构建整个工作区,而第二个命令仅构建一个 crate,则可能会导致 crates.io 的依赖项启用不同的功能集,从而导致它及其所依赖的所有内容都被重建。不幸的是,对于这种情况没有真正的好的解决方法,尽管如果可能,最好使 crate 上启用的功能集保持不变,而不管您在工作区中构建什么。
-
某些文件系统在时间戳方面表现出异常行为。Cargo 主要使用文件上的时间戳来管理是否需要发生重建,但是如果您使用的是非标准文件系统,则可能会以某种方式影响时间戳(例如,截断时间戳,导致时间戳漂移等)。在这种情况下,请随时打开一个问题,我们可以看看是否可以以某种方式适应文件系统。
-
并发构建过程正在删除工件或修改文件。有时,您可能有一个后台进程试图构建或检查您的项目。这些后台进程可能会令人惊讶地删除一些构建工件或触摸文件(或者可能只是意外地删除或触摸),这可能会导致重建看起来是虚假的!这里最好的解决方法是控制后台进程,以避免与您的工作发生冲突。
但是,如果在尝试调试问题后,您仍然遇到问题,请随时打开一个问题!
“版本冲突”是什么意思,以及如何解决它?
未能为
x
选择一个可以解决此冲突的版本
您是否见过上面的错误消息?
对于 Cargo 用户来说,这是最令人恼火的错误消息之一。有几种情况可能导致版本冲突。下面我们将探讨可能的原因,并提供诊断技巧来帮助您解决问题。
-
项目及其依赖项使用 links 来重复链接本地库。 Cargo 禁止链接两个具有相同原生库的包,因此即使在多层依赖的情况下也不允许。在这种情况下,错误消息会提示:
Only one package in the dependency graph may specify the same links value
,您可能需要手动检查并删除重复的 link 值。社区也制定了 相关的约定来缓解这种情况。 -
当项目依赖不同的 crate 时,如果这些 crate 使用相同的依赖库,但使用的版本受到限制,导致无法确定正确的版本,也会导致冲突。错误消息会提示:
all possible versions conflict with previously selected packages
。您可能需要修改版本要求以使其保持一致。 -
如果项目中有多个版本的依赖项,当使用
direct-minimal-versions
时,无法满足最低版本要求,这将导致冲突。您可能需要修改直接依赖项的版本要求,以满足相应的最低 SemVer 版本。 -
如果依赖的 crate 没有您选择的功能,也会导致冲突。此时,您需要检查依赖的版本及其功能。
-
当合并分支或 PR 时可能会发生冲突,如果存在非平凡的冲突,您可以重置所有“您的”更改,修复分支中的所有其他冲突,然后运行一些 cargo 命令(如
cargo tree
或cargo check
),这将使用您自己的本地更改重新更新 lockfile。如果您之前在您的分支中运行了一些cargo update
命令,您可以再次运行它们。社区一直在寻求使用自定义合并工具来解决Cargo.lock
和Cargo.toml
的合并冲突。