跳转到内容

Rust 错误 E0463:can't find crate(找不到 crate)

E0463 的意思是:编译器去找一整个 crate(一个库),结果空手而归。通常是你的代码里有一行 extern crate,而那个 crate 并不在 Cargo.toml 里。有时候找不到的 crate 就是 std 本身,这发生在你为另一种机器编译、却还没安装那个目标平台的时候。这两种情况都有很快的修法,而且你不需要懂链接器也能修好。这一页属于 Rust 编译错误详解系列。

error[E0463]: can't find crate for `rand`
--> src/main.rs:1:1
|
1 | extern crate rand;
| ^^^^^^^^^^^^^^^^^^ can't find crate

意思是“找不到 rand 这个 crate”。在一个刚用 cargo new 创建、[dependencies] 下面什么都没有的项目里,下面的程序就会产生这个错误:

extern crate rand;
fn main() {
let roll = rand::random_range(1..=6);
println!("你掷出了 {roll}");
}

第二种常见形式根本没有行号,因为你的代码里没有哪一行要求 std。每个程序都需要它:

error[E0463]: can't find crate for `std`
|
= note: the `aarch64-unknown-linux-gnu` target may not be installed
= help: consider downloading the target with `rustup target add aarch64-unknown-linux-gnu`

note 说这个目标平台可能没有安装,help 建议你用 rustup target add 下载它。当你的电脑上只装了本机的目标平台,却运行 cargo build --target aarch64-unknown-linux-gnu(64 位 ARM Linux,比如树莓派)时,就会看到它。需要哪种修法,取决于 crate 的名字和 note: 的内容:

你看到的 通常哪里出了问题 修法
extern crate 那一行报 can't find crate for `rand` 这个 crate 不在 Cargo.toml 里 修复 1
同样的错误,出现在带 #[macro_use] 的老代码里 代码写于 2018 版次之前 修复 2
can't find crate for `std` + target may not be installed 为 rustup 还没下载的目标平台编译 修复 3
E0463 旁边出现 crate name using dashes are not valid 代码里的 crate 名字带了 - 修复 4

extern crate rand; 告诉编译器:“把名叫 rand 的已编译库链接进这个程序”。编译器不会下载任何东西,也不会上网搜索。它只看 Cargo 交给它的那些库,而 Cargo 只交出 Cargo.toml 里列出的 crate。那里没有 rand,清单上就没有 rand 这个库,于是就是 E0463。

std 的情况是同一个道理,只是往下深了一层。标准库也是一个已编译的库,rustup 会为每个目标平台各装一份。你平常的工具链里只有给本机用的那一份。你要求编译 ARM 版本,编译器就去找 ARM 版的 std,而它并不存在。

这就像一份菜谱写着“用橱柜里的面粉”。如果没人买过面粉,菜谱写得再好,厨师也没法开工。

Rust 没有全局共享的“已安装库”文件夹,不像 Python 的 pip install 或系统级的 node_modules。每个项目都在 Cargo.toml 里写清楚自己用了什么、用哪个版本,Cargo 再专门为这个项目构建这些 crate。所以同一个项目在你的笔记本、同事的电脑和 CI 上都能以同样的方式构建。没写下来的 crate,对你的代码来说就是不存在的。

extern crate 基本上是 Rust 2015 留下来的东西。从 2018 版次开始,Cargo.toml 里的每个 crate 都会自动可用,所以现代代码直接写 use rand::random_range; 就行。你仍然会在老教程和 Stack Overflow 的回答里看到 extern crate,大多数 E0463 也正是从那里来的。如今在缺少依赖的情况下,use 那一行会报 E0432,代码里的路径会报 E0433。原因一样,代码不同。

依赖是怎么工作的,见 Cargo 和 crate;工具链和目标平台,见 Rust 工具。

修复 1:用 cargo add 添加这个 crate

Section titled “修复 1:用 cargo add 添加这个 crate”

当缺少的 crate 来自 crates.io(比如 rand、regex 或 serde_json)时,选这个方法。这是最常见的情况。在包含 Cargo.toml 的文件夹里运行:

Terminal window
cargo add rand

Cargo 会替你加上最新的版本:

[dependencies]
rand = "0.10.3"

光是这样就能修好 E0463。顺手把 extern crate rand; 这一行删掉吧;在 2018 及以后的版次里不需要它(看看 Cargo.toml 里的 edition = )。下面这个版本打印的是一个检查结果,而不是点数,所以输出永远一样:

fn main() {
let roll = rand::random_range(1..=6);
println!("点数在 1 到 6 之间:{}", (1..=6).contains(&roll));
}

输出:

点数在 1 到 6 之间:true
▶ 动手试一试

老代码可能还会调用在不同版本之间变过的函数。如果 cargo add 修好了 E0463,接着却因为 thread_rng 之类的东西报 E0425 或 E0432,就去查一下你所用版本的 crate 文档。参见用 cargo add 添加依赖。

修复 2:把旧的 extern crate 换成 use

Section titled “修复 2:把旧的 extern crate 换成 use”

当你复制的是 2018 年之前的代码时,选这个方法。这种代码常常以这样一段开头,而每一行都可能报 E0463:

#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[derive(Serialize)]
struct Order {
item: String,
qty: u32,
}
error[E0463]: can't find crate for `serde_derive`
--> src/main.rs:2:1
|
2 | extern crate serde_derive;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate
error[E0463]: can't find crate for `serde_json`
--> src/main.rs:3:1
|
3 | extern crate serde_json;
| ^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate

不要把 serde_derive 当作单独的 crate 添加。如今,只要打开 serde 的 derive 特性,派生宏就会随 serde 一起提供:

