Redian新闻
>
我最喜欢的 Go 构建选项 | Linux 中国

我最喜欢的 Go 构建选项 | Linux 中国

科技
 
导读:这些方便的 Go 构建选项可以帮助你更好地理解 Go 的编译过程。                       
本文字数:7227,阅读时长大约:9分钟

LCTT 译者 :六开箱
🌟🌟🌟🌟
翻译: 36.0 篇
|
贡献: 46 天
2022-03-16
2022-04-30
https://linux.cn/lctt/lkxed

学习一门新的编程语言最令人欣慰的部分之一,就是最终运行了一个可执行文件,并获得预期的输出。当我开始学习 Go 这门编程语言时,我先是阅读一些示例程序来熟悉语法,然后是尝试写一些小的测试程序。随着时间的推移,这种方法帮助我熟悉了编译和构建程序的过程。

Go 的构建选项提供了更好地控制构建过程的方法。它们还可以提供额外的信息,帮助把这个过程分成更小的部分。在这篇文章中,我将演示我所使用的一些选项。注意:我使用的“构建(build)”和“编译(compile)”这两个词是同一个意思。

开始使用 Go

我使用的 Go 版本是 1.16.7。但是,这里给出的命令应该也能在最新的版本上运行。如果你没有安装 Go,你可以从 Go 官网🔗 go.dev 上下载它,并按照说明进行安装。你可以通过打开一个命令提示符,并键入下面的命令来验证你所安装的版本:

  1. $ go version

你应该会得到类似下面这样的输出,具体取决于你安装的版本:

  1. go version go1.16.7 linux/amd64

基本的 Go 程序的编译和执行方法

我将从一个在屏幕上简单打印 “Hello World” 的 Go 程序示例开始,就像下面这样:

  1. $ cat hello.go
  2. package main
  3. import "fmt"
  4. func main() {
  5. fmt.Println("Hello World")
  6. }

在讨论更高级的选项之前,我将解释如何编译这个 Go 示例程序。我使用了 build 命令,后面跟着 Go 程序的源文件名,本例中是 hello.go,就像下面这样:

  1. $ go build hello.go

如果一切工作正常,你应该看到在你的当前目录下创建了一个名为 hello 的可执行文件。你可以通过使用 file 命令验证它是 ELF 二进制可执行格式(在 Linux 平台上)。你也可以直接执行它,你会看到它输出 “Hello World”。

  1. $ ls
  2. hello  hello.go
  3. $ file ./hello
  4. ./hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
  5. $ ./hello
  6. Hello World

Go 提供了一个方便的 run 命令,以便你只是想看看程序是否能正常工作,并获得预期的输出,而不想生成一个最终的二进制文件。请记住,即使你在当前目录中没有看到可执行文件,Go 仍然会在某个地方编译并生成可执行文件并运行它,然后把它从系统中删除。我将在本文后面的章节中解释。

  1. $ go run hello.go
  2. Hello World
  3. $ ls
  4. hello.go

更多细节

上面的命令就像一阵风一样,一下子就运行完了我的程序。然而,如果你想知道 Go 在编译这些程序的过程中做了什么,Go 提供了一个 -x 选项,它可以打印出 Go 为产生这个可执行文件所做的一切。

简单看一下你就会发现,Go 在 /tmp 内创建了一个临时工作目录,并生成了可执行文件,然后把它移到了 Go 源程序所在的当前目录。

  1. $ go build -x hello.go
  2. WORK=/tmp/go-build1944767317
  3. mkdir -p $WORK/b001/
  4. << snip >>
  5. mkdir -p $WORK/b001/exe/
  6. cd .
  7. /usr/lib/golang/pkg/tool/linux_amd64/link -o $WORK \
  8. /b001/exe/a.out -importcfg $WORK/b001 \
  9. /importcfg.link -buildmode=exe -buildid=K26hEYzgDkqJjx2Hf-wz/\
  10. nDueg0kBjIygx25rYwbK/W-eJaGIOdPEWgwC6o546 \
  11. /K26hEYzgDkqJjx2Hf-wz -extld=gcc /root/.cache/go-build /cc \
  12. /cc72cb2f4fbb61229885fc434995964a7a4d6e10692a23cc0ada6707c5d3435b-d
  13. /usr/lib/golang/pkg/tool/linux_amd64/buildid -w $WORK \
  14. /b001/exe/a.out # internal
  15. mv $WORK/b001/exe/a.out hello
  16. rm -r $WORK/b001/

