1. 条件编译
Go
能根据所处环境选择对应的源码进行编译。让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃,这就叫做条件编译。
在 Go
中,也称之为 Build Constraints
编译约束,添加编译约束的以下 2 种:
- 编译标签(
build tag
) - 文件后缀
2. 编译标签
编译标签是一种通过在源码文件顶部添加注释,来决定文件是否参与编译的约束方式。其格式如下:
// +build <tags>
注意:
// +build
的下一行必须是空行,否则会被解析为包注释。
// +build linux// main package comment
package main
Go
语言在构建一个包的时候会读取这个包里的每个源文件并且分析编译标签,这些标签决定了这个源文件是否参与本次编译。
tags
说明:
- 以空格分开表示
OR
- 以逗号分开表示
AND
!
表示NOT
- 一个文件可以有多个
+build
构建标记,它们之间的关系是逻辑与
的关系
标签可以指定为以下内容:
- 操作系统,环境变量中
GOOS
的值,如:linux
、darwin
、windows
等; - 操作系统的架构,环境变量中
GOARCH
的值,如:amd64
、x86
、i386
等; - 使用的编译器,
gc
或者gccgo
; - 是否开启
CGO
,cgo
go
版本号:比如Go Version 1.1
为go1.1
,Go Version 1.12
版本为go1.12
以此类推。
其它自定义标签,通过 go build -tags
指定的值。
使用示例:
- 编译条件为
(linux AND 386) OR (darwin AND (NOT cgo))
// +build linux,386 darwin,!cgo
- 多个编译约束,比如条件为
(linux OR darwin) AND amd64
// +build linux darwin// +build amd64
- 也可以使用
ignore
标签将一个文件从编译中排除。
// +build ignore
linux
或者windows amd64
// +build linux windows,amd64package main
多个 +build
构建标记一般分成每行一个 +build
构建标记。
在 Gin
框架中,也较多地使用了编译标签,例如 internal/json
目录,这个目录目前只有 json
包。在 json
包中,这个包的两个文件分别都使用了标签 jsoniter
。
jsoniter.go
内容
// Copyright 2017 Bo-Yi Wu. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.// +build jsoniterpackage jsonimport "github.com/json-iterator/go"var (json = jsoniter.ConfigCompatibleWithStandardLibrary// 通过函数值,Marshal 等函数都由 Gin 下的 json 包导出Marshal = json.MarshalUnmarshal = json.UnmarshalMarshalIndent = json.MarshalIndentNewDecoder = json.NewDecoderNewEncoder = json.NewEncoder
)
json.go
内容
// Copyright 2017 Bo-Yi Wu. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.// +build !jsoniterpackage jsonimport "encoding/json"var (// 通过函数值,Marshal 等函数都由 Gin 下的 json 包导出Marshal = json.MarshalUnmarshal = json.UnmarshalMarshalIndent = json.MarshalIndentNewDecoder = json.NewDecoderNewEncoder = json.NewEncoder
)
Gin
使用 encoding/json
作为默认的 json
包,但可以通过从其他标签构建来改变它。
- jsoniter
$ go build -tags=jsoniter .
上述命令表示使用 jsoniter.go
文件来编译生成可执行文件。
- go_json
$ go build -tags=go_json .
在 Gin
框架编译时,可以通过编译标签自由选择性编译。编译时如果指定 -tags=jsoniter
,则会选择 jsoniter.go
进行编译,默认情况下一般都没有指定这个标签,所以使用的是标准库的 json
包。
由于第三方包 jsoniter
性能上要优于标准库的 json
包,而且这个包提供 100% 与标准库 json
包兼容选项,加上主要函数签名一致,所以 Gin
这里特意封装了新的 json
包,通过编译标签,程序编译时很容易根据实际标签来选择具体实现的代码包。
3. 文件后缀
除了编译标签,第二种添加编译约束的方法是通过源码文件的文件名实现的,这种方案比构造标签方案更简单。编译器也会根据文件后缀来自动选择编译文件:
$filename_$GOOS.go
$filename_$GOARCH.go
$filename_$GOOS_$GOARCH.go
$filename
: 源文件名称;$GOOS
: 表示操作系统,从环境变量中获取;$GOARCH
: 表示系统架构,从环境变量中获取;
后缀的顺序记住不要颠倒,后缀中同时出现系统和架构名时,需要保持$filename_$GOOS_$GOARCH.go
的顺序。
标准库 os
源代码的部分截图:
构建标签和文件名后缀在功能上是重叠的,根据需要选择合适的就行。
参考:
https://mp.weixin.qq.com/s?__biz=MzAxNzY0NDE3NA==&mid=2247489316&idx=2&sn=5b556235a63781c852e490da67823f7d&chksm=9be338c5ac94b1d376f94b3d8990ec8062cae9745f1d1e0314b116d6003b48e8bbd72701b249&scene=126&&sessionid=1642228531#rd