Terminal window
cargo add serde --features derive
cargo add serde_json

然后删掉那段 extern crate,用普通的 use 导入你要用的东西。#[macro_use] 也不需要了:

use serde::Serialize;
#[derive(Serialize)]
struct Order {
item: String,
qty: u32,
}
fn main() {
let order = Order { item: String::from("apple"), qty: 3 };
println!("{}", serde_json::to_string(&order).unwrap());
}

输出:

{"item":"apple","qty":3}
▶ 动手试一试

如果某行 extern crate 引入的 crate 你的代码其实根本没用到,直接删掉这一行就好。用 serde 处理 JSON 这一课完整展示了现代的写法。

修复 3:用 rustup target add 安装目标平台

Section titled “修复 3:用 rustup target add 安装目标平台”

当错误说的是 std(或 core),并且 note: 说目标平台可能没有安装时,选这个方法。从 help: 那一行复制目标平台的名字:

Terminal window
rustup target add aarch64-unknown-linux-gnu
rustup target list --installed # 查看现在装了哪些目标平台

然后用同样的 --target 再构建一次。目标平台(target)就是你要为之编译的机器类型,写成一个“三元组”(triple),比如 aarch64-unknown-linux-gnu 或 wasm32-unknown-unknown。rustup 会为它下载预编译好的 std,E0463 就消失了。

有两点要注意。第一,对很多目标平台来说,这还不是最后一步:要为另一个操作系统构建完整的程序,通常还需要那个平台的链接器,那是另一个错误。第二,如果项目里有 rust-toolchain.toml,要在项目文件夹里运行这条命令,这样 rustup 才会把目标平台加到这个项目实际使用的工具链上。参见组件和目标平台,以及你很可能会用到的一个目标平台:WebAssembly 这一课。

修复 4:在代码里把短横线写成下划线

Section titled “修复 4:在代码里把短横线写成下划线”

当 crate 的名字带短横线(比如 serde-json 或 tracing-subscriber)时,选这个方法。在 Cargo.toml 和命令行里,短横线没问题。但在 Rust 代码里,- 是减号,所以名字永远要写成 _。带短横线的老代码会报这样的错:

error: crate name using dashes are not valid in `extern crate` statements
--> src/main.rs:1:14
|
1 | extern crate serde-json;
| ^^^^^^^^^^ dash-separated idents are not valid
|
help: if the original crate name uses dashes you need to use underscores in the code
|
1 - extern crate serde-json;
1 + extern crate serde_json;
|
error[E0463]: can't find crate for `serde_json`

第一个错误是说:extern crate 语句里的 crate 名字不能带短横线;help 告诉你,如果原来的 crate 名字带短横线,在代码里要改用下划线。rustc 已经把名字读成了 serde_json,所以下面那个 E0463 只有在这个 crate 同时也没写进 Cargo.toml 时才会出现。在 use 那一行里,短横线会给出另一条信息:expected one of `::`, `;`, or `as`, found `-` 。修法在哪里都一样:需要的话先 cargo add 这个 crate,然后在代码里写 _:

use serde_json::json;
fn main() {
let order = json!({ "item": "apple", "qty": 3 });
println!("{order}");
}

输出:

{"item":"apple","qty":3}
▶ 动手试一试

同样的规则也适用于你自己的包:一个名叫 shop-app 的项目,在它的 main.rs 和测试里要以 shop_app 的名字导入。

直接运行 rustc main.rs。 单独的 rustc 不会读 Cargo.toml,所以就算已经 cargo add rand 了,rustc --edition 2021 src/main.rs 对 extern crate rand; 这一行还是会报 can't find crate for `rand` (对 use rand::... 这一行则报 E0432)。修法:用 cargo run 或 cargo build 构建,它们会把依赖传给编译器。

写在 [dev-dependencies] 下面的 crate。 开发依赖(用 cargo add --dev 添加)只给测试、示例和基准测试用。在普通代码里用它,配合 extern crate 会报 E0463,配合路径会报 E0433。修法:先运行 cargo remove --dev serde_json,再运行 cargo add serde_json,把它移到 [dependencies]。

没有操作系统的嵌入式开发板。 像 thumbv7em-none-eabihf 这样的目标平台,光安装是不够的,因为它根本没有 std。这时 note 会变成:

error[E0463]: can't find crate for `std`
|
= note: the `thumbv7em-none-eabihf` target may not support the standard library
= note: `std` is required by `shop` because it does not declare `#![no_std]`

意思是这个目标平台可能不支持标准库,而 shop 没有声明 #![no_std],所以需要 std。修法:把程序写成 #![no_std],这也意味着没有 println!,还得自己写 panic 处理函数。The Embedded Rust Book(英文)会一步步带你完成。

  • E0432:unresolved import(无法解析的导入),当 crate 不在 Cargo.toml 里时,use 那一行报的错。
  • E0433:failed to resolve(无法解析),当 crate 缺失时,rand::rng() 这样的路径报的错。
  • E0603:crate 找到了,但你要的那个项是私有的。
  • crate name using dashes are not valid:这个错误没有错误代码;把 - 改成 _ 就好(修复 4)。
  • 所有编译错误:全部错误页面的列表。

小测验

1. 老代码以 extern crate regex; 开头,你得到了 E0463。在一个 2021 版次的项目里,最好的修法是什么?

2. cargo build --target wasm32-unknown-unknown 说找不到 std 这个 crate,还说目标平台可能没有安装。你该运行什么?

3. 你的 Cargo.toml 里有 tracing-subscriber = "0.3"。在 Rust 代码里,这个 crate 的名字怎么写?

得分: 0 / 3