Allow mutitple SemVer-compatible version with `=` exact requirement
Problem
Adding multiple exact (=) versions of the same crate which Cargo considers semver compatible will produce a dependency conflict.
[dependencies]
foo = "=1.2.0"
foo_old = { version = "=1.1.0", package = "foo" }
error: failed to select a version for `foo`.
... required by package `rusttest v0.0.1`
versions that meet the requirements `=1.1.0` are: 1.1.0
all possible versions conflict with previously selected packages.
previously selected package `foo v1.2.0`
... which satisfies dependency `foo = "=1.2.0"` of package `rusttest v0.0.1`
failed to select a version for `foo` which could resolve this conflict
Is this a technical problem, or is it Cargo thinking it knows better than me because those two versions should be semver compatible?
If it's the latter, I would consider this a bug.
Steps
See above
Possible Solution(s)
No response
Notes
No response
Version
No response
1.1.0 and 1.2.0 are considered SemVer-compatible. Cargo allows only one Semver-compatible version per package. Copied from the discussion:
A compromise that was made way back at the beginning of cargo. One version per package, like Python, ends up to strict. Dependency hell. As many versions as needed, like NPM, ends up with blote. And errors of the form
can not use foo as fooThe compromise was keep more than one copy as long as the copies are not semver compatible
Cargo strictly follows SemVer. I would recommend remove = requirement as they should be compatible, otherwise they should be released under SemVer-incompat versions. See this chapter for more info on SemVer compatibility.
I have a use case for doing this, so what I'm currently forced to do is vendor the package code and rename it to something else. That would have the same issue with dependency bloat, right?
Could you share more details of your use case? That's a better way to move forward. Changing the behavior requires an RFC, as the comment states.
Without knowing the details, as I see it. The author of the package may misuse SemVer. You can also consider patching the package if possible.
I'm working on a way to detect breaking changes in dependencies. Patch releases can include behavior changes in APIs, but because they're bugfixes they are considered compatible. What's more, semver is just a pinky promise.
In order to write tests for migrating from one minor / patch version to another, I need to include both in a binary and compare results.
The cargo team talked about this a bit today. Just to clarify, this isn't a bug and how it is intended to behave.
We recognized that there seemed to be some use cases that could benefit from something like this, but we had various concerns, such as:
- How difficult is this to implement? Cargo deeply assumes that only a single version of semver-compatible range is used, so it could have wide-reaching impacts, possibly to many corner cases that could be difficult to find and resolve.
- How confusing might this be? For example, if an arbitrary dependency could impact resolution in this way, it could lead to confusing or deleterious effects. One thought was to maybe restrict this in some fashion as to where these could be specified.
- As noted, there are some workarounds such as moving things to vendored or path dependencies.
We didn't have any conclusions at this time.
Someone could check my understanding, but this looks like it could be a duplicate of https://github.com/rust-lang/cargo/issues/13594.
To clarify, this issue is specifically allowing it for direct dependencies, not arbitrary transitive ones.
I'm hitting this same problem with
# Cargo.toml
niri-ipc-25-2-0 = { package = "niri-ipc", version = "=25.2.0" }
niri-ipc-25-5-1 = { package = "niri-ipc", version = "=25.5.1" }
Which really hurts because my dependency explicitly documents that it does not follow semver for versioning, so I must use multiple semver compatible versions of it renamed (to provide application compatibility to my users).
The cargo team talked about this a bit today. Just to clarify, this isn't a bug and how it is intended to behave. [...] How difficult is this to implement? [...] How confusing might this be?
So you gonna declare this "not a bug" because you couldn't figure out an easy solution? That is just wrong.
I told cargo - with the exact versioning syntax - to give me "=25.2.0" renamed to X and give me "=25.5.1" renamed to Y. I'm using the exact syntax "=0.0.0" because I don't care about semver here, so cargo should shut the hell up about any semver things and give me the exact versions I'm asking for. So THIS IS A BUG!
As noted, there are some workarounds such as moving things to vendored or path dependencies.
This is not a solution because of crates.io publishing requirements disallowing vendored or path dependencies. You want me to republish my dependecy to crates.io - not only once but multiple times renamed to funky crate names e.g. here my-app-niri-ipc-25-2-0 and my-app-niri-ipc-25-5-1. This is just a very ugly hack (unless I'm missing something that's what this workaround would mean with regards for crates.io).