Can we influence indirect dependency resolution in Cargo?

In Cargo, can we influence the resolution of nested dependencies from our own top-level crate? Is there a way to request Cargo to "unify" a particular nested dependency and either:

  • forcibly resolve every copy of that dep in the tree to one singular version XYZ
  • fail the resolution if it can't satisfy all constraints simultaneously

...rather than introducing duplicates of differing versions?

it seems like dependency lines I add to my own crates' Cargo.toml don't alter what my dependencies are able to pull in, so I can't tell how else I might be able to influence the decisions, or if I indeed can. I've found cargo tree -d to identify duplicates once it happens, and cargo-deny to fail CI on PRs introducing such a problem, but I'm not sure how to fix it. I also don't know exactly what downsides there are besides size bloat and time spent compiling.

I see this concern hurt new Tokio users who get mixed versions due to deps that haven't been upgraded to 1.0, and I observe it myself with i.e. the crossbeam crate family, or itertools, or crates building on/around rand. The Bevy game engine project has a number of duplicates in its own tree, for an open example.

In one of my projects using Bevy, both of these commands below fail, because I took a dev dependency on criterion and the newest version of criterion did not particularly demand brand-new rayon/crossbeam, but received it anyway:

cargo update -p crossbeam-utils:0.7.2 --precise 0.8.1 --dry-run
cargo update -p crossbeam-utils:0.8.1 --precise 0.7.2 --dry-run

What I'm hoping for is an opt-in way to say in practice, "give me the newest version of criterion that won't duplicate any of my deps", or else to say "for criterion's dependency on i.e. rayon, resolve that to version X as long as it satisfies", which would let me solve the first, I think.

I wonder if this is behavior is fuzzier because the duplication straddles the boundary between some of my formal deps and my dev-deps?

1 Like

Currently, there is no good automated way to resolve these problems. I wrote a bit about this here, along with notes on the manual workaround process.

For your specific case, downgrading Rayon may be sufficient to eliminate the dependency on crossbeam-utils 0.8:

cargo update -p rayon --precise 1.4.1

However, this means that you won't benefit from any of fixes or improvements in the newer versions of Rayon and Crossbeam. In most cases, I would not worry too much about duplicated dependencies unless (a) they cause type mismatches in public APIs, like in the Tokio case, or (b) the specific crate being duplicated is large enough to have a meaningful impact on my compile times or binary sizes.

For example, our Rust code at work is shipped to mobile devices where code size is very important, so we keep dependencies locked to a set of versions that minimizes duplication. But most of my hobby projects are on platforms where an extra 100KB of code has no actual user-visible effects, so I don't worry as much.

The problem is minimized if all crates update to the latest versions of their dependencies as soon as possible. I try to help by submitting pull requests to crates that I use, when their dependencies fall out of date.

2 Likes