Go 程序构建编译
编译代码
go build
命令负责处理项目依赖,将代码编译成可执行文件。
在旧版中,go build
也用来编译库(生成 .a
文件)。现在不再需要显式地去编译一个库,构建程序时会自动下载编译依赖库,并缓存依赖库编译结果,以便后续再次使用。
基本语法
go build
命令语法如下:go build [-o output] [flags] [packages]
。
- [-o output]:指定输出文件名和路径。
- [flags]:读作标志,也就是命令参数或选项。
- [packages]:指定要构建的源文件或包。
常用参数如下:
-a
:强制重新编译所有相关源代码包,包括标准库的包。-n
:仅打印执行命令,不实际执行,用于调试。-x
:打印详细命令。-v
:显示正在编译的包名。-race
:启用数据竞争检测,常用于并发编程中。-ldflags
:将选项传递给链接器,例如设置二进制版本号或去掉调试信息等。-work
:打印编译时所在的工作目录路径,并在编译完成后保留它。
构建程序
不带任何参数运行 go build
命令时,如果当前目录中包含 Go 文件,且包含 main
包和 main
函数,会生成与当前目录同名的可执行文件:
go build
也可以指定具体文件或目录进行编译:
go build hello.go
go build -o api.exe ./cmd/api
如果在库目录中用 go build
命令,会编译当前目录下所有 Go 文件,但不会生成任何文件。用于验证库代码是否有编译错误。
交叉编译
默认情况下,编译生成的二进制文件只适合编译时所在系统平台。Go 语言支持交叉编译,可以通过设置环境变量 GOOS
和 GOARCH
来指定目标操作系统和处理器架构,以实现交叉编译。例如在 Win 平台编译 Linux 版本程序:
set GOOS=linux
set GOARCH=amd64
go build -o target/hello_linux_amd64 main.go
set
是 cmd 命令,用于临时修改环境变量值,只会影响当前会话。如果上面命令在 powershell 中运行,不能修改环境变量值,替代命令为:$env:GOOS = "linux"
。
编译成功后,会自动新建 target
目录,在其中生成 Linux x64 版本可执行文件 hello_linux_amd64
。如果构建目标文件已存在,会直接覆盖写入。
常用的 GOOS 和 GOARCH 值:
- GOOS:
linux
、windows
、darwin
(macOS)、freebsd
。 - GOARCH:
amd64
(x64)、386
(x86)、arm
、arm64
。
压缩体积
通过指定一些编译标志,可压缩编译生成的二进制文件大小:
go build -ldflags="-s -w" main.go
标志 "-s -w"
,表示移除符号表和调试信息。调试信息会占用大量体积,移除后不影响日常使用,但生成物大小减小了三分之一。
要进一步压缩可执行文件大小,可尝试 UPX 压缩。下载解压后,将程序路径添加到系统变量:
setx PATH "%PATH%;D:\Software\Program\Upx"
跳转到项目路径,对文件进行最高级别压缩:
D:\Software\Programming\Go\new>upx -9 main.exe
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2024
UPX 4.2.4 Markus Oberhumer, Laszlo Molnar & John Reiser May 9th 2024
File size Ratio Format Name
-------------------- ------ ----------- -----------
1338368 -> 539648 40.32% win64/pe main.exe Packed 1 file.
结果显示,文件大小压缩到 40%,最终体积从 2 MB 变为 0.5 MB。
使用 UPX 压缩后,常被杀毒软件误报。此外,UPX 压缩会改变文件原始结构,从而变得难以调试。
快速运行
开发时,可使用 go run
命令来快速测试代码。go run
命令会在临时目录中编译代码,运行完后自动清理痕迹。
基本语法
命令基本用法为:go run [flags] [files] [arguments...]
。
- [flags]:参考编译代码的参数。
- [files]:指定要编译和运行的文件。
- [arguments]:传递给程序的参数。
运行源码
和 go build
不同,直接运行 go run
命令会提示没有找到 Go 文件,必须指定一个包含 main
函数的 Go 源文件:
go run main.go
如果源文件中有多个文件依赖,可以一次性传给命令:
go run main.go dependency.go
如果源程序有参数,在传入文件名后用 --
分隔程序参数列表。支持多参数:
go run hello.go -- arg1 arg2
加入 -work
参数显示临时工作目录路径,并在运行完成后保留,用于调试分析:
PS D:\Software\Programming\Go\new> go run -work main.go -- 1194
WORK=C:\Users\ADMINI~1\AppData\Local\Temp\go-build3687578180
清理缓存
go clean
命令用于清理当前模块和相关依赖的缓存文件,帮助项目保持干净状态。
基本语法
命令基本用法为:go clean [clean flags] [build flags] [packages]
。
常用清理选项:
-i
:用于删除与指定包相关的可执行文件。-n
:仅打印详细清理命令,不执行。-x
:和-n
一样打印出详细清理命令,但会执行。-cache
:清除所有编译缓存。-modcache
:清理 Go 模块缓存。-testcache
:清除所有测试缓存。
清理生成物
在项目目录使用 go clean -i
命令,会删除所有编译产出的可执行文件。除了当前目录,也会到 $GOPATH\bin
目录中去搜索:
D:\Software\Programming\Go\new>go clean -i -n
cd D:\Software\Programming\Go\new
rm -f new new.exe new new.exe new.test new.test.exe new.test new.test.exe main main.exe main.test main.test.exe main_test main_test.ex
e
rm -f D:\Software\Program\go\bin\linux_amd64\new
清理编译缓存
编译缓存包含之前编译结果,复用能加速后续编译过程。具体路径配置在 $GOCACHE
变量中,例如 Linux 下面(使用 root 用户)为 /root/.cache/go-build
。缓存目录下面又分多个子目录,目录中存放一些不带后缀名的文件:
root@k8s-204:~/.cache/go-build# ls
00 07 0e 15 1c 23 2a 31 38 3f 46 4d 54 5b 62 69 70 77 7e 85 8c 93 9a a1 a8 af b6 bd c4 cb d2 d9 e0 e7 ee f5 fc
01 08 0f 16 1d 24 2b 32 39 40 47 4e 55 5c 63 6a 71 78 7f 86 8d 94 9b a2 a9 b0 b7 be c5 cc d3 da e1 e8 ef f6 fd
02 09 10 17 1e 25 2c 33 3a 41 48 4f 56 5d 64 6b 72 79 80 87 8e 95 9c a3 aa b1 b8 bf c6 cd d4 db e2 e9 f0 f7 fe
03 0a 11 18 1f 26 2d 34 3b 42 49 50 57 5e 65 6c 73 7a 81 88 8f 96 9d a4 ab b2 b9 c0 c7 ce d5 dc e3 ea f1 f8 ff
04 0b 12 19 20 27 2e 35 3c 43 4a 51 58 5f 66 6d 74 7b 82 89 90 97 9e a5 ac b3 ba c1 c8 cf d6 dd e4 eb f2 f9 README
05 0c 13 1a 21 28 2f 36 3d 44 4b 52 59 60 67 6e 75 7c 83 8a 91 98 9f a6 ad b4 bb c2 c9 d0 d7 de e5 ec f3 fa trim.txt
06 0d 14 1b 22 29 30 37 3e 45 4c 53 5a 61 68 6f 76 7d 84 8b 92 99 a0 a7 ae b5 bc c3 ca d1 d8 df e6 ed f4 fb
root@k8s-204:~/.cache/go-build# ll 77
total 16
drwxr-xr-x 2 root root 80 Jul 25 15:58 ./
drwxr-xr-x 258 root root 8192 Jul 25 15:58 ../
-rw-r--r-- 1 root root 175 Jul 25 15:58 77d57df9bb89883adb64c446ffa4294b455731b60a934769f4ef61f505e1297c-a
root@k8s-204:~/.cache/go-build# cat 77/77d57df9bb89883adb64c446ffa4294b455731b60a934769f4ef61f505e1297c-a
v1 77d57df9bb89883adb64c446ffa4294b455731b60a934769f4ef61f505e1297c e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 172189428593703674
大多数缓存文件无法正常查看,但通常也不需要关心其内容,Go 工具链会根据过期策略自动清理编译缓存,只有在缓存目录过大时需要手动清理:
root@k8s-204:~/.cache/go-build# go clean -n -cache
rm -r /root/.cache/go-build/00 /root/.cache/go-build/01 /root/.cache/go-build/02 /root/.cache/go-build/03 /root/.cache/go-build/04 /root/.cache/go-build/05
rm -f /root/.cache/go-build/log.txt
清理模块缓存
模块缓存中主要存放下载的模块,便于构建时直接使用,而不用每次都重新下载。模块缓存目录由 $GOMODCACHE
变量指定,默认为 $GOPATH/pkg/mod
。
使用 go clean -modcache
命令将简单粗暴地删除整个 pkg/mod
目录:
root@k8s-204:~/.cache/go-build# go clean -modcache -n
rm -rf /root/go/pkg/mod
一般很少用到这个命令。在持续集成环境中,甚至要想办法将 pkg/mod
目录持久化。仅仅在模块文件损坏导致行为异常时,可能需要这样整个清理。
清理后,重新安装项目依赖模块可以使用 go install
命令,或直接运行 go build
构建。
清理测试缓存
测试缓存和编译缓存作用类似,用于在代码或测试用例未发生变化时,加速测试运行。
测试缓存和编译缓存共用目录,如果用 go clean -cache
命令会一并清理测试缓存,而用 -testcache
参数只会删除测试结果缓存,用于确保测试结果不被缓存影响:
go clean -testcache