1 回答
TA贡献1943条经验 获得超7个赞
在 GNU/Linux 上,几乎所有的 Go 可执行文件都属于这些类别:
那些包括应用程序、Go 运行时和 glibc(的一部分)的静态链接副本。
那些只包含应用程序和 Go 运行时的静态链接,没有 glibc。
那些只包括应用程序和 Go 运行时、静态链接和动态链接到 glibc 的。
不幸的是,与 Go 相关的工具通常会混淆这些链接模式。依赖 glibc 的主要原因是应用程序使用主机名和用户查找(功能如getaddrinfo
和getpwuid_r
)。 CGO_ENABLED=0
从src/os/user/cgo_lookup_unix.go
(使用 glibc)等实现切换到src/os/user/lookup_unix.go
(不使用 glibc)。非 glibc 实现不使用 NSS,因此提供的功能有些有限(通常不会影响不在 LDAP/Active Directory 中存储用户信息的用户)。
在您的情况下,设置CGO_ENABLED=0
将您的应用程序从第三类移至第二类。(还有其他与 Go 相关的工具可以构建第一种应用程序。)非 NSS 查找代码不是很大,因此二进制大小的增加并不显着。由于 Go 运行时已经静态链接,静态链接减少的开销甚至可能导致可执行文件大小的净减少。
这里要考虑的最重要的问题是 NSS、线程和静态链接在 glibc 中并不是那么好。所有的 Go 程序都是多线程的,(静态)将 glibc 链接到 Go 程序中的原因正是访问 NSS 函数。因此,将 Go 程序静态链接到 glibc 始终是错误的做法。它基本上总是 有问题。即使 Go 程序不是多线程的,使用 NSS 函数的静态链接程序在运行时也需要与构建时使用的 glibc版本完全相同,因此此类应用程序的静态链接会降低可移植性。
所有这些都是第一类 Go 应用程序如此糟糕的原因。使用 生成静态链接的应用程序CGO_ENABLED=0
没有这些问题,因为这些应用程序(第二类)不包含任何 glibc 代码(以用户/主机查找功能的功能减少为代价)。
如果你想创建一个需要 glibc 的可移植二进制文件,你需要动态链接你的应用程序(第三种),在你想要支持的最旧的 glibc 系统上。然后应用程序将在该 glibc 版本和所有更高版本上运行(目前,Go 没有正确链接 libc,所以即使是 glibc 也没有很强的兼容性保证)。发行版通常与 ABI 兼容,但它们具有不同版本的 glibc。glibc 竭尽全力确保动态链接到旧版本 glibc 的应用程序将继续在新版本的 glibc 上运行,但反之则不然:一旦您将应用程序链接到特定版本的 glibc,它可能会获得功能(符号)在旧版本上不可用,因此该应用程序将无法与那些旧版本一起使用。
- 1 回答
- 0 关注
- 121 浏览
添加回答
举报