`//go:build` 和 `// +build` 指令有什么区别?
What's the difference between `//go:build` and `// +build` directives?
例如,https://github.com/golang/sys/blob/master/cpu/cpu_gccgo_x86.go#L5:
//go:build (386 || amd64 || amd64p32) && gccgo
// +build 386 amd64 amd64p32
// +build gccgo
package cpu
在我看来,作为构建标签,// +build ...
可以很好地工作。
为什么 //go:build
仍然明确指定?
顺便说一下,很难找到 //go:build
的手册,但是 // +build
很容易(https://pkg.go.dev/cmd/go#hdr-Build_constraints)
Go 1.18
现在首选新指令 //go:build
,工具链将主动删除旧指令;如 Go 1.18 发行说明中所述:
In Go 1.18, go fix
now removes the now-obsolete // +build
lines in modules declaring go 1.18 or later in their go.mod files.
由于上述原因,如果您尝试使用 go.mod
1.17 或更低版本构建一个需要 1.18 或更高版本依赖项的模块,如果缺少依赖项 // +build
,构建可能会失败行。
Go 1.17
//go:build
是用于指定 build constraints 的新条件编译指令。它是在 Go 1.17 中引入的。
它旨在取代旧的 // +build
指令;用例仍然相同:它“列出了文件应包含在包中的条件”。新语法带来了一些关键改进:
- 与其他现有的 Go 指令和编译指示一致,例如
//go:generate
- 支持标准布尔表达式,例如
//go:build foo && bar
,而旧的 // +build
注释语法不太直观。例如,AND 用逗号 // +build foo,bar
表示,OR 用空格 // +build foo bar
go fmt
支持它,它会自动修复指令在源文件中的错误位置,从而避免 common mistakes 在指令和包语句之间不留空行。
这两个构建指令 将在几个 Go 版本中共存 以确保平稳过渡,如相关提案文档中的 outlined (在下面的引用中N是17,强调我的):
Go 1.N would start the transition. In Go 1.N:
Builds will start preferring //go:build
lines for file selection. If there is no //go:build
in a file, then any // +build
lines still apply.
Builds will no longer fail if a Go file contains //go:build
without // +build
.
Builds will fail if a Go or assembly file contains //go:build
too late in the file. Gofmt will move misplaced //go:build
and // +build lines to their proper location in the file.
Gofmt
will format the expressions in //go:build
lines using the same rules as for other Go boolean expressions (spaces around all &&
and ||
operators).
If a file contains only // +build
lines, gofmt
will add an equivalent //go:build
line above them.
If a file contains both //go:build
and // +build
lines, gofmt
will consider the //go:build
the source of truth and update the // +build
lines to match, preserving compatibility with earlier versions of Go. Gofmt
will also reject //go:build
lines that are deemed too complex to convert into // +build
format, although this situation will be rare. (Note the “If” at the start of this bullet. Gofmt
will not add // +build
lines to a file that only has //go:build
.)
The buildtags
check in go vet
will add support for //go:build
constraints. It will fail when a Go source file contains //go:build
and // +build
lines with different meanings. If the check fails, one can run gofmt -w
.
The buildtags
check will also fail when a Go source file contains //go:build
without // +build
and its containing module has a go line listing a version before Go 1.N. If the check fails, one can add any // +build
line and then run gofmt -w
, which will replace it with the correct ones. Or one can bump the go.mod
go version to Go 1.N.
有关语法更改的更多信息:Golang conditional compilation
例如,https://github.com/golang/sys/blob/master/cpu/cpu_gccgo_x86.go#L5:
//go:build (386 || amd64 || amd64p32) && gccgo
// +build 386 amd64 amd64p32
// +build gccgo
package cpu
在我看来,作为构建标签,// +build ...
可以很好地工作。
为什么 //go:build
仍然明确指定?
顺便说一下,很难找到 //go:build
的手册,但是 // +build
很容易(https://pkg.go.dev/cmd/go#hdr-Build_constraints)
Go 1.18
现在首选新指令 //go:build
,工具链将主动删除旧指令;如 Go 1.18 发行说明中所述:
In Go 1.18,
go fix
now removes the now-obsolete// +build
lines in modules declaring go 1.18 or later in their go.mod files.
由于上述原因,如果您尝试使用 go.mod
1.17 或更低版本构建一个需要 1.18 或更高版本依赖项的模块,如果缺少依赖项 // +build
,构建可能会失败行。
Go 1.17
//go:build
是用于指定 build constraints 的新条件编译指令。它是在 Go 1.17 中引入的。
它旨在取代旧的 // +build
指令;用例仍然相同:它“列出了文件应包含在包中的条件”。新语法带来了一些关键改进:
- 与其他现有的 Go 指令和编译指示一致,例如
//go:generate
- 支持标准布尔表达式,例如
//go:build foo && bar
,而旧的// +build
注释语法不太直观。例如,AND 用逗号// +build foo,bar
表示,OR 用空格// +build foo bar
go fmt
支持它,它会自动修复指令在源文件中的错误位置,从而避免 common mistakes 在指令和包语句之间不留空行。
这两个构建指令 将在几个 Go 版本中共存 以确保平稳过渡,如相关提案文档中的 outlined (在下面的引用中N是17,强调我的):
Go 1.N would start the transition. In Go 1.N:
Builds will start preferring
//go:build
lines for file selection. If there is no//go:build
in a file, then any// +build
lines still apply.Builds will no longer fail if a Go file contains
//go:build
without// +build
.Builds will fail if a Go or assembly file contains
//go:build
too late in the file. Gofmt will move misplaced //go:build and // +build lines to their proper location in the file.
Gofmt
will format the expressions in//go:build
lines using the same rules as for other Go boolean expressions (spaces around all&&
and||
operators).If a file contains only
// +build
lines,gofmt
will add an equivalent//go:build
line above them.If a file contains both
//go:build
and// +build
lines,gofmt
will consider the//go:build
the source of truth and update the// +build
lines to match, preserving compatibility with earlier versions of Go.Gofmt
will also reject//go:build
lines that are deemed too complex to convert into// +build
format, although this situation will be rare. (Note the “If” at the start of this bullet.Gofmt
will not add// +build
lines to a file that only has//go:build
.)The
buildtags
check ingo vet
will add support for//go:build
constraints. It will fail when a Go source file contains//go:build
and// +build
lines with different meanings. If the check fails, one can rungofmt -w
.The
buildtags
check will also fail when a Go source file contains//go:build
without// +build
and its containing module has a go line listing a version before Go 1.N. If the check fails, one can add any// +build
line and then rungofmt -w
, which will replace it with the correct ones. Or one can bump thego.mod
go version to Go 1.N.
有关语法更改的更多信息:Golang conditional compilation