【问题标题】:How does CGO_ENABLED affect dynamic vs static linking?CGO_ENABLED 如何影响动态与静态链接?
【发布时间】:2020-07-09 14:23:30
【问题描述】:

我们正在编译我们的 Go 代码以在 docker 上运行,并且我们正在调查为什么我们的二进制文件没有执行。我们发现它缺少一些动态库(尽管我们需要静态链接的二进制文件)。

这就是它的编译方式。

env GOOS=linux CGO_ENABLED=1 GO111MODULE=on GOPRIVATE=github.com/ourrepo GOPROXY=https://proxy.golang.org go build --installsuffix cgo --ldflags='-extldflags=-static' -o program main.go

使用带有CGO_ENABLED=0same 构建命令最终解决了问题,并且输出二进制文件是静态链接的。

现在奇怪的是我们有另一个程序使用相同的构建命令,这次使用CGO_ENABLED=1 并且...它是静态链接的!

所以我很困惑为什么在某些情况下CGO_ENABLED=1 会产生动态链接,有时还会产生静态链接。很高兴提供更多详细信息。

【问题讨论】:

  • 只有在需要时才动态链接二进制文件。如果你不使用 cgo,那么CGO_ENABLED=1 没有区别。
  • 我不确定这里的问题是什么。如果来自CGO_ENABLED=0 的二进制文件是你想要的,你想用原始的go build 命令完成什么? (该原始命令看起来像是刚刚粘贴在一起的随机事物的组合)
  • @JimB 我试图理解为什么在一种情况下(cgo_enabled=1)二进制文件是动态链接的,而在另一种情况下不是。对于您的问题“我们想要的是 CGO_ENABLED=0 吗?”并不真地。我们想要静态的。 CGO_ENABLED=0 只是神奇地使这种情况发生,我不明白为什么。它更有意义吗?您是否建议完全删除 --installsuffix cgo 和 GO111MODULE 和 CGO?
  • 因为一个在使用cgo,一个没有。该命令本身没有意义,您将-static 传递给您未调用的外部链接器(没有-linkmode external),您似乎没有进行交叉编译,但您定义了GOOS ,虽然没有 GOARCH;你有GO111MODULE=on 但你没有构建一个包。看起来您添加了一堆选项而不知道它们的作用,这造成了混乱。
  • CGO_ENABLED=0 不会“神奇地”实现它,它会阻止使用 cgo,这将导致静态二进制文件,这听起来像你想要的。

标签: go static-linking dynamic-linking


【解决方案1】:

一些 Go 包在底层使用 CGO,利用(非常)通用的 C 库来实现跨环境和运行时遇到的边缘情况的更广泛的兼容性。

这些通用库可以在大多数主要操作系统发行版中找到 - 但显然不包含在 Scratch 映像中(本质上是完全空的)。

CGO_ENABLED 默认设置为 1,这意味着必须使用 CGO_ENABLED=0 显式禁用它才能避免它,即使使用 -static 标志也是如此。

【讨论】:

  • 值得注意的是,net 包默认使用一些libc 函数。
  • "减少编译后的二进制文件大小。"并不真地。在 Cgo 下,二进制文件包含两个解析器。 Pure-Go 是默认设置,并且始终使用,除非您明确告知它,或者操作系统配置有纯 Go 不支持的内容。 Cgo 解析器在资源上要困难得多,因为每个 Cgo 调用都消耗整个线程而不是 goroutine。它可能是为了兼容性(pure-Go 尝试模拟常见的实现),并且因为在某些系统上您不能自己发送 DNS 请求(macOS)。 Go 不需要 libc。
  • 有趣的地方!我读了更多(github.com/golang/go/issues/25670),你是绝对正确的。我知道调用 Cgo 的开销成本,但始终认为默认包含 C 钩子的好处是优化大小。感谢分享。我会更新答案以反映
  • 我认为这不会以任何方式改变答案的实质...... @Flimzy 的问题是尝试使用 Scratch 容器中的那些底层库,这是通过禁用 CGO 来解决的。
猜你喜欢
  • 2010-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-27
  • 2011-01-11
相关资源
最近更新 更多