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

问题描述:

我有一个项目依赖Hyper和Diesel,因此,本地库OpenSSL和libpq。该项目建立在夜间Rust,因为它使用编译器插件。如何使用本地依赖项编译Rust项目的静态musl二进制文件?

我目前的尝试是建立在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的”产业链!什么地方出了错?

我可以静态链接,简单的纯锈项目没有问题。 ldd表示它们是静态链接的,并且它们运行时没有问题,与我遇到问题的可执行文件不同。

当我使用--verbose有货,我得到了以下rustc命令,即实际编制的可执行文件:http://pastebin.com/ywv0zNBK(哎呀,这人有一个自定义outdir-Z print-link-args,由我添加) 添加print-link-args标志,我得到了以下链接器命令:http://pastebin.com/Aw43qd7h

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

+0

我很确定答案是:“你不,很容易”。你将需要重建libpq和OpenSSL作为静态库(并链接到MUSL?)。然后您必须弄清楚如何更改相应的Rust库以链接到静态版本。我很喜欢70%,但并不完全。 – Shepmaster

+0

事情是,我用前缀'/ usr/local/musl'重建了它们对抗MUSL。我试图通过尝试设置环境来获得相应的库链接到静态版本,但显然我失败了。你的方式听起来像我不得不自己修改库,那是什么意思? – GolDDranks

+0

我的意思是,一旦编译了C库的MUSL版本(很好地完成!),您将不得不嘲讽每个Rust绑定,以弄清楚如何更改它们之间的链接和关联。例如,[openssl有环境变量](https://github.com/sfackler/rust-openssl#manual-configuration)。 – Shepmaster

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

因此,只需设置“标准”GCC环境变量就不会产生任何影响。您必须分别检查每个build.rs以了解如何强制确切的箱子来传达货物的选项。对于OpenSSL,它的环境变量如OPENSSL_DIR,OPENSSL_STATIC

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

我做了一个全面评论的Dockerfile,用一些本地依赖项静态构建我的项目。这可能对其他人也有帮助。

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