Denys Séguret
Denys Séguret

Reputation: 382112

Resolver fails to select dependency version in cargo publish

While programs importing termimad 0.25.4 can compile, they fail to be published with cargo publish seemingly because two versions of the crossterm import are selected.

termimad 0.25.4 declares those imports in its Cargo.toml:

[package]
edition = "2021"
resolver = "1"

[dependencies]
coolor = { version="0.6.1", features=["crossterm"] }
crossterm = "=0.23.2"

coolor 0.6.1 imports crossterm with this in its Cargo.toml:

[dependencies]
crossterm = { optional=true, version=">=0.23.2" }

So it looks to me that termimad should use crossterm 0.23.2 while coolor users can use any version starting from 0.23.2.

While would the resolver not just select crossterm 0.23.2 for termimad ? How to fix that ?


Appendix: the Cargo.toml of a program importing termimad 0.25.4 and failing on cargo publish:

[package]
name = "dysk"
version = "2.8.2"
authors = ["dystroy <[email protected]>"]
edition = "2018"
keywords = ["linux", "filesystem", "fs", "lfs", "disk"]
license = "MIT"
categories = ["filesystem", "command-line-utilities"]
description = "give information on mounted filesystems"
repository = "https://github.com/Canop/dysk"
homepage = "https://dystroy.org/dysk"
documentation = "https://dystroy.org/dysk"
readme = "README.md"
rust-version = "1.70"
exclude = ["website", "dysk*.zip"]
build = "build.rs"
resolver = "1"

[dependencies]
dysk-cli = { version = "2.8.2", path = "cli" } # beware: version is also in build dependencies

[build-dependencies]
clap = { version = "4.4", features = ["derive", "cargo"] }
clap_complete = "4.4"
clap_mangen = "0.2.12"
dysk-cli = { version = "2.8.2", path = "cli" }
serde = { version = "1.0", features = ["derive"] }
toml = "0.7"

[profile.release]
strip = true

Upvotes: 0

Views: 287

Answers (1)

&#214;mer Erden
&#214;mer Erden

Reputation: 8793

Problem

If not limited, cargo tends to use the latest version of the dependencies.

crossterm's semantic version is stated as >=0.23.2, which means use the latest, if latest is 0.23.2 or anything greater than that, which is currently 0.27.0.

If we try to limit this on parent crate; like setting crossterm = "=0.23.2" as termimad, intuitively we might expect that resolver will select a common possible version to prevent duplication, but it doesn't, unless they are SemVer-Compatible.

Since both stated versions of crossterm in coolor and termimad are SemVer-Incompatible then resolver will resolve 2 different crate,[email protected] and [email protected] and this will cause conflict between termimad and coolor on a crossterm basis.


Reference

This situation is stated in cargo book as unexpected dependency duplication, reference

Quote from the reference :

The resolver algorithm may converge on a solution that includes two copies of a dependency when one would suffice. For example:

# Package A
[dependencies]
rand = "0.7"

# Package B
[dependencies]
rand = ">=0.6" 

In this example, Cargo may build two copies of the rand crate, even though a single copy at version 0.7.3 would meet all requirements. This is because the resolver’s algorithm favors building the latest available version of rand for Package B, which is 0.8.5 at the time of this writing, and that is incompatible with Package A’s specification. The resolver’s algorithm does not currently attempt to “deduplicate” in this situation.


Solution

To Build : Updating cargo.lock, manually or with cargo update -p [email protected] --precise 0.23.2 will make things compatible with each other and prevent duplication but this will not a solution for publishing case. Each user needs to manage that which is not a desired thing for crates.

To Publish : Updating the version requirements, with considering recommendations in cargo book, some topics regarding this issue:

...

  • Avoid overly broad version requirements. For example, >=2.0.0 can pull in any >SemVer-incompatible version, like version 5.0.0, which can result in broken >builds in the future.
  • Avoid overly narrow version requirements if possible. For example, if you >specify a tilde requirement like bar="~1.3", and another package specifies a >requirement of bar="1.4", this will fail to resolve, even though minor releases >should be compatible.
  • Try to keep the dependency versions up-to-date with the actual minimum versions >that your library requires. For example, if you have a requirement of >bar="1.0.12", and then in a future release you start using new features added in the 1.1.0 >release of “bar”, update your dependency requirement to bar="1.1.0".

...

Upvotes: 2

Related Questions