我是一个相当新手的程序员,我遇到了一个我认为我理解但不知道如何修复的问题.我正在尝试使用Rust FFI与英特尔的DPDK进行交互,这完全在C中.我的第一次尝试是重新创建helloworld示例应用程序.
我正在达到一个编译错误,我认为这是由于DPDK的函数是静态的而不能直接从库中获得.我的FFI界面在这里:
use libc::{c_uint, c_int, c_void, c_char};
pub type LcoreFunctionT =
extern "C" fn(arg1: *mut c_void) -> c_int;
extern {
pub fn rte_eal_init(argc: c_int,
argv: *mut *mut c_char) -> c_int;
pub fn rte_eal_remote_launch(f: *mut LcoreFunctionT,
arg: *mut c_void,
slave_id: c_uint) -> c_int;
pub fn rte_eal_mp_wait_lcore() -> ();
pub fn rte_lcore_id() -> c_uint;
pub fn rte_get_next_lcore(i: c_uint,
skip_master: c_int,
wrap: c_int) -> c_uint;
}
Run Code Online (Sandbox Code Playgroud)
我还有一个引用它的库并包装函数:
extern crate libc;
use libc::{c_uint, c_int, c_char, c_void};
use std::ffi::CString;
use std::ptr;
mod ffi_rte_eal;
pub fn dpdk_rte_eal_init(argc: i32, argv: Vec<String>) -> i32 {
let mut args: Vec<*mut c_char> =
argv.iter().map(|x| CString::new(x.clone()).unwrap().into_raw()).collect();
let retc: c_int = unsafe {ffi_rte_eal::rte_eal_init(argc as c_int, args.as_mut_ptr())};
let ret: i32 = retc as i32;
ret
}
pub fn dpdk_rte_eal_remote_launch(f: extern "C" fn(*mut c_void) -> i32,
slave_id: u32 ) -> i32 {
let mut fc: ffi_rte_eal::LcoreFunctionT = f;
let retc: c_int = unsafe {ffi_rte_eal::rte_eal_remote_launch(&mut fc,
ptr::null_mut() as *mut c_void,
slave_id as c_uint)};
let ret: i32 = retc as i32;
ret
}
pub fn dpdk_rte_eal_mp_wait_lcore() -> (){
unsafe {
ffi_rte_eal::rte_eal_mp_wait_lcore();
}
}
pub fn dpdk_rte_lcore_id() -> u32 {
let retc: c_uint = unsafe {ffi_rte_eal::rte_lcore_id()};
let ret: u32 = retc as u32;
ret
}
pub fn dpdk_rte_get_next_lcore(i: u32,
skip_master: i32,
wrap: i32) -> u32 {
let retc: c_uint = unsafe {ffi_rte_eal::rte_get_next_lcore(i as c_uint,
skip_master as c_int,
wrap as c_int)};
let ret: u32 = retc as u32;
ret
}
Run Code Online (Sandbox Code Playgroud)
以及用于链接库的build.rs文件 -
//build.rs
fn main() {
println!("cargo:rustc-link-lib=static=rte_eal");
println!("cargo:rustc-link-search=native=/usr/local/lib");
println!("cargo:rustc-link-lib=static=rte_mempool");
println!("cargo:rustc-link-search=native=/usr/local/lib");
println!("cargo:rustc-link-lib=static=rte_ring");
println!("cargo:rustc-link-search=native=/usr/local/lib");
}
Run Code Online (Sandbox Code Playgroud)
当我尝试编译我自己对FFI接口应用,我把即将未定义的引用收到错误rte_lcore_id和rte_get_next_lcore.根据DPDK的API文档,这些函数是librte_eal库的一部分,但在rte_lcore.h中定义为静态函数.我假设这些是静态函数,我将无法从Rust中看到它们.
在与DPDK捆绑在一起的helloworld示例应用程序中,它们直接导入rte_lcore.h.我认为这就是为什么他们可以在不引用librte_eal的情况下访问这些功能?
是否有一种方法可以在Rust中访问它,或者在C中是否需要像垫片这样的东西来包装这些函数并通过FFI使它们可用?
如您所见,如果打开相应的头文件,则会直接在那里声明这些函数.这意味着这些函数将包含在包含此标头的每个 .c/.cpp文件中,但由于它们是static,链接器不会为它们创建符号,因此它们实际上不存在于库的编译版本中.这里描述了为什么需要这样做,但遗憾的是这种设计对FFI不是很友好.
你可以做的是创建一个存根C库,它包含完全相同的函数,这些函数从头部委托给静态函数,但它们本身不是静态的.像这样:
#include <rte_lcore.h>
unsigned my_rte_lcore_count(void) {
return rte_lcore_count();
}
// and so forth for every function you need
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用自定义编写的Makefile或Cargo构建脚本将此存根文件编译为静态库,并将最终程序链接到该文件.那么,当然,您应该在extern块中编写这些函数,而不是原始函数:
extern {
fn my_rte_lcore_count() -> libc::c_uint;
}
Run Code Online (Sandbox Code Playgroud)
我认为没有更简单,更正确的方法.
更新:哦,我没有注意到你在问题中的最后一句话.是的,你是对的,写这样的垫片是正确的方法.