10. golang的编译过程

  1. 词法分析与语法分析
  • 词法分析

​ 通过正则匹配的方式将机器原本很难理解的字符串进行分解成很多的Token序列

  • 语法分析

​ 将词法分析器输出的Token序列,将编程语言的所有生产规则映射到对应的方法上,这些方法构成的树形结构最终会返回一个抽象语法树(Go 源文件)

  1. 类型检查
  • 静态类型检查

​ 静态类型检查是基于对源码的分析来确定运行程序类型安全的过程,如果代码能够通过静态类型检查,那么当前程序在一定程度上就满足了类型安全的要求,它也可以被看作是一种代码优化的方式,能够减少程序在运行时的类型检查

  • 动态类型检查

​ 动态类型检查是在运行时确定程序类型安全的过程,这个过程需要编程语言在编译时为所有的对象加入类型标签和信息,运行时就可以使用这些存储的类型信息来实现动态派发、向下转型、反射等其他特性

  • Golang类型检查

​ Go语言的编译器不仅使用静态类型检查来保证程序运行的类型安全,还会在编程期引入类型信息,让工程师能够使用反射来判断参数和变量的类型

img

类型检查分别会按照以下的顺序对不同的类型的节点进行验证和处理

① 常量、类型和函数名及类型;

② 变量的赋值和初始化;

③ 函数和闭包的主体;

④ 哈希键值对的类型;

⑤ 导入函数体;

⑥外部的声明;

关键词OMAKE节点,根据make的第一个参数

img

  1. 中间代码生成

在类型检查之后,会通过一个名为compileFunctions 的函数开始对整个 Go 语言项目中的全部函数进行编译,这些函数会在一个编译队列中等待几个后端工作协程的消费,这些并发执行的 Goroutine 会将所有函数对应的抽象语法树转换成中间代码。

  1. 最终机器代码生成

机器码的生成过程其实就是对 SSA 中间代码的降级(lower)过程,在 SSA 中间代码降级的过程中,编译器将一些值重写成了目标 CPU 架构的特定值,降级的过程处理了所有机器特定的重写规则并对代码进行了一定程度的优化

  • 复杂指令集(CISC)和精简指令集(RISC)

    • 复杂指令集通过增加指令的数量减少需要执行的指令数;(x86)
    • 精简指令集能使用更少的指令完成目标的计算任务;(arm)
  • Go语言支持的架构

img

交叉编译

$ Mac 下编译 Linux 和 Windows 64位可执行程序CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.goCGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.goLinux 下编译 Mac 和 Windows 64位可执行程序CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.goCGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go
  • 机器代码生成
src/cmd/compile/internal/ssasrc/cmd/internal/obj
  • src/cmd/compile/internal/ssa 主要负责对 SSA 中间代码进行降级、执行架构特定的优化和重写并生成 obj.Prog 指令;

  1. // 通过命令输出汇编结果
  2. GOOS=linux GOARCH=amd64 go tool compile -S hello.go

img