从 Ubuntu 20 构建适用于 Ubuntu 18 的应用程序

问题描述 投票:0回答:2

我使用

go build -o myApp
在 Ubuntu 20.04 操作系统中构建 Go 应用程序。

当我在 Ubuntu Server 18.04 上运行此应用程序时,出现此错误:

/lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found (required by ./myApp)

当我在 stackoverflow 中搜索时,有人提到在服务器上安装

glibc 2.29
。但也有人回复说这种方式有风险,可能会破坏OS。

其他人建议使用

glibc 2.27
构建应用程序。

我该怎么做?

linux ubuntu go glibc cgo
2个回答
5
投票

如何制作静态二进制文件主要取决于您的代码(或库)是否使用cgo。

如果不需要cgo,这相当简单:只需使用环境变量禁用它:

CGO_ENABLED
。这将自动切换一些基于 cgo 的功能以使用纯 go 实现(netgoosusergo):

CGO_ENABLED=0 go build -o myApp

如果需要cgo,您可以告诉链接器静态链接C代码,如下所示:

go build -ldflags="-extldflags=-static" -o myApp

请注意,并非所有 cgo 代码都会对此感到高兴。如何解决取决于所使用的库。


0
投票

(实际上是在回答那个问题

问题

默认情况下,在 Linux for Linux 上构建时,常用的 Go 工具链(可以从 there 获得)会再次动态链接平台的标准 C 库(也称为

libc
)。 这是与“名称解析”相关的两个任务所需要的:

  • DNS 解析(主机名到 IP 地址,反之亦然)和
  • 用户/组解析。

Go 尝试在基于 Linux 的平台上使用

libc
来完成这些任务,因为内核本身(Linux 是内核,而不是操作系统)并没有实现上面列出的名称解析工具,它们都是以以下形式实现的:图书馆。

大多数基于 Linux 的操作系统中使用的标准 C 库是 GNU libc,通常称为“glibc”。它以共享库(

.so
文件)的形式提供,并具有版本化符号——也就是说,它不会导出,比如说,
gethostbyname
,它会导出类似
gethostbyname@GLIBC_X.YY
的东西,其中那些
 X.YY
是 glibc 的某个版本。出于兼容性目的,glibc 的单个版本甚至可能导出同一符号的多个版本:“当前”版本和多个“过去”版本。

现在,当你在一个基于 glibc 且附带 glibc vA.BC 的操作系统上构建一个 Go 程序时,链接器会以一种在其符号表中表示它有一堆未解析的 versioned 符号的方式链接你的程序 –说,

[email protected]
。现在假设您将生成的可执行映像文件复制到运行操作系统的主机,该操作系统具有某些过去版本的glibc,例如
X.YZ
 < 
A.BC
。 现在显然 glibc 不包含
[email protected]
,因为它最多只能提供
[email protected]
,因为 vA.BC 在 glibc 版本构建时甚至不存在。

解决方案

另一个问题部分提出了一个解决方案:强制 Go 不链接到

libc

以最简单的形式禁用

cgo
,因此 Go 工具链被迫使用变通办法。 这种情况下的解决方法是对 DNS 和用户/组解析使用特殊的存根实现,仅处理最常见的情况 - 基本上,DNS 解析代码读取
/etc/resolv.conf
,然后使用 UDP 与此处列出的名称服务器和用户进行通信/group 解析代码为
/etc/passwd
/etc/groups
。 虽然在 DNS 解析的情况下,与 libc 提供的解析的差异应该很小,但在用户/组解析的情况下,差异可能很大,因为存根实现完全错过了 NSS 提供的“高级”设置,例如从 LDAP 服务器获取用户和/或组的列表。

请注意,有时程序必须使用

cgo
,除了 DNS 和用户/组解析之外的其他原因 - 例如,它想要链接到自定义 C 库,但不想链接到 libc。 在这种情况下,可以启用
cgo
,但使用特殊的构建标签构建程序:
netgo
osusergo
,例如:

$ go build -tags netgo,osusergo

另一个解决方案是让链接器使用目标系统将具有的 libc 版本。

如今,实现这一目标的最简单方法是使用

chroot
-ed环境或基于具有所需libc版本的操作系统映像的容器。 因为我是个老家伙,我发现 chroots 更容易设置和使用,而且更轻量,但是 YMMV。

TL;博士

如果您希望 Go 程序在 Ubuntu 42 上运行,而您在 Ubuntu 24 上进行开发,并且它们的 glibc 版本恰好不同,请使用特殊环境来进行最终部署构建 - 任何具有包含以下内容的 glibc 版本的环境所需的符号。最简单的方法是在 Ubuntu 42 上构建。

© www.soinside.com 2019 - 2024. All rights reserved.