代码改变世界

golang build 参数

2023-02-25 21:21  youxin  阅读(518)  评论(0编辑  收藏  举报
  • 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,386darwin,!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"