在运行时使用 C,我可以:
- 创建函数的源代码,
- 调用 gcc 将其编译为 .so (Linux)(或使用 llvm 等),
- 加载.so,然后
- 调用函数。
在 Rust 中是否可能发生类似的事情?
特别是我想使用代数数据类型,所以使用 Rust 功能的 C 子集是不够的。
在运行时使用 C,我可以:
在 Rust 中是否可能发生类似的事情?
特别是我想使用代数数据类型,所以使用 Rust 功能的 C 子集是不够的。
还没有,正式的,虽然它至少应该是可能的,没有太多的黑客攻击。最大的障碍是这些库还没有任何动态加载的能力。这是使其工作的潜在策略(在 Rust 的传入分支上)。
#[no_mangle]
。这应该(我没有尝试过)产生一个未损坏的符号名称,因此很容易找到。sys::Closure
)。Rust 也有一个经过最低限度测试的 JIT 可以用于这种类型的事情,但它有一些主要的错误。
可能还有其他一些可能的解决方案,但是我最近使用了以下解决方案,并且它一直适用于我的特定要求。
希望它对您也有用,或者它可以为您提供更复杂和更强大的解决方案的起点。
main.rs
use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::process::Command;
use libloading::{Library, Symbol};
/// signature of function which should be called from plugin
type AddFunc = unsafe fn(isize, isize) -> isize;
/// Create a plugin file at runtime which will be converted to shared library
fn write_file() -> std::io::Result<()> {
let mut file = File::create("plugin.rs")?;
file.write_all(b"fn main() {\n")?;
file.write_all(b"\t#[no_mangle]\n")?;
file.write_all(b"\tpub extern \"C\" fn add(a: isize, b: isize) -> isize {\n")?;
file.write_all(b"\t\ta + b\n")?;
file.write_all(b"\t}\n")?;
file.write_all(b"}\n")?;
Ok(())
}
/// compile plugin code file to shared library
/// todo 1) should allow to pass file path.
/// 2) should return path to generated shared library
fn compile_file() {
let mut compile_file = Command::new("cmd");
compile_file.args(&["/C", "rustc", "--crate-type", "cdylib", "plugin.rs"]).status().expect("process failed to execute");
}
/// call function from shared library
/// todo suffix should be selected based on OS.
fn call_plugin(a: isize, b: isize) -> isize {
let lib = Library::new("plugin.dll").unwrap();
unsafe {
let func: Symbol<AddFunc> = lib.get(b"add").unwrap();
let answer = func(a, b);
answer
}
}
fn main(){
let args: Vec<String> = env::args().collect();
if args.len() == 3 {
write_file();
compile_file();
/// get argument from commandline to pass to function
let a: isize = args[1].trim().parse().expect("number required");
let b: isize = args[2].trim().parse().expect("number required");
println!("{}+{}:{}",a,b,call_plugin(a,b));
}
else {
println!("USAGE: main.exe NUM NUM");
}
}
货运.toml
[package]
name = "runtime_plugin"
version = "0.1.0"
authors = ["Manthan R Tilva"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libloading = "0.5.2"
您也可以在github中找到此代码