Go的交叉编译与减小体积的若干尝试

交叉编译

在配置好环境之后,交叉编译变得异常的简单,几乎只要执行相关环境变量,就可以直接编译了。
如我在Mac下尝试使用Go进行编译Windows上的可执行文件,下面是一小段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//+build windows
package main
import (
"fmt"
"syscall"
"unsafe"
)
func main() {
var mod = syscall.NewLazyDLL("kernel32.dll")
var proc = mod.NewProc("GetPhysicallyInstalledSystemMemory")
var mem uint64
ret, _, err := proc.Call(uintptr(unsafe.Pointer(&mem)))
fmt.Printf("Ret: %d, err: %v, Physical memory: %d\n", ret, err, mem)
}

如上代码保存为 wintest.go,编译也非常在简单,在iTerm中直接输入

export GOOS=windows && export GOARCH=amd64 && go build wintest.go

就可以看到已经生成好PE文件了,扔到Win10的虚拟机中也运行OK。一般来说,Go的跨平台编译不需要额外指定太多的参数,确定好GOOS以及GOARCH即可编译针对不同位数版本及操作系统的可执行文件了。

减少体积

最常见的方式当时是进行加壳了,比如Upx这类压缩壳能减少很大的体积。其次就是利用一些编译选项来进行优化,如使用Strip等。我们还是用刚刚的代码,稍微修改一下编译参数

export GOOS=windows && export GOARCH=amd64 && go build -ldflags “-s -w” test.go

比较可以发现,原来的PE体积大概在1.9M左右,Strip过后减少到1.2M,我们再加上Upx的壳试试。比较之后,发现Upx壳压缩过之后体积变成了468K

其实这个问题Gopher们也一直在进行讨论,详情可以参见后面参考中的连接。

详细分析

本来打算写的,忽然间发现CFC4N写了一篇关于Go编译ELF和GCC编译ELF体积比较大小的原理性文章,于是贴出来,感谢他的文章:

http://www.cnxct.com/why-golang-elf-binary-file-is-large-than-c/

参考

https://stackoverflow.com/questions/3861634/how-to-reduce-compiled-file-size

https://github.com/golang/go/issues/6853

https://blog.filippo.io/shrink-your-go-binaries-with-this-one-weird-trick/