Rust调用C++库

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2023/05/07/rust-call-cplusplus/



Rust基于FFI可以调用其他语言,这个支持对于C是很完备的,对于C++有一些限制。常用的工具有cxx和autocxx,前者可控简单,后者强大易用。我一般喜欢使用autocxx,可以少写一些代码。

我们这里用Rust调用V8为例子。

打印固定字符串

首先引入autocxx

[dependencies]
autocxx = "0.25.0"
cxx = "1.0"

[build-dependencies]
autocxx-build = "0.25.0"

我们先尝试查询一下V8的版本号。

新建input文件,定义一个方法version,先返回一个固定字符串。

inline std::string version() {
    return "0.0.1";
}

main.rs方法添加代码

use autocxx::prelude::*;
include_cpp! {
    #include "../include/input.h"
    safety!(unsafe_ffi)
    generate!("version")
}

fn main() {
    let rv8 = ffi::version();
    println!("Hello, world! - from RV8, version= {:?}", rv8);
}

最后是build.rs文件,当前没有外部依赖,直接编译

fn main() -> miette::Result<()> {
    let path = std::path::PathBuf::from("src");
    let mut b = autocxx_build::Builder::new("src/main.rs", [&path]).build()?;
    b.flag_if_supported("-std=c++14").compile("rv8");

    println!("cargo:rerun-if-changed=src/main.rs");
    println!("cargo:rerun-if-changed=include/input.h");
    Ok(())
}

运行效果如下

引入V8

我这里使用V8 10版本,下载头文件和预构建包,

然后修改input.h。

#include "v8-headers/v8.h"

using namespace v8;

inline std::string version()
{
    return v8::V8::GetVersion();
}

然后build文件中添加相关信息

fn main() -> miette::Result<()> {
    let path = std::path::PathBuf::from("src");
    let header_path = std::path::PathBuf::from("include/v8-headers");
    let header_platform_path = std::path::PathBuf::from("include/v8-headers/libplatform");
    let link_path = std::path::PathBuf::from("v8/linux_x86-64/obj");
    let b =
        autocxx_build::Builder::new("src/main.rs", [&path, &header_path, &header_platform_path])
            .extra_clang_args(&["-std=c++17", "-Wc++17-extensions", "-Wunused-parameter"])
            .build()?;
    b.compile("rv8");

    println!("cargo:rustc-link-lib=v8_monolith");
    println!("cargo:rustc-link-search={}", link_path.display());
    println!("cargo:rerun-if-changed=src/main.rs");
    println!("cargo:rerun-if-changed=include/input.h");
    Ok(())
}

主要改动有几点

  • 路径中添加V8头文件路径
  • 开启C++ 17支持
  • link到预构建包

运行效果

其他使用方法类似,继续在input.h中添加就行了,比如需要执行脚本


inline std::string execute(std::string input)
{
    Isolate *isolate = Isolate::GetCurrent();
    HandleScope handle_scope(isolate);
    Local<Context> context = Context::New(isolate);
    Context::Scope context_scope(context);
    Local<v8::String> source = v8::String::NewFromUtf8(isolate, input.c_str()).ToLocalChecked();
    Local<Script> script = Script::Compile(context, source).ToLocalChecked();
    Local<Value> result = script->Run(context).ToLocalChecked();
    v8::String::Utf8Value utf8(isolate, result);
    return std::string(*utf8);
}

要最大发挥autocxx的功能,还可以直接将所有C++方法和类型都生成rust代码,然后手动封装一层。

参考

https://github.com/google/autocxx



本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2023/05/07/rust-call-cplusplus/

发表评论