cargo-workflows

Installation
SKILL.md

Cargo 工作流

用途

引导代理使用 Cargo 工作区、特性管理、构建脚本(build.rs)、CI 集成、增量编译,以及 Cargo 工具生态系统。

触发场景

  • "如何设置包含多个 crate 的 Cargo 工作区?"
  • "Cargo 中的特性如何工作?"
  • "如何编写 build.rs 脚本?"
  • "如何加速 CI 中的 Cargo 构建?"
  • "如何审计 Rust 依赖?"
  • "什么是 cargo nextest,我应该使用它吗?"

工作流程

1. 工作区设置

my-project/
├── Cargo.toml           # 工作区根
├── Cargo.lock           # 所有成员共享一个锁文件
├── crates/
│   ├── core/
│   │   └── Cargo.toml
│   ├── cli/
│   │   └── Cargo.toml
│   └── server/
│       └── Cargo.toml
└── tools/
    └── codegen/
        └── Cargo.toml
# 工作区根 Cargo.toml
[workspace]
members = [
    "crates/core",
    "crates/cli",
    "crates/server",
    "tools/codegen",
]
resolver = "2"   # 特性解析器 v2(edition 2021 必须)

# 共享依赖版本(workspace.dependencies)
[workspace.dependencies]
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
anyhow = "1"

# 共享 profile 设置
[profile.release]
lto = "thin"
codegen-units = 1
# 成员 Cargo.toml
[package]
name = "myapp-core"
version.workspace = true
edition.workspace = true

[dependencies]
serde.workspace = true    # 从工作区继承
anyhow.workspace = true

2. 特性标志

[features]
default = ["std"]

# 简单标志
std = []

# 启用其他特性的特性
full = ["std", "async", "serde-support"]

# 带可选依赖的特性
async = ["dep:tokio"]
serde-support = ["dep:serde", "serde/derive"]

[dependencies]
tokio = { version = "1", optional = true }
serde = { version = "1", optional = true }
# 使用指定特性构建
cargo build --features "async,serde-support"

# 不使用默认特性构建
cargo build --no-default-features

# 使用所有特性构建
cargo build --all-features

# 检查特性组合
cargo check --no-default-features
cargo check --all-features

特性注意事项:

  • 特性是累加的:一旦在依赖图任何地方启用,就会保持启用状态
  • resolver = "2" 防止 dev-dependencies 和常规依赖之间的特性泄漏
  • 使用 dep:optional_dep 语法(edition 2021)避免隐式特性创建

3. 构建脚本(build.rs)

// build.rs(位于 crate 根目录,在编译前运行)
use std::env;
use std::path::PathBuf;

fn main() {
    // 这些文件变化时重新运行
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=wrapper.h");
    println!("cargo:rerun-if-env-changed=MY_LIB_PATH");

    // 链接系统库
    println!("cargo:rustc-link-lib=mylib");
    println!("cargo:rustc-link-search=/usr/local/lib");

    // 向 Rust 代码传递 cfg 标志
    let target = env::var("TARGET").unwrap();
    if target.contains("linux") {
        println!("cargo:rustc-cfg=target_os_linux");
    }

    // 为下游 crate 设置环境变量
    println!("cargo:rustc-env=MY_GENERATED_VAR=value");

    // 使用 bindgen 生成绑定
    let bindings = bindgen::Builder::default()
        .header("wrapper.h")
        .generate()
        .expect("Unable to generate bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings.write_to_file(out_path.join("bindings.rs")).unwrap();
}
println! 指令 效果
cargo:rerun-if-changed=FILE 文件变化时重新运行构建脚本
cargo:rerun-if-env-changed=VAR 环境变量变化时重新运行
cargo:rustc-link-lib=NAME 链接库
cargo:rustc-link-search=PATH 添加库搜索路径
cargo:rustc-cfg=FLAG 在代码中启用 #[cfg(FLAG)]
cargo:rustc-env=KEY=VAL 在编译时设置 env!("KEY")
cargo:warning=MSG 发出构建警告

4. 增量构建与 CI 缓存

# 使用 sccache 的 GitHub Actions
- uses: Swatinem/rust-cache@v2
  with:
    cache-on-failure: true
    shared-key: "release-build"

# 或手动缓存
- uses: actions/cache@v3
  with:
    path: |
      ~/.cargo/registry/index/
      ~/.cargo/registry/cache/
      ~/.cargo/git/db/
      target/
    key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
# 本地预热缓存
cargo fetch                    # 下载所有依赖但不构建
cargo build --tests            # 构建所有内容,包括测试二进制

# 检查增量构建是否影响 release(通常会影响)
[profile.release]
incremental = false            # 默认;release 版本保持为 false

5. cargo nextest(更快的测试运行器)

# 安装
cargo install cargo-nextest

# 运行测试(默认并行,输出更清晰)
cargo nextest run

# 按过滤条件运行
cargo nextest run test_name_pattern

# 列出测试而不运行
cargo nextest list

# 在 CI 中使用(JUnit 输出)
cargo nextest run --profile ci

nextest.toml

[profile.ci]
fail-fast = false
test-threads = "num-cpus"
retries = { backoff = "exponential", count = 2, delay = "1s" }

[profile.default]
test-threads = "num-cpus"

6. 依赖管理与审计

# 检查安全公告
cargo install cargo-audit
cargo audit

# 拒绝特定许可证、重复依赖、公告
cargo install cargo-deny
cargo deny check

# 检查未使用的依赖
cargo install cargo-machete
cargo machete

# 更新依赖
cargo update                    # 更新到兼容版本
cargo update -p serde           # 更新单个包
cargo upgrade                   # 更新到最新版本(cargo-edit)

deny.toml

[licenses]
allow = ["MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause"]
deny = ["GPL-2.0", "AGPL-3.0"]

[bans]
multiple-versions = "warn"
deny = [{ name = "openssl", reason = "Use rustls instead" }]

[advisories]
ignore = []  # 列出要忽略的公告 ID

7. 常用 cargo 命令

# 仅构建指定二进制
cargo build --bin myapp

# 仅构建指定示例
cargo build --example myexample

# 带参数运行
cargo run -- --flag arg1 arg2

# 展开宏(用于调试过程宏)
cargo install cargo-expand
cargo expand module::path

# 依赖树
cargo tree
cargo tree --duplicates      # 显示有多个版本的 crate
cargo tree -i serde          # 谁依赖 serde?

# Cargo.toml 元数据
cargo metadata --format-version 1 | jq '.packages[].name'

工作区模式和依赖解析详情,参见 references/workspace-patterns.md

相关技能

  • 使用 skills/rust/rustc-basics 了解编译器标志和 profile 配置
  • 使用 skills/rust/rust-debugging 调试 Cargo 构建的二进制文件
  • 使用 skills/rust/rust-ffi 了解带 C 库绑定的 build.rs
  • 使用 skills/build-systems/cmake 将 Rust 集成到 CMake 构建中
Related skills

More from killvxk/low-level-dev-skills-zh

Installs
1
First Seen
Mar 21, 2026