Cargo 指南

本指南会告诉你使用 Cargo 开发 Rust 包所需的全部知识。

  • Cargo 为何存在
  • 创建新包
  • 开发已有 Cargo 包
  • 依赖管理
  • 包目录结构
  • Cargo.toml 与 Cargo.lock 的区别
  • 测试
  • 持续集成
  • 在 crates.io 上发布
  • Cargo Home

Cargo 为何存在

前置知识

你可能知道,在 Rust 中,库或可执行程序都称为 crate。Crate 通过 Rust 编译器 rustc 编译。刚开始学 Rust 时,大多数人接触的第一段代码都是经典的 “Hello World” 程序,通常会直接调用 rustc 编译:

$ rustc hello.rs
$ ./hello
Hello, world!

注意,上面这条命令需要你明确指定文件名。如果想用 rustc 编译另一个程序,就得换一条命令;要是需要指定编译器参数或引入外部依赖,那命令会更复杂、更特殊。

而且,大多数非简单程序都可能依赖外部库,进而还会间接依赖这些库的依赖。如果手动获取所有必需依赖的正确版本并保持更新,不仅麻烦还容易出错。

所以,与其只靠 crate 和 rustc 工作,不如引入更高级的 “包” 概念,再用包管理器来规避上述麻烦 —— 这就是 Cargo 的作用。

登场:Cargo

Cargo 是 Rust 的包管理器。它能让 Rust 包声明各类依赖,还能确保你每次构建都能复现相同的结果。

为实现这个目标,Cargo 主要做四件事:

  1. 引入两个元数据文件,包含包的各类信息。
  2. 拉取并构建包的依赖。
  3. 调用 rustc 或其他构建工具,并传入正确参数来构建包。
  4. 制定规范,让操作 Rust 包更简单。

很大程度上,Cargo 统一了构建程序或库所需的命令 —— 这正是上面提到的 “规范” 的一部分。后面你会看到,不管产物名称是什么,都能用同一个命令构建。不用再直接调用 rustc,而是用 cargo build 这类通用命令,让 Cargo 去处理 rustc 的正确调用方式。而且,Cargo 会自动从仓库拉取你为产物定义的所有依赖,并按需配置到构建流程中。

说 “只要会构建一个基于 Cargo 的项目,就会构建所有这类项目”,其实也不算太夸张。

创建新包

用 Cargo 创建新包,需要执行 cargo new 命令:

$ cargo new hello_world --bin

我们传入 --bin 是因为要创建二进制程序;如果要创建库,就传 --lib。默认情况下,这个命令还会初始化一个 git 仓库,要是不想这样,就加个 --vcs none

来看看 Cargo 帮我们生成了什么文件:

$ cd hello_world
$ tree .
.
├── Cargo.toml
└── src
    └── main.rs
1 directory, 2 files

细看 Cargo.toml

[package]
name = "hello_world"
version = "0.1.0"
edition = "2024"
[dependencies]

这个文件叫清单文件(manifest),包含 Cargo 编译包所需的所有元数据,用 TOML 格式编写(发音为 /tɑməl/)。

细看 src/main.rs

fn main() {
    println!("Hello, world!");
}

Cargo 帮你生成了一个 “Hello World” 程序,也就是二进制 crate。现在来编译它:

