是否可以在运行时生成并执行Rust代码?
使用C,在运行时,我可以:是否可以在运行时生成并执行Rust代码?,rust,algebraic-data-types,Rust,Algebraic Data Types,使用C,在运行时,我可以: 创建函数的源代码 调用gcc将其编译为.so(Linux)(或使用llvm等) 加载。那么,和 调用函数 在锈病中也可能发生类似的情况吗 特别是我想使用代数数据类型,所以使用Rust特性的C子集是不够的。官方还没有,但至少在不太多黑客攻击的情况下应该是可能的。最大的障碍是这些库还没有进行动态加载的能力。 这里有一个潜在的策略使它工作(在Rust的传入分支上) 链接到rustc板条箱以编程方式驱动编译器。请注意,编译器不是线程安全的,因此一次只能运行一个进程内构建 用
特别是我想使用代数数据类型,所以使用Rust特性的C子集是不够的。官方还没有,但至少在不太多黑客攻击的情况下应该是可能的。最大的障碍是这些库还没有进行动态加载的能力。 这里有一个潜在的策略使它工作(在Rust的传入分支上)
- 链接到rustc板条箱以编程方式驱动编译器。请注意,编译器不是线程安全的,因此一次只能运行一个进程内构建
- 用
标记要调用的函数。这应该(我没有试过)产生一个不混合的符号名,这样就很容易找到#[no\u mangle]
- 创建到dlopen/dlsym的最小绑定
- 找到函数指针并将其安全地转换为Rust闭包类型(当前在
中定义)sys::closure
- 结束吧
Rust也有一个经过最低限度测试的JIT,可以用于这种类型的东西,但它有一些主要的bug。可能还有其他可能的解决方案,但是,我最近使用了下面的解决方案,它对于我的特定需求一直运行良好 希望它也能对您有所帮助,或者它能为您提供一个起点,帮助您找到更复杂、更健壮的解决方案 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");
}
}
您也可以在中找到此代码。此答案非常古老。同时情况发生了多大的变化?OP特别指出:我特别想使用代数数据类型,因此使用Rust特征的C子集是不够的(我的重点)。这个答案构建了一个cdylib,其中包含使用C ABI的函数。
[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"