- go 的编译是以 package main 的 main() 函数作为主入口,生成可执行文件。若 build 的是非 main 包,则不会生成可执行文件,只检查是否可执行编译。
可以输入 go help build 查看官方解释。
go build 编译包时,会忽略“_test.go”结尾的文件(即测试文件)
参数 含义
-o output 指定编译输出的名称,代替包名
-i install 安装作为目标的依赖关系的包(用于增量编译提速)
-a 强行对项目所有的代码包(包含标准库中的代码包)进行重新构建,即使它们已经是最新的了
-n 打印编译期间所用到的命令,仅仅是打印并不真正执行它们
-p n 指定编译过程中执行各任务的并行数量(确切地说应该是并发数量)。在默认情况下,该数量等于CPU的逻辑核数。但是在darwin/arm平台(即iPhone和iPad所用的平台)下,该数量默认是1
-race 开启竞态条件的检测。不过此标记目前仅在linux/amd64、freebsd/amd64、darwin/amd64和windows/amd64平台下受到支持
-msan 使用内存清除器启用互操作。只支持Linux/AMD 64、Linux/ARM 64,并且只有clang/llvm作为主机c+编译器
-v 打印出那些被编译时的代码包的名字
-x 打印编译期间所用到的其它命令(且执行),注意它与-n标记的区别
-work 打印出编译时生成的临时工作目录的路径,并在编译结束时保留它。在默认情况下,编译结束时会删除该目录
以下为不常用命令
-asmflags 此标记可以后跟另外一些标记,如-D、-I、-S等。这些后跟的标记用于控制Go语言编译器编译汇编语言文件时的行为
-buildmode 此标记用于指定编译模式,使用方式如-buildmode=default(这等同于默认情况下的设置)。此标记支持的编译模式目前有6种。借此,我们可以控制编译器在编译完成后生成静态链接库(即.a文件,也就是我们之前说的归档文件)、动态链接库(即.so文件)或/和可执行文件(在Windows下是.exe文件) go help buildmode
-compiler 此标记用于指定当前使用的编译器的名称。其值可以为gc或gccgo。其中,gc编译器即为Go语言自带的编辑器,而gccgo编译器则为GCC提供的Go语言编译器
-gccgoflags 此标记用于指定需要传递给gccgo编译器或链接器的标记的列表
-gcflags 此标记用于指定需要传递给go tool compile命令的标记的列表
-installsuffix 为了使当前的输出目录与默认的编译输出目录分离,可以使用这个标记。此标记的值会作为结果文件的父目录名称的后缀。其实,如果使用了-race标记,这个标记会被自动追加且其值会为race。如果我们同时使用了-race标记和-installsuffix,那么在-installsuffix标记的值的后面会再被追加_race,并以此来作为实际使用的后缀
-ldflags 此标记用于指定需要传递给go tool link命令的标记的列表
-linkshared 此标记用于与-buildmode=shared一同使用。后者会使作为编译目标的非main代码包都被合并到一个动态链接库文件中,而前者则会在此之上进行链接操作
-pkgdir 指定一个目录,并从改目录下加载编译好的.a 文件,并把编译可能产生新的 .a 文件放入到该目录中
-tags 此标记用于指定在实际编译期间需要受理的编译标签(也可被称为编译约束)的列表
-toolexec 此标记可以让我们去自定义在编译期间使用一些Go语言自带工具(如vet、asm等)的方式 -
build 约束 (Build Constraint, 构建约束) 又叫 build 标签 (Build Tag, 构建标签) , 是以// +build
开头的注释 - 它列出了在一个包中应该包含哪一个文件的条件。约束 (Constraints) 可能出现在任何类型的文件中 (不仅仅是 go 文件),但他们必须在文件的顶端位置,前面可以有空行和其他注释行。这就意味着 build 约束必须出现在 package 语句之前。
为了从包文档中区分出 build 约束, 一连串的 build 约束必须后面跟一个空行。
build 约束选项中, 以空格分隔来表示 OR 的关系;以逗号分隔来表示 AND 的关系。每一项可以由 字母、数字、下划线、点 组成。一个项可以用!
前缀来表是否定。
例如:
// +build linux,386 darwin,!cgo
对应的 boolean 公式为:
(linux AND 386) OR (darwin AND (NOT cgo))
一个文件可能有多个 build 约束,所有的约束是 AND 的关系,即:
// +build linux darwin
// +build 386
对应的 boolean 公式为:
(linux OR darwin) AND 386
在指定的编译期间,下面的词语可以生效
- 目标操作系统 runtime.GOOS 的拼写
- 目标架构 runtime.GOARCH 的拼写
- 使用的编译器 `gc` 或 `gccgo`
- "cgo", 如果 ctxt.CgoEnabled 是 true
- "go1.1", 从 Go 版本 1.1 起
- "go1.2", 从 Go 版本 1.2 起
- "go1.3", 从 Go 版本 1.3 起
- "go1.4", 从 Go 版本 1.4 起
- "go1.5", 从 Go 版本 1.5 起
- "go1.6", 从 Go 版本 1.6 起
- "go1.7", 从 Go 版本 1.7 起
- "go1.8", 从 Go 版本 1.8 起
- "go1.9", 从 Go 版本 1.9 起
- "go1.10", 从 Go 版本 1.10 起
- "go1.11", 从 Go 版本 1.11 起
- "go1.12", 从 Go 版本 1.12 起
- "go1.13", 从 Go 版本 1.13 起
- "go1.14", 从 Go 版本 1.14 起
- **任何在 ctxt.BuildTags 中列出的标签** (`go build -tags a,b,c ./...`)
还有一些在 beta 或 minor 版本中指定了不需要编译的标签。
如果一个文件的名字,在剥除扩展字段好可能的 _test
后缀后,与如下模式匹配:
*_GOOS
*_GOARCH
*_GOOS_GOARCH
(例如 example: source_windows_amd64.go
) GOOS 和 GOARCH 分别表示任何可能的操作系统和架构,那么这个文件被认为有一个隐式的构建约束。
为了避免一个文件被构建,可以用:
// +build ignore
(any other unsatisfied word will work as well, but “ignore” is conventional.)
如果仅在用 cgo 且在 linux 或 OS X 上构建一个文件,用:
// +build linux,cgo darwin,cgo
这样的一个文件通常有一个成对的文件来用于其他系统,这时成对的文件会用:
// +build !linux,!darwin !cgo
文件名为 dns_windows.go
将仅包含在 Windows 系统中构建的包中;类似的,math_386.s
将仅在 32-bit x86 系统中构建的包中包含。
用 GOOS=android 来匹配构建标签和文件
Using GOOS=android matches build tags and files as for GOOS=linux in addition to android tags and files.
Using GOOS=illumos matches build tags and files as for GOOS=solaris in addition to illumos tags and files.
重点归纳
目前我们在做一个功能,引入 go-fuzz, 想要实现在正常编译的时候不将 *_fuzz.go
文件编译进二进制文件中,而只有在使用 fuzz 时构建
阅读了以上文档后,可以按如下方式实现
- 在
*_fuzz.go
文件顶部中加入// +build fuzz
(前面只允许有注释行和空行) - 在
go-fuzz-build.exe
中加入参数-tags fuzz
第一步就可以在真实构建服务时, 屏蔽 *_fuzz.go
文件,因为只有使用了 -tags fuzz
参数才会构建;
在第二步中使用了 -tags fuzz
, 已经测试过了 go-fuzz-build.exe
支持此参数且符合预期
Go语言 通过go bulid -tags 实现编译控制
Go语言提供的build tag 条件编译特性,顾名思义,只有在特定条件下才会构建对应的代码。
比如下面的源文件只有在设置debug构建标志时才会被构建:
// +build debug
package main
var buildMode = "debug"
可以用以下命令构建:
go build -tags="debug"
go build -tags="windows debug"
关于tags的说明:
- 构建约束以一行
+build
开始的注释。在+build
之后列出了一些条件,在这些条件成立时,该文件应包含在编译的包中; - 约束可以出现在任何源文件中,不限于go文件;
+build
必须出现在package
语句之前,+build
注释之后应要有一个空行。- 多个条件之间,空格表示OR;逗号表示AND;叹号(!)表示NOT
- 一个文件可以有多个+build,它们之间的关系是AND。
例如:
我们可以通过-tags
命令行参数同时指定多个build标志,它们之间用空格分隔。
当有多个build tag时,我们将多个标志通过逻辑操作的规则来组合使用。比如以下的构建标志表示只有在”linux/386“或”darwin平台下非cgo环境“才进行构建。
// +build linux,386 darwin,!cgo
// +build windows
其中linux,386
中linux和386用逗号连接表示AND的意思;
而linux,386
和darwin,!cgo
之间通过空白分割来表示OR的意思;
两行语句表示AND。
tags 应用场景:
不同环境下编译不同的文件,实现版本控制 、 环境配置控制等。
例如:项目中有如下文件代表不同的运行环境,通过 tag 控制不同环境下要编译的文件
dev.go
// +build dev
package main
import "fmt"
var version = "dev"
func main() {
fmt.Printf("running %s version", version)
}
release.go
// +build release
package main
import "fmt"
var version = "release"
func main() {
fmt.Printf("running %s version", version)
}
编译时通过指定不同的标签来编译不同文件:
编译 dev 环境
go build -tags="dev"
编译 release 环境
go build -tags="release"