$ cargo build
   Compiling hello_world v0.1.0 (file:///path/to/package/hello_world)

编译完成后运行:

$ ./target/debug/hello_world
Hello, world!

你也可以用 cargo run 一步完成 “编译 + 运行”(如果上次编译后没改代码,就不会显示 “Compiling” 那行):

$ cargo run
   Compiling hello_world v0.1.0 (file:///path/to/package/hello_world)
     Running `target/debug/hello_world`
Hello, world!

现在你会看到一个新文件 Cargo.lock,它记录了依赖信息 —— 不过目前还没有依赖,所以内容很简单。

等你准备发布程序时,可以用 cargo build --release 开启优化编译:

$ cargo build --release
   Compiling hello_world v0.1.0 (file:///path/to/package/hello_world)

cargo build --release 会把生成的二进制文件放在 target/release 目录下,而不是 target/debug

开发时默认用调试模式(debug mode)编译:编译速度快(因为编译器不做优化),但程序运行慢;发布模式(release mode)编译慢,但程序运行快。

开发已有 Cargo 包

如果你下载了一个用 Cargo 管理的现有包,上手非常简单。

首先,从某处获取包。比如这里我们克隆 GitHub 上的 regex 仓库:

$ git clone https://github.com/rust-lang/regex.git
$ cd regex

然后用 cargo build 构建:

$ cargo build
   Compiling regex v1.5.0 (file:///path/to/package/regex)

这个命令会拉取所有依赖,先构建依赖,再构建当前包。

依赖管理

crates.io 是 Rust 社区的中央包仓库,是发现和下载包的地方。Cargo 默认配置为从这里查找所需的包。

要依赖 crates.io 上的库,只需把它添加到你的 Cargo.toml 里。

添加依赖

如果你的 Cargo.toml 还没有 [dependencies] 段落,先加上它,然后列出要使用的 crate 名称和版本。比如下面这样添加对 time crate 的依赖:

[dependencies]
time = "0.1.12"

版本字符串遵循 SemVer 版本规范,更多配置选项可以参考 “指定依赖” 的官方文档。

如果还想加 regex crate 的依赖,不用重复加 [dependencies],直接在下面续上就行。完整的 Cargo.toml 会是这样:

[package]
name = "hello_world"
version = "0.1.0"
edition = "2024"
[dependencies]
time = "0.1.12"
regex = "0.1.41"

重新运行 cargo build,Cargo 会拉取新依赖及其所有子依赖,编译它们,然后更新 Cargo.lock

$ cargo build
      Updating crates.io index
   Downloading memchr v0.1.5
   Downloading libc v0.1.10
   Downloading regex-syntax v0.2.1
   Downloading memchr v0.1.5
   Downloading aho-corasick v0.3.0
   Downloading regex v0.1.41
     Compiling memchr v0.1.5
     Compiling libc v0.1.10
     Compiling regex-syntax v0.2.1
     Compiling memchr v0.1.5
     Compiling aho-corasick v0.3.0
     Compiling regex v0.1.41
     Compiling hello_world v0.1.0 (file:///path/to/package/hello_world)

Cargo.lock 会记录所有依赖的精确版本信息(包括具体修订版)。就算 regex 后来更新了,你也会一直用当前这个版本构建,直到执行 cargo update

现在可以在 main.rs 里使用 regex 库了:

use regex::Regex;
fn main() {
    let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
    println!("Did our date match? {}", re.is_match("2014-01-01"));
}

运行结果如下:

$ cargo run
   Running `target/hello_world`
Did our date match? true

包目录结构

Cargo 用统一的文件放置规范,让你能快速上手新的 Cargo 包。目录结构如下:

.
├── Cargo.lock
├── Cargo.toml
├── src/
│   ├── lib.rs          # 默认库文件
│   ├── main.rs         # 默认二进制文件
│   └── bin/            # 其他二进制文件
│       ├── named-executable.rs
│       ├── another-executable.rs
│       └── multi-file-executable/  # 多文件二进制(目录名即执行文件名)
│           ├── main.rs
│           └── some_module.rs
├── benches/            # 基准测试
│   ├── large-input.rs
│   └── multi-file-bench/  # 多文件基准测试
│       ├── main.rs
│       └── bench_module.rs
├── examples/           # 示例代码
│   ├── simple.rs
│   └── multi-file-example/  # 多文件示例
│       ├── main.rs
│       └── ex_module.rs
└── tests/              # 集成测试
    ├── some-integration-tests.rs
    └── multi-file-test/  # 多文件集成测试
        ├── main.rs
        └── test_module.rs

核心规范说明

  1. Cargo.toml 和 Cargo.lock 放在包的根目录(包根)。
  2. 源代码放在 src 目录下。
  3. 其他二进制文件放在 src/bin/,基准测试在 benches/,示例在 examples/,集成测试在 tests/
  4. 如果二进制、示例、基准测试或集成测试是多文件的,需要在对应目录下建子目录,把 main.rs 和其他模块文件放进去 —— 子目录名就是最终产物的名称。

命名风格

按规范,二进制文件、示例、基准测试和集成测试的文件名 / 目录名要用 kebab-case(全小写,用连字符连接),除非有兼容性需求(比如要和已有的二进制名保持一致);而这些目标内部的模块文件,要遵循 Rust 标准用 snake_case(全小写,用下划线连接)。

想了解更多 Rust 模块系统的内容,可以看 Rust 官方书籍;想手动配置目标或控制目标自动发现规则,可参考 “配置目标” 和 “目标自动发现” 的官方文档。

Cargo.toml 与 Cargo.lock 的区别

Cargo.toml 和 Cargo.lock 的用途完全不同。先总结核心区别:

  • Cargo.toml:从宏观上描述依赖,由你编写。
  • Cargo.lock:包含依赖的精确信息(如具体版本、修订版),由 Cargo 自动维护,不要手动编辑

不确定时,建议把 Cargo.lock 加入版本控制(比如 Git)。想了解这么做的原因和其他选择,可以看 FAQ 里的 “为什么要把 Cargo.lock 加入版本控制?”,最好配合 “验证最新依赖” 一起使用。

深入理解

Cargo.toml 是清单文件,你可以在里面写包的各种元数据,比如依赖另一个包:

[package]
name = "hello_world"
version = "0.1.0"
[dependencies]
regex = { git = "https://github.com/rust-lang/regex.git" }

这个包依赖 regex 库,且指定了 GitHub 上的仓库地址。因为没写其他信息,Cargo 会默认用仓库默认分支的最新提交来构建。

但这里有个问题:你今天构建这个包,明天把包传给别人,对方构建时可能 regex 已经有新提交了 —— 这样你们的构建结果会不一样,而我们需要 “可复现构建”。

你可以在 Cargo.toml 里加 rev 字段指定具体修订版,比如:

[dependencies]
regex = { git = "https://github.com/rust-lang/regex.git", rev = "9f9f693" }

这样构建结果就一致了,但缺点很明显:每次更新库都要手动记 SHA-1 哈希,又麻烦又容易错。

这时候 Cargo.lock 就派上用场了。有了它,你不用手动跟踪精确修订版 ——Cargo 会帮你做。比如用之前没加 rev 的 Cargo.toml,第一次构建时,Cargo 会拉取最新提交,然后把精确信息写入 Cargo.lock,文件内容会像这样:

[[package]]
name = "hello_world"
version = "0.1.0"
dependencies = [
 "regex 1.5.0 (git+https://github.com/rust-lang/regex.git#9f9f693768c584971a4d53bc3c586c33ed3a6831)",
]
[[package]]
name = "regex"
version = "1.5.0"
source = "git+https://github.com/rust-lang/regex.git#9f9f693768c584971a4d53bc3c586c33ed3a6831"

里面包含了构建用的精确修订版。就算你没在 Cargo.toml 里写,别人拿到你的包后,也会用同一个 SHA-1 修订版构建。

等你想更新库时,用 cargo update 就行:

$ cargo update         # 更新所有依赖
$ cargo update regex   # 只更新 regex

这个命令会生成新的 Cargo.lock,写入最新的版本信息。注意,cargo update 后面的参数是 “包 ID 规范”,regex 只是简化写法。

测试

Cargo 可以用 cargo test 命令运行测试。Cargo 会在两个地方找测试代码:

  1. src 目录下的文件:这里的测试应该是单元测试文档测试
  2. tests/ 目录:这里的测试应该是集成式测试,所以需要在 tests/ 的文件里导入你的 crate。

运行测试示例

在我们之前的包(还没写测试)里运行 cargo test

$ cargo test
   Compiling regex v1.5.0 (https://github.com/rust-lang/regex.git#9f9f693)
   Compiling hello_world v0.1.0 (file:///path/to/package/hello_world)
     Running target/test/hello_world-9c2b65bbb79eabce
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

如果你的包有测试,输出会显示具体的测试数量和结果。

运行特定测试

可以传筛选条件来运行特定测试,比如:

$ cargo test foo

这会运行所有名称包含 foo 的测试。

额外检查

cargo test 还会做其他检查:

  • 编译所有示例,确保能通过。
  • 运行文档测试,确保文档注释里的代码示例能编译。

想了解 Rust 测试的整体写法和组织方式,可以看 Rust 官方文档的 “测试指南”;想了解 Cargo 中不同类型的测试,可参考 “Cargo 目标:测试”。

持续集成

入门

基础的持续集成(CI)主要做两件事:构建项目、运行测试。下面是主流 CI 工具的配置示例。

GitHub Actions

要在 GitHub Actions 上测试包,可创建 .github/workflows/ci.yml 文件,内容如下:

name: Cargo Build & Test
on:
  push:
  pull_request:
env:
  CARGO_TERM_COLOR: always
jobs:
  build_and_test:
    name: Rust project - latest
    runs-on: ubuntu-latest
    strategy:
      matrix:
        toolchain:
          - stable
          - beta
          - nightly
    steps:
      - uses: actions/checkout@v4
      - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
      - run: cargo build --verbose
      - run: cargo test --verbose

这个配置会测试三个 Rust 发布通道(stable/beta/nightly),任何一个工具链失败都会导致整个任务失败。你也可以在 GitHub 仓库的 “Actions” 页面点击 “new workflow”,选择 Rust 模板来添加默认配置。更多细节看 GitHub Actions 官方文档。

GitLab CI

要在 GitLab CI 上测试包,可创建 .gitlab-ci.yml 文件,内容如下:

stages:
  - build
rust-latest:
  stage: build
  image: rust:latest
  script:
    - cargo build --verbose
    - cargo test --verbose
rust-nightly:
  stage: build
  image: rustlang/rust:nightly
  script:
    - cargo build --verbose
    - cargo test --verbose
  allow_failure: true

这个配置会测试 stable 和 nightly 通道,但 nightly 通道的失败不会影响整体构建。更多细节看 GitLab CI 官方文档。

builds.sr.ht

要在 sr.ht 上测试包,可创建 .build.yml 文件(记得把 <your repo> 和 <your project> 换成实际的仓库地址和项目目录):

image: archlinux
packages:
  - rustup
sources:
  - 
tasks:
  - setup: |
      rustup toolchain install nightly stable
      cd /
      rustup run stable cargo fetch
  - stable: |
      rustup default stable
      cd /
      cargo build --verbose
      cargo test --verbose
  - nightly: |
      rustup default nightly
      cd /
      cargo build --verbose ||:
      cargo test --verbose  ||:
  - docs: |
      cd /
      rustup run stable cargo doc --no-deps
      rustup run nightly cargo doc --no-deps ||:

这个配置会在 stable 和 nightly 通道测试并构建文档,nightly 通道的失败不会影响整体构建。更多细节看 builds.sr.ht 官方文档。

CircleCI

要在 CircleCI 上测试包,可创建 .circleci/config.yml 文件,内容如下:

version: 2.1
jobs:
  build:
    docker:
      # 查看最新镜像标签:https://circleci.com/developer/images/image/cimg/rust#image-tags
      - image: cimg/rust:1.77.2
    steps:
      - checkout
      - run: cargo test

想实现更复杂的流水线(如不稳定测试检测、缓存、产物管理),可参考 CircleCI 配置文档。

验证最新依赖

在 Cargo.toml 里指定依赖时,通常是匹配一个版本范围。要测试所有版本组合不现实,但至少要验证 “最新版本”—— 这能覆盖用 cargo add 或 cargo install 的用户场景。

考虑因素

验证最新依赖时,需要考虑:

  1. 减少对本地开发或 CI 的外部影响。
  2. 依赖的发布频率。
  3. 项目能接受的风险等级。
  4. CI 成本(包括间接成本,比如并行 runner 达上限导致任务排队)。
解决方案

常见的解决方案有四种:

  1. 不把 Cargo.lock 加入版本控制
    • 缺点:如果 PR 频率低,很多版本可能没测到;且失去了构建确定性。
  2. 加一个 CI 任务验证最新依赖,但设置 “失败不中断”
    • 缺点:不同 CI 工具的失败提示可能不明显;PR 频率高时会浪费资源。
  3. 定时运行 CI 任务验证最新依赖
    • 缺点:部分托管 CI 会对长期未更新的仓库禁用定时任务;通知可能无法触达负责人;若和依赖发布频率不匹配,可能测试不足或重复测试。
  4. 通过 PR 定期更新依赖(如用 Dependabot 或 RenovateBot)
    • 优点:可将依赖隔离到单独 PR 或合并成一个 PR;只使用必要资源;可配置频率来平衡 CI 资源和版本覆盖度。
GitHub Actions 示例

下面是一个验证最新依赖的 GitHub Actions 任务配置:

jobs:
  latest_deps:
    name: Latest Dependencies
    runs-on: ubuntu-latest
    continue-on-error: true
    env:
      CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: allow
    steps:
      - uses: actions/checkout@v4
      - run: rustup update stable && rustup default stable
      - run: cargo update --verbose
      - run: cargo build --verbose
      - run: cargo test --verbose

注意CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS 设为 allow,是为了确保依赖解析器不会因项目的 Rust 版本而限制依赖选择。如果项目在不同平台或 Rust 版本上失败风险高,可能需要测试更多组合。

验证 rust-version

如果发布的包指定了 rust-version(最低支持的 Rust 版本),必须验证这个字段的正确性。

辅助工具

可借助第三方工具:

  • cargo-msrv:用于查找最小支持的 Rust 版本。
  • cargo-hack:提供额外的构建 / 检查功能。
GitHub Actions 示例

下面是用 cargo-hack 验证 rust-version 的配置:

jobs:
  msrv:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: taiki-e/install-action@cargo-hack
    - run: cargo hack check --rust-version --workspace --all-targets --ignore-private

这个配置在 “全面性” 和 “速度” 之间做了平衡:

  1. 只用一个平台(大多数项目是跨平台的,依赖平台相关的包会自行验证)。
  2. 用 cargo check(大多数问题是 API 可用性,而非运行行为)。
  3. 跳过未发布的包(假设只有通过仓库使用项目的用户才关心 rust-version)。

在 crates.io 上发布

如果你有一个想分享给全世界的库,就可以把它发布到 crates.io 上!“发布 crate” 指的是把某个特定版本上传到 crates.io 托管 —— 注意,发布是永久性的:版本不能覆盖,代码不能删除,但发布的版本数量没有限制。

首次发布前的准备

首先,你需要一个 crates.io 账号来获取 API 令牌。步骤如下:

  1. 访问 crates.io 首页,用 GitHub 账号登录(目前仅支持 GitHub 登录)。
  2. 去 “Account Settings” 页面填写并验证邮箱。
  3. 创建 API 令牌,一定要复制下来—— 离开页面后就再也看不到了。

然后运行 cargo login 命令:

$ cargo login

在提示符后粘贴刚才的令牌:

plaintext

please paste the API Token found on https://crates.io/me below
abcdefghijklmnopqrstuvwxyz012345

这个命令会让 Cargo 记录你的 API 令牌,并存储在本地的 ~/.cargo/credentials.toml 中。注意:这个令牌是机密,不要分享给他人;一旦泄露,要立即吊销。

如果想删除本地存储的令牌,可以用 cargo logout 命令。

发布新 crate 前的注意

  1. crates.io 上的 crate 名称是 “先到先得” 的,一旦被占用,其他 crate 就不能用了。
  2. 完善 Cargo.toml 中的元数据,让你的 crate 更容易被发现。发布前至少要填这些字段:
    • license 或 license-file(许可证)
    • description(描述)
    • homepage(主页)
    • repository(仓库地址)
    • readme(说明文档)也可以加一些 keywords(关键词)和 categories(分类),不过这两个不是必需的。
  3. 如果发布的是库,建议参考《Rust API 指南》(Rust API Guidelines)。

打包 crate

下一步是把 crate 打包并上传到 crates.io,用 cargo publish 命令。这个命令会做四件事:

  1. 对包做一些验证检查。
  2. 把源代码压缩成 .crate 文件。
  3. 把 .crate 文件解压到临时目录,验证能否编译。
  4. 把 .crate 文件上传到 crates.io(仓库会做额外检查后才添加)。

建议:先运行 cargo publish --dry-run(或等效的 cargo package),确认没有警告或错误再正式发布 —— 这个命令会执行上面的前三步。

$ cargo publish --dry-run

生成的 .crate 文件在 target/package 目录下。crates.io 目前对 .crate 文件的大小限制是 10MB,建议检查文件大小,避免不小心把不需要的大文件(如测试数据、网站文档、代码生成文件)打包进去。

想查看打包包含哪些文件,可以运行:

$ cargo package --list

Cargo 会自动忽略版本控制工具(如 Git)标记为 “忽略” 的文件。如果想额外指定忽略的文件,可以在清单文件中用 exclude 字段:

[package]
# ...
exclude = [
    "public/assets/*",
    "videos/*",
]

如果想明确指定要包含的文件,可以用 include 字段(会覆盖 exclude):

[package]
# ...
include = [
    "**/*.rs",
]

上传 crate

准备好后,运行 cargo publish 上传到 crates.io:

$ cargo publish

这样就完成了首次发布!

发布已有 crate 的新版本

要发布新版本,只需修改 Cargo.toml 中的 version 字段(遵循 SemVer 规范,明确哪些变更属于兼容变更),然后再运行 cargo publish 即可。

建议:考虑完整的发布流程,并自动化尽可能多的步骤。每个版本最好包含:

  1. 一个更新日志条目(手动整理最佳,自动生成也比没有好)。
  2. 一个指向发布提交的 Git 标签。

常用的第三方工具(按字母排序):

  • cargo-release
  • cargo-smart-release
  • release-plz

更多工具可在 crates.io 上查找。

管理 crates.io 上的 crate

crate 的管理主要通过命令行工具 cargo 完成,而非 crates.io 网页界面。下面是两个常用的管理子命令。

cargo yank(撤回版本)

有时你可能发布了有问题的 crate 版本(比如语法错误、漏传文件等),这时可以用 cargo yank 撤回版本:

$ cargo yank --version 1.0.1    # 撤回 1.0.1 版本
$ cargo yank --version 1.0.1 --undo  # 取消撤回

注意:撤回(yank)不会删除任何代码。这个功能不是用来删除不小心上传的机密信息(如密钥)的 —— 如果发生这种情况,必须立即重置这些机密。

撤回版本的语义是:新的依赖不能再使用这个版本,但已有的依赖仍然能正常工作。crates.io 的核心目标之一是作为 crate 的永久归档,不允许删除版本,而撤回正好平衡了 “归档稳定性” 和 “修复错误版本” 的需求。

cargo owner(管理所有者)

一个 crate 可能由多人开发,或者主要维护者会变更。crate 的所有者有权发布新版本,但也可以添加其他所有者。

$ cargo owner --add github-handle  # 添加 GitHub 用户为所有者
$ cargo owner --remove github-handle  # 移除 GitHub 用户
$ cargo owner --add github:rust-lang:owners  # 添加 GitHub 团队
$ cargo owner --remove github:rust-lang:owners  # 移除 GitHub 团队

cargo owner 接受的 “所有者 ID” 只能是 GitHub 用户名或 GitHub 团队。

  • 添加用户:被添加的用户会成为 “命名所有者”(named owner),拥有完整权限 —— 不仅能发布 / 撤回版本,还能添加 / 移除其他所有者(包括添加他的人)。所以不要把不熟悉的人设为命名所有者。且用户必须先登录过 crates.io 才能成为命名所有者。
  • 添加团队:被添加的团队会成为 “团队所有者”(team owner),权限受限 —— 能发布 / 撤回版本,但不能添加 / 移除所有者。团队所有者更适合管理多人协作,且安全性更高(避免单个所有者作恶)。

团队的格式是 github:org:team(如上面的例子)。添加团队时,操作人必须是该团队的成员;移除团队则没有这个限制。

GitHub 权限问题

GitHub 的团队成员信息没有简单的公开访问接口,操作时可能会遇到这样的提示:

It looks like you don’t have permission to query a necessary property from GitHub to complete this request. You may need to re-authenticate on crates.io to grant permission to read GitHub org memberships.

这通常是因为:

  1. 你上次登录 crates.io 时,该平台还没添加 “查询团队成员” 的功能 —— 早期 crates.io 登录 GitHub 时不需要任何权限,只用来验证身份;但现在查询团队成员需要 read:org 权限。
  2. 你拒绝了 read:org 权限 —— 这会导致你无法添加团队所有者,也无法以团队所有者身份发布 crate,但其他功能不受影响。

如果想授权,可以去 crates.io 重新登录,此时会提示授予 read:org 权限。

另外,GitHub 组织可能会主动限制第三方应用访问。要检查这一点,可以访问:https://github.com/organizations/:org/settings/oauth_application_policy(把 :org 换成组织名,如 rust-lang)。在 “Organization Access Control” 下,可以把 crates.io 从黑名单中移除,或点击 “Remove Restrictions” 允许所有第三方应用访问。

也可以在 crates.io 请求 read:org 权限时,点击组织名旁边的 “Grant Access”,明确允许 crates.io 查询该组织。

排查 GitHub 团队权限错误

添加 GitHub 团队为所有者时,可能会遇到这样的错误:

error: failed to invite owners to crate <crate_name>: api errors (status 200 OK): could not find the github team org/repo

这时可以按以下步骤排查:

  1. 去 GitHub 的 “Application settings” 页面(https://github.com/settings/applications),检查 “Authorized OAuth Apps” 标签下是否有 crates.io—— 没有的话,先去 crates.io 授权登录。
  2. 在授权应用列表中找到 crates.io,点击进入,确认你或你的组织在 “Organization access” 列表中,且标记为绿色对勾。如果有 “Grant” 或 “Request” 按钮,点击授权或请求组织所有者授权。

Cargo Home

“Cargo Home” 是一个下载和源码缓存目录。构建 crate 时,Cargo 会把下载的构建依赖存储在这里。你可以通过设置 CARGO_HOME 环境变量来修改它的位置;如果你的 Rust crate 里需要获取这个路径,可以用 home crate 提供的 API。

默认情况下,Cargo Home 位于 $HOME/.cargo/注意:Cargo Home 的内部结构尚未稳定,可能随时变化。

Cargo Home 的组成

Cargo Home 包含以下文件和目录:

文件
  • config.toml:Cargo 的全局配置文件,详见官方参考中的 “config” 条目。
  • credentials.toml:存储 cargo login 生成的私有登录凭证,用于登录仓库。
  • .crates.toml.crates2.json:隐藏文件,记录通过 cargo install 安装的 crate 信息 ——不要手动编辑
目录
  • bin:存储通过 cargo install 或 rustup 安装的 crate 可执行文件。要让这些二进制文件全局可用,需要把这个目录的路径加入 $PATH 环境变量。
  • git:存储 Git 源码:
    • git/db:如果 crate 依赖 Git 仓库,Cargo 会把仓库克隆成 “裸仓库”(bare repo)存在这里,必要时会更新。
    • git/checkouts:使用 Git 源码时,Cargo 会从 git/db 的裸仓库中,检出该依赖指定提交的代码到这里,供编译器使用。同一个仓库的不同提交可以有多个检出目录。
  • registry:存储仓库(如 crates.io)的包和元数据:
    • registry/index:裸 Git 仓库,包含该仓库所有可用 crate 的元数据(版本、依赖等)。
    • registry/cache:存储下载的依赖,以 .crate 为后缀的 gzip 压缩包。
    • registry/src:如果某个下载的 .crate 包被需要,Cargo 会把它解压到这里,供 rustc 查找 .rs 文件。

在 CI 中缓存 Cargo Home

为了避免在持续集成中重复下载所有依赖,可以缓存 $CARGO_HOME 目录。但不建议缓存整个目录—— 这样效率低,因为源码会被存储两次(比如依赖 serde 1.0.92 时,registry/cache 里有 serde-1.0.92.crateregistry/src 里还有解压后的 .rs 文件),会增加下载、解压、压缩和上传缓存的时间。

如果要缓存 cargo install 安装的二进制文件,需要缓存 bin/ 目录和 .crates.toml.crates2.json 文件。

推荐缓存的文件和目录:

  • .crates.toml
  • .crates2.json
  • bin/
  • registry/index/
  • registry/cache/
  • git/db/

vendoring 项目的所有依赖

详见 cargo vendor 子命令的官方文档。

清理缓存

理论上,你可以删除缓存的任何部分 ——Cargo 会在需要时自动恢复(比如重新解压压缩包、检出裸仓库,或从网络重新下载)。

另外,cargo-cache crate 提供了一个简单的命令行工具,可以只清理缓存的特定部分,或查看各部分的大小。

posted on 2025-10-21 14:00  ycfenxi  阅读(3)  评论(0)    收藏  举报