3

Rust编译Linux通用可执行文件

 1 year ago
source link: https://note.qidong.name/2023/03/rust-universal-bin/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Rust编译Linux通用可执行文件

2023-03-30 21:24:13 +08  字数:839  标签: Rust

问题描述

在glibc环境编译的Rust可执行文件,不能在Docker的scratch镜像中运行。

把一个Rust二进制项目,编译成一个可执行文件,并且可以在任意Linux系统独立运行—— 这应该是一个Rust二进制项目的默认需求,Golang也能默认做到。 但实际尝试会发现,Rust不行。

因为绝大部分Linux环境,都是基于GNU,包括主流的Ubuntu、Debian、RedHat等。 而Rust在这些环境编译时,glibc默认不会被打包进去。 结果导致编译后的二进制文件,对glibc的so有依赖,而且有版本限制。 不仅不能在非glibc环境运行(如Alpine),也不能在glibc过低的环境运行。

这不知道是出于技术原因,还是GPL协议原因。

解决方案

glibc不行,使用musl的libc即可。

rustup target add x86_64-unknown-linux-musl

本文在Deepin上撰写,默认的target是x86_64-unknown-linux-gnu

实战演示

cargo init demo
cd demo
cargo build -r
cargo build -r --target=x86_64-unknown-linux-musl

这里利用Cargo生成了一个demo项目,它可以编译出一个可执行文件demo。 并且使用默认(gnu)和musl分别编译了一个可执行文件。

然后新增一个Dockerfile文件,添加以下内容:

FROM scratch
COPY ./target/release/demo /demo0
COPY ./target/x86_64-unknown-linux-musl/release/demo /demo1

并且构建一个本地测试镜像:

docker build -t demo .

接下来,分别对demo0demo1进行运行测试:

$ docker run --rm demo /demo0
standard_init_linux.go:207: exec user process caused "no such file or directory"
$ sudo docker run --rm demo /demo1
Hello, world!

可见,在scratch(啥也没有的基础镜像)中, 基于gnu的demo0不能正常运行,而基于musl的demo1则没有问题。

上面的demo0有4.1MB,而demo1由于多打包了libc进去,有4.3MB。

其它信息

  • 在musl环境,使用默认编译方式得到的可执行文件,可以在glibc环境运行。
  • 以上示例,只能在x86的Linux/Darwin环境运行。
    • 不能在Windows运行。
    • 不能在其它架构运行,如ARM。 若有需要,则可尝试ARM架构上的target,如arm-unknown-linux-musleabi

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK