go build

命令

  • go build [-o output] [-i] [build flags] [packages]
  • go build 命令用于编译我们指定的源码文件或代码包以及它们的依赖包
  • 如果在执行 go build 命令时不后跟任何代码包,那么命令将试图编译当前目录所对应的代码包
  • 编译码包 cnet/ctcp
    • GOPATH/src/cnet/ctcp 执行 go build
    • GOPATH/src/cnet/ 执行 go build ctcp
    • 在任意目录下执行 go build cnet/ctcp
  • go build 会忽略目录下以 “_” 或 “.” 开头的 go 文件
  • -o 强制将生成的可执行文件或目标文件写到指定的输出文件或文件夹。如果指定的输出是存在的文件夹,生成的可执行文件会写到文件夹
  • -i 安装依赖包

源码文件

  • Go 语言的源码文件有三大类,即:命令源码文件、库源码文件和测试源码文件
    • 命令源码文件:总是作为可执行的程序的入口
    • 库源码文件:一般用于集中放置各种待被使用的程序实体(全局常量、全局变量、接口、结构体、函数等等)
    • 测试源码文件:主要用于对前两种源码文件中的程序实体的功能和性能进行测试。另外也可以用于展现命令源码文件和库源码文件中程序的使用方法
  • 如果是库源码文件,执行 go build 之后,不会产生任何文件。如果需要在 $GOPATH/pkg 下生成相应的文件,那就得执行 go install
  • 如果是命令源码文件(main 包),执行 go build 之后,它就会调用链接器在当前目录下生成一个可执行文件,可执行程序的名字取自包的导入路径的最后一段。如果需要在 $GOPATH/bin 下生成相应的文件,需要执行 go install,或者使用 go build -o 可执行文件

编译多个 Go 源码文件

  • go build 默认会编译当前目录下的所有 go 文件
    • 构建所有需要的包及其依赖,然后丢弃除了可执行程序之外的所有编译的代码
  • 可以同时编译多个 Go 源码文件,在 go build 后跟要编译的文件名,用空格分隔
    • 限制:作为参数的多个 Go 源码文件必须在同一个目录中
  • go build 命令在编译只包含库源码文件的代码包(或者同时编译多个代码包)时,只会做检查性的编译,而不会输出任何结果文件
  • go build 命令既不能编译包含多个命令源码文件的代码包,也不能同时编译多个命令源码文件。因为,如果把多个命令源码文件作为一个整体看待,那么每个文件中的 main 函数就属于重名函数,在编译时会抛出重复定义错误
  • 如果编译的多个属于 main 包的源码文件中没有 main 函数的声明,那么就会使编译器立即报出“未定义 main 函数声明”的错误并中止编译
  • 总结:同时编译多个 main 包的源码文件时,要保证其中有且仅有一个 main 函数声明,否则编译是无法成功的
  • 如果有多个声明为属于 main 包的源码文件,且其中只有一个文件声明了 main 函数的话,那么是可以使用 go build 命令同时编译它们的。在这种情况下,不包含 main 函数声明的那几个源码文件会被视为库源码文件。如此编译之后的可执行文件的名称来自指定的编译目标中最左边的那个源码文件的主文件名相同

go build 的参数

  • 下面的编译标志被 build/clean/get/install/list/run/test 共享
标志 描述
-a 强行重新构建包,即使它们已经是最新的了,但是对标准包不适用
-n 打印将要执行的命令,但是不执行
-p n 指定执行命令的并行程序数量。默认等于可用的 CPU 逻辑数。在 darwin/arm (iPhone 和 iPad) 平台,默认是1
-race 开启竞态条件检测。仅在 linux/amd64、freebsd/amd64、darwin/amd64和windows/amd64 平台支持
-v 打印被编译的包名
-work 打印临时工作目录名称,且如果存在不会在执行命令后删除。默认结束命令时会删除该目录
-x 打印命令。注意它与 -n 标记的区别
  • 其他参数
    • -mod 控制对 go.mod 的更新和使用
    • -mod=readonly 不能隐式自动更新 go.mod。当需要修改 go.mod 时会失败。用于检查 go.mod 不需要任何更新,比如在持续集成和测试系统
      • 这个参数对 go get 不生效,即命令仍然可以更新 go.mod 文件
    • -mod=vendor: 使用模块的顶层的 vendor 目录来编译以满足依赖(不使用通常的网络源码和本地缓存)

依赖包

  • go build 命令在执行时,编译程序会先查找目标代码包的所有依赖包,以及这些依赖包的依赖包,直至找到最深层的依赖包为止。在此过程中,如果发现有循环依赖的情况,编译程序就会输出错误信息并立即退出。此过程完成之后,所有的依赖关系也就形成了一棵含有重复元素的依赖树。对于依赖树中的一个节点(代码包)来说,它的直接分支节点(前者的依赖包),是按照代码包导入路径的字典序从左到右排列的。最左边的分支节点会最先被编译。编译程序会依此设定每个代码包的编译优先级
  • 执行 go build 命令的计算机如果拥有多个逻辑 CPU 核心,那么编译代码包的顺序可能会存在一些不确定性。但是,它一定会满足这样的约束条件:依赖代码包 -> 当前代码包 -> 触发代码包
  • 在执行 go build 命令时加入标记 -p 1,那么就可以保证代码包编译顺序严格按照预先设定好的优先级进行

构建标签

  • 构建标签:go build 只会在构建指定规格的目标文件的时候才进行编译,叫做构建标签的特殊注释,提供更细力度的控制。
  • 注释需要加在包的声明之前,这是文档注释。如 // +build linux darwin
  • // +build ignore 指出任何时候都不要编译这个文件

相关