Go 语言的构建约束

go Feb 06, 2019
Golang 语言作为21世纪出现的少数语言之一,它有吸收并继承了上世纪发明的那些语言的优点。

build constraints (构建约束)就是其中不错的设计。有了这些设计, 我们可以在源码中通过注释的方式指定编译选项,比如只允许在 Linux 下, 或者在 386 的平台上编译之类的情况; 还可以通过文件名来约束构建, 比如 *_linux.go, 就是只允许在Linux 下编译, *_windows_amd64.go 就是只允许在 windows 和 amd64 下进行编译。

构建约束可以在很多文件中进行使用, 不单单适用 .go 文件。但是必须要注意的是, 通过注释实施构建约束的话, 必须要放在文件的开头, 要优先于空行和其它注释(包含包注释和协议注释)之前。也就是说必须在 package 语句的前面写。

因为 Go 的 godoc 是可以提取代码中的注释然后转换为文档的, 在 package 语句之前写的注释会被认为是包级别的注释。而构建约束又得在所有注释之前, 那么为了区分包级别的注释, 官方给出的方法是: To distinguish build constraints from package documentation, a series of build constraints must be followed by a blank line.
要在构建约束与包级别的注释之间添加空行进行区分。

通过注释实施的构建约束还可以进行逻辑表达, 即 and, or 之类的语义。Go 官方定义的是:
A build constraint is evaluated as the OR of space-separated options. Each option evaluates as the AND of its comma-separated terms. Each term consists of letters, digits, underscores, and dots. A term may be negated with a preceding !.
如果构建约束中有空格, 那么就是 or 关系; 如果是逗号分隔, 那么就是 and 关系; ! 表示 not。例如:

// +build linux,386 darwin,!cgo

就是表示 (linux and 386) or (darwin and (not cgo))

而且 Go 还支持多行的构建约束, 多行之间是 and 关系, 例如:

// +build linux darwin
// +build 386

就是表示 (linux or darwin) and 386

Go 官方还定义了常用的一些约束:

  • 限制目标操作系统, 也就是要和 runtime.GOOS 一致
  • 限制目标架构平台, 也就是要和 runtime.GOARCH 一致
  • GC 或者 GCCGO 等编译器支持的约束
  • cgo 约束, 也就是说如果支持 cgo 的话, 就可以参与编译
  • 限制 go 版本, go1.1 表示从 go1.1 开始向前兼容; go1.2 表示从 go1.2 开始向前兼容;...
  • 自定义的约束

如果你想临时让某个文件不参与编译, 可以添加注释约束: // +build ignore.

Go 官方定义里还表示可以自定义约束, 那么这个可以这么使用呢? 了解 Go 的人都知道 Go 内置了 testing 库和单元测试框架, 跑跑一般的单元测试还是可以, 但是如果要做一些简单的集成测试就会出现很多麻烦了, 因为 go test 命令默认就是跑最基本的单元测试。那么这么只执行集成测试的代码呢? 其实这就可以借助自定义约束来实施。例如我们可以在需要进行集成测试的 .go 文件头加上 // +build integration 注释, 然后运行 go test -tags="integration" 就可以只运行我们的集成测试代码了。

虽然可以通过注释的方式对构建进行了约束, 但是文件名的构建约束反而显得更不错, 至上在工程文件目录里看着一目了然。文件名前缀只要含有 _GOOS, _GOARCH, _GOOS_GOARCH 的就可以。例如 xxx_linux.go, yyy_windows_amd64.go, zzz_386.go 等等。



相关资料链接:

Go official doc#Build Constraints
Binary Only Packages
Using Go’s build constraint tag to help build mock services for service testing
Golang | cmd - go build 构建约束

huiyifyj

你记得也好, 最好你忘掉...