`//go:build` 和 `// +build` 指令之间有什么区别?

时间:2021-07-13 10:27:56

标签: go build go-build

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

1 个答案:

答案 0 :(得分:9)

//go:build 是 Go 1.17(将于明年 8 月发布)中引入的新条件编译指令。

它旨在替换 // +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 将开始转换。在 Go 1.N 中:

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

  • 如果 Go 文件包含 //go:build 而没有 // +build,构建将不再失败。

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

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

  • 如果一个文件只包含 // +build 行,gofmt 会在它们上面添加一个等效的 //go:build 行。

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

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

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

更多信息:Golang conditional compilation