【问题标题】:When using CGO_ENABLED is must and what happens必须使用 CGO_ENABLED 时会发生什么
【发布时间】:2020-08-14 07:57:36
【问题描述】:

问题

请帮助了解CGO_ENABLED何时是必须且不可避免的,以及go编译过程会发生什么。

当必须使用 CGO_ENABLED 时

看了参考中的文章,看来go对目标平台有交叉编译原生支持,CGO_ENABLED绝不是必须的。这是正确的吗?

cgoCGO_ENABLED绝对必须的情况是go编译器无法为目标平台生成二进制代码。例如,假设我正在用 Go 编写一个 Space X 控制板嵌入式程序,我必须使用 C 库和板的编译器。该板没有其他可用的库或编译器。

在这种情况下,我必须执行 CGO_ENABLED=1 并告诉 cgo 要使用的编译器和链接器以及 C 库二进制文件在我的笔记本电脑中的复制位置,并设置编译器 CFLAGS 等。在这种情况下,也许我必须使用 C 进行所有编码,而不是使用 Go,但不知何故,我不得不使用 Go。这时候 CGO_ENABLED=1 是必须的。这是正确的吗?

否则,如果 Go 尤其支持目标平台交叉编译,则使用 CGO_ENABLED=1 可能是为目标平台重用现有 C 库的捷径。这是正确的还是需要 CGO_ENABLED 的任何其他原因?

会发生什么

我想当使用 CGO_ENABLED=1 时,基本上会有一个来自 Go 部分的二进制文件,以及由 go build 命令。并且在运行时,执行在 go 和 C 两个二进制世界之间来回执行。go 二进制端不知道 C 端,因此调试器等 go 工具将不可用。

我想可执行文件是硬链接所有库还是使用动态链接取决于目标平台编译器。

这些理解正确吗?

之所以交叉编译默认CGO_ENABLED=0是因为我们应该使用目标平台交叉编译的go内置支持,没有理由不这样做。

本地本地平台默认情况下 CGO_ENABLED=1 的原因是因为 cgo 编译器知道(或编译器的作者知道)本地机器架构和 OS 库(或众所周知的 3rd方的)可用,因此可以预期最佳优化?但我不确定这是不是真的,因为 go 编译器本身可以针对本地操作系统和架构进行最佳优化,那么为什么需要使用 cgo 呢?

请解释为什么本地本地平台默认为 CGO_ENABLED=1

参考文献

  • cgo is not Go

    有些人在遇到问题时会想:“我知道,我会使用 cgo。”现在他们有两个问题。

    cgo 是一项了不起的技术,它允许 Go 程序与 C 库进行互操作。这是一个非常有用的功能,没有它,Go 就不会处于今天的位置。 cgo 是在 Android 和 iOS 上运行 Go 程序的关键。

    然而,为了明确这些是我的观点,我不代表任何人,我认为 cgo 在 Go 项目中被过度使用。我相信当面对在 Go 中重新实现一大段 C 代码时,程序员会选择使用 cgo 来包装库,认为这是一个更容易处理的问题。我相信这是一种虚假的经济。

    显然,在某些情况下 cgo 是不可避免的,最明显的是您必须与只能作为二进制 blob 使用的图形驱动程序或窗口系统进行互操作。但是,使用 cgo 证明其权衡取舍合理的情况比许多人愿意承认的要少得多。

    Go 对交叉编译的支持是同类中最好的。从 Go 1.5 开始,您可以使用 Go 项目网站上提供的官方安装程序从任何受支持的平台交叉编译到任何其他平台。

    默认情况下,交叉编译时禁用 cgo。如果您的项目是纯 Go,通常这不是问题。当您混合对 C 库的依赖项时,您要么必须放弃交叉编译产品的选项,要么必须花时间为所有目标查找和维护交叉编译 C 工具链。

    Go 支持的平台数量持续增长。 Go 1.5 添加了对 64 位 ARM 和 PowerPC 的支持。 Go 1.6 增加了对 64 位 MIPS 的支持,IBM 的 s390 架构被吹捧为 Go 1.7。 RISC-V 正在筹备中。如果您的产品依赖于 C 库,那么您不仅会遇到上述交叉编译的所有问题,还必须确保您所依赖的 C 代码在 Go 支持的新平台上可靠地工作——您必须这样做C/Go 混合为您提供有限的可调试性。这让我想到了下一点。

  • Why does CGO_ENABLE make a such impact on virtual memory?

    “参考”Go 实现的编译器(历史上称为“gc”;可从主站点下载)默认生成静态链接的二进制文件。这意味着,此类二进制文件仅依赖于操作系统内核提供的所谓“系统调用”,而不依赖于操作系统(或第三方)提供的任何共享库。

    在基于 Linux 的平台上,这并不完全正确:在默认设置中(在 Linux 上为 Linux 构建,即不交叉编译),生成的二进制文件实际上与 libc 和 libpthread 链接(间接,通过 libc)。

  • cmd/cgo: document how CGO_ENABLED works today

    默认情况下,cgo 工具在系统上的本地构建中启用 预计会起作用。时默认禁用 交叉编译。您可以通过设置 CGO_ENABLED 来控制它 运行 go 工具时的环境变量:设置为 1 启用 使用 cgo,并为 0 禁用它。 go 工具将设置 如果启用了 cgo,则构建约束“cgo”。

    交叉编译时,必须为 cgo 指定一个 C 交叉编译器 采用。您可以通过设置 CC_FOR_TARGET 环境来做到这一点 使用 make.bash 构建工具链时的变量,或者通过设置 每次运行 go 工具时的 CC 环境变量。这 CXX_FOR_TARGET 和 CXX 环境变量以类似的方式工作 C++ 代码。

  • C? Go? Cgo!

  • cgo

【问题讨论】:

    标签: go cross-compiling


    【解决方案1】:

    许多东西只能以 C 库的形式提供,并且在 Go 中重新实现这一切将是昂贵的。 cgo 有其缺点,但它可以是一个很好的权衡。甚至标准库也使用它(net 用于 DNS 查找,os/user 用于用户查找),因为它不会 100% 地重新实现 Go 中的行为。

    交叉编译 C 代码仍然相当困难;您将需要目标架构的 C 编译器和工具链(例如 CC=aarch64-linux-musl-gccgo build 来构建 arm64 二进制文件)。默认情况下都没有安装,因此对于大多数人来说,cgo 在交叉编译时根本无法工作;他们需要先手动进行设置。

    cgo 通常不是严格要求的(例如在 net 和 os/user 包中),因此默认禁用它似乎是最用户友好的选项。

    但是在原生平台上没有这样的限制,并且预计在没有任何用户设置的情况下默认工作;那为什么不默认启用呢?

    【讨论】:

      猜你喜欢
      • 2018-05-22
      • 2014-09-06
      • 2012-04-22
      • 2011-10-19
      • 2013-04-30
      • 1970-01-01
      • 2012-09-08
      • 2022-06-11
      • 1970-01-01
      相关资源
      最近更新 更多