Skip to content
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: build tag constraint vs go.mod version #64308

Closed
oliverpool opened this issue Nov 21, 2023 · 9 comments
Closed

cmd/go: build tag constraint vs go.mod version #64308

oliverpool opened this issue Nov 21, 2023 · 9 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Unfortunate WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.
Milestone

Comments

@oliverpool
Copy link

What version of Go are you using (go version)?

$ go version
go version go1.21.4 linux/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=''
GOARCH='amd64'
GOBIN='/home/oliver/.local/bin'
GOCACHE='/home/oliver/.cache/go/build'
GOENV='/home/oliver/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/oliver/.cache/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/oliver/.cache/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='local'
GOTOOLDIR='/usr/lib/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.21.4'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/home/oliver/e/exp/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build172397718=/tmp/go-build -gno-record-gcc-switches'

What did you do?

I want to publish a package compatible with go1.20 and go1.21, which uses the min function.
Since the builtin was introduced in go1.21, I added a pseudo-polyfill in a file with a build constraint //go:build !go1.21.

main.go

package main

import "fmt"

func main() {
	fmt.Println("min", min(1, 2))
}

min_polyfill.go

//go:build !go1.21

package main

// min is a pseudo-polyfill for go1.21 min function
func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

go.mod

module code.pfad.fr/exp

go 1.20

Complete program available here: https://git.sr.ht/~oliverpool/exp/tree/main/item/min_polyfill

I then run my program using go run ./min_polyfill

What did you expect to see?

min 1

Either the build constraint indicates that go is not 1.21 yet and the polyfill should be used, or the builtin should be used

What did you see instead?

# code.pfad.fr/exp/min_polyfill
min_polyfill/main.go:6:21: min requires go1.21 or later (-lang was set to go1.20; check go.mod)

Maybe a build constraint is not the right tool, or I a misusing it?

Anyway, how can I use the min builtin from go1.21 with a fallback for go1.20?

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Nov 21, 2023
@mknyszek mknyszek removed the compiler/runtime Issues related to the Go compiler and/or runtime. label Nov 21, 2023
@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Nov 21, 2023
@mknyszek mknyszek changed the title cmd/compile: build tag constraint vs go.mod version cmd/go: build tag constraint vs go.mod version Nov 21, 2023
@mknyszek mknyszek added GoCommand cmd/go and removed compiler/runtime Issues related to the Go compiler and/or runtime. labels Nov 21, 2023
@mknyszek mknyszek added this to the Backlog milestone Nov 21, 2023
@mknyszek mknyszek added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Nov 21, 2023
@mknyszek
Copy link
Contributor

CC @bcmills @matloob

I think this question is more related to the Go command? Feel free to switch it back to cmd/compile -- sorry for the noise if I'm wrong.

Also, for future reference, I think situations where you're unsure if there's a bug in the toolchain or if you're just misunderstanding something, a good place to start is the golang-nuts mailing list.

@bcmills
Copy link
Contributor

bcmills commented Nov 21, 2023

@oliverpool, a negative build constraint is not the right tool, unfortunately. A toolchain that knows how to compile go1.21 will satisfy that constraint even if the language version specified in go.mod is lower.

See:

@bcmills
Copy link
Contributor

bcmills commented Nov 21, 2023

This seems to be working as designed given #59033, although it's unfortunate that that makes the polyfill use-case more difficult.

Given that you have the polyfill file anyway, is there some reason you can't use the polyfill definition of min all the time?

@bcmills bcmills added WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. compiler/runtime Issues related to the Go compiler and/or runtime. and removed GoCommand cmd/go labels Nov 21, 2023
@dmitshur
Copy link
Contributor

dmitshur commented Nov 22, 2023

Anyway, how can I use the min builtin from go1.21 with a fallback for go1.20?

In this particular case, you could take advantage of the property that the meaning of the go directive changed between 1.20 and 1.21. In 1.20, it was advisory, and in 1.21, it becomes the minimum required.

Specifically, a way for you to use the predeclared min in 1.21 and a fallback in 1.20 is to set the go directive to 1.21. It'll work with 1.21 (where it's the minimum, but satisfied), and it will work in 1.20 (where it's below minimum, but still considered advisory). Consider:

 module code.pfad.fr/exp

-go 1.20
+go 1.21
$ go run .
min 1

$ GOTOOLCHAIN=go1.20.11 go run .
min 1

This is a one-time transitional quirk that won't apply in the future though.

@oliverpool
Copy link
Author

@dmitshur thanks for the tip! The main drawback is that I won't know if I use any features of go1.20 without a proper polyfill (without actually using go1.20).

Another (cumbersome, but I believe still available in the future) solution is to rename to min_ and add 2 files:

min_21.go

//go:build go1.21

package main

func min_(a, b int) int {
	return min(a, b)
}

min.go

//go:build !go1.21

package main

// min is a pseudo-polyfill for go1.21 min function
func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

In any case, I find think this unexpected behavior should be better documented (if not changed):

the language version declared by the go directive of the go.mod is not used to satisfy build constraints (which are checked against the currently running Go toolchain).

Should I close this issue in favor of #61894 ?

@oliverpool
Copy link
Author

Thinking more about this, it is only relevant for builtins since syntax changes and new stdlib features can't have a "single-file" polyfill (they need the "2-files" workaround from above).

Because it only concerns builtins:

  • a special treatment could be implemented in the toolchain, if a builtin was introduced in a later version, check for a polyfill using build tags
  • or maybe such a "special treatment" is too cumbersome for such a niche usecase: simply improve the documentation

I guess the second option is much easier, what do you think?

@seankhliao
Copy link
Member

given #59033 i think it should work in the future when the go directive is > 1.21.0 ?

@oliverpool
Copy link
Author

@seankhliao apparently it is already implemented: #59033 (comment)

My "2-file" example seems to take advantage of it: #64308 (comment) (however my go.mod states "go 1.20", so maybe this is unrelated?)

@seankhliao
Copy link
Member

I think this can be folded into #61894

@seankhliao seankhliao closed this as not planned Won't fix, can't repro, duplicate, stale Dec 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Unfortunate WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.
Projects
None yet
Development

No branches or pull requests

6 participants