针对旧的 libc 版本构建和绑定

Build and bind against older libc version

我的代码中有需要 libc 的依赖项。在 Ubuntu 20.04 (glibc 2.31) 上构建 (cargo build --release) 时,生成的可执行文件不会在 CentOS 7 (glibc 2.17) 上 运行。它抛出一个错误,说它需要 GLIBC 2.18。

在 CentOS 7 上构建相同的代码时,在 CentOS 7 和 Ubuntu 20.04.

上生成的可执行文件 运行s

有没有办法控制在 Ubuntu 20.04 上构建此版本需要哪个 GLIBC 版本?

一般来说,您需要在 OS 上为给定的 OS 构建二进制文件,或者至少在您打算支持的最旧的 OS 上构建二进制文件。

glibc 使用符号版本控制来保留旧程序的行为,同时添加对新功能的支持。例如,pthread_mutex_lock 的较新版本可能支持锁省略,而旧版本则不支持。您看到此错误是因为当您 link 反对 libc 时,如果未明确指定版本,则您 link 反对符号的默认版本,并且至少在一种情况下,您 linked against 来自 glibc 2.18。更改此设置需要重新编译 libstd(和 libc crate,如果您正在使用它)并进行自定义更改以选择旧版本化的符号,这是一项工作量大而收效甚微的工作。

如果您唯一的依赖项是 glibc,那么仅在 CentOS 7 上编译就足够了。但是,如果您依赖其他库,例如 OpenSSL,那么它们在 OS 版本,因为它们的 SONAME 不同,而且没有办法解决这个问题。所以这就是为什么通常要为每个 OS.

构建不同的二进制文件的原因

如果您的项目不依赖于任何本机库,那么最简单的方法可能是使用 x86_64-unknown-linux-musl 目标。

此目标静态 links 针对 MUSL Libc 而不是动态 linking 针对系统的 libc。因此,它会生成完全静态的二进制文件,应该 运行 在广泛的系统上。

要安装此目标:

rustup target add x86_64-unknown-linux-musl

要使用此目标构建您的项目:

cargo build --target x86_64-unknown-linux-musl

有关详细信息,请参阅 the edition guide

如果您正在使用任何 non-rust 库,它会变得更加困难,因为它们可能是动态 linked 并且可能反过来依赖于系统 libc。在那种情况下,您要么需要静态 link 外部库(假设这甚至是可能的,并且您使用的库将与 MUSL libc 一起使用),要么为您想要定位的每个平台进行不同的构建。

如果您最终不得不为每个平台进行不同的构建,docker 容器将是实现这一目标的最简单方法。

尝试cross

全局安装:

cargo install cross

然后用它构建你的项目:

cross build --target x86_64-unknown-linux-gnu --release

cross 采用与 cargo 相同的参数,但您必须明确指定目标。此外,构建目录始终是 target/{TARGET}/(debug|release),而不是 target/(debug|release)

cross 使用 docker 为不同目标体系结构预构建的图像,但没有什么能阻止您针对主机体系结构“交叉编译”。这些 docker 图像中的 glibc 版本应该足够保守。如果不是,您可以随时配置 cross 以使用自定义图像。