在看别人源码的时候有时会看到类似这样打头的注释:
//go:build xxxx
比如gin的gin/internal/json
包里面就有。
这到底什么意思呢?
这其实是go里面的构建约束,也叫构建标签,build的时候给编译器的标签,可以决定一个文件是否需要包含在包之中。
比如://go:build (linux && 386) || (darwin && !cgo)
表示执行go build的时候,目标系统是386的linux或者没有启用cgo的darwin时,当前文件会被编译进来。
这个就是编译约束。
特性:
- 可以出现在任何源文件里面,不仅仅是go源文件。
- 必须写在文件顶部,前面只可以有空白行或其他注释
- 为了区分构建约束和包文件,在构建约束后面应该有一空白行
- 由
||
、&&
、!
运算符(或、与、非)和括号组成的表达式
可用的标签:
- 目标操作系统,拼写和
runtime.GOOS
一致,可以用命令go tool dist list
查看可能的值 - 目标系统架构,拼写和
runtime.GOARCH
一致 unix
,标识GOOS
是Unix或者Unix-like系统- 正在使用的编译器,
gc
或者gccgo
cgo
,如果支持cgo
命令- 每个go主要发布版本的术语,比如:
go1.1
,满足从go1.1版本开始,go1.12
从go1.12版本开始,其他类推 - 通过
-tags
标记给出的其他标签,-tags
多个标签用逗号分隔列出
//go:build ignore
:忽略编译
go 1.16和之前的版本的语法是使用// +build
,gofmt命令在遇到旧语法时会自动添加等效的新语法
gin的gin/internal/json
就是通过标签来确定使用哪个json库的:
go build -tags=jsoniter
go build -tags=go_json
如果一个文件名称,满足如下条件:
*_GOOS
*_GOARCH
*_GOOS_GOARCH
比如一个文件名称source_windows_amd64.go
当目标系统是windows系统amd64架构时会包含编译,GOOS
和 GOARCH
分别代表目标系统的类别和架构类型,满足上面规则的文件被认为需要满足这些条件的隐式约束。
例如以下文件名:
dns_windows.go
:编译windows包时才会本文件
math_386.s
:编译包目标是32-bit x86时包含
这样的好处就是,当同一个方法在不通操作系统下实现是不一样的时候,可以用相同的函数名称分别实现,编译的时候根据目标系统类型编译对应系统的源文件:
// test_windows.go
package pkg
import "log"
func PrintOS() {
log.Println("windows")
}
// test_linux.go
package pkg
import "log"
func PrintOS() {
log.Println("linux")
}
//main.go
package main
import (
"test/pkg"
)
func main() {
pkg.PrintOS()
}
有疑问加站长微信联系(非本文作者))

ignore
是习惯用法,并不是强制用法,理论上只要和tag不冲突就行。 //go:build 只有在文件名无法确定constraints的时候才会读取。 必须写在文件顶部,是为了Parse的时候只处理Comments即可。 //go:build go1.x是因为每发布一个版本都要往toolchain里添加一个release tag,所以高版本永远比低版本的tag列表多。 toolchain还包含了很多experiment相关的tag,很少人注意。