Cargo duplicating dependency when it seems like it shouldn't be

Hi all,

I have a case where Cargo is duplicating a dependency when I feel like it shouldn't be. The streamlined scenario is this:

  • I have a crate, inner, that depends on ndarray >=0.8
  • I have another crate, outer, that depends on inner and ndarray 0.14

In this case, I end up with two copies of ndarray: one at 0.14.0, for outer, and one at 0.15.6 (the latest release) for inner. It really seems to me, based on what seems sensible and the docs, that Cargo should realize that 0.14.0 satisfies both of these version constraints, and not duplicate the package. Am I missing something here?

(Some extra experiments:

  • Same thing happens if I switch the >= dep to outer
  • Same kind of thing happens if I have, e.g, a dep on clap >=2 and one on clap 3
  • Choice of resolver = "1" or resolver = "2" does not affect results

)

If outer's dependency looks like ndarray = "0.14", that is equivalent to ndarray = "^0.14".

^0.14 means 'the newest version that is semver compatible with 0.14'. 0.x versions are not semver compatible with each other[1], so 0.15 would not satisfy that requirement.

>=0.8, on the other hand, means 'the newest version greater than or equal to 0.8, and 0.15 does satisfy that.


  1. At least in Cargo's implementation of semver - I think the original spec is less strict? ↩︎

1 Like

0.14.x and 0.15.x are not semver-compatible.

1 Like

OP's question seems to be, why is 0.14 not selected to satisfy the >=0.8 constraint?

In general, Cargo will always try to pick the newest versions available when it's asked to resolve from scratch.

3 Likes

Yes, @riking gets the point here. The crux of the question is why 0.15 is even coming up at all when 0.14 easily satisfies all of the requirements.

This seems like a non-trivial bug/misbehavior to me? If inner is a helper that's compatible with a dependency that has multiple versions that are formally semver-incompatible (that is, ndarray >=0.8), I'd hope that specifying that wide compatibility range would allow inner to play nice with crates that use any of those versions (e.g., outer can depend on ndarray 0.14, 0.13, or whatever). But instead the default resolution results in a duplicated dep, unless the crate happens to call for the latest available version of the common dep.

edit: for reference, the Cargo implementation is here. The header comment describes the resolution algorithm in a bit more detail. Its description is consistent with the observed behavior, I think, but it still seems to me that this behavior has some unfortunate consequences.

After doing a bit more digging, I see that this issue is explored in:

See also:

and