-
Notifications
You must be signed in to change notification settings - Fork 17.9k
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
cmd/go: dependencies in go.mod of older versions of modules in require cycles affect the current version's build #36369
Comments
Editing |
Also note that in general you should use Any time the |
This behavior is a result of how the minimal version selection (MVS) algorithm works. It basically traverses the module version graph and makes a list of the highest versions encountered of each module in the graph. We can't really change this algorithm: doing so would mean different versions of Go would select different versions, possibly breaking builds. To expand on @bcmills's comment, |
Sorry, my brain was tired. I meant to write that I edited go.mod. I've edited the text to fix this.
Sure. Except in this case it just fails, since there is no version of b old enough. a, b and c all predate go modules. I expected one version of a to be used in the build. Not two. I understand the MVS algorithm, but I expected it to have a check that if it currently planed to use version X of a, and it saw b needs needs version Y of a, Y<X (and same major versions), that it would not continue down into a@Y's dependencies because it wasn't going to use a@Y in the end.
That didn't work so easily. Because of the cycle of dependency between a and b goes back long before go modules, there is no version of a or b suitable. Updating a leaves it depending on a b which itself depends on the older a, which depends on the older b, which ... eventually recuses to an a depending on the c I don't want. What I ended up doing, once I understood what was going on, is breaking the back dependencies by hand editing both a/go.mod and b/go.mod to depend on the future (not-yet-exiting) versions of a and b. I pushed that to source control. Then I created those future versions by tagging a and b. And finally did a build to pull in the go.sum lines, now that those versions of a and b did exist, and pushed again. Now, even though MVS followed the dependencies all the way back, it stops at these releases or a and b, and doesn't go forward. |
I don't think this can work without some path dependence or non-determinism which would add complication and change results. For example, say the main module
I'm glad this worked out. I'm sorry this wasn't easier though. This is an area where our tooling and documentation could improve a bit. @bcmills Any thoughts on how this could be better? I think any change here would require changing MVS results, which may break existing builds. |
As it so happens, writing a design doc for an algorithm to break cycles using lazy loading is my #1 task for this week. |
Change https://golang.org/cl/220080 mentions this issue: |
Updates golang/go#36460 Updates golang/go#27900 Updates golang/go#26955 Updates golang/go#30831 Updates golang/go#32058 Updates golang/go#32380 Updates golang/go#32419 Updates golang/go#33370 Updates golang/go#33669 Updates golang/go#36369 Change-Id: I1d4644e3e8b4e688c2fc5a569312495e5072b7d7 Reviewed-on: https://go-review.googlesource.com/c/proposal/+/220080 Reviewed-by: Russ Cox <[email protected]>
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes. 1.13.5 is the latest release at this date.
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
I have three modules, a, b and c. All use go modules. a/go.mod requires b and c, and (due to history) b/go.mod requires a. One (or both) of those cyclic requires refers to an older version than the newest, but it's new enough for both a and b to build.
Now I wanted to downgrade module c to an older version. So I edited a/go.mod, and rebuild a. The c line in a/go.mod was edited to the newer version of c, which I had been using before, and which I did not want to use anymore.
Investigating with go mod graph showed that the newer c was required by an older a, which was required by the current b, which was required by the current a. In other words
a@now -> b@now -> a@older -> c@newer
What did you expect to see?
I did not expect the a@older/go.mod to be of any consequence to the go modules choice of version of c, since in the end it was going to use a@now to build, not a@older.
What did you see instead?
go mod graph showed that because of the cycling in the module dependency graph, a@older/go.mod was consulted, as if a@older wasn't an older version of a module already in the graph, but rather some other independent module.
As a consequence a@older's dependencies changed a@now's build.
The text was updated successfully, but these errors were encountered: