用 cargo-machete 清掉了一个没被引用的 feature 依赖
项目是个 workspace,Rust 1.76,Linux x86_64,CI 跑在 GitHub Actions 上。某天在一个 crate 的 Cargo.toml 里看到 serde_json 挂在 [dependencies] 下,但代码里搜不到 serde_json::。删掉再 cargo build 也能过,说明确实没被直接引用。问题在于这个 crate 还有几个可选 feature,我不确定是哪个 feature 把它带进来的。
做法是先装 cargo-machete:
cargo install cargo-machete
cargo machete --with-metadata
它扫一遍 workspace,把「在 Cargo.toml 里声明但源码中没有 use」的依赖列出来。输出里 serde_json 被标为 unused,但旁边同时标了 dev-dependencies 里也有一个同名项——那是测试里用的,不能动。
接下来确认它是不是被 feature 间接引入。用 cargo tree 看 feature 归属:
cargo tree -e features -i serde_json
输出显示它只作为本 crate 的直接依赖出现,没有被任何子依赖拉进来。也就是说,它纯粹是历史遗留:早期有个 json_log feature 用过它,后来 feature 被删了,依赖声明没跟着删。
删掉 [dependencies] 里的 serde_json,把 [dev-dependencies] 里的保留,因为测试里还要 serde_json::json! 构造断言数据。再跑:
cargo check --all-features
cargo test --workspace
全绿。编译时间没明显变化(这个 crate 不大),但 cargo machete 之后每次 CI 都能在 PR 上拦住新加的无用依赖。
为什么值得做:Cargo.toml 里的无用依赖不会报错,只会拖慢编译、增加审计面,尤其是带默认 feature 的 crate 会连锁拉进一堆传递依赖。代价是 cargo-machete 只能查「源码里没出现路径」的情况,宏展开、#[derive] 生成的引用、以及通过 use 重命名后再用的情况它都可能漏判,所以它报 unused 不等于一定能删,得自己 cargo build 验证一遍。
我踩过的坑:有个依赖只在 #[cfg(test)] 模块里用,cargo-machete 默认也会标 unused,删了之后 cargo test 才炸。后来我在 CI 里只对 [dependencies] 做检查,dev-dependencies 手工确认。另一个坑是 --with-metadata 在旧版 cargo 上会读不到 workspace 继承的依赖,升级 cargo 后才正常。
你们的 workspace 里有没有那种「feature 删了、依赖还留着」的条目?是怎么在 CI 里卡住的?
0 条评论
还没有评论,写下第一条。