这有助于解决在程序运行后却在当前目录下没有生成可执行文件的谜团。使用 -x 显示可执行文件确实在 /tmp 工作目录下创建并被执行了。然而,与 build 命令不同的是,可执行文件并没有移动到当前目录,这使得看起来没有可执行文件被创建。

  1. $ go run -x hello.go
  2. mkdir -p $WORK/b001/exe/
  3. cd .
  4. /usr/lib/golang/pkg/tool/linux_amd64/link -o $WORK/b001 \
  5. /exe/hello -importcfg $WORK/b001/importcfg.link -s -w -buildmode=exe -buildid=hK3wnAP20DapUDeuvAAS/E_TzkbzwXz6tM5dEC8Mx \
  6. /7HYBzuaDGVdaZwSMEWAa/hK3wnAP20DapUDeuvAAS -extld=gcc \
  7. /root/.cache/go-build/75/ \
  8. 7531fcf5e48444eed677bfc5cda1276a52b73c62ebac3aa99da3c4094fa57dc3-d
  9. $WORK/b001/exe/hello
  10. Hello World

模仿编译而不产生可执行文件

假设你不想编译程序并产生一个实际的二进制文件,但你确实想看到这个过程中的所有步骤。你可以通过使用 -n 这个构建选项来做到这一点,该选项会打印出通常的执行步骤,而不会实际创建二进制文件。

  1. $ go build -n hello.go

保存临时目录

很多工作都发生在 /tmp 工作目录中,一旦可执行文件被创建和运行,它就会被删除。但是如果你想看看哪些文件是在编译过程中创建的呢?Go 提供了一个 -work 选项,它可以在编译程序时使用。-work 选项除了运行程序外,还打印了工作目录的路径,但它并不会在这之后删除工作目录,所以你可以切换到该目录,检查在编译过程中创建的所有文件。

  1. $ go run -work hello.go
  2. WORK=/tmp/go-build3209320645
  3. Hello World
  4. $ find /tmp/go-build3209320645
  5. /tmp/go-build3209320645
  6. /tmp/go-build3209320645/b001
  7. /tmp/go-build3209320645/b001/importcfg.link
  8. /tmp/go-build3209320645/b001/exe
  9. /tmp/go-build3209320645/b001/exe/hello
  10. $ /tmp/go-build3209320645/b001/exe/hello
  11. Hello World

其他编译选项

如果说,你想手动编译程序,而不是使用 Go 的 build 和 run 这两个方便的命令,最后得到一个可以直接由你的操作系统(这里指 Linux)运行的可执行文件。那么,你该怎么做呢?这个过程可以分为两部分:编译和链接。你可以使用 tool 选项来看看它是如何工作的。

首先,使用 tool compile 命令产生结果的 ar 归档文件,它包含了 .o 中间文件。接下来,对这个 hello.o 文件执行 tool link 命令,产生最终的可执行文件,然后你就可以运行它了。

  1. $ go tool compile hello.go
  2. $ file hello.o
  3. hello.o: current ar archive
  4. $ ar t hello.o
  5. __.PKGDEF
  6. _go_.o
  7. $ go tool link -o hello hello.o
  8. $ file hello
  9. hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
  10. $ ./hello
  11. Hello World

如果你想进一步查看基于 hello.o 文件产生可执行文件的链接过程,你可以使用 -v 选项,它会搜索每个 Go 可执行文件中包含的 runtime.a 文件。

  1. $ go tool link -v -o hello hello.o
  2. HEADER = -H5 -T0x401000 -R0x1000
  3. searching for runtime.a in /usr/lib/golang/pkg/linux_amd64/runtime.a
  4. 82052 symbols, 18774 reachable
  5. 1 package symbols, 1106 hashed symbols, 77185 non-package symbols, 3760 external symbols
  6. 81968 liveness data

交叉编译选项

现在我已经解释了 Go 程序的编译过程,接下来,我将演示 Go 如何通过在实际的 build 命令之前提供 GOOS 和 GOARCH 这两个环境变量,来允许你构建针对不同硬件架构和操作系统的可执行文件。

这有什么用呢?举个例子,你会发现为 ARM(arch64)架构制作的可执行文件不能在英特尔(x86_64)架构上运行,而且会产生一个 Exec 格式错误。

下面的这些选项使得生成跨平台的二进制文件变得小菜一碟:

  1. $ GOOS=linux GOARCH=arm64 go build hello.go
  2. $ file ./hello
  3. ./hello: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, not stripped
  4. $ ./hello
  5. bash: ./hello: cannot execute binary file: Exec format error
  6. $ uname -m
  7. x86_64

你可以阅读我之前的博文,以更多了解我在 使用 Go 进行交叉编译🔗 opensource.com 方面的经验。

查看底层汇编指令

源代码并不会直接转换为可执行文件,尽管它生成了一种中间汇编格式,然后最终被组装为可执行文件。在 Go 中,这被映射为一种中间汇编格式,而不是底层硬件汇编指令。

要查看这个中间汇编格式,请在使用 build 命令时,提供 -gcflags 选项,后面跟着 -S。这个命令将会显示使用到的汇编指令:

  1. $ go build -gcflags="-S" hello.go
  2. # command-line-arguments
  3. "".main STEXT size=138 args=0x0 locals=0x58 funcid=0x0
  4. 0x0000 00000 (/test/hello.go:5) TEXT "".main(SB), ABIInternal, $88-0
  5. 0x0000 00000 (/test/hello.go:5) MOVQ (TLS), CX
  6. 0x0009 00009 (/test/hello.go:5) CMPQ SP, 16(CX)
  7. 0x000d 00013 (/test/hello.go:5) PCDATA $0, $-2
  8. 0x000d 00013 (/test/hello.go:5) JLS 128
  9. << snip >>

