R和Rust都可以与C代码接口,所以我认为这很有可能.但是,我对如何继续有点不清楚.
我已阅读这些部分寻找答案:
但是,虽然我精通,R但我不是一个系统程序员,并且对构建链看起来像这样的努力感到困惑.
使用Rinternals.h将是理想的,但我也会满足于更简单的.C界面.
我一直在努力争取这个问题,但是一旦你知道我实际上并不那么困难.
首先按照以下说明创建一个Rust库:rust-inside-other-languages.这是一个示例Rust库:
//src/lib.rs
#[no_mangle]
pub fn kelvin_to_fahrenheit(n: f64) -> f64 {
n * 9.0/5.0 - 459.67
}
Run Code Online (Sandbox Code Playgroud)
如果您按照其他语言生锈的说明进行操作,那么您应该能够生成*.so(*.dll或者.dylib,取决于您的系统).让我们假设这个编译过的文件被调用了libtempr.so.
现在创建一个C++文件,它将把你需要的函数传递给R:
//embed.cpp
extern "C" {
double kelvin_to_fahrenheit(double);
}
// [[Rcpp::export]]
double cpp_kelvin_to_fahrenheit(double k) {
double f = kelvin_to_fahrenheit(k);
return(f);
}
Run Code Online (Sandbox Code Playgroud)
现在,在启动R之前,请确保环境变量LD_LIBRARY_PATH包含libtempr.so存储先前生成的共享对象()的目录.在shell中执行:
$ export LD_LIBRARY_PATH=/home/sam/path/to/shared/object:$LD_LIBRARY_PATH
$ rstudio # I highly recommend using Rstudio for your R coding
Run Code Online (Sandbox Code Playgroud)
最后在Rstudo中,写下这个文件:
library(Rcpp)
Sys.setenv("PKG_LIBS"="-L/home/sam/path/to/shared/object -ltempr")
sourceCpp("/home/sam/path/to/embed.cpp", verbose = T, rebuild = T)
cpp_kelvin_to_fahrenheit(300)
Run Code Online (Sandbox Code Playgroud)
Sys.setenv该-L选项指向包含Rust共享对象的目录.-loption是没有lib前缀的共享对象的名称,也没有.so(或系统中的任何内容)后缀.Sys.setenv在R中使用设置LD_LIBRARY_PATH变量不工作.在开始R之前导出变量.verbose选项是有那么你可以看到什么Rcpp呢编译C++文件.请注意PKG_LIBS上面的选项如何用于编译C++文件.rebuild选项是有强制每次运行此行的R代码里面的时间重建C++文件.如果你做得很好,那么在交互式控制台中运行上面的R文件,80.33当你到达最后一行时它应该输出.
如果有任何不清楚的地方,请在评论中提问,我会尽力改善我的答案.
希望它有帮助:)
最后要注意,基函数dyn.load和.C可以被用作一个替代方法.但这需要编写比这种方法更多的样板包装代码.
如果 R 可以与 C 代码交互,那么从公开 C 风格函数的 Rust 代码编译共享库完全没有问题。
然后您就可以轻松使用您的库,因为它是用 C 或 C++ 编写的。当然,您将无法直接从 R 使用 Rust 对象和库,您必须创建适当的 C 接口来转换它们的函数。
以下是我如何为 SBCL 做到这一点,我想这对于 R 来说非常相似:
一些代码:
% cat experiment.rs
extern crate libc;
use libc::{c_int, c_char};
use std::{ffi, str};
#[no_mangle]
pub extern fn rust_code_string_to_int(s: *const c_char, r: *mut c_int) -> c_int {
let string = String::from_utf8_lossy(unsafe { ffi::CStr::from_ptr(s).to_bytes() });
match <isize as str::FromStr>::from_str(&*string) {
Ok(value) => { unsafe { *r = value as c_int }; 0 },
Err(_) => -1,
}
}
Run Code Online (Sandbox Code Playgroud)
然后我正在制作共享库:
% rustc --crate-type dylib experiment.rs
% nm -a libexperiment.dylib | grep rust_code_string_to_int
0000000000001630 t __ZN23rust_code_string_to_int10__rust_abiE
00000000000015e0 T _rust_code_string_to_int
Run Code Online (Sandbox Code Playgroud)
现在我只需加载我的共享库,然后我就可以访问我的rust_code_string_to_int函数:
RUST> (sb-alien:load-shared-object "libexperiment.dylib")
#P"libexperiment.dylib"
RUST> (sb-alien:with-alien ((result sb-alien:int 0))
(values (sb-alien:alien-funcall (sb-alien:extern-alien "rust_code_string_to_int"
(sb-alien:function sb-alien:int
(sb-alien:c-string :external-format :utf-8)
(sb-alien:* sb-alien:int)))
(sb-alien:make-alien-string "42")
(sb-alien:addr result))
result))
0
42
Run Code Online (Sandbox Code Playgroud)