用 cargo udeps 清掉了一个没人用的 dev-dependency
项目是 Rust 1.79、Linux x86_64、workspace 下 14 个 crate,编译一次 release 大概 6 分钟。某次改 Cargo.toml 时发现某个 crate 的 dev-dependencies 里躺着 criterion,但那个 crate 根本没有 bench 目录,测试文件里也没出现 Criterion。手写 grep 太容易漏,尤其宏和重导出之后,名字根本对不上。
我的做法是装 cargo-udeps,用 nightly 跑一遍全 workspace:
rustup toolchain install nightly
cargo install cargo-udeps --locked
cargo +nightly udeps --workspace --all-targets
输出会按 crate 列出 unused dependencies,包括 dev-dependencies。我那次跑出来 9 条,其中 4 条是真的:criterion、lazy_static、serde_yaml,还有一个只在某个测试里用了一次、后来测试被删掉的 mockall。删之前我逐条确认过:cargo tree -i
原理不复杂:udeps 走的是 nightly 的 -Z binary-dep-depinfo,让编译器把实际读到的 rlib 记下来,再和 Cargo.toml 声明的依赖做差集。所以它看到的是「编译产物层面没被用」,比 grep 靠谱,但也不是语义分析——你在代码里 use 了某个 crate 的宏,宏展开后没产生任何对它的引用,也可能被判成 unused。
失效的地方我踩过两个。一是 proc-macro 依赖,有些 derive 宏只在编译期展开,udeps 偶尔会把它标成未使用,删了直接编译失败,所以 proc-macro 相关的条目我从来不当场删,先注释掉跑一遍 build。二是 –all-targets 会带上 benches、examples,某个依赖只在 example 里用,不加这个参数就会误报。
清完之后 release 编译从 6 分钟降到 4 分半,主要省在 criterion 那一大坨依赖上。但我更在意的是 Cargo.toml 变干净之后,新人看依赖列表不用再猜哪个是历史遗留。
你们 workspace 里有没有那种「不知道谁加的、也没人敢删」的依赖?一般是怎么确认它真的没用的?
0 条评论
还没有评论,写下第一条。