如何在Rust中运行编译的生锈代码

发布于 2025-02-02 05:02:00 字数 1399 浏览 5 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

貪欢 2025-02-09 05:02:00

如果您真的想要这样的东西(我怀疑),这里有两个非常丑陋的解决方案。

第一个生成一些源代码,对其进行编译以获取可执行文件,然后在另一个过程中运行可执行文件。

第二个生成一些源代码,对其进行编译以获取动态库,然后加载此库(作为插件)并访问生成的函数的符号,以便从当前过程中调用它。

所有这些都认为您可以在执行平台上使用Rust工具链。
名称是硬编码的,并且特定于我的平台(UNIX);为了适应各种平台,可能需要一些逻辑。
可以将临时目录用于源代码,可执行文件和库,以便以后清洁所有内容,但这是一个细节。

fn code_for_another_process() -> Result<(), Box<dyn std::error::Error>> {
    let exe_name = "./rust_prog";
    let code_name = "rust_prog.rs";
    let mut file = std::fs::File::create(code_name)?;
    use std::io::Write;
    file.write_all(
        "fn main() {\n\
             println!(\"in another process\");\n\
         }\n"
        .as_bytes(),
    )?;
    drop(file); // ensure file is closed
    let comp_status = std::process::Command::new("rustc")
        .arg(code_name)
        .status()?;
    if comp_status.success() {
        println!("~~~~ compilation of {} OK ~~~~", code_name);
        let run_status = std::process::Command::new(exe_name).status()?;
        if run_status.success() {
            println!("~~~~ execution of {} OK ~~~~", exe_name);
        }
    }
    Ok(())
}

fn code_for_this_process() -> Result<(), Box<dyn std::error::Error>> {
    let lib_name = "./librust_lib.so";
    let code_name = "rust_lib.rs";
    let mut file = std::fs::File::create(code_name)?;
    use std::io::Write;
    file.write_all(
        "#[no_mangle]\n\
        pub extern \"C\" fn call_me(arg: i32) -> i32 {\n\
             println!(\"called with {}\", arg);\n\
             arg*2
         }\n"
        .as_bytes(),
    )?;
    drop(file); // ensure file is closed
    let comp_status = std::process::Command::new("rustc")
        .arg("--crate-type")
        .arg("cdylib")
        .arg(code_name)
        .status()?;
    if comp_status.success() {
        println!("~~~~ compilation of {} OK ~~~~", code_name);
        unsafe {
            // requires dependency   libloading = "0.7"
            let lib = libloading::Library::new(lib_name)?;
            let call_me: libloading::Symbol<
                unsafe extern "C" fn(i32) -> i32,
            > = lib.get(b"call_me")?;
            for i in 0..5 {
                println!("--> {}", call_me(i));
            }
        }
    }
    Ok(())
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    code_for_another_process()?;
    code_for_this_process()?;
    Ok(())
}
/*
~~~~ compilation of rust_prog.rs OK ~~~~
in another process
~~~~ execution of ./rust_prog OK ~~~~
~~~~ compilation of rust_lib.rs OK ~~~~
called with 0
--> 0
called with 1
--> 2
called with 2
--> 4
called with 3
--> 6
called with 4
--> 8
*/

If you really want something like this (I doubt) here are two very ugly solutions.

The first one generates some source code, compiles it in order to obtain an executable, then runs the executable in another process.

The second one generates some source code, compiles it in order to obtain a dynamic library, then loads this library (as a plugin) and accesses the symbol of the generated function in order to call it from the current process.

All of this supposes that you can use a Rust toolchain on the execution platform.
The names are hardcoded and specific to my platform (UNIX); some logic may be needed in order to adapt to various platforms.
A temporary directory could be used for the source code, the executable and the library in order to clean everything afterwards, but this is a detail.

fn code_for_another_process() -> Result<(), Box<dyn std::error::Error>> {
    let exe_name = "./rust_prog";
    let code_name = "rust_prog.rs";
    let mut file = std::fs::File::create(code_name)?;
    use std::io::Write;
    file.write_all(
        "fn main() {\n\
             println!(\"in another process\");\n\
         }\n"
        .as_bytes(),
    )?;
    drop(file); // ensure file is closed
    let comp_status = std::process::Command::new("rustc")
        .arg(code_name)
        .status()?;
    if comp_status.success() {
        println!("~~~~ compilation of {} OK ~~~~", code_name);
        let run_status = std::process::Command::new(exe_name).status()?;
        if run_status.success() {
            println!("~~~~ execution of {} OK ~~~~", exe_name);
        }
    }
    Ok(())
}

fn code_for_this_process() -> Result<(), Box<dyn std::error::Error>> {
    let lib_name = "./librust_lib.so";
    let code_name = "rust_lib.rs";
    let mut file = std::fs::File::create(code_name)?;
    use std::io::Write;
    file.write_all(
        "#[no_mangle]\n\
        pub extern \"C\" fn call_me(arg: i32) -> i32 {\n\
             println!(\"called with {}\", arg);\n\
             arg*2
         }\n"
        .as_bytes(),
    )?;
    drop(file); // ensure file is closed
    let comp_status = std::process::Command::new("rustc")
        .arg("--crate-type")
        .arg("cdylib")
        .arg(code_name)
        .status()?;
    if comp_status.success() {
        println!("~~~~ compilation of {} OK ~~~~", code_name);
        unsafe {
            // requires dependency   libloading = "0.7"
            let lib = libloading::Library::new(lib_name)?;
            let call_me: libloading::Symbol<
                unsafe extern "C" fn(i32) -> i32,
            > = lib.get(b"call_me")?;
            for i in 0..5 {
                println!("--> {}", call_me(i));
            }
        }
    }
    Ok(())
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    code_for_another_process()?;
    code_for_this_process()?;
    Ok(())
}
/*
~~~~ compilation of rust_prog.rs OK ~~~~
in another process
~~~~ execution of ./rust_prog OK ~~~~
~~~~ compilation of rust_lib.rs OK ~~~~
called with 0
--> 0
called with 1
--> 2
called with 2
--> 4
called with 3
--> 6
called with 4
--> 8
*/
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文