快速掌握 Go 二进制文件的静态和动态链接

开发 前端
今天我们快速的介绍了 Go 语言中的静态和动态链接的基本概念,打了个底。静态链接会实现 ALL IN ONE 的效果,确保编译出来的二进制文件能够在标准的环境下运行。而动态链接则相反。

大家好,我是煎鱼。

在编写 Go 应用程序时,Go 本身提供了跨平台编译,提供了非常大的便利。但内部其实有许多静态和动态链接的相关知识点。

今天给大家分享这一块的基本知识。

如何选择?Go 团队的讨论

Go 核心团队在创造这门编程语言时已经做了大量的讨论和权衡。

图片图片

“静态链接有很多优点。部署简单是其中之一。没有版本问题是另一个优点(升级可能永远不会破坏您的 go 二进制文件。但动态链接或解释语言则不然,因为依赖关系可能会中断)。启动时间更快也是另一个优点。

不过,动态链接也有很好的理由。真实原因是:因为 go 作者已经研究了静态链接与动态链接的权衡,并决定静态链接更适合他们的用例。而且 go 社区中的大多数人都同意这一点。”

静态和动态链接是什么?

静态和动态链接是两种不同的程序链接方式,一般会根据实际的程序运行情况进行选择。

图片图片

静态链接

在编译时,链接器将程序所需的所有库文件直接复制到可执行文件中,生成一个完整的可执行文件。

一旦生成后,执行时不再依赖外部库。

  • 优点:简单且不需要额外的库文件。
  • 缺点:可执行文件较大,更新库时需要重新编译。

动态链接

在程序运行时,操作系统根据需要加载共享库到内存中。

这使得可执行文件更小,因为它不包含所有的库代码,但程序执行时依赖于外部库的存在。

  • 优点:在于节省内存和便于库的更新。
  • 缺点:可能存在一些版本兼容性问题等。

快速例子

静态链接

对于 Go 这一门编程语言而言,静态链接是他大力宣传的一个招牌:只需要编译一个二进制文件,哪里都可以部署。

示例代码如下:

package main

import (
 "fmt"
)

func main() {
 fmt.Println("脑子进煎鱼了!")
}

输出结果:

脑子进煎鱼了!

强制指定 CGO_ENABLED=0 来进行编译:

CGO_ENABLED=0 go build main.go

使用 file 工具查看目标文件信息:

$ file greet
greet: Mach-O 64-bit executable arm64

结合查看 fmt.Println 是否固定地址:

图片图片

结合来看,可以确定 Go 程序本身的依赖是静态链接的。而编译出来的二进制程序到底有没有动态链接库,取决于你所编写的程序。

动态链接

Go 应用程序在进行 go build 的时候,可以加入 -buildmode 参数来指定构建模式,以此实现动态链接的目的。

以下是可用的 buildmode 选项:

  • archive: 将非 main 包构建成 .a 文件,main 包将被排除。
  • c-archive: 构建 main 包及其依赖的所有包为 C 归档文件。
  • c-shared: 构建指定的 main 包及其所有依赖为 C 动态库。
  • shared: 将所有非 main 包整合到一个动态库中。
  • exe: 构建指定的 main 包及其依赖为可执行文件,未命名为 main 的包将被忽略。

默认情况下,main 包会被内置到可执行文件中,非 main 包则会被内置到 .a 文件中。

这块我们写 Web 程序的用的不多,如果是写 C 库或者调第三方语言的动态库时用得多。此时需要在编译时指定 CGO_ENABLED=1 才可以。

有兴趣的话,CGO 例子可以参考:andreiavrammsd/cgo-examples[1],这里不展开。

总结

今天我们快速的介绍了 Go 语言中的静态和动态链接的基本概念,打了个底。静态链接会实现 ALL IN ONE 的效果,确保编译出来的二进制文件能够在标准的环境下运行。而动态链接则相反。

这是 Go 这门编程语言设计时的一个招牌特性,而我们做 Web 开发的话,一般都是以静态链接为主。

如果有涉及到第三方调用才会用到动态链接等。我见过用 CGO 逐步重构 C 服务的,甚至要慎防内存泄露。这时候又是另外一套逻辑、体系了,要进一步进修!

责任编辑:武晓燕 来源: 脑子进煎鱼了
相关推荐

2020-05-22 18:00:26

Go二进制文件编程语言

2022-07-26 13:00:01

安全符号源代码

2009-08-12 18:06:53

C#读取二进制文件

2009-12-16 10:49:42

Ruby操作二进制文件

2009-02-27 09:37:33

Google二进制代码

2009-12-10 09:24:50

PHP函数fwrite

2023-09-18 23:50:25

二进制文件裁剪Layout

2020-10-19 11:35:47

Ghidra逆向分析G

2015-07-21 11:43:14

CentosRPM

2020-10-21 09:49:31

Ghidra逆向分析

2024-02-01 09:04:12

2013-04-28 15:37:35

JBoss

2022-01-26 00:02:01

Go二进制元信息

2010-10-13 15:45:23

MySQL二进制日志

2009-11-02 11:27:42

VB.NET二进制文件

2018-10-22 14:37:16

二进制数据存储

2022-10-31 08:02:42

二进制计算乘法

2017-04-11 10:48:53

JS二进制

2023-12-26 15:10:00

处理二进制文件

2023-12-20 07:36:58

GoLinux语言
点赞
收藏

51CTO技术栈公众号