Wandering Thoughts archives

2022-06-25

A limitation on what 'go install' can install (as of Go 1.18)

As all people dealing with Go programs know or are learning, now that Go is module-only, the way you install third party Go programs from source is now 'go install <name>@latest', not the old way of 'go get <name>'. However, this is not always a completely smooth process that just works, because it's possible to have Go programs in a state where they won't install this way. Here's an illustration:

$ go install github.com/monsterxx03/gospy@latest
go: downloading github.com/monsterxx03/gospy v0.5.0
go: github.com/monsterxx03/gospy@latest (in github.com/monsterxx03/gospy@v0.5.0):
    The go.mod file for the module providing named packages contains one or
    more replace directives. It must not contain directives that would cause
    it to be interpreted differently than if it were the main module.

What is happening here is that internally, gospy uses packages from its own repository (module) and one of them, github.com/monsterxx03/gospy/pkg/term, in turn uses github.com/gizak/termui/v3. However, the github.com/monsterxx03/gospy module has a replace directive for this termui module that changes it to github.com/monsterxx03/termui/v3.

If you clone the repository and run 'go install' inside it, everything works and you wind up with a gospy binary in your $HOME/go/bin. However, as we see here 'go install ...@latest' works differently enough that the replace directive causes this error. To fix the problem (ie, to build gospy or any program like it), you must clone the repository and run 'go install' in the right place inside the repository.

(Alternately you can file bugs with the upstream to get them to fix this, for example by dropping the replace directive and directly using the replacement in their code. But if the upstream is neglected, this may not work very well.)

Unsurprisingly, there is a long standing but closed Go issue on this 'go install' behavior, cmd/go: go install cmd@version errors out when module with main package has replace directive #44840. This was closed more than a year ago in 2021 with a 'working as designed', and indeed the help for 'go install' explicitly says about this mode:

No module is considered the "main" module. If the module containing packages named on the command line has a go.mod file, it must not contain directives (replace and exclude) that would cause it to be interpreted differently than if it were the main module. The module must not require a higher version of itself.

(The apparent Go reference for why this exists is issue #40276, which I haven't tried to read through because I'm not that interested.)

Possible this will be changed someday, especially since it seems to keep coming up over and over again; issue #44840 contains quite the laundry list of projects that have hit this issue. Amusingly, one of the gopls releases hit this issue.

For now, if you're developing a Go program and you need to use replace directives in your go.mod during development, you'll have to do some extra work. One option is to strip the replace directives out for releases (and you need to make releases, because 'go install ...@master' won't work because of your replace directives). Another option is to switch to using Go workspaces for local development and drop the go.mod replace directives entirely. If you need to actually release a version of your program that uses the replacement module, well, you're out of luck; you need to actually change your code to explicitly use the replacement module and drop the replace directive.

programming/GoInstallLimitation written at 22:25:17; Add Comment


Page tools: See As Normal.
Search:
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.