Rust 编译静态单体执行文件


关于windows环境: https://blog.csdn.net/u013195275/article/details/103397888

Linux 环境

Linux 下 rust 默认使用 gcc 作为链接器,编译后的文件在运行时需要glibc 运行库和其他的一些库。

这就导致在某个Linux版本下编译的执行文件,无法在另一个Linux版本上顺利运行。而且,如果你的程序还使用了OpenSSL动态库,那这样的问题会更加突出。

下面,我们做个最简单的实验。

  1. 用Cargo创建一个可执行项目。
  2. 编译这个项目
  3. 用ldd命令查看编译出来的执行文件依赖了哪些动态链接库
$ cargo -V
cargo 1.31.0 (339d9f9c8 2018-11-16)
$ cargo new --bin hello
$ cd hello
$ cargo build
$ ldd target/debug/hello
        linux-vdso.so.1 (0x00007ffdc47e4000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f6db611a000)
        librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f6db5f12000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f6db5cf3000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f6db5adb000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6db56ea000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f6db6587000)

可以看到这个执行文件依赖了多个.so的动态链接库。而且这种依赖是基于绝对路径的。一旦运行时环境下没有这些动态库文件,那程序执行的结果就只有一个:报错!

那么,Rust能否像Golang那样编译成独立的静态可执行文件呢?答案是可以的,这需要使用MUSL 静态库。

使用MUSL进行静态编译

使用MUSL编译,首先需要安装musl环境。命令如下:

$ rustup target add x86_64-unknown-linux-musl
或者
$ rustup target add x86_64-unknown-linux-musl --toolchain=nightly

然后,我们编译前面创建的hello工程。

$ cd hello
$ cargo build --release --target=x86_64-unknown-linux-musl
$ ldd target/x86_64-unknown-linux-musl/release/hello
        not a dynamic executable

可以看到新的可执行文件已经不再依赖任何动态链接库。我们可以将这个文件放到任何一个Linux操作系统里运行了。

当然,这只是一个最简单的例子。实际工作中,我们可能会遇到更复杂的场景。如:依赖了OpenSSL库。在这样的场景里,我们还需要做很多配置才能获得我们想要的静态编译文件。这里就不再详细介绍了。

笔者想介绍的是如何避免各种繁复的配置,尽可能快捷的进行MUSL编译。就是下面章节的内容。

使用预置好的Docker容器进行MUSL编译

为解决使用MUSL编译配置繁琐的问题,国外的开发者贡献了一个预置好的容器。用这个容器来进行MUSL编译会非常方便快捷。

项目地址是:https://gitlab.com/rust_musl_docker/image

我们直接用这个容器来编译我们前面创建的hello工程。然后依然用ldd来查看编译好的可执行文件。

$ cd hello
$ docker run -it --rm \
> -v $PWD:/workdir \
> -v ~/.cargo/git:/root/.cargo/git \
> -v ~/.cargo/registry:/root/.cargo/registry \
> registry.gitlab.com/rust_musl_docker/image:stable-latest \
> cargo build --release -vv --target=x86_64-unknown-linux-musl

$ ldd target/x86_64-unknown-linux-musl/release/hello
        not a dynamic executable
12345678910

这个容器镜像里已经配置了对OpenSSL库的静态编译。笔者亲测可用。更详细的内容,读者可以去看项目里的注释,已经非常详尽了。

CentOS docker

rust docker交叉编译静态单体执行文件
编译对应平台的docker image(https://github.com/messense/rust-musl-cross).

Rust toolchainCross Compile TargetDocker Image Tag
stablex86_64-unknown-linux-muslx86_64-musl
stablei686-unknown-linux-musli686-musl
stablearm-unknown-linux-musleabiarm-musleabi
stablearm-unknown-linux-musleabihfarm-musleabihf
stablearmv7-unknown-linux-musleabihfarmv7-musleabihf
stablearmv5te-unknown-linux-musleabiarmv5te-musleabi
stablemips-unknown-linux-muslmips-musl
stablemipsel-unknown-linux-muslmipsel-musl

用法:

  1. 先拉取对应镜像:docker pull messense/rust-musl-cross:armv7-musleabihf
  2. 为了方便使用,重命名
    alias rust-musl-builder='docker run --rm -it -v "$(pwd)":/home/rust/src messense/rust-musl-cross:armv7-musleabihf'
  3. 用"rust-musl-builder"这个命令简化使用
    rust-musl-builder cargo build --release
  4. 上面就和使用普通cargo打包一样了,调这个命令其它就相当于挂载本地项目到容器中打包。
  5. 以上镜像为了打包静态单体,镜像中已包含了(为了有这个教程,就是在centos中打包静态单体时需要openssl,解决了普通openssl的打包,发现静态打包还需要musl-gcc,而centos找了半天也没有找到,所以就想到了docker省得自己搭环境了)
    • The standard musl-libc libraries.
    • OpenSSL, which is needed by many Rust applications.

https://blog.csdn.net/u013195275/article/details/106074495
https://blog.csdn.net/castellan/article/details/86063775

©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页