在运行测试时防止未使用的静态函数被优化掉

har*_*mic 5 ffi llvm rust

我正在编写一个库,它将利用 LLVM(通过inkwell)来JIT 编译一些函数。这些函数需要能够回调到我的代码中的一些 rust 函数中。

我让它工作了,但我的单元测试不起作用,因为似乎在构建测试时回调函数被优化掉了。这些回调函数不会被 Rust 代码本身调用——只能被动态生成的 JIT 函数调用——所以我猜链接器认为它们没有被使用并删除它们。

如果我在单元测试中从 rust 代码中调用它们,那么它们不会被删除 - 但这不是一个理想的解决方法。另请注意,当包作为库构建时,函数不会被删除,只有在构建测试时才会删除。

下面是一个MVCE。

// lib.rs

use inkwell::{OptimizationLevel, context::Context};
use inkwell::execution_engine::JitFunction;

#[no_mangle]
pub extern "C" fn my_callback(x:i64) {
    println!("Called Back x={}", x);
}

type FuncType = unsafe extern "C" fn();

pub fn compile_fn() {
    let context = Context::create();
    let module = context.create_module("test");
    let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();
    let builder = context.create_builder();

    let func_type = context.void_type().fn_type(&[], false);
    let function = module.add_function("test", func_type, None);
    let basic_block = context.append_basic_block(function, "entry");
    builder.position_at_end(basic_block);

    let cb_fn_type = context.void_type().fn_type(&[context.i64_type().into()], false);
    let cb_fn = module.add_function("my_callback", cb_fn_type, None);
    let x = context.i64_type().const_int(42, false);
    builder.build_call(cb_fn, &[x.into()], "callback");
    builder.build_return(None);
    function.print_to_stderr();
    let jit_func:JitFunction<FuncType> = unsafe { execution_engine.get_function("test").unwrap() };
    unsafe { jit_func.call() };
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        // If I uncomment this line, it works, otherwise it segfaults
        //super::my_callback(1);
        super::compile_fn();
    }
}
Run Code Online (Sandbox Code Playgroud)
# Cargo.toml
[package]
name = "so_example_lib"
version = "0.1.0"
authors = ["harmic <harmic@no-reply.com>"]
edition = "2018"

[dependencies]
inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm7-0"] }
Run Code Online (Sandbox Code Playgroud)
# Cargo.toml
[package]
name = "so_example_lib"
version = "0.1.0"
authors = ["harmic <harmic@no-reply.com>"]
edition = "2018"

[dependencies]
inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm7-0"] }
Run Code Online (Sandbox Code Playgroud)

您可以通过nm在生成的测试二进制文件上运行来判断该函数已被删除。当您运行测试时,它会出现段错误。如果您在 gdb 中运行它,您可以看到它正在尝试调用0x0000000000000000.

#0  0x0000000000000000 in ?? ()
#1  0x00007ffff7ff201f in test ()
Run Code Online (Sandbox Code Playgroud)

如何指示 Rust 不要删除这些函数?