交叉编译和静态链接 RUST 库
Posted 跨链技术践行者
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了交叉编译和静态链接 RUST 库相关的知识,希望对你有一定的参考价值。
在 CSIS 中,我们过去使用 Python 编写后端,同时为 Incident Response Toolkit 编写一些 C/C++ 代码。
几年前,主要是由于性能原因,我们开始用 Rust 替换 Python 重写了一些特定的后端服务,并取得了巨大的成功。现在,为了便于开发和测试,我们正在探索将 C/C++ 代码库的某些部分也迁移到 Rust 的方法。
为了做到这一点,我们决定尝试将Rust集成到现有的代码库中,而不是一次重写所有内容。
下面是我们实验的摘要,以及编写一个Rust库并从 C/C++ 应用程序调用它的框架。
TARGETS
为了能够交叉编译代码,我们需要确保安装了相应的 target
。可用的targets
可以用过 rustc --print target-list
或 rustup target list
查看,可以通过 rustup target add <target>
安装新的 target
。
查看已经安装的 targets
可以用 rustup show
:
$ rustup show
Default host: x86_64-unknown-linux-gnu
installed toolchains
--------------------
stable-x86_64-unknown-linux-gnu (default)
nightly-x86_64-unknown-linux-gnu
installed targets for active toolchain
--------------------------------------
i686-pc-windows-gnu
i686-pc-windows-msvc
i686-unknown-linux-gnu
i686-unknown-linux-musl
x86_64-pc-windows-gnu
x86_64-pc-windows-msvc
x86_64-unknown-linux-gnu
x86_64-unknown-linux-musl
active toolchain
----------------
stable-x86_64-unknown-linux-gnu (default)
rustc 1.31.0 (abe02cefd 2018-12-04)
项目设置
target
正确设置好后,我们需要设置项目,从 Cargo.toml
开始 :
[package]
name = "mylib"
version = "0.1.0"
authors = ["john doe<jdo@csis.dk>"]
[dependencies]
libc = "*"
[lib]
crate-type = ["staticlib"]
现在我们的库的源代码src/lib.rs
:
extern crate libc;
use libc::uint32_t;
#[no_mangle]
pub extern "C" fn addition(a: uint32_t, b: uint32_t) -> uint32_t {
a + b
}
以及应用程序调用者的源代码 caller.cpp
:
#include <stdio.h>
#include <stdint.h>
extern "C" {
uint32_t
addition(uint32_t, uint32_t);
}
int main(void) {
uint32_t sum = addition(1, 2);
printf("%u\\n", sum);
}
如果这是个 C 应用,只需要删除extern "C"
。
接下来,我们需要指定我们想要的 target
, 这是在.cargo/config
中完成的, 比如:
[build]
target="i686-pc-windows-gnu"
LINUX 二进制文件
为了静态链接 Linux 二进制文件,我们需要将 target
设置为 -linux-musl
。
.cargo/config
或者,对于 64 位 二进制文件,我们可以选择 x86_64-unknown-linux-musl
。
[build]
target="i686-unknown-linux-musl"
- build
$ g++ -m32 -c -o linux_cpp_caller.o caller.cpp
$ g++ -static -m32 linux_cpp_caller.o -o linux_cpp_caller \\
-L./target/i686-unknown-linux-musl/debug/ -lmylib
如果我们的目标是 64 位,我们需要删除 -m32
选项,并相应的调整 -L
标志。
WINDOWS 二进制文件
为了静态链接 Windows 二进制文件,我们需要将 target
设置为 -pc-windows-gnu
。对于 32 位二进制文件,需要特别注明异常处理模型。可以在 “rust-lang” Github repository 和 stack overflow 找到一个很好的摘要。
.cargo/config
[build]
target="i686-pc-windows-gnu"
rustflags = "-C panic=abort"
或者,对于 64 位二进制文件,我们可以选择 x86_64-pc-windows-gnu
。如果是这种情况,可以删除 rustflags
选项。
- build
$ i686-w64-mingw32-g++ -c -o win_cpp_caller.o caller.cpp
$ i686-w64-mingw32-g++ -static win_cpp_caller.o -o win_cpp_caller \\
-L./target/i686-pc-windows-gnu/debug/ \\
-lmylib \\
-ladvapi32 \\
-lws2_32 \\
-luserenv
如果是 64 位环境,用该使用 x86_64-w64-mingw32-g++
,并相应调整 -L
标志。
结论
通过这篇文章,我们希望提供一个简单的工作示例,说明 Rust 和 C / C++ 如何相互操作,这可以作为一个起点。
我们要感谢以下链接资源的贡献者。
资源
这篇文章总结了以下链接中的信息:
- https://doc.rust-lang.org/cargo/reference/manifest.html#building-dynamic-or-static-libraries
- https://www.reddit.com/r/rust/comments/8vnf2h/statically_linking_a_rust_program_for_c/
- https://stackoverflow.com/a/15685229
- https://github.com/rust-lang/rust/issues/32859
- https://github.com/rust-lang/rust/pull/55444#issuecomment-434580987
- https://github.com/rust-lang/rust/issues/47493
本文翻译自 cross compiling and statically linking against Rust libraries
以上是关于交叉编译和静态链接 RUST 库的主要内容,如果未能解决你的问题,请参考以下文章