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 .
接下来,分别对demo0
和demo1
进行运行测试:
$ 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
。