交叉编译和静态链接 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++ 如何相互操作,这可以作为一个起点。

我们要感谢以下链接资源的贡献者。

资源

这篇文章总结了以下链接中的信息:


本文翻译自 cross compiling and statically linking against Rust libraries

以上是关于交叉编译和静态链接 RUST 库的主要内容,如果未能解决你的问题,请参考以下文章

Rust交叉编译和不依赖glic之类的编译(内嵌这些依赖库)

如何在 ARM 交叉编译时选择要链接的静态库?

makefile 交叉编译怎么引用静态库

Rust库交叉编译以及在Android与iOS中使用

Rust库交叉编译以及在Android与iOS中使用

为 ARM 交叉编译 Rust 程序时的 ALSA 链接