【问题标题】:How to compile a static musl binary of a Rust project with native dependencies?如何编译具有本机依赖项的 Rust 项目的静态 musl 二进制文件?
【发布时间】:2016-11-19 16:06:05
【问题描述】:

我有一个项目依赖于 Hyper 和 Diesel,因此依赖于原生库 OpenSSL 和 libpq。该项目基于 nightly Rust 构建,因为它使用编译器插件。

我目前的尝试是在 Docker 容器上构建。我有 MUSL libc 和库 make'd 并以前缀 /usr/local/musl 安装。我使用以下命令运行cargo:(不确定某些选项是否是多​​余的,我对编译器链不太熟悉,甚至不确定它们是否最终到达链接器,但我必须试试吧。)

LDFLAGS="-static -L/usr/local/musl/lib" \
LD_LIBRARY_PATH=/usr/local/musl/lib:$LD_LIBRARY_PATH \
CFLAGS="-I/usr/local/musl/include" \
PKG_CONFIG_PATH=/usr/local/musl/lib/pkgconfig \
cargo build --release --target=x86_64-unknown-linux-musl

当我ldd 生成的文件时,它会显示:

$ ldd server
linux-vdso.so.1 (0x00007fffb878e000)
libpq.so.5 => /usr/local/musl/lib/libpq.so.5 (0x00007f4d730e7000)
libssl.so.1.0.0 => /usr/lib/x86_64-linux-gnu/libssl.so.1.0.0 (0x00007f4d72e82000)
libcrypto.so.1.0.0 => /usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0 (0x00007f4d72a85000)
libc.so => /usr/local/musl/lib/libc.so (0x00007f4d727f6000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f4d725f2000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4d72246000)
/lib/ld64.so.1 => /lib64/ld-linux-x86-64.so.2 (0x000055e2124a2000)

有所有动态链接的东西,有些甚至使用“x86_64-linux-gnu”链!出了什么问题?

我可以毫无问题地制作静态链接的简单纯 Rust 项目。 ldd 说它们是静态链接的,它们运行没有问题,不像我遇到问题的可执行文件。

当我将 --verbose 与 Cargo 一起使用时,我得到了以下 rustc 命令,它实际上构建了可执行文件:http://pastebin.com/ywv0zNBK(糟糕,那个有自定义的 outdir-Z print-link-args,由我添加) 添加print-link-args 标志,我得到以下链接器命令:http://pastebin.com/Aw43qd7h

如何让cargorustc 相信我想要一个静态二进制文件?

【问题讨论】:

  • 我很确定答案是:“你不会,很容易”。您需要将 libpq 和 OpenSSL 重新构建为静态库(并链接到 MUSL?)。然后,您必须弄清楚如何更改相应的 Rust 库以链接到静态版本。我有 70% 的把握,但不完全是。
  • 问题是,我确实针对 MUSL 重建了它们,前缀为 /usr/local/musl。而且我试图通过尝试正确设置环境来让相应的库链接到静态版本,但显然我失败了。你说的好像我必须自己修改库,是你的意思吗?
  • 我的意思是,一旦你编译了 C 库的 MUSL 版本(做得很好!),你将不得不检查每个 Rust 绑定以弄清楚如何更改它们的链接方式并什么。例如,openssl has environment variables
  • 感谢有关环境变量的指针!这是一个重要的线索。

标签: rust static-linking rust-cargo musl


【解决方案1】:

问题在于,对于每个提供本机依赖项的 crate(例如 OpenSSL),都有一个 build.rs 构建脚本负责将构建和链接选项传递给 Cargo 和 rustc。 (例如:他们打印出类似 cargo:rustc-link-lib=static=ssl 的内容,然后 Cargo 会读取并采取相应的行动。)

因此,仅设置“标准”GCC 环境变量几乎不会产生任何影响。您必须分别检查每个build.rs,以了解如何强制该确切的板条箱运送其选项。对于 OpenSSL,其环境变量如 OPENSSL_DIROPENSSL_STATIC 等。

另一个障碍是,如果您使用编译器插件,它们也可能与目标三元组一起编译(至少是 docker_codegen)。另一方面,它们在编译过程中是动态链接的。这意味着不仅静态库必须正确链接,您还必须拥有 target 主机种类的动态库,例如 Musl libc.so,并正确设置(LD_LIBRARY_PATH 等)。

我制作了一个经过彻底注释的 Dockerfile,它使用一些本机依赖项静态构建我的项目。它可能对其他人也有帮助。

https://gitlab.com/rust_musl_docker/image

【讨论】:

  • 能否请您重新发布此 docker 文件,该链接已失效
  • 啊,抱歉,项目转移到了 GitLab。我会更新链接。
【解决方案2】:

如果你想静态链接一个没有原生依赖的 Rust 程序,那就容易多了:

$ rustup target add x86_64-unknown-linux-musl
$ cargo build --release --target=x86_64-unknown-linux-musl

【讨论】:

  • 这个找不到 openssl 也没有构建任何东西
  • @nikoss,鉴于您使用的是 Linux,请尝试启用 openssl crate 的“供应商”功能并确保您已安装 musl-gcc。
【解决方案3】:

我在使用 ldd 和 GCC 时遇到了同样的问题。 musl 目标是在不同的目录中生成的;不在target/release/...,而是在target/x86_64-unknown-linux-musl/release/...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-03
    • 2017-07-25
    • 1970-01-01
    • 2018-10-22
    • 1970-01-01
    • 2018-05-28
    • 1970-01-01
    • 2017-08-31
    相关资源
    最近更新 更多