最近在用 Rust 开发一些提效小工具,在 Mac 平台编码但运行环境为 Linux(裸跑,非容器),将相关过程记录一下。

之前这种跨平台的编译是使用 cross 来完成的,使用类似下面的命令来进行编译:

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

本次直接用 cargo 来解决:

  • 使用 rustup target add 来添加目标平台的标准库
  • 安装目标平台的 链接器(linker)
  • 配置 cargo 来使 rustc 能够使用正确的链接器
  • 设置 TARGET_CC 环境变量
  • 使用 cargo build 来进行编译

添加目标 target

rustup target add x86_64-unknown-linux-gnu

安装目标平台的链接器

brew install SergioBenitez/osxct/x86_64-unknown-linux-gnu

添加 cargo 配置文件

mkdir .cargo
touch config.toml

添加下面的配置文件:

[target.x86_64-unknown-linux-gnu]
linker = "x86_64-unknown-linux-gnu-gcc"

设置环境变量

export TARGET_CC=x86_64-unknown-linux-gnu-gcc

开始编译

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

设置环境变量和编译可以在同一步进行:

TARGET_CC=x86_64-unknown-linux-gnu-gcc cargo build --release --target x86_64-unknown-linux-gnu

然后在 ./target/x86_64-unknown-linux-gnu/release/ 可以找到编译产物。

运行环境 glibc 版本过低问题

当在运行环境执行 ./tool-name 时,部分服务器报错了:

./tool-name: /lib64/libc.so.6: version GLIBC_2.25' not found (required by ./tool-name)

查看 ldd 版本:

ldd --version
ldd (GNU libc) 2.17
Copyright (C) 2012 Free Software Foundation, Inc.

这是因为 glibc 版本较低(部分服务器运行好多年了,一直未替换),此时可以升级版本或者使用静态链接方案。升级版本考虑的问题比较多,下面继续看使用静态链接来编译。

当 target 是 x86_64-unknown-linux-gnu 时,会使用动态链接,也就是在运行时来链接。因此会出现运行环境 glibc 版本不满足要求的情况。换用 x86_64-unknown-linux-musl 这个目标平台来解决问题。

# 添加目标平台
rustup target add x86_64-unknown-linux-musl
# 安装链接器
brew install FiloSottile/musl-cross/musl-cross

然后在 cargo 配置文件 .cargo/config.toml 中添加如下内容:

[target.x86_64-unknown-linux-musl]
linker = "x86_64-linux-musl-gcc"
# -static-pie 如果不支持,则再添加下面这一行
# rustflags = ["-C", "link-args=-static"]

最后执行编译:

TARGET_CC=x86_64-linux-musl-gcc cargo build --release --target x86_64-unknown-linux-musl

./target/x86_64-unknown-linux-musl/release/ 可以找到编译产物。这样得到的可执行文件就是通过静态链接的了,应该在大部分的 Linux 上都可以执行。