我正在编写一个将利用 LLVM 的库(通过inkwell https://github.com/TheDan64/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();
}
}
# Cargo.toml
[package]
name = "so_example_lib"
version = "0.1.0"
authors = ["harmic <[email protected] /cdn-cgi/l/email-protection>"]
edition = "2018"
[dependencies]
inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm7-0"] }
// build.rs
fn main() {
println!("cargo:rustc-link-search=/usr/lib64/llvm7.0/lib");
println!("cargo:rustc-link-lib=LLVM-7");
}
您可以通过运行来判断该功能已被删除nm
在生成的测试二进制文件上。当您运行测试时,它会出现段错误。如果你在 gdb 中运行它,你可以看到它正在尝试调用一个函数0x0000000000000000
.
#0 0x0000000000000000 in ?? ()
#1 0x00007ffff7ff201f in test ()
我如何指示 Rust 不要删除这些函数?