你也可以使用 objdump -s 选项,来查看已经编译好的可执行程序的汇编指令,就像下面这样:

  1. $ ls
  2. hello hello.go
  3. $ go tool objdump -s main.main hello
  4. TEXT main.main(SB) /test/hello.go
  5. hello.go:5 0x4975a0 64488b0c25f8ffffff MOVQ FS:0xfffffff8, CX
  6. hello.go:5 0x4975a9 483b6110 CMPQ 0x10(CX), SP
  7. hello.go:5 0x4975ad 7671 JBE 0x497620
  8. hello.go:5 0x4975af 4883ec58 SUBQ $0x58, SP
  9. hello.go:6 0x4975d8 4889442448 MOVQ AX, 0x48(SP)
  10. << snip >>

分离二进制文件以减少其大小

Go 的二进制文件通常比较大。例如, 一个简单的 “Hello World” 程序将会产生一个 1.9M 大小的二进制文件。

  1. $ go build hello.go
  2. $
  3. $ du -sh hello
  4. 1.9M    hello
  5. $
  6. $ file hello
  7. hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
  8. $

为了减少生成的二进制文件的大小,你可以分离执行过程中不需要的信息。使用 -ldflags 和 -s -w 选项可以使生成的二进制文件略微变小为 1.3M。

  1. $ go build -ldflags="-s -w" hello.go
  2. $
  3. $ du -sh hello
  4. 1.3M    hello
  5. $
  6. $ file hello
  7. hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
  8. $

总结

我希望这篇文章向你介绍了一些方便的 Go 编译选项,同时帮助了你更好地理解 Go 编译过程。关于构建过程的其他信息和其他有趣的选项,请参考 Go 命令帮助:

  1. $ go help build


题图由 Ashraf Chemban🔗 pixabay.com 在 Pixabay🔗 pixabay.com 上发布。 


via: https://opensource.com/article/22/4/go-build-options

作者:Gaurav Kamathe 选题:lkxed 译者:lkxed 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出


欢迎遵照 CC-BY-SA 协议规定转载,
如需转载,请在文章下留言 “转载:公众号名称”,
我们将为您添加白名单,授权“转载文章时可以修改”。


微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
我如何在 Linux 上扫描家庭照片 | Linux 中国在 Linux 上使用 sudo 命令的 5 个理由 | Linux 中国实测 Linux Mint 升级工具 | Linux 中国最适合程序员的 10 款 Linux 发行版 | Linux 中国与糖共舞-15HydraPaper:一个支持多显示器的 Linux 壁纸管理器 | Linux 中国Linux 中国开通播客频道:“开源朗读者”和“硬核观察” | Linux 中国Fudgie?令人惊叹的 Budgie 桌面即将登陆 Fedora Linux | Linux 中国好消息!Docker Desktop 现已支持 Linux | Linux 中国在虚拟机中运行 Linux 的十大优点 | Linux 中国在美国29. 在大学的生活CentOS 的继承者 AlmaLinux 9 发布 | Linux 中国亚城周边地区深受大型工业青睐,揭秘它们最喜欢的地段……System76 与惠普合作为开发者提供功能强大的 Linux 笔记本电脑 | Linux 中国如何在 Fedora Linux 中安装多媒体编码器 | Linux 中国你的 Linux 启动时有几只小企鹅? | Linux 中国用 Gwenview 在 Linux 上裁剪和调整照片大小 | Linux 中国在 Ubuntu Linux 如何安装 H.264 解码器 | Linux 中国如何在 Linux 和 Windows 电脑之间共享文件 | Linux 中国分享 8 篇使用 Linux 命令行的技巧 | Linux 中国如何在 Linux 桌面中启用 “激活 Linux” 水印通知 | Linux 中国下一个风口在哪里?跟着英雄走英伟达在提升 Linux 上的 GPU 使用体验上迈出了一大步 | Linux 中国微软还有另一个 Linux 发行版,而且是基于 Debian 的 | Linux 中国上一个说“丼”不读jǐng的人,已经被我骂哭了Fedora Linux 36 发布 | Linux 中国使用 dnf 进行 Linux 包管理 | Linux 中国使用 apt 进行 Linux 包管理 | Linux 中国最能代表杭州的三个地标建筑,网友最喜欢的原来是…无声世界里的爱,简评《健听女孩》倒计时2天!谁是学生们最喜欢的行业导师?Linux 内核 5.18 版本正式发布,新增显卡驱动以及硬件支持 | Linux 中国使用 watch 和 tail 命令监视 Linux 上的活动 | Linux 中国今天唱坛歌多,都插不上嘴,送花给无糖版主!《桃花谣》花儿传情!Archinstall 新的菜单系统让安装 Arch Linux 更容易了 | Linux 中国
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。