Description
I tried this code:
Consider a crate setup with the clap
dependency, where clap
is used only by the lib
target:
Cargo.toml
:
[package]
name = "multiple_targets"
[dependencies]
clap = { version = "3", features = ["derive"] }
src/lib.rs
:
use clap::Parser;
#[derive(Parser)]
pub struct Args {}
This is fine when checking with this lint enabled:
$ RUSTFLAGS=-Wunused-crate-dependencies cargo c --all --all-targets
Now, consider adding multiple targets to this crate. For the sake of demonstration, we use a test
and bin
target that both utilize the library crate defined above:
src/main.rs
:
fn main() {
let _x = multiple_targets::Args {};
}
tests/test.rs
:
#[test]
fn test() {
let _x = multiple_targets::Args {};
}
We run the same check
command again:
$ RUSTFLAGS=-Wunused-crate-dependencies cargo c --all --all-targets
I expected to see this happen:
No external crate `clap` unused
warnings show up.
Instead, this happened:
Every target seems to be checked individually against the set of defined crate dependencies, instead of identifying dependencies that are not used by all targets combined (or at the very least lib+bins, as test-only dependencies should reside under dev-dependencies
). As such, both the test and binary targets above are accused of not using clap
:
warning: external crate `clap` unused in `multiple_targets`: remove the dependency or add `use clap as _;`
|
= note: requested on the command line with `-W unused-crate-dependencies`
= help: remove unnecessary dependency `clap`
warning: external crate `clap` unused in `test`: remove the dependency or add `use clap as _;`
|
= note: requested on the command line with `-W unused-crate-dependencies`
= help: remove unnecessary dependency `clap`
warning: `multiple_targets` (bin "multiple_targets") generated 1 warning
warning: `multiple_targets` (bin "multiple_targets" test) generated 1 warning (1 duplicate)
warning: `multiple_targets` (test "test") generated 1 warning
For the most part, especially larger library crates, this makes it impossible to write clean test binaries without having the top half filled with use {dep_a as _, dep_b as _, ...};
.
Note that our project currently comprises 92 crates in a single git
repository, and we use a single .cargo/config.toml
in the workspace root to configure lints all at once. It is completely infeasible for us to duplicate these to every existing and up and coming crate, nor keep them in sync after the fact. As such, copy-pasting #[warn(unused-crate-dependencies)]
across just the lib.rs
/main.rs
bits of our code base (where only a single target is used) is pretty much impossible.
EDIT: I can understand this warning to show up for the binary (test) targets if they do not reference the library target, but it is particularly confusing when these binary targets at least transitively use the dependency through the library target.
Meta
rustc --version --verbose
:
rustc 1.61.0-nightly (c5cf08d37 2022-03-30)
binary: rustc
commit-hash: c5cf08d37b85f953b132951e868df5b924250fdc
commit-date: 2022-03-30
host: x86_64-unknown-linux-gnu
release: 1.61.0-nightly
LLVM version: 14.0.0