go tool compile
称为编译命令,用来生成对象文件,生成对象文件最后通过go tool link
命令链接成可执行文件。
编译命名用法示例如下:
go tool compile [flags] file...
在使用编译命令时候,我们可以设置GOOS
和 GOARCH
环境变量来指定目标操作系统和系统架构。这个和go build
命令是一致的。
go tool compile
支持的选项有:
选项 | 说明 |
---|---|
-D path | Set relative path for local imports. |
-I dir1 -I dir2 | Search for imported packages in dir1, dir2, etc, after consulting $GOROOT/pkg/$GOOS_$GOARCH. |
-L | Show complete file path in error messages. |
-N | Disable optimizations. |
-S | Print assembly listing to standard output (code only). |
-S -S | Print assembly listing to standard output (code and data). |
-V | Print compiler version and exit. |
-asmhdr file | Write assembly header to file. |
-asan | Insert calls to C/C++ address sanitizer. |
-buildid id | Record id as the build id in the export metadata. |
-blockprofile file | Write block profile for the compilation to file. |
-c int | Concurrency during compilation. Set 1 for no concurrency (default is 1). |
-complete | Assume package has no non-Go components. |
-cpuprofile file | Write a CPU profile for the compilation to file. |
-dynlink | Allow references to Go symbols in shared libraries (experimental). |
-e | Remove the limit on the number of errors reported (default limit is 10). |
-goversion string | Specify required go tool version of the runtime. Exits when the runtime go version does not match goversion. |
-h | Halt with a stack trace at the first error detected. |
-importcfg file | Read import configuration from file. In the file, set importmap, packagefile to specify import resolution. |
-installsuffix suffix | Look for packages in $GOROOT/pkg/$GOOS_$GOARCH_suffix instead of $GOROOT/pkg/$GOOS_$GOARCH. |
-l | Disable inlining. |
-lang version | Set language version to compile, as in -lang=go1.12. Default is current version. |
-linkobj file | Write linker-specific object to file and compiler-specific object to usual output file (as specified by -o). Without this flag, the -o output is a combination of both linker and compiler input. |
-m | Print optimization decisions. Higher values or repetition produce more detail. |
-memprofile file | Write memory profile for the compilation to file. |
-memprofilerate rate | Set runtime.MemProfileRate for the compilation to rate. |
-msan | Insert calls to C/C++ memory sanitizer. |
-mutexprofile file | Write mutex profile for the compilation to file. |
-nolocalimports | Disallow local (relative) imports. |
-o file | Write object to file (default file.o or, with -pack, file.a). |
-p path | Set expected package import path for the code being compiled, and diagnose imports that would cause a circular dependency. |
-pack | Write a package (archive) file rather than an object file |
-race | Compile with race detector enabled. |
-s | Warn about composite literals that can be simplified. |
-shared | Generate code that can be linked into a shared library. |
-spectre list | Enable spectre mitigations in list (all, index, ret). |
-traceprofile file | Write an execution trace to file. |
-trimpath prefix | Remove prefix from recorded source file paths. |
Go 编译器可以读取来自注释里面的指令,这些指令称为编译指令,这些编译指令往往以//go:
开头。
由于历史缘故,line指令并不是由//go:
开头。它通常出现在机器码生成时候,这样编译器或者调试器才能报告出原始输入文件的位置。比如查看cgo编译过程中的中间文件会出现(go tool cgo xxx.go)。
noescape = no + escape。noescape意味着禁止逃逸,该编译指令后面必须跟着函数声明(没有函数体)。该函数的具体实现是由汇编实现的。
该指令后面必须跟一个函数声明。它表明该函数的 uintptr 参数是一个指针指,需要将其分配到堆上,来保证调用期间不被回收,造成悬挂现象。
//go:noinline 指令后面必须跟一个函数定义。它指定不对该函数进行内联优化。这通常仅在特殊运行时函数或调试编译器时需要。
//go:noinline
func add(a, b int) int {
return a + b
}
func main() {
c := add(3, 5)
fmt.Println(c)
}
内联优化的优点:
- 减少函数调用的开销,提高执行速度,毕竟call指令是比较耗时的。
- 消除分支,并改善空间局部性和指令顺序性,同样可以提高性能
内联优化并不是银弹,如果有大量重复代码,反而会降低CPU缓存命中率。需要注意的是Go编译器没有强制使用内联优化的编译指令。
该指令后面必须跟一个函数声明。它指定函数的内存访问必须被竞争检测器忽略。这最常用于在调用竞争检测器运行时不安全时调用的低级代码。
该指令后面必须跟一个函数声明。它指定函数必须省略其通常的堆栈溢出检查。当调用 goroutine 被抢占是不安全的时候,这最常被调用的低级运行时代码使用。
Go中gorountine的栈初始大小为2K,正常情况下每个函数最开始部分都有一个堆栈检测的序言指令,执行函数前检查goroune栈是否需要扩容。
该指令用来将源代码localname符号链接到源代码中的importpath.name符号。由于该指令破坏了类型系统和软件包的模块化,因此使用的时候,需要导入unsafe
包。
import "unsafe"
//go:linkname zerobase runtime.zerobase
var zerobase uintptr // 使用go:linkname编译指令,将zerobase变量指向runtime.zerobase
该指令是用于构建约束(build constraint),它是在Go1.17版本中引入,之前版本都是通过+build
来实现的。Go1.17中,为了兼容性,两者都需要保留,否则编译不通过。
//go:build linux && 386
// +build linux,386
func add(a, b int) int {
return a + b
}