16

例如,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

4

1 回答 1

27

//go:build是 Go 1.17 中引入的新条件编译指令。

它旨在替换// +build指令,因为新语法带来了一些关键改进:

  • 与其他现有的 Go 指令和 pragma 保持一致,例如//go:generate
  • 支持标准布尔表达式,例如//go:build foo && bar,而旧// +build注释的语法不太直观。例如 AND 用逗号表示// +build foo,bar,OR 用空格表示// +build foo bar
  • 它由 支持go fmt,它将自动修复指令在源文件中的不正确放置,从而避免常见错误,例如在指令和包语句之间没有留空行。

这两个构建指令将在几个 Go 版本中共存,以确保顺利过渡,如相关提案文档中所述(低于 N = 17,强调我的)

Go 1.N 将开始转换。在 Go 1.N 中:

  • 构建将开始优先//go:build选择文件行。如果//go:build文件中没有,则任何// +build行仍然适用。

  • 如果 Go 文件包含//go:build不包含// +build.

  • //go:build如果 Go 或程序集文件在文件中包含太晚,则构建将失败。Gofmt 会将错位的 //go:build 和 // +build 行移动到文件中的正确位置。

  • Gofmt将使用与其他 Go 布尔表达式(所有和运算符//go:build周围的空格)相同的规则来格式化表达式。&&||

  • 如果文件仅包含// +build行,gofmt将在它们上方添加等效//go:build行。

  • 如果文件同时包含//go:build// +build行,gofmt将考虑//go:build事实来源并更新// +build行以匹配,保持与早期版本的 Go 的兼容性。Gofmt也会拒绝//go:build被认为太复杂而无法转换为// +build格式的行,尽管这种情况很少见。(请注意此项目符号开头的“如果”。Gofmt不会将// +build行添加到只有 .)的文件中 //go:build。)

  • buildtags签入go vet将添加对//go:build约束的支持。当 Go 源文件包含不同含义行时,它将失败//go:build// +build。如果检查失败,可以运行gofmt -w.

  • 当一个 Go 源文件包含without并且其包含的模块有一个 go 行列出 Go 1.N 之前的版本时,buildtags检查也会失败。如果检查失败,可以添加任何一行然后运行,它将用正确的行替换它。或者可以将 Go 版本升级到 Go 1.N。//go:build// +build// +buildgofmt -wgo.mod

有关语法更改的更多信息:Golang 条件编译

于 2021-07-13T11:02:28.207 回答