-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cargo resolver picks two versions of a crate, even when one is enough #10599
Comments
From the explanation of the resolver //! Actually solving a constraint graph is an NP-hard problem. This algorithm
//! is basically a nice heuristic to make sure we get roughly the best answer
//! most of the time. The constraints that we're working with are:
//!
//! 1. Each crate can have any number of dependencies. Each dependency can
//! declare a version range that it is compatible with.
//! 2. Crates can be activated with multiple version (e.g., show up in the
//! dependency graph twice) so long as each pairwise instance have
//! semver-incompatible versions.
//!
//! The algorithm employed here is fairly simple, we simply do a DFS, activating
//! the "newest crate" (highest version) first and then going to the next
//! option. The heuristics we employ are:
//!
//! * Never try to activate a crate version which is incompatible. This means we
//! only try crates which will actually satisfy a dependency and we won't ever
//! try to activate a crate that's semver compatible with something else
//! activated (as we're only allowed to have one) nor try to activate a crate
//! that has the same links attribute as something else
//! activated.
//! * Always try to activate the highest version crate first. The default
//! dependency in Cargo (e.g., when you write `foo = "0.1.2"`) is
//! semver-compatible, so selecting the highest version possible will allow us
//! to hopefully satisfy as many dependencies at once.
So this seems to match up with the expected heuristics of the resolver (activates the higher version and then finds that a lower version is needed which is fine because its semver incompatible). I found unexpected cases like this is common when going outside the common path dependency declaration path. I'd recommend reporting this to Diesel so they can weigh out if they still want to go this route for 2.0. I'm not a resolver expert to say if anything can be done shorter term. Longer term, we are looking at changing out the algorithm for PubGrub solver though I have no idea if that will improve this situation. @Eh2406 would be more likely to know the answer for both cases. |
Cargoes resolver optimizes for each dependency edge getting the largest version within its requirements. As such this is working as intended. However this is known to be insufficiently flexible. Public/private dependencies would allow you to control this exactly (and only) where it matters, however progress on that is rather stalled. Someday I would like to experiment with some more flexible syntax for adding requirements to the generation of the lock file. One rather crude option, that probably get some 80% of the use cases, would be a The existing resolver is collapsing under its own complexity. It is technically possible to add these sorts of features to it, but I have not succeeded in doing so. The PubGrub solver itself will make some of these problems easier, but more importantly will be a more organized and up-to-date code base to start from. Is having this duplication actually causing you problems for your use case? |
I'm assuming the use case is similar to sqlx where they want integration with types from other crates without worrying about breaking changes unrelated to the types they integrate with. See sqlx's discussion on the topic. |
Thanks
Yes, exactly as @epage said.
I haven't tried it, but as you said, it's very hacky. And I guess it will install the latest as soon as I run cargo update. |
I'm well aware of this fact. The problem is I do not see a good solution to this problem. So my question at the cargo team is the following: What's the correct way to handle this? I see the following bad options:
Maybe you can comment officially on how to solve this? I feel this issue is holding back the ecosystem at all, as it makes it really hard to provide integration for other crates. I understand that this is not an easy problem to solve, but I really would like to see a canonical solution here. Especially as this problem is known for quite a bit of time. |
A couple of solutions from sqlx that weren't on your list
On top of those is how the potential for relaxing orphan rules could change what solution is chosen. This shows the problem, and potential solutions, are wider than just cargo. We need to look at this holistically. |
I don't really think a smarter solver can fully solve this issue. If you have just one bit of integration code for the uuid crate, it can only apply to one specific version within given crate graph. Now if multiple crates in the dependency graph want this integration for different versions of uuid, that won't work. This is already a problem if two crates specify uuid deps that have to be different, something like |
Forgot to mention, another weakness in this solution is it assumes the types being integrated will never have a significant breaking change. For the most part, they are pretty simple, so it should be rare, but if is a risk. |
@jplatte sure there will be some conflicts here and there. That's understandable, and some cases are unsolvable. I'm not familiar with the source code and the algorithms. But I would say, the main part of resolver works fine. Just the time we sort by |
Neither of this are great either if you want to provide actual integration.
I remember that some persons talked about a similar proposal years back, so that just seems not to be moving at all. Sorry if that sounds harsh, but I feel that this is holding back the ecosystem more and more. I think one way to address the fundamental problem that there are always cases where you cannot solve version constraints is the following approach:
|
You are not wrong that this is holding back the ecosystem. And that none of these ideas are new. |
I can understand the frustration with any of the routes for this to move forward. A big challenge right now is that the cargo team in particular is limited in availability both to implement and to mentor on tasks. That combined with the current resolver complexity makes it difficult for cargo to be able to move forward with a solution at this time. |
I'm well aware of this and I didn't plan to blame anyone here. It's just as you've already written quite frustrating to see this long standing issue here without any signs of moving, while observing at the "same" time changes to cargo's resolver algorithm that broke diesel a while back. That written: If there is anything actionable here I'm happy to hear that, maybe I can find some time later this year to work on this. |
Another possibility would be for uuid to publish a version 0.8.3 that depends on uuid 1.0.0 and uses the same underlying type, which would eliminate the compatibility issue. Long-term, I'm hoping in lang we can find a way to allow a separate Meanwhile, I would suggest just supporting the latest semver-major version of uuid. |
@joshtriplett Just supporting the latest semvar-major version is not necessarily a solution, as this would require a breaking diesel release whenever one of the dependency crates releases a new major version, even if the relevant part of their API remains the same. |
@weiznich That's part of why I'm suggesting that uuid might want to release a version in the 0.8 series that provides compatibility with the 1.0 series. If you don't want to go that route, then you may need to use feature flags. |
Problem
Diesel 2 (rc.0) depends on
uuid >=0.7.0, <2.0.0
and my app depends onuuid =0.8.2
because some other deps depend on that.Cargo resolver always pick two versions of
uuid
,0.8.2
and1.0.0
. (in my case)It's the same if I remove the
=
, also the same if I removeuuid
dep from my app and only some other deps depend onuuid 0.8.2
.Test scenario to cover this case:
Steps
cargo tree -i uuid
Possible Solution(s)
No response
Notes
No response
Version
The text was updated successfully, but these errors were encountered: