跳转至

Rust使用musl静态编译

Rust默认运行时环境

  • Linux 下 rust 默认使用 gcc 作为链接器, 编译后的文件在运行时需要glibc 运行库和其他的一些库
  • 这就导致在某个Linux版本下编译的执行文件, 无法在另一个Linux版本上顺利运行, 而且, 如果你的程序还使用了OpenSSL动态库,, 那这样的问题会更加突出
  • 下面, 我们做个最简单的实验

  • 用Cargo创建一个可执行项目

  • 编译这个项目
  • 用ldd命令查看编译出来的执行文件依赖了哪些动态链接库
$ 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的动态链接库, 而且这种依赖是基于绝对路径的, 一旦运行时环境下没有这些动态库文件,那程序执行的结果就只有一个: 报错!

使用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操作系统里运行了

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

  • 为解决使用MUSL编译配置繁琐的问题,国外的开发者贡献了一个预置好的容器。用这个容器来进行MUSL编译会非常方便快捷
$ docker run -it --rm \
>    -v $PWD:/workdir \
>    -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