Go 提供了按条件编译某文件的能力,通过在 Go 文件中加入一行特殊的注释来实现:
//go:build (darwin && cgo) || linux
// +build darwin,cgo linux
packaget getIP
func main() {
// ...
}
其中这两行 build 注释是等价的:
//go:build
是 Go 1.17 及以后的语法。只能存在一行//+build
是 Go 1.16 及之前的语法。可以存在多行,多行间的关系是 AND。1.17 及以上的 gofmt 遇到这种老语法时,会自动生成新的语法
你可以看到里面用了这些变量 darwin
, cgo
等。可用的变量来源于:
- GOOS 的值,比如
linux
,darwin
,windows
等 - GOARCH 的值,比如
386
,amd64
,arm
等 - Go 编译器,
gc
或gccgo
cgo
,如果CGO_ENABLED
被设置成 1- Go 版本号,如
go1.1
表示 Go 1.1 版本及以上,go1.12
表示 Go 1.12 版本及以上 - 其他在
go build -tags
中指定的 tag
另外,如果你的 go 文件名,除去扩展名和 _test
后缀后,满足这些 pattern:
*_GOOS
,比如a_windows.go
a_windows_test.go
*_GOARCH
,比如a_arm.go
math_386.s
*_GOOS_GOARCH
,比如a_linux_arm.go
表示隐式的 build constraints。
使用 -tags
的例子
google/wire 使用了 -tags
的能力。
在编写 wire.go
时你需要指定 wireinject
//go:build wireinject
// +build wireinject
使用 wire CLI,它会通过 -tags
机制,扫描目录下的带 wireinject
的文件,并生成 wire_gen.go
,其中带有这样的头:
//go:generate go run github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
这使得 go 在正常编译此项目时,会跳过 wire.go
而仅使用 wire_gen.go
。
参考
Build constraints 注释的语法在 Go 1.17 版本后有变化:
JetBrains 也有一个 文档 描述此功能。