如何使用本机依赖项编译Rust项目的静态musl二进制文件?

时间:2016-11-19 16:06:05

标签: rust static-linking rust-cargo musl

我有一个依赖Hyper和Diesel的项目,因此,在本机库OpenSSL和libpq上。该项目建立在每晚Rust上,因为它使用编译器插件。

我目前的尝试是在Docker容器上构建。我有MUSL libc和库make'并安装了前缀/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和{ {1}},由我添加) 添加-Z print-link-args标志,我得到以下链接器命令:http://pastebin.com/Aw43qd7h

如何让print-link-argscargo相信我想要一个静态二进制文件?

3 个答案:

答案 0 :(得分:7)

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

因此,仅设置“标准”GCC环境变量几乎不会产生任何影响。您必须分别检查每一个build.rs,以了解如何强制确切的箱子来传达货物的选择。对于OpenSSL,它包括OPENSSL_DIROPENSSL_STATIC等等。

另一个障碍是,如果你使用编译器插件,它们也可能使用目标三元组进行编译(至少是docker_codegen)。另一方面,它们在编译过程中动态链接。这意味着不仅必须正确链接静态库,还必须具有目标变体的动态库,如MUSL libc.so,并正确设置(LD_LIBRARY_PATH等。)。

我做了一个彻底评论的Dockerfile,它使用一些本机依赖项静态地构建我的项目。它也可能对其他人有所帮助。

https://github.com/golddranks/rust_musl_docker/blob/master/Dockerfile.template

答案 1 :(得分:0)

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

答案 2 :(得分:-1)

如果您要静态链接不带本机依赖项的Rust程序,那会容易得多:

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