Windows和MacOS下Rust与C的交互.md

本文将分别介绍在WindowsMacOS的环境下,在C中调用Rust的库函数的方法和步骤。

Windows

默认你已经安装了Visual Studio 2019 community并勾选了C/C++开发以及Windows 10 SDK的部分

首先我们要在命令行中使用cl.exe,即MVSC中的C/C++编译器,具体可看这篇文章

关于Rust的部分

初始化一个新的库

> cd Desktop
> cargo new --lib bridge_c

Cargo.toml中添加

[lib]
crate-type = ["cdylib"]

这样,编译后生成的动态链接库xxx.dll可供C调用。

重新编辑bridge_c/src/lib.rs

#[no_mangle]
pub extern "C" fn bridge_c() {
    println!("A hello from Rust :)");
}

使用cbindgen生成对应的头文件,将bridge.h拖放到桌面上备用

> cbindgen bridge_c/src/lib.rs -l c > "bridge.h"

上述步骤都完成后,开始编译该库

> cargo build --release

bridge_c/target/release目录下的bridge_c.dll.libbridge_c.dll拖放到桌面上备用。

关于C的部分

Desktop目录下新建一个文件夹hello,把桌面上的bridge.hbridge_c.dll.libbridge_c.dll拖到hello目录下。

hello目录下新建一个main.c文件,写上:

#include "bridge.h"

int main(int argc, char const *argv[])
{
    bridge_c();
    return 0;
}

接下来开始编译main.c

> cd hello
> cl.exe /Iheaders/ bridge_c.dll.lib main.c

运行main.exe

> main.exe
A hello from Rust :)

如果报错中出现"undefined_symbols"的字样,多半是配置cl.exe时环境变量设置的不对,届时请仔细阅读前述提到的那篇文章。

MacOS

默认你已经安装了Xcode的最新版,并且执行过xcode-select --install

在mac上的交互与上述有些细小的差别。

关于Rust的部分

$ cd Desktop
$ cargo new --lib bridge_c

这次我们使用静态库,即在Cargo.toml中添加

[lib]
crate-type = ["lib", "staticlib"]

我们也可以添加依赖,例如

[dependencies]
ferris-says = "0.1"

bridge_c/src/lib.rs改为

use std::io::{stdout, BufWriter};

#[no_mangle]
pub extern "C" fn hello_devworld() {
    let phrase = b"Hello, /dev/world/2019!";
    let stdout = stdout();
    let mut writer = BufWriter::new(stdout.lock());
    ferris_says::say(phrase, 30, &mut writer).unwrap();
}

cbindgen生成头文件:

cbindgen bridge_c/src/lib.rs -l c > "bridge.h"

编译库:

$ cargo build --release

target/release目录下的libbridge_c.abridge.h拖到桌面上备用

除此之外,我们还需要一个信息,即在编译C时需要哪些本地库

$ cargo rustc -- --print native-static-libs

Compiling ...
note: Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms.

note: native-static-libs: -lSystem -lresolv -lc -lm

    Finished dev [unoptimized + debuginfo] target(s) in 9.95s

注意note: native-static-libs:后的几个选项,一会儿要用。

关于C的部分

$ mkdir hello

libbridge_c.abridge.h拖到hello文件夹中,新建main.c

$ touch main.c

编辑main.c的内容为:

#include "bridge.h"

int main() {
    hello_devworld();
    return 0;
}

编译main.c

$ cc main.c libbridge_c.a -lSystem -lresolv -lc -lm -o main

运行main

$ ./main
    ----------------------------------
    | Hello, /dev/world/2019!        |
    ----------------------------------
                \
                 \
                     _~^~^~_
                 \) /  o o  \ (/
                   '_   -   _'
                   / '-----' \

成功啦~

参考链接:

  • https://experimentalworks.net/posts/2018-10-21-rust-c-ffi-windows/
  • https://zhuanlan.zhihu.com/p/98384105
  • https://github.com/thombles/dw2019rust/blob/master/modules/01%20-%20Hello%20DevWorld.md

你可能感兴趣的:(Windows和MacOS下Rust与C的交互.md)